| 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 |