• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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