Home | History | Annotate | Download | only in pdf417
      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 2013 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/barcode.h"
     24 #include "xfa/src/fxbarcode/BC_ResultPoint.h"
     25 #include "BC_PDF417BarcodeMetadata.h"
     26 #include "BC_PDF417BoundingBox.h"
     27 #include "BC_PDF417Codeword.h"
     28 #include "BC_PDF417BarcodeValue.h"
     29 #include "BC_PDF417Common.h"
     30 #include "BC_PDF417DetectionResultColumn.h"
     31 #include "BC_PDF417DetectionResultRowIndicatorColumn.h"
     32 CBC_DetectionResultRowIndicatorColumn::CBC_DetectionResultRowIndicatorColumn(
     33     CBC_BoundingBox* boundingBox,
     34     FX_BOOL isLeft)
     35     : CBC_DetectionResultColumn(boundingBox) {
     36   m_isLeft = isLeft;
     37 }
     38 CBC_DetectionResultRowIndicatorColumn::
     39     ~CBC_DetectionResultRowIndicatorColumn() {}
     40 void CBC_DetectionResultRowIndicatorColumn::setRowNumbers() {
     41   for (int32_t i = 0; i < m_codewords->GetSize(); i++) {
     42     CBC_Codeword* codeword = (CBC_Codeword*)m_codewords->GetAt(i);
     43     if (codeword != NULL) {
     44       codeword->setRowNumberAsRowIndicatorColumn();
     45     }
     46   }
     47 }
     48 int32_t
     49 CBC_DetectionResultRowIndicatorColumn::adjustCompleteIndicatorColumnRowNumbers(
     50     CBC_BarcodeMetadata barcodeMetadata) {
     51   CFX_PtrArray* codewords = getCodewords();
     52   setRowNumbers();
     53   removeIncorrectCodewords(codewords, barcodeMetadata);
     54   CBC_BoundingBox* boundingBox = getBoundingBox();
     55   CBC_ResultPoint* top =
     56       m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight();
     57   CBC_ResultPoint* bottom =
     58       m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight();
     59   int32_t firstRow = imageRowToCodewordIndex((int32_t)top->GetY());
     60   int32_t lastRow = imageRowToCodewordIndex((int32_t)bottom->GetY());
     61   FX_FLOAT averageRowHeight =
     62       (lastRow - firstRow) / (FX_FLOAT)barcodeMetadata.getRowCount();
     63   int32_t barcodeRow = -1;
     64   int32_t maxRowHeight = 1;
     65   int32_t currentRowHeight = 0;
     66   for (int32_t codewordsRow = firstRow; codewordsRow < lastRow;
     67        codewordsRow++) {
     68     if (codewords->GetAt(codewordsRow) == NULL) {
     69       continue;
     70     }
     71     CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordsRow);
     72     int32_t rowDifference = codeword->getRowNumber() - barcodeRow;
     73     if (rowDifference == 0) {
     74       currentRowHeight++;
     75     } else if (rowDifference == 1) {
     76       maxRowHeight =
     77           maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight;
     78       currentRowHeight = 1;
     79       barcodeRow = codeword->getRowNumber();
     80     } else if (rowDifference < 0) {
     81       codewords->SetAt(codewordsRow, NULL);
     82     } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) {
     83       codewords->SetAt(codewordsRow, NULL);
     84     } else if (rowDifference > codewordsRow) {
     85       codewords->SetAt(codewordsRow, NULL);
     86     } else {
     87       int32_t checkedRows;
     88       if (maxRowHeight > 2) {
     89         checkedRows = (maxRowHeight - 2) * rowDifference;
     90       } else {
     91         checkedRows = rowDifference;
     92       }
     93       FX_BOOL closePreviousCodewordFound = checkedRows >= codewordsRow;
     94       for (int32_t i = 1; i <= checkedRows && !closePreviousCodewordFound;
     95            i++) {
     96         closePreviousCodewordFound = codewords->GetAt(codewordsRow - i) != NULL;
     97       }
     98       if (closePreviousCodewordFound) {
     99         codewords->SetAt(codewordsRow, NULL);
    100       } else {
    101         barcodeRow = codeword->getRowNumber();
    102         currentRowHeight = 1;
    103       }
    104     }
    105   }
    106   return (int32_t)(averageRowHeight + 0.5);
    107 }
    108 CFX_Int32Array* CBC_DetectionResultRowIndicatorColumn::getRowHeights(
    109     int32_t& e) {
    110   CBC_BarcodeMetadata* barcodeMetadata = getBarcodeMetadata();
    111   if (barcodeMetadata == NULL) {
    112     e = BCExceptionCannotMetadata;
    113     return NULL;
    114   }
    115   adjustIncompleteIndicatorColumnRowNumbers(*barcodeMetadata);
    116   CFX_Int32Array* result = new CFX_Int32Array;
    117   result->SetSize(barcodeMetadata->getRowCount());
    118   for (int32_t i = 0; i < getCodewords()->GetSize(); i++) {
    119     CBC_Codeword* codeword = (CBC_Codeword*)getCodewords()->GetAt(i);
    120     if (codeword != NULL) {
    121       result->SetAt(codeword->getRowNumber(),
    122                     result->GetAt(codeword->getRowNumber()) + 1);
    123     }
    124   }
    125   return result;
    126 }
    127 int32_t CBC_DetectionResultRowIndicatorColumn::
    128     adjustIncompleteIndicatorColumnRowNumbers(
    129         CBC_BarcodeMetadata barcodeMetadata) {
    130   CBC_BoundingBox* boundingBox = getBoundingBox();
    131   CBC_ResultPoint* top =
    132       m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight();
    133   CBC_ResultPoint* bottom =
    134       m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight();
    135   int32_t firstRow = imageRowToCodewordIndex((int32_t)top->GetY());
    136   int32_t lastRow = imageRowToCodewordIndex((int32_t)bottom->GetY());
    137   FX_FLOAT averageRowHeight =
    138       (lastRow - firstRow) / (FX_FLOAT)barcodeMetadata.getRowCount();
    139   CFX_PtrArray* codewords = getCodewords();
    140   int32_t barcodeRow = -1;
    141   int32_t maxRowHeight = 1;
    142   int32_t currentRowHeight = 0;
    143   for (int32_t codewordsRow = firstRow; codewordsRow < lastRow;
    144        codewordsRow++) {
    145     if (codewords->GetAt(codewordsRow) == NULL) {
    146       continue;
    147     }
    148     CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordsRow);
    149     codeword->setRowNumberAsRowIndicatorColumn();
    150     int32_t rowDifference = codeword->getRowNumber() - barcodeRow;
    151     if (rowDifference == 0) {
    152       currentRowHeight++;
    153     } else if (rowDifference == 1) {
    154       maxRowHeight =
    155           maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight;
    156       currentRowHeight = 1;
    157       barcodeRow = codeword->getRowNumber();
    158     } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) {
    159       codewords->SetAt(codewordsRow, NULL);
    160     } else {
    161       barcodeRow = codeword->getRowNumber();
    162       currentRowHeight = 1;
    163     }
    164   }
    165   return (int32_t)(averageRowHeight + 0.5);
    166 }
    167 CBC_BarcodeMetadata*
    168 CBC_DetectionResultRowIndicatorColumn::getBarcodeMetadata() {
    169   CFX_PtrArray* codewords = getCodewords();
    170   CBC_BarcodeValue barcodeColumnCount;
    171   CBC_BarcodeValue barcodeRowCountUpperPart;
    172   CBC_BarcodeValue barcodeRowCountLowerPart;
    173   CBC_BarcodeValue barcodeECLevel;
    174   for (int32_t i = 0; i < codewords->GetSize(); i++) {
    175     CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(i);
    176     if (codeword == NULL) {
    177       continue;
    178     }
    179     codeword->setRowNumberAsRowIndicatorColumn();
    180     int32_t rowIndicatorValue = codeword->getValue() % 30;
    181     int32_t codewordRowNumber = codeword->getRowNumber();
    182     if (!m_isLeft) {
    183       codewordRowNumber += 2;
    184     }
    185     switch (codewordRowNumber % 3) {
    186       case 0:
    187         barcodeRowCountUpperPart.setValue(rowIndicatorValue * 3 + 1);
    188         break;
    189       case 1:
    190         barcodeECLevel.setValue(rowIndicatorValue / 3);
    191         barcodeRowCountLowerPart.setValue(rowIndicatorValue % 3);
    192         break;
    193       case 2:
    194         barcodeColumnCount.setValue(rowIndicatorValue + 1);
    195         break;
    196     }
    197   }
    198   if ((barcodeColumnCount.getValue()->GetSize() == 0) ||
    199       (barcodeRowCountUpperPart.getValue()->GetSize() == 0) ||
    200       (barcodeRowCountLowerPart.getValue()->GetSize() == 0) ||
    201       (barcodeECLevel.getValue()->GetSize() == 0) ||
    202       barcodeColumnCount.getValue()->GetAt(0) < 1 ||
    203       barcodeRowCountUpperPart.getValue()->GetAt(0) +
    204               barcodeRowCountLowerPart.getValue()->GetAt(0) <
    205           CBC_PDF417Common::MIN_ROWS_IN_BARCODE ||
    206       barcodeRowCountUpperPart.getValue()->GetAt(0) +
    207               barcodeRowCountLowerPart.getValue()->GetAt(0) >
    208           CBC_PDF417Common::MAX_ROWS_IN_BARCODE) {
    209     return NULL;
    210   }
    211   CBC_BarcodeMetadata* barcodeMetadata =
    212       new CBC_BarcodeMetadata(barcodeColumnCount.getValue()->GetAt(0),
    213                               barcodeRowCountUpperPart.getValue()->GetAt(0),
    214                               barcodeRowCountLowerPart.getValue()->GetAt(0),
    215                               barcodeECLevel.getValue()->GetAt(0));
    216   removeIncorrectCodewords(codewords, *barcodeMetadata);
    217   return barcodeMetadata;
    218 }
    219 FX_BOOL CBC_DetectionResultRowIndicatorColumn::isLeft() {
    220   return m_isLeft;
    221 }
    222 CFX_ByteString CBC_DetectionResultRowIndicatorColumn::toString() {
    223   return (CFX_ByteString) "IsLeft: " + (CFX_ByteString)m_isLeft + '\n' +
    224          CBC_DetectionResultColumn::toString();
    225 }
    226 void CBC_DetectionResultRowIndicatorColumn::removeIncorrectCodewords(
    227     CFX_PtrArray* codewords,
    228     CBC_BarcodeMetadata barcodeMetadata) {
    229   for (int32_t codewordRow = 0; codewordRow < codewords->GetSize();
    230        codewordRow++) {
    231     CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordRow);
    232     if (codeword == NULL) {
    233       continue;
    234     }
    235     int32_t rowIndicatorValue = codeword->getValue() % 30;
    236     int32_t codewordRowNumber = codeword->getRowNumber();
    237     if (codewordRowNumber > barcodeMetadata.getRowCount()) {
    238       codewords->SetAt(codewordRow, NULL);
    239       continue;
    240     }
    241     if (!m_isLeft) {
    242       codewordRowNumber += 2;
    243     }
    244     switch (codewordRowNumber % 3) {
    245       case 0:
    246         if (rowIndicatorValue * 3 + 1 !=
    247             barcodeMetadata.getRowCountUpperPart()) {
    248           codewords->SetAt(codewordRow, NULL);
    249         }
    250         break;
    251       case 1:
    252         if (rowIndicatorValue / 3 !=
    253                 barcodeMetadata.getErrorCorrectionLevel() ||
    254             rowIndicatorValue % 3 != barcodeMetadata.getRowCountLowerPart()) {
    255           codewords->SetAt(codewordRow, NULL);
    256         }
    257         break;
    258       case 2:
    259         if (rowIndicatorValue + 1 != barcodeMetadata.getColumnCount()) {
    260           codewords->SetAt(codewordRow, NULL);
    261         }
    262         break;
    263     }
    264   }
    265 }
    266