// 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 "core/fxcrt/include/fx_basic.h" #include "xfa/fxbarcode/BC_ResultPoint.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_PDF417Common.h" #include "xfa/fxbarcode/pdf417/BC_PDF417DetectionResultColumn.h" #include "xfa/fxbarcode/pdf417/BC_PDF417DetectionResultRowIndicatorColumn.h" #include "xfa/fxbarcode/utils.h" CBC_DetectionResultRowIndicatorColumn::CBC_DetectionResultRowIndicatorColumn( CBC_BoundingBox* boundingBox, FX_BOOL isLeft) : CBC_DetectionResultColumn(boundingBox) { m_isLeft = isLeft; } CBC_DetectionResultRowIndicatorColumn:: ~CBC_DetectionResultRowIndicatorColumn() {} void CBC_DetectionResultRowIndicatorColumn::setRowNumbers() { for (int32_t i = 0; i < m_codewords->GetSize(); i++) { CBC_Codeword* codeword = (CBC_Codeword*)m_codewords->GetAt(i); if (codeword) { codeword->setRowNumberAsRowIndicatorColumn(); } } } int32_t CBC_DetectionResultRowIndicatorColumn::adjustCompleteIndicatorColumnRowNumbers( CBC_BarcodeMetadata barcodeMetadata) { CFX_ArrayTemplate<CBC_Codeword*>* codewords = getCodewords(); setRowNumbers(); removeIncorrectCodewords(codewords, barcodeMetadata); CBC_BoundingBox* boundingBox = getBoundingBox(); CBC_ResultPoint* top = m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight(); CBC_ResultPoint* bottom = m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight(); int32_t firstRow = imageRowToCodewordIndex((int32_t)top->GetY()); int32_t lastRow = imageRowToCodewordIndex((int32_t)bottom->GetY()); FX_FLOAT averageRowHeight = (lastRow - firstRow) / (FX_FLOAT)barcodeMetadata.getRowCount(); int32_t barcodeRow = -1; int32_t maxRowHeight = 1; int32_t currentRowHeight = 0; for (int32_t codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { if (codewords->GetAt(codewordsRow) == NULL) { continue; } CBC_Codeword* codeword = codewords->GetAt(codewordsRow); int32_t rowDifference = codeword->getRowNumber() - barcodeRow; if (rowDifference == 0) { currentRowHeight++; } else if (rowDifference == 1) { maxRowHeight = maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight; currentRowHeight = 1; barcodeRow = codeword->getRowNumber(); } else if (rowDifference < 0) { codewords->SetAt(codewordsRow, NULL); } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) { codewords->SetAt(codewordsRow, NULL); } else if (rowDifference > codewordsRow) { codewords->SetAt(codewordsRow, NULL); } else { int32_t checkedRows; if (maxRowHeight > 2) { checkedRows = (maxRowHeight - 2) * rowDifference; } else { checkedRows = rowDifference; } FX_BOOL closePreviousCodewordFound = checkedRows >= codewordsRow; for (int32_t i = 1; i <= checkedRows && !closePreviousCodewordFound; i++) { closePreviousCodewordFound = codewords->GetAt(codewordsRow - i) != NULL; } if (closePreviousCodewordFound) { codewords->SetAt(codewordsRow, NULL); } else { barcodeRow = codeword->getRowNumber(); currentRowHeight = 1; } } } return (int32_t)(averageRowHeight + 0.5); } CFX_Int32Array* CBC_DetectionResultRowIndicatorColumn::getRowHeights( int32_t& e) { CBC_BarcodeMetadata* barcodeMetadata = getBarcodeMetadata(); if (barcodeMetadata == NULL) { e = BCExceptionCannotMetadata; return NULL; } adjustIncompleteIndicatorColumnRowNumbers(*barcodeMetadata); CFX_Int32Array* result = new CFX_Int32Array; result->SetSize(barcodeMetadata->getRowCount()); for (int32_t i = 0; i < getCodewords()->GetSize(); i++) { CBC_Codeword* codeword = (CBC_Codeword*)getCodewords()->GetAt(i); if (codeword) { result->SetAt(codeword->getRowNumber(), result->GetAt(codeword->getRowNumber()) + 1); } } return result; } int32_t CBC_DetectionResultRowIndicatorColumn:: adjustIncompleteIndicatorColumnRowNumbers( CBC_BarcodeMetadata barcodeMetadata) { CBC_BoundingBox* boundingBox = getBoundingBox(); CBC_ResultPoint* top = m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight(); CBC_ResultPoint* bottom = m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight(); int32_t firstRow = imageRowToCodewordIndex((int32_t)top->GetY()); int32_t lastRow = imageRowToCodewordIndex((int32_t)bottom->GetY()); FX_FLOAT averageRowHeight = (lastRow - firstRow) / (FX_FLOAT)barcodeMetadata.getRowCount(); CFX_ArrayTemplate<CBC_Codeword*>* codewords = getCodewords(); int32_t barcodeRow = -1; int32_t maxRowHeight = 1; int32_t currentRowHeight = 0; for (int32_t codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { if (codewords->GetAt(codewordsRow) == NULL) { continue; } CBC_Codeword* codeword = codewords->GetAt(codewordsRow); codeword->setRowNumberAsRowIndicatorColumn(); int32_t rowDifference = codeword->getRowNumber() - barcodeRow; if (rowDifference == 0) { currentRowHeight++; } else if (rowDifference == 1) { maxRowHeight = maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight; currentRowHeight = 1; barcodeRow = codeword->getRowNumber(); } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) { codewords->SetAt(codewordsRow, NULL); } else { barcodeRow = codeword->getRowNumber(); currentRowHeight = 1; } } return (int32_t)(averageRowHeight + 0.5); } CBC_BarcodeMetadata* CBC_DetectionResultRowIndicatorColumn::getBarcodeMetadata() { CFX_ArrayTemplate<CBC_Codeword*>* codewords = getCodewords(); CBC_BarcodeValue barcodeColumnCount; CBC_BarcodeValue barcodeRowCountUpperPart; CBC_BarcodeValue barcodeRowCountLowerPart; CBC_BarcodeValue barcodeECLevel; for (int32_t i = 0; i < codewords->GetSize(); i++) { CBC_Codeword* codeword = codewords->GetAt(i); if (codeword == NULL) { continue; } codeword->setRowNumberAsRowIndicatorColumn(); int32_t rowIndicatorValue = codeword->getValue() % 30; int32_t codewordRowNumber = codeword->getRowNumber(); if (!m_isLeft) { codewordRowNumber += 2; } switch (codewordRowNumber % 3) { case 0: barcodeRowCountUpperPart.setValue(rowIndicatorValue * 3 + 1); break; case 1: barcodeECLevel.setValue(rowIndicatorValue / 3); barcodeRowCountLowerPart.setValue(rowIndicatorValue % 3); break; case 2: barcodeColumnCount.setValue(rowIndicatorValue + 1); break; } } if ((barcodeColumnCount.getValue()->GetSize() == 0) || (barcodeRowCountUpperPart.getValue()->GetSize() == 0) || (barcodeRowCountLowerPart.getValue()->GetSize() == 0) || (barcodeECLevel.getValue()->GetSize() == 0) || barcodeColumnCount.getValue()->GetAt(0) < 1 || barcodeRowCountUpperPart.getValue()->GetAt(0) + barcodeRowCountLowerPart.getValue()->GetAt(0) < CBC_PDF417Common::MIN_ROWS_IN_BARCODE || barcodeRowCountUpperPart.getValue()->GetAt(0) + barcodeRowCountLowerPart.getValue()->GetAt(0) > CBC_PDF417Common::MAX_ROWS_IN_BARCODE) { return NULL; } CBC_BarcodeMetadata* barcodeMetadata = new CBC_BarcodeMetadata(barcodeColumnCount.getValue()->GetAt(0), barcodeRowCountUpperPart.getValue()->GetAt(0), barcodeRowCountLowerPart.getValue()->GetAt(0), barcodeECLevel.getValue()->GetAt(0)); removeIncorrectCodewords(codewords, *barcodeMetadata); return barcodeMetadata; } FX_BOOL CBC_DetectionResultRowIndicatorColumn::isLeft() { return m_isLeft; } CFX_ByteString CBC_DetectionResultRowIndicatorColumn::toString() { return CFX_ByteString("IsLeft: ") + m_isLeft + '\n' + CBC_DetectionResultColumn::toString(); } void CBC_DetectionResultRowIndicatorColumn::removeIncorrectCodewords( CFX_ArrayTemplate<CBC_Codeword*>* codewords, CBC_BarcodeMetadata barcodeMetadata) { for (int32_t codewordRow = 0; codewordRow < codewords->GetSize(); codewordRow++) { CBC_Codeword* codeword = codewords->GetAt(codewordRow); if (codeword == NULL) { continue; } int32_t rowIndicatorValue = codeword->getValue() % 30; int32_t codewordRowNumber = codeword->getRowNumber(); if (codewordRowNumber > barcodeMetadata.getRowCount()) { codewords->SetAt(codewordRow, NULL); continue; } if (!m_isLeft) { codewordRowNumber += 2; } switch (codewordRowNumber % 3) { case 0: if (rowIndicatorValue * 3 + 1 != barcodeMetadata.getRowCountUpperPart()) { codewords->SetAt(codewordRow, NULL); } break; case 1: if (rowIndicatorValue / 3 != barcodeMetadata.getErrorCorrectionLevel() || rowIndicatorValue % 3 != barcodeMetadata.getRowCountLowerPart()) { codewords->SetAt(codewordRow, NULL); } break; case 2: if (rowIndicatorValue + 1 != barcodeMetadata.getColumnCount()) { codewords->SetAt(codewordRow, NULL); } break; } } }