diff options
Diffstat (limited to 'xfa/src/fxbarcode/qrcode/BC_QRDetector.cpp')
-rw-r--r-- | xfa/src/fxbarcode/qrcode/BC_QRDetector.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/xfa/src/fxbarcode/qrcode/BC_QRDetector.cpp b/xfa/src/fxbarcode/qrcode/BC_QRDetector.cpp new file mode 100644 index 0000000000..01d90832b9 --- /dev/null +++ b/xfa/src/fxbarcode/qrcode/BC_QRDetector.cpp @@ -0,0 +1,264 @@ +// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+// Original code is licensed as follows:
+/*
+ * Copyright 2007 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../barcode.h"
+#include "../common/BC_CommonBitMatrix.h"
+#include "../BC_ResultPoint.h"
+#include "BC_QRFinderPattern.h"
+#include "BC_QRCoderVersion.h"
+#include "BC_FinderPatternInfo.h"
+#include "BC_QRGridSampler.h"
+#include "BC_QRAlignmentPatternFinder.h"
+#include "BC_QRFinderPatternFinder.h"
+#include "BC_QRDetectorResult.h"
+#include "BC_QRDetector.h"
+CBC_QRDetector::CBC_QRDetector(CBC_CommonBitMatrix *image): m_image(image)
+{
+}
+CBC_QRDetector::~CBC_QRDetector()
+{
+}
+CBC_QRDetectorResult *CBC_QRDetector::Detect(FX_INT32 hints, FX_INT32 &e)
+{
+ CBC_QRFinderPatternFinder finder(m_image);
+ CBC_QRFinderPatternInfo* qpi = finder.Find(hints, e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ CBC_AutoPtr<CBC_QRFinderPatternInfo> info(qpi);
+ CBC_QRDetectorResult* qdr = ProcessFinderPatternInfo(info.get(), e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ return qdr;
+}
+CBC_QRDetectorResult* CBC_QRDetector::ProcessFinderPatternInfo(CBC_QRFinderPatternInfo *info, FX_INT32 &e)
+{
+ CBC_AutoPtr<CBC_QRFinderPattern> topLeft(info->GetTopLeft());
+ CBC_AutoPtr<CBC_QRFinderPattern> topRight(info->GetTopRight());
+ CBC_AutoPtr<CBC_QRFinderPattern> bottomLeft(info->GetBottomLeft());
+ FX_FLOAT moduleSize = CalculateModuleSize(topLeft.get(), topRight.get(), bottomLeft.get());
+ if(moduleSize < 1.0f) {
+ e = BCExceptionRead;
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ }
+ FX_INT32 dimension = ComputeDimension(topLeft.get(), topRight.get(), bottomLeft.get(), moduleSize, e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ CBC_QRCoderVersion *provisionalVersion = CBC_QRCoderVersion::GetProvisionalVersionForDimension(dimension, e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ FX_INT32 modulesBetweenFPCenters = provisionalVersion->GetDimensionForVersion() - 7;
+ CBC_QRAlignmentPattern * alignmentPattern = NULL;
+ if(provisionalVersion->GetAlignmentPatternCenters()->GetSize() > 0) {
+ FX_FLOAT bottomRightX = topRight->GetX() - topLeft->GetX() + bottomLeft->GetX();
+ FX_FLOAT bottomRightY = topRight->GetY() - topLeft->GetY() + bottomLeft->GetY();
+ FX_FLOAT correctionToTopLeft = 1.0f - 3.0f / (FX_FLOAT) modulesBetweenFPCenters;
+ FX_FLOAT xtemp = (topLeft->GetX() + correctionToTopLeft * (bottomRightX - topLeft->GetX()));
+ FX_INT32 estAlignmentX = (FX_INT32)xtemp ;
+ FX_FLOAT ytemp = (topLeft->GetY() + correctionToTopLeft * (bottomRightY - topLeft->GetY()));
+ FX_INT32 estAlignmentY = (FX_INT32)ytemp;
+ for(FX_INT32 i = 4; i <= 16; i <<= 1) {
+ CBC_QRAlignmentPattern *temp = FindAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (FX_FLOAT) i, e);
+ alignmentPattern = temp;
+ break;
+ }
+ }
+ CBC_CommonBitMatrix *bits = SampleGrid(m_image, topLeft.get(), topRight.get(), bottomLeft.get(), (CBC_ResultPoint*)(alignmentPattern), dimension, e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ CFX_PtrArray *points = FX_NEW CFX_PtrArray;
+ if(alignmentPattern == NULL) {
+ points->Add(bottomLeft.release());
+ points->Add(topLeft.release());
+ points->Add(topRight.release());
+ } else {
+ points->Add(bottomLeft.release());
+ points->Add(topLeft.release());
+ points->Add(topRight.release());
+ points->Add(alignmentPattern);
+ }
+ return FX_NEW CBC_QRDetectorResult(bits, points);
+}
+CBC_CommonBitMatrix *CBC_QRDetector::SampleGrid(CBC_CommonBitMatrix *image, CBC_ResultPoint *topLeft, CBC_ResultPoint *topRight,
+ CBC_ResultPoint *bottomLeft, CBC_ResultPoint* alignmentPattern,
+ FX_INT32 dimension, FX_INT32 &e)
+{
+ FX_FLOAT dimMinusThree = (FX_FLOAT) dimension - 3.5f;
+ FX_FLOAT bottomRightX;
+ FX_FLOAT bottomRightY;
+ FX_FLOAT sourceBottomRightX;
+ FX_FLOAT sourceBottomRightY;
+ if (alignmentPattern != NULL) {
+ bottomRightX = alignmentPattern->GetX();
+ bottomRightY = alignmentPattern->GetY();
+ sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f;
+ } else {
+ bottomRightX = (topRight->GetX() - topLeft->GetX()) + bottomLeft->GetX();
+ bottomRightY = (topRight->GetY() - topLeft->GetY()) + bottomLeft->GetY();
+ sourceBottomRightX = sourceBottomRightY = dimMinusThree;
+ }
+ CBC_QRGridSampler &sampler = CBC_QRGridSampler::GetInstance();
+ CBC_CommonBitMatrix* cbm = sampler.SampleGrid(image,
+ dimension, dimension,
+ 3.5f,
+ 3.5f,
+ dimMinusThree,
+ 3.5f,
+ sourceBottomRightX,
+ sourceBottomRightY,
+ 3.5f,
+ dimMinusThree,
+ topLeft->GetX(),
+ topLeft->GetY(),
+ topRight->GetX(),
+ topRight->GetY(),
+ bottomRightX,
+ bottomRightY,
+ bottomLeft->GetX(),
+ bottomLeft->GetY(), e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ return cbm;
+}
+FX_INT32 CBC_QRDetector::ComputeDimension(CBC_ResultPoint *topLeft, CBC_ResultPoint *topRight,
+ CBC_ResultPoint *bottomLeft, FX_FLOAT moduleSize, FX_INT32 &e)
+{
+ FX_INT32 tltrCentersDimension = Round(CBC_QRFinderPatternFinder::Distance(topLeft, topRight) / moduleSize);
+ FX_INT32 tlblCentersDimension = Round(CBC_QRFinderPatternFinder::Distance(topLeft, bottomLeft) / moduleSize);
+ FX_INT32 dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
+ switch(dimension & 0x03) {
+ case 0:
+ dimension++;
+ break;
+ case 2:
+ dimension--;
+ break;
+ case 3: {
+ e = BCExceptionRead;
+ BC_EXCEPTION_CHECK_ReturnValue(e, 0);
+ }
+ }
+ return dimension;
+}
+FX_FLOAT CBC_QRDetector::CalculateModuleSize(CBC_ResultPoint *topLeft, CBC_ResultPoint *topRight, CBC_ResultPoint *bottomLeft)
+{
+ return (CalculateModuleSizeOneWay(topLeft, topRight) + CalculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f;
+}
+FX_FLOAT CBC_QRDetector::CalculateModuleSizeOneWay(CBC_ResultPoint *pattern, CBC_ResultPoint *otherPattern)
+{
+ FX_FLOAT moduleSizeEst1 = SizeOfBlackWhiteBlackRunBothWays((FX_INT32) pattern->GetX(),
+ (FX_INT32) pattern->GetY(),
+ (FX_INT32) otherPattern->GetX(),
+ (FX_INT32) otherPattern->GetY());
+ FX_FLOAT moduleSizeEst2 = SizeOfBlackWhiteBlackRunBothWays((FX_INT32) otherPattern->GetX(),
+ (FX_INT32) otherPattern->GetY(),
+ (FX_INT32) pattern->GetX(),
+ (FX_INT32) pattern->GetY());
+ if (FXSYS_isnan(moduleSizeEst1)) {
+ return moduleSizeEst2;
+ }
+ if (FXSYS_isnan(moduleSizeEst2)) {
+ return moduleSizeEst1;
+ }
+ return (moduleSizeEst1 + moduleSizeEst2) / 14.0f;
+}
+FX_INT32 CBC_QRDetector::Round(FX_FLOAT d)
+{
+ return (FX_INT32)(d + 0.5f);
+}
+FX_FLOAT CBC_QRDetector::SizeOfBlackWhiteBlackRunBothWays(FX_INT32 fromX, FX_INT32 fromY, FX_INT32 toX, FX_INT32 toY)
+{
+ FX_FLOAT result = SizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
+ FX_INT32 otherToX = fromX - (toX - fromX);
+ if (otherToX < 0) {
+ otherToX = -1;
+ } else if (otherToX >= m_image->GetWidth()) {
+ otherToX = m_image->GetWidth();
+ }
+ FX_INT32 otherToY = fromY - (toY - fromY);
+ if (otherToY < 0) {
+ otherToY = -1;
+ } else if (otherToY >= m_image->GetHeight()) {
+ otherToY = m_image->GetHeight();
+ }
+ result += SizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY);
+ return result - 1.0f;
+}
+FX_FLOAT CBC_QRDetector::SizeOfBlackWhiteBlackRun(FX_INT32 fromX, FX_INT32 fromY, FX_INT32 toX, FX_INT32 toY)
+{
+ FX_BOOL steep = FXSYS_abs(toY - fromY) > FXSYS_abs(toX - fromX);
+ if (steep) {
+ FX_INT32 temp = fromX;
+ fromX = fromY;
+ fromY = temp;
+ temp = toX;
+ toX = toY;
+ toY = temp;
+ }
+ FX_INT32 dx = FXSYS_abs(toX - fromX);
+ FX_INT32 dy = FXSYS_abs(toY - fromY);
+ FX_INT32 error = -dx >> 1;
+ FX_INT32 ystep = fromY < toY ? 1 : -1;
+ FX_INT32 xstep = fromX < toX ? 1 : -1;
+ FX_INT32 state = 0;
+ for (FX_INT32 x = fromX, y = fromY; x != toX; x += xstep) {
+ FX_INT32 realX = steep ? y : x;
+ FX_INT32 realY = steep ? x : y;
+ if (state == 1) {
+ if (m_image->Get(realX, realY)) {
+ state++;
+ }
+ } else {
+ if (!m_image->Get(realX, realY)) {
+ state++;
+ }
+ }
+ if (state == 3) {
+ FX_INT32 diffX = x - fromX;
+ FX_INT32 diffY = y - fromY;
+ return (FX_FLOAT) sqrt((double) (diffX * diffX + diffY * diffY));
+ }
+ error += dy;
+ if (error > 0) {
+ y += ystep;
+ error -= dx;
+ }
+ }
+ FX_INT32 diffX = toX - fromX;
+ FX_INT32 diffY = toY - fromY;
+ return (FX_FLOAT) sqrt((double) (diffX * diffX + diffY * diffY));
+}
+CBC_QRAlignmentPattern *CBC_QRDetector::FindAlignmentInRegion(FX_FLOAT overallEstModuleSize, FX_INT32 estAlignmentX,
+ FX_INT32 estAlignmentY, FX_FLOAT allowanceFactor, FX_INT32 &e)
+{
+ FX_INT32 allowance = (FX_INT32) (allowanceFactor * overallEstModuleSize);
+ FX_INT32 alignmentAreaLeftX = FX_MAX(0, estAlignmentX - allowance);
+ FX_INT32 alignmentAreaRightX = FX_MIN(m_image->GetWidth() - 1, estAlignmentX + allowance);
+ if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
+ e = BCExceptionRead;
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ }
+ FX_INT32 alignmentAreaTopY = FX_MAX(0, estAlignmentY - allowance);
+ FX_INT32 alignmentAreaBottomY = FX_MIN(m_image->GetHeight() - 1, estAlignmentY + allowance);
+ CBC_QRAlignmentPatternFinder alignmentFinder(m_image,
+ alignmentAreaLeftX,
+ alignmentAreaTopY,
+ alignmentAreaRightX - alignmentAreaLeftX,
+ alignmentAreaBottomY - alignmentAreaTopY,
+ overallEstModuleSize);
+ CBC_QRAlignmentPattern *qap = alignmentFinder.Find(e);
+ BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
+ return qap;
+}
|