| // 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 2013 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 <memory> |
| |
| #include "xfa/fxbarcode/BC_DecoderResult.h" |
| #include "xfa/fxbarcode/BC_ResultPoint.h" |
| #include "xfa/fxbarcode/common/BC_CommonBitMatrix.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417BarcodeMetadata.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417BarcodeValue.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417BoundingBox.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417Codeword.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417CodewordDecoder.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417Common.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DecodedBitStreamParser.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DecodedBitStreamParser.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DecodedBitStreamParser.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DetectionResult.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DetectionResultColumn.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417DetectionResultRowIndicatorColumn.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417ECErrorCorrection.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417ECModulusGF.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417ECModulusPoly.h" |
| #include "xfa/fxbarcode/pdf417/BC_PDF417ScanningDecoder.h" |
| #include "xfa/fxbarcode/utils.h" |
| |
| int32_t CBC_PDF417ScanningDecoder::CODEWORD_SKEW_SIZE = 2; |
| int32_t CBC_PDF417ScanningDecoder::MAX_ERRORS = 3; |
| int32_t CBC_PDF417ScanningDecoder::MAX_EC_CODEWORDS = 512; |
| CBC_PDF417ECErrorCorrection* CBC_PDF417ScanningDecoder::errorCorrection = |
| nullptr; |
| |
| CBC_PDF417ScanningDecoder::CBC_PDF417ScanningDecoder() {} |
| CBC_PDF417ScanningDecoder::~CBC_PDF417ScanningDecoder() {} |
| void CBC_PDF417ScanningDecoder::Initialize() { |
| errorCorrection = new CBC_PDF417ECErrorCorrection; |
| } |
| void CBC_PDF417ScanningDecoder::Finalize() { |
| delete errorCorrection; |
| } |
| CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::decode( |
| CBC_CommonBitMatrix* image, |
| CBC_ResultPoint* imageTopLeft, |
| CBC_ResultPoint* imageBottomLeft, |
| CBC_ResultPoint* imageTopRight, |
| CBC_ResultPoint* imageBottomRight, |
| int32_t minCodewordWidth, |
| int32_t maxCodewordWidth, |
| int32_t& e) { |
| CBC_BoundingBox* boundingBox = new CBC_BoundingBox( |
| image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn = nullptr; |
| CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn = nullptr; |
| CBC_DetectionResult* detectionResult = nullptr; |
| for (int32_t i = 0; i < 2; i++) { |
| if (imageTopLeft) { |
| leftRowIndicatorColumn = |
| getRowIndicatorColumn(image, boundingBox, *imageTopLeft, TRUE, |
| minCodewordWidth, maxCodewordWidth); |
| } |
| if (imageTopRight) { |
| rightRowIndicatorColumn = |
| getRowIndicatorColumn(image, boundingBox, *imageTopRight, FALSE, |
| minCodewordWidth, maxCodewordWidth); |
| } |
| detectionResult = merge(leftRowIndicatorColumn, rightRowIndicatorColumn, e); |
| if (e != BCExceptionNO) { |
| e = BCExceptiontNotFoundInstance; |
| delete leftRowIndicatorColumn; |
| delete rightRowIndicatorColumn; |
| delete boundingBox; |
| return nullptr; |
| } |
| if (i == 0 && (detectionResult->getBoundingBox()->getMinY() < |
| boundingBox->getMinY() || |
| detectionResult->getBoundingBox()->getMaxY() > |
| boundingBox->getMaxY())) { |
| delete boundingBox; |
| boundingBox = detectionResult->getBoundingBox(); |
| } else { |
| detectionResult->setBoundingBox(boundingBox); |
| break; |
| } |
| } |
| int32_t maxBarcodeColumn = detectionResult->getBarcodeColumnCount() + 1; |
| detectionResult->setDetectionResultColumn(0, leftRowIndicatorColumn); |
| detectionResult->setDetectionResultColumn(maxBarcodeColumn, |
| rightRowIndicatorColumn); |
| FX_BOOL leftToRight = !!leftRowIndicatorColumn; |
| for (int32_t barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; |
| barcodeColumnCount++) { |
| int32_t barcodeColumn = leftToRight ? barcodeColumnCount |
| : maxBarcodeColumn - barcodeColumnCount; |
| if (detectionResult->getDetectionResultColumn(barcodeColumn)) { |
| continue; |
| } |
| CBC_DetectionResultColumn* detectionResultColumn = nullptr; |
| if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) { |
| detectionResultColumn = new CBC_DetectionResultRowIndicatorColumn( |
| boundingBox, barcodeColumn == 0); |
| } else { |
| detectionResultColumn = new CBC_DetectionResultColumn(boundingBox); |
| } |
| detectionResult->setDetectionResultColumn(barcodeColumn, |
| detectionResultColumn); |
| int32_t startColumn = -1; |
| int32_t previousStartColumn = startColumn; |
| for (int32_t imageRow = boundingBox->getMinY(); |
| imageRow <= boundingBox->getMaxY(); imageRow++) { |
| startColumn = |
| getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight); |
| if (startColumn < 0 || startColumn > boundingBox->getMaxX()) { |
| if (previousStartColumn == -1) { |
| continue; |
| } |
| startColumn = previousStartColumn; |
| } |
| CBC_Codeword* codeword = detectCodeword( |
| image, boundingBox->getMinX(), boundingBox->getMaxX(), leftToRight, |
| startColumn, imageRow, minCodewordWidth, maxCodewordWidth); |
| if (codeword) { |
| detectionResultColumn->setCodeword(imageRow, codeword); |
| previousStartColumn = startColumn; |
| minCodewordWidth = minCodewordWidth < codeword->getWidth() |
| ? minCodewordWidth |
| : codeword->getWidth(); |
| maxCodewordWidth = maxCodewordWidth > codeword->getWidth() |
| ? maxCodewordWidth |
| : codeword->getWidth(); |
| } |
| } |
| } |
| CBC_CommonDecoderResult* decoderresult = |
| createDecoderResult(detectionResult, e); |
| if (e != BCExceptionNO) { |
| delete detectionResult; |
| return nullptr; |
| } |
| return decoderresult; |
| } |
| |
| CFX_ByteString CBC_PDF417ScanningDecoder::toString( |
| CBC_BarcodeValueArrayArray* barcodeMatrix) { |
| CFX_ByteString result; |
| for (int32_t row = 0; row < barcodeMatrix->GetSize(); row++) { |
| result += row; |
| for (int32_t l = 0; l < barcodeMatrix->GetAt(row)->GetSize(); l++) { |
| CBC_BarcodeValue* barcodeValue = barcodeMatrix->GetAt(row)->GetAt(l); |
| if (barcodeValue->getValue()->GetSize() == 0) { |
| result += ""; |
| } else { |
| result += barcodeValue->getValue()->GetAt(0); |
| result += |
| barcodeValue->getConfidence(barcodeValue->getValue()->GetAt(0)); |
| } |
| } |
| } |
| return result; |
| } |
| |
| CBC_DetectionResult* CBC_PDF417ScanningDecoder::merge( |
| CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn, |
| CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn, |
| int32_t& e) { |
| if (!leftRowIndicatorColumn && !rightRowIndicatorColumn) { |
| e = BCExceptionIllegalArgument; |
| return nullptr; |
| } |
| CBC_BarcodeMetadata* barcodeMetadata = |
| getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn); |
| if (!barcodeMetadata) { |
| e = BCExceptionCannotMetadata; |
| return nullptr; |
| } |
| CBC_BoundingBox* leftboundingBox = |
| adjustBoundingBox(leftRowIndicatorColumn, e); |
| if (e != BCExceptionNO) { |
| delete barcodeMetadata; |
| return nullptr; |
| } |
| CBC_BoundingBox* rightboundingBox = |
| adjustBoundingBox(rightRowIndicatorColumn, e); |
| if (e != BCExceptionNO) { |
| delete barcodeMetadata; |
| return nullptr; |
| } |
| CBC_BoundingBox* boundingBox = |
| CBC_BoundingBox::merge(leftboundingBox, rightboundingBox, e); |
| if (e != BCExceptionNO) { |
| delete barcodeMetadata; |
| return nullptr; |
| } |
| CBC_DetectionResult* detectionresult = |
| new CBC_DetectionResult(barcodeMetadata, boundingBox); |
| return detectionresult; |
| } |
| CBC_BoundingBox* CBC_PDF417ScanningDecoder::adjustBoundingBox( |
| CBC_DetectionResultRowIndicatorColumn* rowIndicatorColumn, |
| int32_t& e) { |
| if (!rowIndicatorColumn) |
| return nullptr; |
| |
| CFX_Int32Array* rowHeights = rowIndicatorColumn->getRowHeights(e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| int32_t maxRowHeight = getMax(*rowHeights); |
| int32_t missingStartRows = 0; |
| for (int32_t i = 0; i < rowHeights->GetSize(); i++) { |
| int32_t rowHeight = rowHeights->GetAt(i); |
| missingStartRows += maxRowHeight - rowHeight; |
| if (rowHeight > 0) { |
| break; |
| } |
| } |
| CFX_ArrayTemplate<CBC_Codeword*>* codewords = |
| rowIndicatorColumn->getCodewords(); |
| for (int32_t row = 0; missingStartRows > 0 && !codewords->GetAt(row); row++) { |
| missingStartRows--; |
| } |
| int32_t missingEndRows = 0; |
| for (int32_t row1 = rowHeights->GetSize() - 1; row1 >= 0; row1--) { |
| missingEndRows += maxRowHeight - rowHeights->GetAt(row1); |
| if (rowHeights->GetAt(row1) > 0) { |
| break; |
| } |
| } |
| for (int32_t row2 = codewords->GetSize() - 1; |
| missingEndRows > 0 && !codewords->GetAt(row2); row2--) { |
| missingEndRows--; |
| } |
| CBC_BoundingBox* boundingBox = |
| rowIndicatorColumn->getBoundingBox()->addMissingRows( |
| missingStartRows, missingEndRows, rowIndicatorColumn->isLeft(), e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| return boundingBox; |
| } |
| int32_t CBC_PDF417ScanningDecoder::getMax(CFX_Int32Array& values) { |
| int32_t maxValue = -1; |
| for (int32_t i = 0; i < values.GetSize(); i++) { |
| int32_t value = values.GetAt(i); |
| maxValue = maxValue > value ? maxValue : value; |
| } |
| return maxValue; |
| } |
| CBC_BarcodeMetadata* CBC_PDF417ScanningDecoder::getBarcodeMetadata( |
| CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn, |
| CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn) { |
| CBC_BarcodeMetadata* leftBarcodeMetadata = |
| leftRowIndicatorColumn ? leftRowIndicatorColumn->getBarcodeMetadata() |
| : nullptr; |
| if (!leftBarcodeMetadata) { |
| return rightRowIndicatorColumn |
| ? rightRowIndicatorColumn->getBarcodeMetadata() |
| : nullptr; |
| } |
| |
| CBC_BarcodeMetadata* rightBarcodeMetadata = |
| rightRowIndicatorColumn ? rightRowIndicatorColumn->getBarcodeMetadata() |
| : nullptr; |
| if (!rightBarcodeMetadata) { |
| return leftRowIndicatorColumn ? leftRowIndicatorColumn->getBarcodeMetadata() |
| : nullptr; |
| } |
| |
| if (leftBarcodeMetadata->getColumnCount() != |
| rightBarcodeMetadata->getColumnCount() && |
| leftBarcodeMetadata->getErrorCorrectionLevel() != |
| rightBarcodeMetadata->getErrorCorrectionLevel() && |
| leftBarcodeMetadata->getRowCount() != |
| rightBarcodeMetadata->getRowCount()) { |
| delete leftBarcodeMetadata; |
| delete rightBarcodeMetadata; |
| return nullptr; |
| } |
| delete rightBarcodeMetadata; |
| return leftBarcodeMetadata; |
| } |
| CBC_DetectionResultRowIndicatorColumn* |
| CBC_PDF417ScanningDecoder::getRowIndicatorColumn(CBC_CommonBitMatrix* image, |
| CBC_BoundingBox* boundingBox, |
| CBC_ResultPoint startPoint, |
| FX_BOOL leftToRight, |
| int32_t minCodewordWidth, |
| int32_t maxCodewordWidth) { |
| CBC_DetectionResultRowIndicatorColumn* rowIndicatorColumn = |
| new CBC_DetectionResultRowIndicatorColumn(boundingBox, leftToRight); |
| for (int32_t i = 0; i < 2; i++) { |
| int32_t increment = i == 0 ? 1 : -1; |
| int32_t startColumn = (int32_t)startPoint.GetX(); |
| for (int32_t imageRow = (int32_t)startPoint.GetY(); |
| imageRow <= boundingBox->getMaxY() && |
| imageRow >= boundingBox->getMinY(); |
| imageRow += increment) { |
| CBC_Codeword* codeword = |
| detectCodeword(image, 0, image->GetWidth(), leftToRight, startColumn, |
| imageRow, minCodewordWidth, maxCodewordWidth); |
| if (codeword) { |
| rowIndicatorColumn->setCodeword(imageRow, codeword); |
| if (leftToRight) { |
| startColumn = codeword->getStartX(); |
| } else { |
| startColumn = codeword->getEndX(); |
| } |
| } |
| } |
| } |
| return rowIndicatorColumn; |
| } |
| |
| void CBC_PDF417ScanningDecoder::adjustCodewordCount( |
| CBC_DetectionResult* detectionResult, |
| CBC_BarcodeValueArrayArray* barcodeMatrix, |
| int32_t& e) { |
| std::unique_ptr<CFX_Int32Array> numberOfCodewords( |
| barcodeMatrix->GetAt(0)->GetAt(1)->getValue()); |
| int32_t calculatedNumberOfCodewords = |
| detectionResult->getBarcodeColumnCount() * |
| detectionResult->getBarcodeRowCount() - |
| getNumberOfECCodeWords(detectionResult->getBarcodeECLevel()); |
| if (numberOfCodewords->GetSize() == 0) { |
| if (calculatedNumberOfCodewords < 1 || |
| calculatedNumberOfCodewords > |
| CBC_PDF417Common::MAX_CODEWORDS_IN_BARCODE) { |
| e = BCExceptiontNotFoundInstance; |
| BC_EXCEPTION_CHECK_ReturnVoid(e); |
| } |
| barcodeMatrix->GetAt(0)->GetAt(1)->setValue(calculatedNumberOfCodewords); |
| } else if (numberOfCodewords->GetAt(0) != calculatedNumberOfCodewords) { |
| barcodeMatrix->GetAt(0)->GetAt(1)->setValue(calculatedNumberOfCodewords); |
| } |
| } |
| |
| CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::createDecoderResult( |
| CBC_DetectionResult* detectionResult, |
| int32_t& e) { |
| std::unique_ptr<CBC_BarcodeValueArrayArray> barcodeMatrix( |
| createBarcodeMatrix(detectionResult)); |
| adjustCodewordCount(detectionResult, barcodeMatrix.get(), e); |
| if (e != BCExceptionNO) { |
| for (int32_t i = 0; i < barcodeMatrix->GetSize(); i++) { |
| CBC_BarcodeValueArray* temp = barcodeMatrix->GetAt(i); |
| for (int32_t j = 0; j < temp->GetSize(); j++) |
| delete temp->GetAt(j); |
| delete temp; |
| } |
| return nullptr; |
| } |
| CFX_Int32Array erasures; |
| CFX_Int32Array codewords; |
| codewords.SetSize(detectionResult->getBarcodeRowCount() * |
| detectionResult->getBarcodeColumnCount()); |
| CFX_ArrayTemplate<CFX_Int32Array*> ambiguousIndexValuesList; |
| CFX_Int32Array ambiguousIndexesList; |
| for (int32_t row = 0; row < detectionResult->getBarcodeRowCount(); row++) { |
| for (int32_t l = 0; l < detectionResult->getBarcodeColumnCount(); l++) { |
| CFX_Int32Array* values = |
| barcodeMatrix->GetAt(row)->GetAt(l + 1)->getValue(); |
| int32_t codewordIndex = |
| row * detectionResult->getBarcodeColumnCount() + l; |
| if (values->GetSize() == 0) { |
| erasures.Add(codewordIndex); |
| } else if (values->GetSize() == 1) { |
| codewords[codewordIndex] = values->GetAt(0); |
| } else { |
| ambiguousIndexesList.Add(codewordIndex); |
| ambiguousIndexValuesList.Add(values); |
| } |
| } |
| } |
| CFX_ArrayTemplate<CFX_Int32Array*> ambiguousIndexValues; |
| ambiguousIndexValues.SetSize(ambiguousIndexValuesList.GetSize()); |
| for (int32_t i = 0; i < ambiguousIndexValues.GetSize(); i++) { |
| ambiguousIndexValues.SetAt(i, ambiguousIndexValuesList.GetAt(i)); |
| } |
| for (int32_t l = 0; l < barcodeMatrix->GetSize(); l++) { |
| CBC_BarcodeValueArray* temp = barcodeMatrix->GetAt(l); |
| for (int32_t j = 0; j < temp->GetSize(); j++) |
| delete temp->GetAt(j); |
| temp->RemoveAll(); |
| delete temp; |
| } |
| CBC_CommonDecoderResult* decoderResult = |
| createDecoderResultFromAmbiguousValues( |
| detectionResult->getBarcodeECLevel(), codewords, erasures, |
| ambiguousIndexesList, ambiguousIndexValues, e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| return decoderResult; |
| } |
| |
| CBC_CommonDecoderResult* |
| CBC_PDF417ScanningDecoder::createDecoderResultFromAmbiguousValues( |
| int32_t ecLevel, |
| CFX_Int32Array& codewords, |
| CFX_Int32Array& erasureArray, |
| CFX_Int32Array& ambiguousIndexes, |
| CFX_ArrayTemplate<CFX_Int32Array*>& ambiguousIndexValues, |
| int32_t& e) { |
| CFX_Int32Array ambiguousIndexCount; |
| ambiguousIndexCount.SetSize(ambiguousIndexes.GetSize()); |
| int32_t tries = 100; |
| while (tries-- > 0) { |
| for (int32_t l = 0; l < ambiguousIndexCount.GetSize(); l++) { |
| codewords[ambiguousIndexes[l]] = |
| ambiguousIndexValues.GetAt(l)->GetAt(ambiguousIndexCount[l]); |
| } |
| CBC_CommonDecoderResult* decoderResult = |
| decodeCodewords(codewords, ecLevel, erasureArray, e); |
| if (e == BCExceptionNO) |
| return decoderResult; |
| |
| e = BCExceptionNO; |
| if (ambiguousIndexCount.GetSize() == 0) { |
| e = BCExceptionChecksumInstance; |
| return nullptr; |
| } |
| for (int32_t i = 0; i < ambiguousIndexCount.GetSize(); i++) { |
| if (ambiguousIndexCount[i] < |
| ambiguousIndexValues.GetAt(i)->GetSize() - 1) { |
| ambiguousIndexCount[i]++; |
| break; |
| } else { |
| ambiguousIndexCount[i] = 0; |
| if (i == ambiguousIndexCount.GetSize() - 1) { |
| e = BCExceptionChecksumInstance; |
| return nullptr; |
| } |
| } |
| } |
| } |
| e = BCExceptionChecksumInstance; |
| return nullptr; |
| } |
| CBC_BarcodeValueArrayArray* CBC_PDF417ScanningDecoder::createBarcodeMatrix( |
| CBC_DetectionResult* detectionResult) { |
| CBC_BarcodeValueArrayArray* barcodeMatrix = new CBC_BarcodeValueArrayArray; |
| barcodeMatrix->SetSize(detectionResult->getBarcodeRowCount()); |
| for (int32_t row = 0; row < barcodeMatrix->GetSize(); row++) { |
| CBC_BarcodeValueArray* temp = new CBC_BarcodeValueArray; |
| temp->SetSize(detectionResult->getBarcodeColumnCount() + 2); |
| for (int32_t column = 0; |
| column < detectionResult->getBarcodeColumnCount() + 2; column++) { |
| temp->SetAt(column, new CBC_BarcodeValue()); |
| } |
| barcodeMatrix->SetAt(row, temp); |
| } |
| for (int32_t i = 0; |
| i < detectionResult->getDetectionResultColumns().GetSize(); i++) { |
| CBC_DetectionResultColumn* detectionResultColumn = |
| detectionResult->getDetectionResultColumns().GetAt(i); |
| if (!detectionResultColumn) |
| continue; |
| |
| CFX_ArrayTemplate<CBC_Codeword*>* temp = |
| detectionResultColumn->getCodewords(); |
| for (int32_t l = 0; l < temp->GetSize(); l++) { |
| CBC_Codeword* codeword = temp->GetAt(l); |
| if (!codeword || codeword->getRowNumber() == -1) |
| continue; |
| |
| barcodeMatrix->GetAt(codeword->getRowNumber()) |
| ->GetAt(i) |
| ->setValue(codeword->getValue()); |
| } |
| } |
| return barcodeMatrix; |
| } |
| FX_BOOL CBC_PDF417ScanningDecoder::isValidBarcodeColumn( |
| CBC_DetectionResult* detectionResult, |
| int32_t barcodeColumn) { |
| return barcodeColumn >= 0 && |
| barcodeColumn <= detectionResult->getBarcodeColumnCount() + 1; |
| } |
| int32_t CBC_PDF417ScanningDecoder::getStartColumn( |
| CBC_DetectionResult* detectionResult, |
| int32_t barcodeColumn, |
| int32_t imageRow, |
| FX_BOOL leftToRight) { |
| int32_t offset = leftToRight ? 1 : -1; |
| CBC_Codeword* codeword = nullptr; |
| if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { |
| codeword = detectionResult->getDetectionResultColumn(barcodeColumn - offset) |
| ->getCodeword(imageRow); |
| } |
| if (codeword) { |
| return leftToRight ? codeword->getEndX() : codeword->getStartX(); |
| } |
| codeword = detectionResult->getDetectionResultColumn(barcodeColumn) |
| ->getCodewordNearby(imageRow); |
| if (codeword) { |
| return leftToRight ? codeword->getStartX() : codeword->getEndX(); |
| } |
| if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { |
| codeword = detectionResult->getDetectionResultColumn(barcodeColumn - offset) |
| ->getCodewordNearby(imageRow); |
| } |
| if (codeword) { |
| return leftToRight ? codeword->getEndX() : codeword->getStartX(); |
| } |
| int32_t skippedColumns = 0; |
| while (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) { |
| barcodeColumn -= offset; |
| for (int32_t i = 0; |
| i < detectionResult->getDetectionResultColumn(barcodeColumn) |
| ->getCodewords() |
| ->GetSize(); |
| i++) { |
| CBC_Codeword* previousRowCodeword = |
| detectionResult->getDetectionResultColumn(barcodeColumn) |
| ->getCodewords() |
| ->GetAt(i); |
| if (previousRowCodeword) { |
| return (leftToRight ? previousRowCodeword->getEndX() |
| : previousRowCodeword->getStartX()) + |
| offset * skippedColumns * (previousRowCodeword->getEndX() - |
| previousRowCodeword->getStartX()); |
| } |
| } |
| skippedColumns++; |
| } |
| return leftToRight ? detectionResult->getBoundingBox()->getMinX() |
| : detectionResult->getBoundingBox()->getMaxX(); |
| } |
| CBC_Codeword* CBC_PDF417ScanningDecoder::detectCodeword( |
| CBC_CommonBitMatrix* image, |
| int32_t minColumn, |
| int32_t maxColumn, |
| FX_BOOL leftToRight, |
| int32_t startColumn, |
| int32_t imageRow, |
| int32_t minCodewordWidth, |
| int32_t maxCodewordWidth) { |
| startColumn = adjustCodewordStartColumn(image, minColumn, maxColumn, |
| leftToRight, startColumn, imageRow); |
| CFX_Int32Array* moduleBitCount = getModuleBitCount( |
| image, minColumn, maxColumn, leftToRight, startColumn, imageRow); |
| if (!moduleBitCount) |
| return nullptr; |
| |
| int32_t endColumn; |
| int32_t codewordBitCount = CBC_PDF417Common::getBitCountSum(*moduleBitCount); |
| if (leftToRight) { |
| endColumn = startColumn + codewordBitCount; |
| } else { |
| for (int32_t i = 0; i<moduleBitCount->GetSize()>> 1; i++) { |
| int32_t tmpCount = moduleBitCount->GetAt(i); |
| moduleBitCount->SetAt( |
| i, moduleBitCount->GetAt(moduleBitCount->GetSize() - 1 - i)); |
| moduleBitCount->SetAt(moduleBitCount->GetSize() - 1 - i, tmpCount); |
| } |
| endColumn = startColumn; |
| startColumn = endColumn - codewordBitCount; |
| } |
| int32_t decodedValue = |
| CBC_PDF417CodewordDecoder::getDecodedValue(*moduleBitCount); |
| int32_t codeword = CBC_PDF417Common::getCodeword(decodedValue); |
| delete moduleBitCount; |
| if (codeword == -1) { |
| return nullptr; |
| } |
| return new CBC_Codeword(startColumn, endColumn, |
| getCodewordBucketNumber(decodedValue), codeword); |
| } |
| CFX_Int32Array* CBC_PDF417ScanningDecoder::getModuleBitCount( |
| CBC_CommonBitMatrix* image, |
| int32_t minColumn, |
| int32_t maxColumn, |
| FX_BOOL leftToRight, |
| int32_t startColumn, |
| int32_t imageRow) { |
| int32_t imageColumn = startColumn; |
| CFX_Int32Array* moduleBitCount = new CFX_Int32Array; |
| moduleBitCount->SetSize(8); |
| int32_t moduleNumber = 0; |
| int32_t increment = leftToRight ? 1 : -1; |
| FX_BOOL previousPixelValue = leftToRight; |
| while (((leftToRight && imageColumn < maxColumn) || |
| (!leftToRight && imageColumn >= minColumn)) && |
| moduleNumber < moduleBitCount->GetSize()) { |
| if (image->Get(imageColumn, imageRow) == previousPixelValue) { |
| moduleBitCount->SetAt(moduleNumber, |
| moduleBitCount->GetAt(moduleNumber) + 1); |
| imageColumn += increment; |
| } else { |
| moduleNumber++; |
| previousPixelValue = !previousPixelValue; |
| } |
| } |
| if (moduleNumber == moduleBitCount->GetSize() || |
| (((leftToRight && imageColumn == maxColumn) || |
| (!leftToRight && imageColumn == minColumn)) && |
| moduleNumber == moduleBitCount->GetSize() - 1)) { |
| return moduleBitCount; |
| } |
| delete moduleBitCount; |
| return nullptr; |
| } |
| int32_t CBC_PDF417ScanningDecoder::getNumberOfECCodeWords( |
| int32_t barcodeECLevel) { |
| return 2 << barcodeECLevel; |
| } |
| int32_t CBC_PDF417ScanningDecoder::adjustCodewordStartColumn( |
| CBC_CommonBitMatrix* image, |
| int32_t minColumn, |
| int32_t maxColumn, |
| FX_BOOL leftToRight, |
| int32_t codewordStartColumn, |
| int32_t imageRow) { |
| int32_t correctedStartColumn = codewordStartColumn; |
| int32_t increment = leftToRight ? -1 : 1; |
| for (int32_t i = 0; i < 2; i++) { |
| while (((leftToRight && correctedStartColumn >= minColumn) || |
| (!leftToRight && correctedStartColumn < maxColumn)) && |
| leftToRight == image->Get(correctedStartColumn, imageRow)) { |
| if (abs(codewordStartColumn - correctedStartColumn) > |
| CODEWORD_SKEW_SIZE) { |
| return codewordStartColumn; |
| } |
| correctedStartColumn += increment; |
| } |
| increment = -increment; |
| leftToRight = !leftToRight; |
| } |
| return correctedStartColumn; |
| } |
| FX_BOOL CBC_PDF417ScanningDecoder::checkCodewordSkew(int32_t codewordSize, |
| int32_t minCodewordWidth, |
| int32_t maxCodewordWidth) { |
| return minCodewordWidth - CODEWORD_SKEW_SIZE <= codewordSize && |
| codewordSize <= maxCodewordWidth + CODEWORD_SKEW_SIZE; |
| } |
| CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::decodeCodewords( |
| CFX_Int32Array& codewords, |
| int32_t ecLevel, |
| CFX_Int32Array& erasures, |
| int32_t& e) { |
| if (codewords.GetSize() == 0) { |
| e = BCExceptionFormatInstance; |
| return nullptr; |
| } |
| int32_t numECCodewords = 1 << (ecLevel + 1); |
| correctErrors(codewords, erasures, numECCodewords, e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| verifyCodewordCount(codewords, numECCodewords, e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| CFX_ByteString bytestring; |
| CBC_CommonDecoderResult* decoderResult = CBC_DecodedBitStreamPaser::decode( |
| codewords, bytestring.FormatInteger(ecLevel), e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, nullptr); |
| return decoderResult; |
| } |
| int32_t CBC_PDF417ScanningDecoder::correctErrors(CFX_Int32Array& codewords, |
| CFX_Int32Array& erasures, |
| int32_t numECCodewords, |
| int32_t& e) { |
| if ((erasures.GetSize() != 0 && |
| erasures.GetSize() > (numECCodewords / 2 + MAX_ERRORS)) || |
| numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS) { |
| e = BCExceptionChecksumInstance; |
| return -1; |
| } |
| int32_t result = CBC_PDF417ECErrorCorrection::decode( |
| codewords, numECCodewords, erasures, e); |
| BC_EXCEPTION_CHECK_ReturnValue(e, -1); |
| return result; |
| } |
| void CBC_PDF417ScanningDecoder::verifyCodewordCount(CFX_Int32Array& codewords, |
| int32_t numECCodewords, |
| int32_t& e) { |
| if (codewords.GetSize() < 4) { |
| e = BCExceptionFormatInstance; |
| return; |
| } |
| int32_t numberOfCodewords = codewords.GetAt(0); |
| if (numberOfCodewords > codewords.GetSize()) { |
| e = BCExceptionFormatInstance; |
| return; |
| } |
| if (numberOfCodewords == 0) { |
| if (numECCodewords < codewords.GetSize()) { |
| codewords[0] = codewords.GetSize() - numECCodewords; |
| } else { |
| e = BCExceptionFormatInstance; |
| return; |
| } |
| } |
| } |
| CFX_Int32Array* CBC_PDF417ScanningDecoder::getBitCountForCodeword( |
| int32_t codeword) { |
| CFX_Int32Array* result = new CFX_Int32Array; |
| result->SetSize(8); |
| int32_t previousValue = 0; |
| int32_t i = result->GetSize() - 1; |
| while (TRUE) { |
| if ((codeword & 0x1) != previousValue) { |
| previousValue = codeword & 0x1; |
| i--; |
| if (i < 0) { |
| break; |
| } |
| } |
| result->SetAt(i, result->GetAt(i) + 1); |
| codeword >>= 1; |
| } |
| return result; |
| } |
| int32_t CBC_PDF417ScanningDecoder::getCodewordBucketNumber(int32_t codeword) { |
| CFX_Int32Array* array = getBitCountForCodeword(codeword); |
| int32_t result = getCodewordBucketNumber(*array); |
| delete array; |
| return result; |
| } |
| int32_t CBC_PDF417ScanningDecoder::getCodewordBucketNumber( |
| CFX_Int32Array& moduleBitCount) { |
| return (moduleBitCount.GetAt(0) - moduleBitCount.GetAt(2) + |
| moduleBitCount.GetAt(4) - moduleBitCount.GetAt(6) + 9) % |
| 9; |
| } |