diff options
Diffstat (limited to 'xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.cpp')
-rw-r--r-- | xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.cpp | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.cpp b/xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.cpp new file mode 100644 index 0000000000..fd410097cc --- /dev/null +++ b/xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.cpp @@ -0,0 +1,406 @@ +// 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 2008 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 "xfa/fxbarcode/datamatrix/BC_DataMatrixDetector.h" + +#include <algorithm> +#include <memory> + +#include "xfa/fxbarcode/BC_ResultPoint.h" +#include "xfa/fxbarcode/common/BC_CommonBitMatrix.h" +#include "xfa/fxbarcode/common/BC_WhiteRectangleDetector.h" +#include "xfa/fxbarcode/qrcode/BC_QRDetectorResult.h" +#include "xfa/fxbarcode/qrcode/BC_QRFinderPatternFinder.h" +#include "xfa/fxbarcode/qrcode/BC_QRGridSampler.h" +#include "xfa/fxbarcode/utils.h" + +const int32_t CBC_DataMatrixDetector::INTEGERS[5] = {0, 1, 2, 3, 4}; +CBC_DataMatrixDetector::CBC_DataMatrixDetector(CBC_CommonBitMatrix* image) + : m_image(image), m_rectangleDetector(NULL) {} +void CBC_DataMatrixDetector::Init(int32_t& e) { + m_rectangleDetector = new CBC_WhiteRectangleDetector(m_image); + m_rectangleDetector->Init(e); + BC_EXCEPTION_CHECK_ReturnVoid(e); +} +CBC_DataMatrixDetector::~CBC_DataMatrixDetector() { + delete m_rectangleDetector; +} +inline FX_BOOL ResultPointsAndTransitionsComparator(void* a, void* b) { + return ((CBC_ResultPointsAndTransitions*)b)->GetTransitions() > + ((CBC_ResultPointsAndTransitions*)a)->GetTransitions(); +} +CBC_QRDetectorResult* CBC_DataMatrixDetector::Detect(int32_t& e) { + CFX_PtrArray* cornerPoints = m_rectangleDetector->Detect(e); + BC_EXCEPTION_CHECK_ReturnValue(e, NULL); + CBC_ResultPoint* pointA = (CBC_ResultPoint*)(*cornerPoints)[0]; + CBC_ResultPoint* pointB = (CBC_ResultPoint*)(*cornerPoints)[1]; + CBC_ResultPoint* pointC = (CBC_ResultPoint*)(*cornerPoints)[2]; + CBC_ResultPoint* pointD = (CBC_ResultPoint*)(*cornerPoints)[3]; + delete cornerPoints; + cornerPoints = NULL; + CFX_PtrArray transitions; + transitions.Add(TransitionsBetween(pointA, pointB)); + transitions.Add(TransitionsBetween(pointA, pointC)); + transitions.Add(TransitionsBetween(pointB, pointD)); + transitions.Add(TransitionsBetween(pointC, pointD)); + BC_FX_PtrArray_Sort(transitions, &ResultPointsAndTransitionsComparator); + delete ((CBC_ResultPointsAndTransitions*)transitions[2]); + delete ((CBC_ResultPointsAndTransitions*)transitions[3]); + CBC_ResultPointsAndTransitions* lSideOne = + (CBC_ResultPointsAndTransitions*)transitions[0]; + CBC_ResultPointsAndTransitions* lSideTwo = + (CBC_ResultPointsAndTransitions*)transitions[1]; + CFX_MapPtrTemplate<CBC_ResultPoint*, int32_t> pointCount; + Increment(pointCount, lSideOne->GetFrom()); + Increment(pointCount, lSideOne->GetTo()); + Increment(pointCount, lSideTwo->GetFrom()); + Increment(pointCount, lSideTwo->GetTo()); + delete ((CBC_ResultPointsAndTransitions*)transitions[1]); + delete ((CBC_ResultPointsAndTransitions*)transitions[0]); + transitions.RemoveAll(); + CBC_ResultPoint* maybeTopLeft = NULL; + CBC_ResultPoint* bottomLeft = NULL; + CBC_ResultPoint* maybeBottomRight = NULL; + FX_POSITION itBegin = pointCount.GetStartPosition(); + while (itBegin) { + CBC_ResultPoint* key = 0; + int32_t value = 0; + pointCount.GetNextAssoc(itBegin, key, value); + if (value == 2) { + bottomLeft = key; + } else { + if (maybeBottomRight == NULL) { + maybeBottomRight = key; + } else { + maybeTopLeft = key; + } + } + } + if (maybeTopLeft == NULL || bottomLeft == NULL || maybeBottomRight == NULL) { + delete pointA; + delete pointB; + delete pointC; + delete pointD; + e = BCExceptionNotFound; + return NULL; + } + CFX_PtrArray corners; + corners.SetSize(3); + corners[0] = maybeTopLeft; + corners[1] = bottomLeft; + corners[2] = maybeBottomRight; + OrderBestPatterns(&corners); + CBC_ResultPoint* bottomRight = (CBC_ResultPoint*)corners[0]; + bottomLeft = (CBC_ResultPoint*)corners[1]; + CBC_ResultPoint* topLeft = (CBC_ResultPoint*)corners[2]; + CBC_ResultPoint* topRight = NULL; + int32_t value; + if (!pointCount.Lookup(pointA, value)) { + topRight = pointA; + } else if (!pointCount.Lookup(pointB, value)) { + topRight = pointB; + } else if (!pointCount.Lookup(pointC, value)) { + topRight = pointC; + } else { + topRight = pointD; + } + int32_t dimensionTop = std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, topRight)) + ->GetTransitions(); + int32_t dimensionRight = std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, topRight)) + ->GetTransitions(); + if ((dimensionTop & 0x01) == 1) { + dimensionTop++; + } + dimensionTop += 2; + if ((dimensionRight & 0x01) == 1) { + dimensionRight++; + } + dimensionRight += 2; + std::unique_ptr<CBC_CommonBitMatrix> bits; + std::unique_ptr<CBC_ResultPoint> correctedTopRight; + if (4 * dimensionTop >= 7 * dimensionRight || + 4 * dimensionRight >= 7 * dimensionTop) { + correctedTopRight.reset( + CorrectTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, + dimensionTop, dimensionRight)); + if (correctedTopRight.get() == NULL) { + correctedTopRight.reset(topRight); + } else { + delete topRight; + topRight = NULL; + } + dimensionTop = std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, correctedTopRight.get())) + ->GetTransitions(); + dimensionRight = + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, correctedTopRight.get())) + ->GetTransitions(); + if ((dimensionTop & 0x01) == 1) { + dimensionTop++; + } + if ((dimensionRight & 0x01) == 1) { + dimensionRight++; + } + bits.reset(SampleGrid(m_image, topLeft, bottomLeft, bottomRight, + correctedTopRight.get(), dimensionTop, dimensionRight, + e)); + BC_EXCEPTION_CHECK_ReturnValue(e, NULL); + } else { + int32_t dimension = std::min(dimensionRight, dimensionTop); + correctedTopRight.reset( + CorrectTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension)); + if (correctedTopRight.get() == NULL) { + correctedTopRight.reset(topRight); + } else { + delete topRight; + topRight = NULL; + } + int32_t dimensionCorrected = + std::max(std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, correctedTopRight.get())) + ->GetTransitions(), + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, correctedTopRight.get())) + ->GetTransitions()); + dimensionCorrected++; + if ((dimensionCorrected & 0x01) == 1) { + dimensionCorrected++; + } + bits.reset(SampleGrid(m_image, topLeft, bottomLeft, bottomRight, + correctedTopRight.get(), dimensionCorrected, + dimensionCorrected, e)); + BC_EXCEPTION_CHECK_ReturnValue(e, NULL); + } + CFX_PtrArray* result = new CFX_PtrArray; + result->SetSize(4); + result->Add(topLeft); + result->Add(bottomLeft); + result->Add(bottomRight); + result->Add(correctedTopRight.release()); + return new CBC_QRDetectorResult(bits.release(), result); +} +CBC_ResultPoint* CBC_DataMatrixDetector::CorrectTopRightRectangular( + CBC_ResultPoint* bottomLeft, + CBC_ResultPoint* bottomRight, + CBC_ResultPoint* topLeft, + CBC_ResultPoint* topRight, + int32_t dimensionTop, + int32_t dimensionRight) { + FX_FLOAT corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT)dimensionTop; + int32_t norm = Distance(topLeft, topRight); + FX_FLOAT cos = (topRight->GetX() - topLeft->GetX()) / norm; + FX_FLOAT sin = (topRight->GetY() - topLeft->GetY()) / norm; + std::unique_ptr<CBC_ResultPoint> c1(new CBC_ResultPoint( + topRight->GetX() + corr * cos, topRight->GetY() + corr * sin)); + corr = Distance(bottomLeft, topLeft) / (FX_FLOAT)dimensionRight; + norm = Distance(bottomRight, topRight); + cos = (topRight->GetX() - bottomRight->GetX()) / norm; + sin = (topRight->GetY() - bottomRight->GetY()) / norm; + std::unique_ptr<CBC_ResultPoint> c2(new CBC_ResultPoint( + topRight->GetX() + corr * cos, topRight->GetY() + corr * sin)); + if (!IsValid(c1.get())) { + if (IsValid(c2.get())) { + return c2.release(); + } + return NULL; + } else if (!IsValid(c2.get())) { + return c1.release(); + } + int32_t l1 = FXSYS_abs(dimensionTop - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, c1.get())) + ->GetTransitions()) + + FXSYS_abs(dimensionRight - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, c1.get())) + ->GetTransitions()); + int32_t l2 = FXSYS_abs(dimensionTop - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, c2.get())) + ->GetTransitions()) + + FXSYS_abs(dimensionRight - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, c2.get())) + ->GetTransitions()); + if (l1 <= l2) { + return c1.release(); + } + return c2.release(); +} +CBC_ResultPoint* CBC_DataMatrixDetector::CorrectTopRight( + CBC_ResultPoint* bottomLeft, + CBC_ResultPoint* bottomRight, + CBC_ResultPoint* topLeft, + CBC_ResultPoint* topRight, + int32_t dimension) { + FX_FLOAT corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT)dimension; + int32_t norm = Distance(topLeft, topRight); + FX_FLOAT cos = (topRight->GetX() - topLeft->GetX()) / norm; + FX_FLOAT sin = (topRight->GetY() - topLeft->GetY()) / norm; + std::unique_ptr<CBC_ResultPoint> c1(new CBC_ResultPoint( + topRight->GetX() + corr * cos, topRight->GetY() + corr * sin)); + corr = Distance(bottomLeft, bottomRight) / (FX_FLOAT)dimension; + norm = Distance(bottomRight, topRight); + cos = (topRight->GetX() - bottomRight->GetX()) / norm; + sin = (topRight->GetY() - bottomRight->GetY()) / norm; + std::unique_ptr<CBC_ResultPoint> c2(new CBC_ResultPoint( + topRight->GetX() + corr * cos, topRight->GetY() + corr * sin)); + if (!IsValid(c1.get())) { + if (IsValid(c2.get())) { + return c2.release(); + } + return NULL; + } else if (!IsValid(c2.get())) { + return c1.release(); + } + int32_t l1 = FXSYS_abs(std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, c1.get())) + ->GetTransitions() - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, c1.get())) + ->GetTransitions()); + int32_t l2 = FXSYS_abs(std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(topLeft, c2.get())) + ->GetTransitions() - + std::unique_ptr<CBC_ResultPointsAndTransitions>( + TransitionsBetween(bottomRight, c2.get())) + ->GetTransitions()); + return l1 <= l2 ? c1.release() : c2.release(); +} +FX_BOOL CBC_DataMatrixDetector::IsValid(CBC_ResultPoint* p) { + return p->GetX() >= 0 && p->GetX() < m_image->GetWidth() && p->GetY() > 0 && + p->GetY() < m_image->GetHeight(); +} +int32_t CBC_DataMatrixDetector::Round(FX_FLOAT d) { + return (int32_t)(d + 0.5f); +} +int32_t CBC_DataMatrixDetector::Distance(CBC_ResultPoint* a, + CBC_ResultPoint* b) { + return Round( + (FX_FLOAT)sqrt((a->GetX() - b->GetX()) * (a->GetX() - b->GetX()) + + (a->GetY() - b->GetY()) * (a->GetY() - b->GetY()))); +} +void CBC_DataMatrixDetector::Increment( + CFX_MapPtrTemplate<CBC_ResultPoint*, int32_t>& table, + CBC_ResultPoint* key) { + int32_t value; + if (table.Lookup(key, value)) { + table.SetAt(key, INTEGERS[value + 1]); + } else { + table.SetAt(key, INTEGERS[1]); + } +} +CBC_CommonBitMatrix* CBC_DataMatrixDetector::SampleGrid( + CBC_CommonBitMatrix* image, + CBC_ResultPoint* topLeft, + CBC_ResultPoint* bottomLeft, + CBC_ResultPoint* bottomRight, + CBC_ResultPoint* topRight, + int32_t dimensionX, + int32_t dimensionY, + int32_t& e) { + CBC_QRGridSampler& sampler = CBC_QRGridSampler::GetInstance(); + CBC_CommonBitMatrix* cbm = sampler.SampleGrid( + image, dimensionX, dimensionY, 0.5f, 0.5f, dimensionX - 0.5f, 0.5f, + dimensionX - 0.5f, dimensionY - 0.5f, 0.5f, dimensionY - 0.5f, + topLeft->GetX(), topLeft->GetY(), topRight->GetX(), topRight->GetY(), + bottomRight->GetX(), bottomRight->GetY(), bottomLeft->GetX(), + bottomLeft->GetY(), e); + BC_EXCEPTION_CHECK_ReturnValue(e, NULL); + return cbm; +} +CBC_ResultPointsAndTransitions* CBC_DataMatrixDetector::TransitionsBetween( + CBC_ResultPoint* from, + CBC_ResultPoint* to) { + int32_t fromX = (int32_t)from->GetX(); + int32_t fromY = (int32_t)from->GetY(); + int32_t toX = (int32_t)to->GetX(); + int32_t toY = (int32_t)to->GetY(); + FX_BOOL steep = FXSYS_abs(toY - fromY) > FXSYS_abs(toX - fromX); + if (steep) { + int32_t temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + int32_t dx = FXSYS_abs(toX - fromX); + int32_t dy = FXSYS_abs(toY - fromY); + int32_t error = -dx >> 1; + int32_t ystep = fromY < toY ? 1 : -1; + int32_t xstep = fromX < toX ? 1 : -1; + int32_t transitions = 0; + FX_BOOL inBlack = m_image->Get(steep ? fromY : fromX, steep ? fromX : fromY); + for (int32_t x = fromX, y = fromY; x != toX; x += xstep) { + FX_BOOL isBlack = m_image->Get(steep ? y : x, steep ? x : y); + if (isBlack != inBlack) { + transitions++; + inBlack = isBlack; + } + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + return new CBC_ResultPointsAndTransitions(from, to, transitions); +} +void CBC_DataMatrixDetector::OrderBestPatterns(CFX_PtrArray* patterns) { + FX_FLOAT abDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[0], + (CBC_ResultPoint*)(*patterns)[1]); + FX_FLOAT bcDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[1], + (CBC_ResultPoint*)(*patterns)[2]); + FX_FLOAT acDistance = (FX_FLOAT)Distance((CBC_ResultPoint*)(*patterns)[0], + (CBC_ResultPoint*)(*patterns)[2]); + CBC_ResultPoint *topLeft, *topRight, *bottomLeft; + if (bcDistance >= abDistance && bcDistance >= acDistance) { + topLeft = (CBC_ResultPoint*)(*patterns)[0]; + topRight = (CBC_ResultPoint*)(*patterns)[1]; + bottomLeft = (CBC_ResultPoint*)(*patterns)[2]; + } else if (acDistance >= bcDistance && acDistance >= abDistance) { + topLeft = (CBC_ResultPoint*)(*patterns)[1]; + topRight = (CBC_ResultPoint*)(*patterns)[0]; + bottomLeft = (CBC_ResultPoint*)(*patterns)[2]; + } else { + topLeft = (CBC_ResultPoint*)(*patterns)[2]; + topRight = (CBC_ResultPoint*)(*patterns)[0]; + bottomLeft = (CBC_ResultPoint*)(*patterns)[1]; + } + if ((bottomLeft->GetY() - topLeft->GetY()) * + (topRight->GetX() - topLeft->GetX()) < + (bottomLeft->GetX() - topLeft->GetX()) * + (topRight->GetY() - topLeft->GetY())) { + CBC_ResultPoint* temp = topRight; + topRight = bottomLeft; + bottomLeft = temp; + } + (*patterns)[0] = bottomLeft; + (*patterns)[1] = topLeft; + (*patterns)[2] = topRight; +} |