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"
CBC_DetectionResultRowIndicatorColumn(CBC_BoundingBox * boundingBox,FX_BOOL isLeft)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::
~CBC_DetectionResultRowIndicatorColumn()39 ~CBC_DetectionResultRowIndicatorColumn() {}
setRowNumbers()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
adjustCompleteIndicatorColumnRowNumbers(CBC_BarcodeMetadata barcodeMetadata)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 }
getRowHeights(int32_t & e)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::
adjustIncompleteIndicatorColumnRowNumbers(CBC_BarcodeMetadata barcodeMetadata)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*
getBarcodeMetadata()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 }
isLeft()219 FX_BOOL CBC_DetectionResultRowIndicatorColumn::isLeft() {
220 return m_isLeft;
221 }
toString()222 CFX_ByteString CBC_DetectionResultRowIndicatorColumn::toString() {
223 return (CFX_ByteString) "IsLeft: " + (CFX_ByteString)m_isLeft + '\n' +
224 CBC_DetectionResultColumn::toString();
225 }
removeIncorrectCodewords(CFX_PtrArray * codewords,CBC_BarcodeMetadata barcodeMetadata)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