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