Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_QRAlignmentPatternFinder.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "barcode.h"\r
8 #include "include/BC_ResultPoint.h"\r
9 #include "include/BC_QRAlignmentPattern.h"\r
10 #include "include/BC_QRAlignmentPatternFinder.h"\r
11 #include "include/BC_CommonBitMatrix.h"\r
12 CBC_QRAlignmentPatternFinder::CBC_QRAlignmentPatternFinder(CBC_CommonBitMatrix *image,\r
13         FX_INT32 startX,\r
14         FX_INT32 startY,\r
15         FX_INT32 width,\r
16         FX_INT32 height,\r
17         FX_FLOAT moduleSize): m_image(image),\r
18     m_startX(startX),\r
19     m_startY(startY),\r
20     m_width(width),\r
21     m_height(height),\r
22     m_moduleSize(moduleSize)\r
23 \r
24 {\r
25     m_crossCheckStateCount.SetSize(3);\r
26 }\r
27 CBC_QRAlignmentPatternFinder::~CBC_QRAlignmentPatternFinder()\r
28 {\r
29     for (FX_INT32 i = 0; i < m_possibleCenters.GetSize(); i++) {\r
30         delete (CBC_QRAlignmentPattern*)m_possibleCenters[i];\r
31     }\r
32     m_possibleCenters.RemoveAll();\r
33 }\r
34 CBC_QRAlignmentPattern  *CBC_QRAlignmentPatternFinder::Find(FX_INT32 &e)\r
35 {\r
36     FX_INT32 startX = m_startX;\r
37     FX_INT32 height = m_height;\r
38     FX_INT32 maxJ = startX + m_width;\r
39     FX_INT32 middleI = m_startY + (height >> 1);\r
40     CFX_Int32Array stateCount;\r
41     stateCount.SetSize(3);\r
42     for (FX_INT32 iGen = 0; iGen < height; iGen++) {\r
43         FX_INT32 i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));\r
44         stateCount[0] = 0;\r
45         stateCount[1] = 0;\r
46         stateCount[2] = 0;\r
47         FX_INT32 j = startX;\r
48         while (j < maxJ && !m_image->Get(j, i)) {\r
49             j++;\r
50         }\r
51         FX_INT32 currentState = 0;\r
52         while (j < maxJ) {\r
53             if (m_image->Get(j, i)) {\r
54                 if (currentState == 1) {\r
55                     stateCount[currentState]++;\r
56                 } else {\r
57                     if (currentState == 2) {\r
58                         if (FoundPatternCross(stateCount)) {\r
59                             CBC_QRAlignmentPattern  *confirmed = HandlePossibleCenter(stateCount, i, j);\r
60                             if (confirmed != NULL) {\r
61                                 return confirmed;\r
62                             }\r
63                         }\r
64                         stateCount[0] = stateCount[2];\r
65                         stateCount[1] = 1;\r
66                         stateCount[2] = 0;\r
67                         currentState = 1;\r
68                     } else {\r
69                         stateCount[++currentState]++;\r
70                     }\r
71                 }\r
72             } else {\r
73                 if (currentState == 1) {\r
74                     currentState++;\r
75                 }\r
76                 stateCount[currentState]++;\r
77             }\r
78             j++;\r
79         }\r
80         if (FoundPatternCross(stateCount)) {\r
81             CBC_QRAlignmentPattern *confirmed = HandlePossibleCenter(stateCount, i, maxJ);\r
82             if (confirmed != NULL) {\r
83                 return confirmed;\r
84             }\r
85         }\r
86     }\r
87     if (m_possibleCenters.GetSize() != 0) {\r
88         return  ((CBC_QRAlignmentPattern*) (m_possibleCenters[0]) )->Clone();\r
89     }\r
90     e = BCExceptionRead;\r
91     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
92     return NULL;\r
93 }\r
94 FX_FLOAT CBC_QRAlignmentPatternFinder::CenterFromEnd(const CFX_Int32Array &stateCount, FX_INT32 end)\r
95 {\r
96     return (FX_FLOAT) (end - stateCount[2]) - stateCount[1] / 2.0f;\r
97 }\r
98 FX_BOOL CBC_QRAlignmentPatternFinder::FoundPatternCross(const CFX_Int32Array &stateCount)\r
99 {\r
100     FX_FLOAT moduleSize = m_moduleSize;\r
101     FX_FLOAT maxVariance = moduleSize / 2.0f;\r
102     for (FX_INT32 i = 0; i < 3; i++) {\r
103         if (fabs(moduleSize - stateCount[i]) >= maxVariance) {\r
104             return false;\r
105         }\r
106     }\r
107     return TRUE;\r
108 }\r
109 FX_FLOAT CBC_QRAlignmentPatternFinder::CrossCheckVertical(FX_INT32 startI, FX_INT32 centerJ, FX_INT32 maxCount, FX_INT32 originalStateCountTotal)\r
110 {\r
111     CBC_CommonBitMatrix *image = m_image;\r
112     FX_INT32 maxI = m_image->GetHeight();\r
113     CFX_Int32Array stateCount;\r
114     stateCount.Copy(m_crossCheckStateCount);\r
115     stateCount[0] = 0;\r
116     stateCount[1] = 0;\r
117     stateCount[2] = 0;\r
118     FX_INT32 i = startI;\r
119     while (i >= 0 && m_image->Get(centerJ, i) && stateCount[1] <= maxCount) {\r
120         stateCount[1]++;\r
121         i--;\r
122     }\r
123     if (i < 0 || stateCount[1] > maxCount) {\r
124         return FXSYS_nan();\r
125     }\r
126     while (i >= 0 && !m_image->Get(centerJ, i) && stateCount[0] <= maxCount) {\r
127         stateCount[0]++;\r
128         i--;\r
129     }\r
130     if (stateCount[0] > maxCount) {\r
131         return FXSYS_nan();\r
132     }\r
133     i = startI + 1;\r
134     while (i < maxI && m_image->Get(centerJ, i) && stateCount[1] <= maxCount) {\r
135         stateCount[1]++;\r
136         i++;\r
137     }\r
138     if (i == maxI || stateCount[1] > maxCount) {\r
139         return FXSYS_nan();\r
140     }\r
141     while (i < maxI && !m_image->Get(centerJ, i) && stateCount[2] <= maxCount) {\r
142         stateCount[2]++;\r
143         i++;\r
144     }\r
145     if (stateCount[2] > maxCount) {\r
146         return FXSYS_nan();\r
147     }\r
148     FX_INT32 stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];\r
149     if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {\r
150         return FXSYS_nan();\r
151     }\r
152     return FoundPatternCross(stateCount) ? CenterFromEnd(stateCount, i) : FXSYS_nan();\r
153 }\r
154 CBC_QRAlignmentPattern *CBC_QRAlignmentPatternFinder::HandlePossibleCenter(const CFX_Int32Array &stateCount, FX_INT32 i, FX_INT32 j)\r
155 {\r
156     FX_INT32 stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];\r
157     FX_FLOAT centerJ = CenterFromEnd(stateCount, j);\r
158     FX_FLOAT centerI = CrossCheckVertical(i, (FX_INT32) centerJ, 2 * stateCount[1], stateCountTotal);\r
159     if (!FXSYS_isnan(centerI)) {\r
160         FX_FLOAT estimatedModuleSize = (FX_FLOAT) (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f;\r
161         FX_INT32 max = m_possibleCenters.GetSize();\r
162         for (FX_INT32 index = 0; index < max; index++) {\r
163             CBC_QRAlignmentPattern *center = (CBC_QRAlignmentPattern *)(m_possibleCenters[index]);\r
164             if (center->AboutEquals(estimatedModuleSize, centerI, centerJ)) {\r
165                 return FX_NEW CBC_QRAlignmentPattern(centerJ, centerI, estimatedModuleSize);\r
166             }\r
167         }\r
168         m_possibleCenters.Add(FX_NEW CBC_QRAlignmentPattern(centerJ, centerI, estimatedModuleSize));\r
169     }\r
170     return NULL;\r
171 }\r