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