OLD | NEW |
| (Empty) |
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 2007 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 "barcode.h" | |
24 #include "include/BC_CommonBitMatrix.h" | |
25 #include "include/BC_ResultPoint.h" | |
26 #include "include/BC_QRFinderPattern.h" | |
27 #include "include/BC_QRCoderVersion.h" | |
28 #include "include/BC_FinderPatternInfo.h" | |
29 #include "include/BC_QRGridSampler.h" | |
30 #include "include/BC_QRAlignmentPatternFinder.h" | |
31 #include "include/BC_QRFinderPatternFinder.h" | |
32 #include "include/BC_QRDetectorResult.h" | |
33 #include "include/BC_QRDetector.h" | |
34 CBC_QRDetector::CBC_QRDetector(CBC_CommonBitMatrix *image): m_image(image) | |
35 { | |
36 } | |
37 CBC_QRDetector::~CBC_QRDetector() | |
38 { | |
39 } | |
40 CBC_QRDetectorResult *CBC_QRDetector::Detect(FX_INT32 hints, FX_INT32 &e) | |
41 { | |
42 CBC_QRFinderPatternFinder finder(m_image); | |
43 CBC_QRFinderPatternInfo* qpi = finder.Find(hints, e); | |
44 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
45 CBC_AutoPtr<CBC_QRFinderPatternInfo> info(qpi); | |
46 CBC_QRDetectorResult* qdr = ProcessFinderPatternInfo(info.get(), e); | |
47 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
48 return qdr; | |
49 } | |
50 CBC_QRDetectorResult* CBC_QRDetector::ProcessFinderPatternInfo(CBC_QRFinderPatte
rnInfo *info, FX_INT32 &e) | |
51 { | |
52 CBC_AutoPtr<CBC_QRFinderPattern> topLeft(info->GetTopLeft()); | |
53 CBC_AutoPtr<CBC_QRFinderPattern> topRight(info->GetTopRight()); | |
54 CBC_AutoPtr<CBC_QRFinderPattern> bottomLeft(info->GetBottomLeft()); | |
55 FX_FLOAT moduleSize = CalculateModuleSize(topLeft.get(), topRight.get(), bot
tomLeft.get()); | |
56 if(moduleSize < 1.0f) { | |
57 e = BCExceptionRead; | |
58 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
59 } | |
60 FX_INT32 dimension = ComputeDimension(topLeft.get(), topRight.get(), bottomL
eft.get(), moduleSize, e); | |
61 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
62 CBC_QRCoderVersion *provisionalVersion = CBC_QRCoderVersion::GetProvisionalV
ersionForDimension(dimension, e); | |
63 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
64 FX_INT32 modulesBetweenFPCenters = provisionalVersion->GetDimensionForVersio
n() - 7; | |
65 CBC_QRAlignmentPattern * alignmentPattern = NULL; | |
66 if(provisionalVersion->GetAlignmentPatternCenters()->GetSize() > 0) { | |
67 FX_FLOAT bottomRightX = topRight->GetX() - topLeft->GetX() + bottomLeft
->GetX(); | |
68 FX_FLOAT bottomRightY = topRight->GetY() - topLeft->GetY() + bottomLeft-
>GetY(); | |
69 FX_FLOAT correctionToTopLeft = 1.0f - 3.0f / (FX_FLOAT) modulesBetweenFP
Centers; | |
70 FX_FLOAT xtemp = (topLeft->GetX() + correctionToTopLeft * (bottomRightX
- topLeft->GetX())); | |
71 FX_INT32 estAlignmentX = (FX_INT32)xtemp ; | |
72 FX_FLOAT ytemp = (topLeft->GetY() + correctionToTopLeft * (bottomRightY
- topLeft->GetY())); | |
73 FX_INT32 estAlignmentY = (FX_INT32)ytemp; | |
74 for(FX_INT32 i = 4; i <= 16; i <<= 1) { | |
75 CBC_QRAlignmentPattern *temp = FindAlignmentInRegion(moduleSize, est
AlignmentX, estAlignmentY, (FX_FLOAT) i, e); | |
76 alignmentPattern = temp; | |
77 break; | |
78 } | |
79 } | |
80 CBC_CommonBitMatrix *bits = SampleGrid(m_image, topLeft.get(), topRight.get(
), bottomLeft.get(), (CBC_ResultPoint*)(alignmentPattern), dimension, e); | |
81 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
82 CFX_PtrArray *points = FX_NEW CFX_PtrArray; | |
83 if(alignmentPattern == NULL) { | |
84 points->Add(bottomLeft.release()); | |
85 points->Add(topLeft.release()); | |
86 points->Add(topRight.release()); | |
87 } else { | |
88 points->Add(bottomLeft.release()); | |
89 points->Add(topLeft.release()); | |
90 points->Add(topRight.release()); | |
91 points->Add(alignmentPattern); | |
92 } | |
93 return FX_NEW CBC_QRDetectorResult(bits, points); | |
94 } | |
95 CBC_CommonBitMatrix *CBC_QRDetector::SampleGrid(CBC_CommonBitMatrix *image, CBC_
ResultPoint *topLeft, CBC_ResultPoint *topRight, | |
96 CBC_ResultPoint *bottomLeft, CBC_ResultPoint* alignmentPattern, | |
97 FX_INT32 dimension, FX_INT32 &e) | |
98 { | |
99 FX_FLOAT dimMinusThree = (FX_FLOAT) dimension - 3.5f; | |
100 FX_FLOAT bottomRightX; | |
101 FX_FLOAT bottomRightY; | |
102 FX_FLOAT sourceBottomRightX; | |
103 FX_FLOAT sourceBottomRightY; | |
104 if (alignmentPattern != NULL) { | |
105 bottomRightX = alignmentPattern->GetX(); | |
106 bottomRightY = alignmentPattern->GetY(); | |
107 sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; | |
108 } else { | |
109 bottomRightX = (topRight->GetX() - topLeft->GetX()) + bottomLeft->GetX()
; | |
110 bottomRightY = (topRight->GetY() - topLeft->GetY()) + bottomLeft->GetY()
; | |
111 sourceBottomRightX = sourceBottomRightY = dimMinusThree; | |
112 } | |
113 CBC_QRGridSampler &sampler = CBC_QRGridSampler::GetInstance(); | |
114 CBC_CommonBitMatrix* cbm = sampler.SampleGrid(image, | |
115 dimension, dimension, | |
116 3.5f, | |
117 3.5f, | |
118 dimMinusThree, | |
119 3.5f, | |
120 sourceBottomRightX, | |
121 sourceBottomRightY, | |
122 3.5f, | |
123 dimMinusThree, | |
124 topLeft->GetX(), | |
125 topLeft->GetY(), | |
126 topRight->GetX(), | |
127 topRight->GetY(), | |
128 bottomRightX, | |
129 bottomRightY, | |
130 bottomLeft->GetX(), | |
131 bottomLeft->GetY(), e); | |
132 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
133 return cbm; | |
134 } | |
135 FX_INT32 CBC_QRDetector::ComputeDimension(CBC_ResultPoint *topLeft, CBC_ResultPo
int *topRight, | |
136 CBC_ResultPoint *bottomLeft, FX_FLOAT moduleSize, FX_INT32 &e) | |
137 { | |
138 FX_INT32 tltrCentersDimension = Round(CBC_QRFinderPatternFinder::Distance(to
pLeft, topRight) / moduleSize); | |
139 FX_INT32 tlblCentersDimension = Round(CBC_QRFinderPatternFinder::Distance(to
pLeft, bottomLeft) / moduleSize); | |
140 FX_INT32 dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) +
7; | |
141 switch(dimension & 0x03) { | |
142 case 0: | |
143 dimension++; | |
144 break; | |
145 case 2: | |
146 dimension--; | |
147 break; | |
148 case 3: { | |
149 e = BCExceptionRead; | |
150 BC_EXCEPTION_CHECK_ReturnValue(e, 0); | |
151 } | |
152 } | |
153 return dimension; | |
154 } | |
155 FX_FLOAT CBC_QRDetector::CalculateModuleSize(CBC_ResultPoint *topLeft, CBC_Resul
tPoint *topRight, CBC_ResultPoint *bottomLeft) | |
156 { | |
157 return (CalculateModuleSizeOneWay(topLeft, topRight) + CalculateModuleSizeOn
eWay(topLeft, bottomLeft)) / 2.0f; | |
158 } | |
159 FX_FLOAT CBC_QRDetector::CalculateModuleSizeOneWay(CBC_ResultPoint *pattern, CBC
_ResultPoint *otherPattern) | |
160 { | |
161 FX_FLOAT moduleSizeEst1 = SizeOfBlackWhiteBlackRunBothWays((FX_INT32) patter
n->GetX(), | |
162 (FX_INT32) pattern->GetY(), | |
163 (FX_INT32) otherPattern->GetX(), | |
164 (FX_INT32) otherPattern->GetY()); | |
165 FX_FLOAT moduleSizeEst2 = SizeOfBlackWhiteBlackRunBothWays((FX_INT32) otherP
attern->GetX(), | |
166 (FX_INT32) otherPattern->GetY(), | |
167 (FX_INT32) pattern->GetX(), | |
168 (FX_INT32) pattern->GetY()); | |
169 if (FXSYS_isnan(moduleSizeEst1)) { | |
170 return moduleSizeEst2; | |
171 } | |
172 if (FXSYS_isnan(moduleSizeEst2)) { | |
173 return moduleSizeEst1; | |
174 } | |
175 return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; | |
176 } | |
177 FX_INT32 CBC_QRDetector::Round(FX_FLOAT d) | |
178 { | |
179 return (FX_INT32)(d + 0.5f); | |
180 } | |
181 FX_FLOAT CBC_QRDetector::SizeOfBlackWhiteBlackRunBothWays(FX_INT32 fromX, FX_INT
32 fromY, FX_INT32 toX, FX_INT32 toY) | |
182 { | |
183 FX_FLOAT result = SizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); | |
184 FX_INT32 otherToX = fromX - (toX - fromX); | |
185 if (otherToX < 0) { | |
186 otherToX = -1; | |
187 } else if (otherToX >= m_image->GetWidth()) { | |
188 otherToX = m_image->GetWidth(); | |
189 } | |
190 FX_INT32 otherToY = fromY - (toY - fromY); | |
191 if (otherToY < 0) { | |
192 otherToY = -1; | |
193 } else if (otherToY >= m_image->GetHeight()) { | |
194 otherToY = m_image->GetHeight(); | |
195 } | |
196 result += SizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); | |
197 return result - 1.0f; | |
198 } | |
199 FX_FLOAT CBC_QRDetector::SizeOfBlackWhiteBlackRun(FX_INT32 fromX, FX_INT32 fromY
, FX_INT32 toX, FX_INT32 toY) | |
200 { | |
201 FX_BOOL steep = FXSYS_abs(toY - fromY) > FXSYS_abs(toX - fromX); | |
202 if (steep) { | |
203 FX_INT32 temp = fromX; | |
204 fromX = fromY; | |
205 fromY = temp; | |
206 temp = toX; | |
207 toX = toY; | |
208 toY = temp; | |
209 } | |
210 FX_INT32 dx = FXSYS_abs(toX - fromX); | |
211 FX_INT32 dy = FXSYS_abs(toY - fromY); | |
212 FX_INT32 error = -dx >> 1; | |
213 FX_INT32 ystep = fromY < toY ? 1 : -1; | |
214 FX_INT32 xstep = fromX < toX ? 1 : -1; | |
215 FX_INT32 state = 0; | |
216 for (FX_INT32 x = fromX, y = fromY; x != toX; x += xstep) { | |
217 FX_INT32 realX = steep ? y : x; | |
218 FX_INT32 realY = steep ? x : y; | |
219 if (state == 1) { | |
220 if (m_image->Get(realX, realY)) { | |
221 state++; | |
222 } | |
223 } else { | |
224 if (!m_image->Get(realX, realY)) { | |
225 state++; | |
226 } | |
227 } | |
228 if (state == 3) { | |
229 FX_INT32 diffX = x - fromX; | |
230 FX_INT32 diffY = y - fromY; | |
231 return (FX_FLOAT) sqrt((double) (diffX * diffX + diffY * diffY)); | |
232 } | |
233 error += dy; | |
234 if (error > 0) { | |
235 y += ystep; | |
236 error -= dx; | |
237 } | |
238 } | |
239 FX_INT32 diffX = toX - fromX; | |
240 FX_INT32 diffY = toY - fromY; | |
241 return (FX_FLOAT) sqrt((double) (diffX * diffX + diffY * diffY)); | |
242 } | |
243 CBC_QRAlignmentPattern *CBC_QRDetector::FindAlignmentInRegion(FX_FLOAT overallEs
tModuleSize, FX_INT32 estAlignmentX, | |
244 FX_INT32 estAlignmentY, FX_FLOAT allowanceFactor, FX_INT32 &e) | |
245 { | |
246 FX_INT32 allowance = (FX_INT32) (allowanceFactor * overallEstModuleSize); | |
247 FX_INT32 alignmentAreaLeftX = FX_MAX(0, estAlignmentX - allowance); | |
248 FX_INT32 alignmentAreaRightX = FX_MIN(m_image->GetWidth() - 1, estAlignmentX
+ allowance); | |
249 if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { | |
250 e = BCExceptionRead; | |
251 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
252 } | |
253 FX_INT32 alignmentAreaTopY = FX_MAX(0, estAlignmentY - allowance); | |
254 FX_INT32 alignmentAreaBottomY = FX_MIN(m_image->GetHeight() - 1, estAlignmen
tY + allowance); | |
255 CBC_QRAlignmentPatternFinder alignmentFinder(m_image, | |
256 alignmentAreaLeftX, | |
257 alignmentAreaTopY, | |
258 alignmentAreaRightX - alignmentAreaLeftX, | |
259 alignmentAreaBottomY - alignmentAreaTopY, | |
260 overallEstModuleSize); | |
261 CBC_QRAlignmentPattern *qap = alignmentFinder.Find(e); | |
262 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
263 return qap; | |
264 } | |
OLD | NEW |