Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_WhiteRectangleDetector.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_WhiteRectangleDetector.h"\r
9 #include "include/BC_CommonBitMatrix.h"\r
10 #include "include/BC_ResultPoint.h"\r
11 const FX_INT32 CBC_WhiteRectangleDetector::INIT_SIZE = 30;\r
12 const FX_INT32 CBC_WhiteRectangleDetector::CORR = 1;\r
13 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector(CBC_CommonBitMatrix *image)\r
14 {\r
15     m_image = image;\r
16     m_height = image->GetHeight();\r
17     m_width = image->GetWidth();\r
18     m_leftInit = (m_width - INIT_SIZE) >> 1;\r
19     m_rightInit = (m_width + INIT_SIZE) >> 1;\r
20     m_upInit = (m_height - INIT_SIZE) >> 1;\r
21     m_downInit = (m_height + INIT_SIZE) >> 1;\r
22 }\r
23 void CBC_WhiteRectangleDetector::Init(FX_INT32 &e)\r
24 {\r
25     if (m_upInit < 0 || m_leftInit < 0 || m_downInit >= m_height || m_rightInit >= m_width) {\r
26         e = BCExceptionNotFound;\r
27         BC_EXCEPTION_CHECK_ReturnVoid(e);\r
28     }\r
29 }\r
30 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector(CBC_CommonBitMatrix *image, FX_INT32 initSize, FX_INT32 x, FX_INT32 y)\r
31 {\r
32     m_image = image;\r
33     m_height = image->GetHeight();\r
34     m_width = image->GetWidth();\r
35     FX_INT32 halfsize = initSize >> 1;\r
36     m_leftInit = x - halfsize;\r
37     m_rightInit = x + halfsize;\r
38     m_upInit = y - halfsize;\r
39     m_downInit = y + halfsize;\r
40 }\r
41 CBC_WhiteRectangleDetector::~CBC_WhiteRectangleDetector()\r
42 {\r
43 }\r
44 CFX_PtrArray *CBC_WhiteRectangleDetector::Detect(FX_INT32 &e)\r
45 {\r
46     FX_INT32 left = m_leftInit;\r
47     FX_INT32 right = m_rightInit;\r
48     FX_INT32 up = m_upInit;\r
49     FX_INT32 down = m_downInit;\r
50     FX_BOOL sizeExceeded = FALSE;\r
51     FX_BOOL aBlackPointFoundOnBorder = TRUE;\r
52     FX_BOOL atLeastOneBlackPointFoundOnBorder = FALSE;\r
53     while (aBlackPointFoundOnBorder) {\r
54         aBlackPointFoundOnBorder = FALSE;\r
55         FX_BOOL rightBorderNotWhite = TRUE;\r
56         while (rightBorderNotWhite && right < m_width) {\r
57             rightBorderNotWhite = ContainsBlackPoint(up, down, right, FALSE);\r
58             if (rightBorderNotWhite) {\r
59                 right++;\r
60                 aBlackPointFoundOnBorder = TRUE;\r
61             }\r
62         }\r
63         if (right >= m_width) {\r
64             sizeExceeded = TRUE;\r
65             break;\r
66         }\r
67         FX_BOOL bottomBorderNotWhite = TRUE;\r
68         while (bottomBorderNotWhite && down < m_height) {\r
69             bottomBorderNotWhite = ContainsBlackPoint(left, right, down, TRUE);\r
70             if (bottomBorderNotWhite) {\r
71                 down++;\r
72                 aBlackPointFoundOnBorder = TRUE;\r
73             }\r
74         }\r
75         if (down >= m_height) {\r
76             sizeExceeded = TRUE;\r
77             break;\r
78         }\r
79         FX_BOOL leftBorderNotWhite = TRUE;\r
80         while (leftBorderNotWhite && left >= 0) {\r
81             leftBorderNotWhite = ContainsBlackPoint(up, down, left, FALSE);\r
82             if (leftBorderNotWhite) {\r
83                 left--;\r
84                 aBlackPointFoundOnBorder = TRUE;\r
85             }\r
86         }\r
87         if (left < 0) {\r
88             sizeExceeded = TRUE;\r
89             break;\r
90         }\r
91         FX_BOOL topBorderNotWhite = TRUE;\r
92         while (topBorderNotWhite && up >= 0) {\r
93             topBorderNotWhite = ContainsBlackPoint(left, right, up, TRUE);\r
94             if (topBorderNotWhite) {\r
95                 up--;\r
96                 aBlackPointFoundOnBorder = TRUE;\r
97             }\r
98         }\r
99         if (up < 0) {\r
100             sizeExceeded = TRUE;\r
101             break;\r
102         }\r
103         if (aBlackPointFoundOnBorder) {\r
104             atLeastOneBlackPointFoundOnBorder = TRUE;\r
105         }\r
106     }\r
107     if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {\r
108         FX_INT32 maxSize = right - left;\r
109         CBC_AutoPtr<CBC_ResultPoint> z(NULL);\r
110         for (FX_INT32 i = 1; i < maxSize; i++) {\r
111             z = CBC_AutoPtr<CBC_ResultPoint>(GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(down - i), (FX_FLOAT)(left + i), (FX_FLOAT)(down)) );\r
112             if (z.get() != NULL) {\r
113                 break;\r
114             }\r
115         }\r
116         if (z.get() == NULL) {\r
117             e = BCExceptionNotFound;\r
118             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
119         }\r
120         CBC_AutoPtr<CBC_ResultPoint> t(NULL);\r
121         for (FX_INT32 j = 1; j < maxSize; j++) {\r
122             t = CBC_AutoPtr<CBC_ResultPoint>(GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(up + j), (FX_FLOAT)(left + j), (FX_FLOAT)up));\r
123             if (t.get() != NULL) {\r
124                 break;\r
125             }\r
126         }\r
127         if (t.get() == NULL) {\r
128             e = BCExceptionNotFound;\r
129             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
130         }\r
131         CBC_AutoPtr<CBC_ResultPoint> x(NULL);\r
132         for (FX_INT32 k = 1; k < maxSize; k++) {\r
133             x = CBC_AutoPtr<CBC_ResultPoint>(GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(up + k), (FX_FLOAT)(right - k), (FX_FLOAT)up));\r
134             if (x.get() != NULL) {\r
135                 break;\r
136             }\r
137         }\r
138         if (x.get() == NULL) {\r
139             e = BCExceptionNotFound;\r
140             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
141         }\r
142         CBC_AutoPtr<CBC_ResultPoint> y(NULL);\r
143         for (FX_INT32 m = 1;    m < maxSize; m++) {\r
144             y = CBC_AutoPtr<CBC_ResultPoint>(GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(down - m), (FX_FLOAT)(right - m), (FX_FLOAT) down));\r
145             if (y.get() != NULL) {\r
146                 break;\r
147             }\r
148         }\r
149         if (y.get() == NULL) {\r
150             e = BCExceptionNotFound;\r
151             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
152         }\r
153         return CenterEdges(y.get(), z.get(), x.get(), t.get());\r
154     } else {\r
155         e = BCExceptionNotFound;\r
156         BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
157     }\r
158     return NULL;\r
159 }\r
160 FX_INT32 CBC_WhiteRectangleDetector::Round(FX_FLOAT d)\r
161 {\r
162     return (FX_INT32) (d + 0.5f);\r
163 }\r
164 CBC_ResultPoint *CBC_WhiteRectangleDetector::GetBlackPointOnSegment(FX_FLOAT aX, FX_FLOAT aY, FX_FLOAT bX, FX_FLOAT bY)\r
165 {\r
166     FX_INT32 dist = DistanceL2(aX, aY, bX, bY);\r
167     float xStep = (bX - aX) / dist;\r
168     float yStep = (bY - aY) / dist;\r
169     for (FX_INT32 i = 0; i < dist; i++) {\r
170         FX_INT32 x = Round(aX + i * xStep);\r
171         FX_INT32 y = Round(aY + i * yStep);\r
172         if (m_image->Get(x, y)) {\r
173             return FX_NEW CBC_ResultPoint((FX_FLOAT)x, (FX_FLOAT) y);\r
174         }\r
175     }\r
176     return NULL;\r
177 }\r
178 FX_INT32 CBC_WhiteRectangleDetector::DistanceL2(FX_FLOAT aX, FX_FLOAT aY, FX_FLOAT bX, FX_FLOAT bY)\r
179 {\r
180     float xDiff = aX - bX;\r
181     float yDiff = aY - bY;\r
182     return Round((float)sqrt(xDiff * xDiff + yDiff * yDiff));\r
183 }\r
184 CFX_PtrArray *CBC_WhiteRectangleDetector::CenterEdges(CBC_ResultPoint *y, CBC_ResultPoint *z, CBC_ResultPoint *x, CBC_ResultPoint *t)\r
185 {\r
186     float yi = y->GetX();\r
187     float yj = y->GetY();\r
188     float zi = z->GetX();\r
189     float zj = z->GetY();\r
190     float xi = x->GetX();\r
191     float xj = x->GetY();\r
192     float ti = t->GetX();\r
193     float tj = t->GetY();\r
194     if (yi < m_width / 2) {\r
195         CFX_PtrArray *result = FX_NEW CFX_PtrArray;\r
196         result->SetSize(4);\r
197         (*result)[0] = FX_NEW CBC_ResultPoint(ti - CORR, tj + CORR);\r
198         (*result)[1] = FX_NEW CBC_ResultPoint(zi + CORR, zj + CORR);\r
199         (*result)[2] = FX_NEW CBC_ResultPoint(xi - CORR, xj - CORR);\r
200         (*result)[3] = FX_NEW CBC_ResultPoint(yi + CORR, yj - CORR);\r
201         return result;\r
202     } else {\r
203         CFX_PtrArray *result = FX_NEW CFX_PtrArray;\r
204         result->SetSize(4);\r
205         (*result)[0] = FX_NEW CBC_ResultPoint(ti + CORR, tj + CORR);\r
206         (*result)[1] = FX_NEW CBC_ResultPoint(zi + CORR, zj - CORR);\r
207         (*result)[2] = FX_NEW CBC_ResultPoint(xi - CORR, xj + CORR);\r
208         (*result)[3] = FX_NEW CBC_ResultPoint(yi - CORR, yj - CORR);\r
209         return result;\r
210     }\r
211 }\r
212 FX_BOOL CBC_WhiteRectangleDetector::ContainsBlackPoint(FX_INT32 a, FX_INT32 b, FX_INT32 fixed, FX_BOOL horizontal)\r
213 {\r
214     if (horizontal) {\r
215         for (FX_INT32 x = a; x <= b; x++) {\r
216             if (m_image->Get(x, fixed)) {\r
217                 return TRUE;\r
218             }\r
219         }\r
220     } else {\r
221         for (FX_INT32 y = a; y <= b; y++) {\r
222             if (m_image->Get(fixed, y)) {\r
223                 return TRUE;\r
224             }\r
225         }\r
226     }\r
227     return FALSE;\r
228 }\r