1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 // Original code is licensed as follows:
7 /*
8 * Copyright 2010 ZXing authors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #include "xfa/src/fxbarcode/barcode.h"
24 #include "xfa/src/fxbarcode/common/BC_WhiteRectangleDetector.h"
25 #include "xfa/src/fxbarcode/common/BC_CommonBitMatrix.h"
26 #include "xfa/src/fxbarcode/BC_ResultPoint.h"
27 const int32_t CBC_WhiteRectangleDetector::INIT_SIZE = 30;
28 const int32_t CBC_WhiteRectangleDetector::CORR = 1;
CBC_WhiteRectangleDetector(CBC_CommonBitMatrix * image)29 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector(
30 CBC_CommonBitMatrix* image) {
31 m_image = image;
32 m_height = image->GetHeight();
33 m_width = image->GetWidth();
34 m_leftInit = (m_width - INIT_SIZE) >> 1;
35 m_rightInit = (m_width + INIT_SIZE) >> 1;
36 m_upInit = (m_height - INIT_SIZE) >> 1;
37 m_downInit = (m_height + INIT_SIZE) >> 1;
38 }
Init(int32_t & e)39 void CBC_WhiteRectangleDetector::Init(int32_t& e) {
40 if (m_upInit < 0 || m_leftInit < 0 || m_downInit >= m_height ||
41 m_rightInit >= m_width) {
42 e = BCExceptionNotFound;
43 BC_EXCEPTION_CHECK_ReturnVoid(e);
44 }
45 }
CBC_WhiteRectangleDetector(CBC_CommonBitMatrix * image,int32_t initSize,int32_t x,int32_t y)46 CBC_WhiteRectangleDetector::CBC_WhiteRectangleDetector(
47 CBC_CommonBitMatrix* image,
48 int32_t initSize,
49 int32_t x,
50 int32_t y) {
51 m_image = image;
52 m_height = image->GetHeight();
53 m_width = image->GetWidth();
54 int32_t halfsize = initSize >> 1;
55 m_leftInit = x - halfsize;
56 m_rightInit = x + halfsize;
57 m_upInit = y - halfsize;
58 m_downInit = y + halfsize;
59 }
~CBC_WhiteRectangleDetector()60 CBC_WhiteRectangleDetector::~CBC_WhiteRectangleDetector() {}
Detect(int32_t & e)61 CFX_PtrArray* CBC_WhiteRectangleDetector::Detect(int32_t& e) {
62 int32_t left = m_leftInit;
63 int32_t right = m_rightInit;
64 int32_t up = m_upInit;
65 int32_t down = m_downInit;
66 FX_BOOL sizeExceeded = FALSE;
67 FX_BOOL aBlackPointFoundOnBorder = TRUE;
68 FX_BOOL atLeastOneBlackPointFoundOnBorder = FALSE;
69 while (aBlackPointFoundOnBorder) {
70 aBlackPointFoundOnBorder = FALSE;
71 FX_BOOL rightBorderNotWhite = TRUE;
72 while (rightBorderNotWhite && right < m_width) {
73 rightBorderNotWhite = ContainsBlackPoint(up, down, right, FALSE);
74 if (rightBorderNotWhite) {
75 right++;
76 aBlackPointFoundOnBorder = TRUE;
77 }
78 }
79 if (right >= m_width) {
80 sizeExceeded = TRUE;
81 break;
82 }
83 FX_BOOL bottomBorderNotWhite = TRUE;
84 while (bottomBorderNotWhite && down < m_height) {
85 bottomBorderNotWhite = ContainsBlackPoint(left, right, down, TRUE);
86 if (bottomBorderNotWhite) {
87 down++;
88 aBlackPointFoundOnBorder = TRUE;
89 }
90 }
91 if (down >= m_height) {
92 sizeExceeded = TRUE;
93 break;
94 }
95 FX_BOOL leftBorderNotWhite = TRUE;
96 while (leftBorderNotWhite && left >= 0) {
97 leftBorderNotWhite = ContainsBlackPoint(up, down, left, FALSE);
98 if (leftBorderNotWhite) {
99 left--;
100 aBlackPointFoundOnBorder = TRUE;
101 }
102 }
103 if (left < 0) {
104 sizeExceeded = TRUE;
105 break;
106 }
107 FX_BOOL topBorderNotWhite = TRUE;
108 while (topBorderNotWhite && up >= 0) {
109 topBorderNotWhite = ContainsBlackPoint(left, right, up, TRUE);
110 if (topBorderNotWhite) {
111 up--;
112 aBlackPointFoundOnBorder = TRUE;
113 }
114 }
115 if (up < 0) {
116 sizeExceeded = TRUE;
117 break;
118 }
119 if (aBlackPointFoundOnBorder) {
120 atLeastOneBlackPointFoundOnBorder = TRUE;
121 }
122 }
123 if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) {
124 int32_t maxSize = right - left;
125 CBC_AutoPtr<CBC_ResultPoint> z(NULL);
126 for (int32_t i = 1; i < maxSize; i++) {
127 z = CBC_AutoPtr<CBC_ResultPoint>(
128 GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(down - i),
129 (FX_FLOAT)(left + i), (FX_FLOAT)(down)));
130 if (z.get() != NULL) {
131 break;
132 }
133 }
134 if (z.get() == NULL) {
135 e = BCExceptionNotFound;
136 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
137 }
138 CBC_AutoPtr<CBC_ResultPoint> t(NULL);
139 for (int32_t j = 1; j < maxSize; j++) {
140 t = CBC_AutoPtr<CBC_ResultPoint>(
141 GetBlackPointOnSegment((FX_FLOAT)left, (FX_FLOAT)(up + j),
142 (FX_FLOAT)(left + j), (FX_FLOAT)up));
143 if (t.get() != NULL) {
144 break;
145 }
146 }
147 if (t.get() == NULL) {
148 e = BCExceptionNotFound;
149 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
150 }
151 CBC_AutoPtr<CBC_ResultPoint> x(NULL);
152 for (int32_t k = 1; k < maxSize; k++) {
153 x = CBC_AutoPtr<CBC_ResultPoint>(
154 GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(up + k),
155 (FX_FLOAT)(right - k), (FX_FLOAT)up));
156 if (x.get() != NULL) {
157 break;
158 }
159 }
160 if (x.get() == NULL) {
161 e = BCExceptionNotFound;
162 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
163 }
164 CBC_AutoPtr<CBC_ResultPoint> y(NULL);
165 for (int32_t m = 1; m < maxSize; m++) {
166 y = CBC_AutoPtr<CBC_ResultPoint>(
167 GetBlackPointOnSegment((FX_FLOAT)right, (FX_FLOAT)(down - m),
168 (FX_FLOAT)(right - m), (FX_FLOAT)down));
169 if (y.get() != NULL) {
170 break;
171 }
172 }
173 if (y.get() == NULL) {
174 e = BCExceptionNotFound;
175 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
176 }
177 return CenterEdges(y.get(), z.get(), x.get(), t.get());
178 } else {
179 e = BCExceptionNotFound;
180 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
181 }
182 return NULL;
183 }
Round(FX_FLOAT d)184 int32_t CBC_WhiteRectangleDetector::Round(FX_FLOAT d) {
185 return (int32_t)(d + 0.5f);
186 }
GetBlackPointOnSegment(FX_FLOAT aX,FX_FLOAT aY,FX_FLOAT bX,FX_FLOAT bY)187 CBC_ResultPoint* CBC_WhiteRectangleDetector::GetBlackPointOnSegment(
188 FX_FLOAT aX,
189 FX_FLOAT aY,
190 FX_FLOAT bX,
191 FX_FLOAT bY) {
192 int32_t dist = DistanceL2(aX, aY, bX, bY);
193 float xStep = (bX - aX) / dist;
194 float yStep = (bY - aY) / dist;
195 for (int32_t i = 0; i < dist; i++) {
196 int32_t x = Round(aX + i * xStep);
197 int32_t y = Round(aY + i * yStep);
198 if (m_image->Get(x, y)) {
199 return new CBC_ResultPoint((FX_FLOAT)x, (FX_FLOAT)y);
200 }
201 }
202 return NULL;
203 }
DistanceL2(FX_FLOAT aX,FX_FLOAT aY,FX_FLOAT bX,FX_FLOAT bY)204 int32_t CBC_WhiteRectangleDetector::DistanceL2(FX_FLOAT aX,
205 FX_FLOAT aY,
206 FX_FLOAT bX,
207 FX_FLOAT bY) {
208 float xDiff = aX - bX;
209 float yDiff = aY - bY;
210 return Round((float)sqrt(xDiff * xDiff + yDiff * yDiff));
211 }
CenterEdges(CBC_ResultPoint * y,CBC_ResultPoint * z,CBC_ResultPoint * x,CBC_ResultPoint * t)212 CFX_PtrArray* CBC_WhiteRectangleDetector::CenterEdges(CBC_ResultPoint* y,
213 CBC_ResultPoint* z,
214 CBC_ResultPoint* x,
215 CBC_ResultPoint* t) {
216 float yi = y->GetX();
217 float yj = y->GetY();
218 float zi = z->GetX();
219 float zj = z->GetY();
220 float xi = x->GetX();
221 float xj = x->GetY();
222 float ti = t->GetX();
223 float tj = t->GetY();
224 if (yi < m_width / 2) {
225 CFX_PtrArray* result = new CFX_PtrArray;
226 result->SetSize(4);
227 (*result)[0] = new CBC_ResultPoint(ti - CORR, tj + CORR);
228 (*result)[1] = new CBC_ResultPoint(zi + CORR, zj + CORR);
229 (*result)[2] = new CBC_ResultPoint(xi - CORR, xj - CORR);
230 (*result)[3] = new CBC_ResultPoint(yi + CORR, yj - CORR);
231 return result;
232 } else {
233 CFX_PtrArray* result = new CFX_PtrArray;
234 result->SetSize(4);
235 (*result)[0] = new CBC_ResultPoint(ti + CORR, tj + CORR);
236 (*result)[1] = new CBC_ResultPoint(zi + CORR, zj - CORR);
237 (*result)[2] = new CBC_ResultPoint(xi - CORR, xj + CORR);
238 (*result)[3] = new CBC_ResultPoint(yi - CORR, yj - CORR);
239 return result;
240 }
241 }
ContainsBlackPoint(int32_t a,int32_t b,int32_t fixed,FX_BOOL horizontal)242 FX_BOOL CBC_WhiteRectangleDetector::ContainsBlackPoint(int32_t a,
243 int32_t b,
244 int32_t fixed,
245 FX_BOOL horizontal) {
246 if (horizontal) {
247 for (int32_t x = a; x <= b; x++) {
248 if (m_image->Get(x, fixed)) {
249 return TRUE;
250 }
251 }
252 } else {
253 for (int32_t y = a; y <= b; y++) {
254 if (m_image->Get(fixed, y)) {
255 return TRUE;
256 }
257 }
258 }
259 return FALSE;
260 }
261