Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / xfa / src / fxbarcode / pdf417 / BC_PDF417ScanningDecoder.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 // Original code is licensed as follows:\r
7 /*\r
8  * Copyright 2013 ZXing authors\r
9  *\r
10  * Licensed under the Apache License, Version 2.0 (the "License");\r
11  * you may not use this file except in compliance with the License.\r
12  * You may obtain a copy of the License at\r
13  *\r
14  *      http://www.apache.org/licenses/LICENSE-2.0\r
15  *\r
16  * Unless required by applicable law or agreed to in writing, software\r
17  * distributed under the License is distributed on an "AS IS" BASIS,\r
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
19  * See the License for the specific language governing permissions and\r
20  * limitations under the License.\r
21  */\r
22 \r
23 #include "../barcode.h"\r
24 #include "../BC_DecoderResult.h"\r
25 #include "../BC_ResultPoint.h"\r
26 #include "../common/BC_CommonBitMatrix.h"\r
27 #include "BC_PDF417Codeword.h"\r
28 #include "BC_PDF417Common.h"\r
29 #include "BC_PDF417BarcodeValue.h"\r
30 #include "BC_PDF417BarcodeMetadata.h"\r
31 #include "BC_PDF417BoundingBox.h"\r
32 #include "BC_PDF417DetectionResultColumn.h"\r
33 #include "BC_PDF417DetectionResultRowIndicatorColumn.h"\r
34 #include "BC_PDF417DetectionResult.h"\r
35 #include "BC_PDF417DecodedBitStreamParser.h"\r
36 #include "BC_PDF417CodewordDecoder.h"\r
37 #include "BC_PDF417DecodedBitStreamParser.h"\r
38 #include "BC_PDF417ECModulusPoly.h"\r
39 #include "BC_PDF417ECModulusGF.h"\r
40 #include "BC_PDF417ECErrorCorrection.h"\r
41 #include "BC_PDF417DecodedBitStreamParser.h"\r
42 #include "BC_PDF417ScanningDecoder.h"\r
43 int32_t CBC_PDF417ScanningDecoder::CODEWORD_SKEW_SIZE = 2;\r
44 int32_t CBC_PDF417ScanningDecoder::MAX_ERRORS = 3;\r
45 int32_t CBC_PDF417ScanningDecoder::MAX_EC_CODEWORDS = 512;\r
46 CBC_PDF417ECErrorCorrection* CBC_PDF417ScanningDecoder::errorCorrection = NULL;\r
47 CBC_PDF417ScanningDecoder::CBC_PDF417ScanningDecoder()\r
48 {\r
49 }\r
50 CBC_PDF417ScanningDecoder::~CBC_PDF417ScanningDecoder()\r
51 {\r
52 }\r
53 void CBC_PDF417ScanningDecoder::Initialize()\r
54 {\r
55     errorCorrection = FX_NEW CBC_PDF417ECErrorCorrection;\r
56 }\r
57 void CBC_PDF417ScanningDecoder::Finalize()\r
58 {\r
59     delete errorCorrection;\r
60 }\r
61 CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::decode(CBC_CommonBitMatrix* image, CBC_ResultPoint* imageTopLeft, CBC_ResultPoint* imageBottomLeft, CBC_ResultPoint* imageTopRight,\r
62         CBC_ResultPoint* imageBottomRight, int32_t minCodewordWidth, int32_t maxCodewordWidth, int32_t &e)\r
63 {\r
64     CBC_BoundingBox* boundingBox = FX_NEW CBC_BoundingBox(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, e);\r
65     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
66     CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn = NULL;\r
67     CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn = NULL;\r
68     CBC_DetectionResult* detectionResult = NULL;\r
69     for (int32_t i = 0; i < 2; i++) {\r
70         if (imageTopLeft != NULL) {\r
71             leftRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, *imageTopLeft, TRUE, minCodewordWidth, maxCodewordWidth);\r
72         }\r
73         if (imageTopRight != NULL) {\r
74             rightRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, *imageTopRight, FALSE, minCodewordWidth, maxCodewordWidth);\r
75         }\r
76         detectionResult = merge(leftRowIndicatorColumn, rightRowIndicatorColumn, e);\r
77         if (e != BCExceptionNO) {\r
78             e = BCExceptiontNotFoundInstance;\r
79             delete leftRowIndicatorColumn;\r
80             delete rightRowIndicatorColumn;\r
81             delete boundingBox;\r
82             return NULL;\r
83         }\r
84         if (i == 0 && (detectionResult->getBoundingBox()->getMinY() < boundingBox->getMinY() || detectionResult->getBoundingBox()->getMaxY() > boundingBox->getMaxY())) {\r
85             delete boundingBox;\r
86             boundingBox = detectionResult->getBoundingBox();\r
87         } else {\r
88             detectionResult->setBoundingBox(boundingBox);\r
89             break;\r
90         }\r
91     }\r
92     int32_t maxBarcodeColumn = detectionResult->getBarcodeColumnCount() + 1;\r
93     detectionResult->setDetectionResultColumn(0, leftRowIndicatorColumn);\r
94     detectionResult->setDetectionResultColumn(maxBarcodeColumn, rightRowIndicatorColumn);\r
95     FX_BOOL leftToRight = leftRowIndicatorColumn != NULL;\r
96     for (int32_t barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) {\r
97         int32_t barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount;\r
98         if (detectionResult->getDetectionResultColumn(barcodeColumn) != NULL) {\r
99             continue;\r
100         }\r
101         CBC_DetectionResultColumn* detectionResultColumn = NULL;\r
102         if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) {\r
103             detectionResultColumn = FX_NEW CBC_DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn == 0);\r
104         } else {\r
105             detectionResultColumn = FX_NEW CBC_DetectionResultColumn(boundingBox);\r
106         }\r
107         detectionResult->setDetectionResultColumn(barcodeColumn, detectionResultColumn);\r
108         int32_t startColumn = -1;\r
109         int32_t previousStartColumn = startColumn;\r
110         for (int32_t imageRow = boundingBox->getMinY(); imageRow <= boundingBox->getMaxY(); imageRow++) {\r
111             startColumn = getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight);\r
112             if (startColumn < 0 || startColumn > boundingBox->getMaxX()) {\r
113                 if (previousStartColumn == -1) {\r
114                     continue;\r
115                 }\r
116                 startColumn = previousStartColumn;\r
117             }\r
118             CBC_Codeword* codeword = detectCodeword(image, boundingBox->getMinX(), boundingBox->getMaxX(), leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth);\r
119             if (codeword != NULL) {\r
120                 detectionResultColumn->setCodeword(imageRow, codeword);\r
121                 previousStartColumn = startColumn;\r
122                 minCodewordWidth = minCodewordWidth < codeword->getWidth() ? minCodewordWidth : codeword->getWidth();\r
123                 maxCodewordWidth = maxCodewordWidth > codeword->getWidth() ? maxCodewordWidth : codeword->getWidth();\r
124             }\r
125         }\r
126     }\r
127     CBC_CommonDecoderResult* decoderresult = createDecoderResult(detectionResult, e);\r
128     if (e != BCExceptionNO) {\r
129         delete detectionResult;\r
130         return NULL;\r
131     }\r
132     return decoderresult;\r
133 }\r
134 CFX_ByteString CBC_PDF417ScanningDecoder::toString(CFX_PtrArray* barcodeMatrix)\r
135 {\r
136     CFX_ByteString result;\r
137     for (int32_t row = 0; row < barcodeMatrix->GetSize(); row++) {\r
138         result += row;\r
139         int32_t l = 0;\r
140         for (; l < ((CFX_PtrArray*)barcodeMatrix->GetAt(row))->GetSize(); l++) {\r
141             CBC_BarcodeValue* barcodeValue = (CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(row))->GetAt(l);\r
142             if (barcodeValue->getValue()->GetSize() == 0) {\r
143                 result +=  "";\r
144             } else {\r
145                 result += barcodeValue->getValue()->GetAt(0);\r
146                 result += barcodeValue->getConfidence(barcodeValue->getValue()->GetAt(0));\r
147             }\r
148         }\r
149     }\r
150     return result;\r
151 }\r
152 CBC_DetectionResult* CBC_PDF417ScanningDecoder::merge(CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn, CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn, int32_t &e)\r
153 {\r
154     if (leftRowIndicatorColumn == NULL && rightRowIndicatorColumn == NULL) {\r
155         e = BCExceptionIllegalArgument;\r
156         return NULL;\r
157     }\r
158     CBC_BarcodeMetadata* barcodeMetadata = getBarcodeMetadata(leftRowIndicatorColumn, rightRowIndicatorColumn);\r
159     if (barcodeMetadata == NULL) {\r
160         e = BCExceptionCannotMetadata;\r
161         return NULL;\r
162     }\r
163     CBC_BoundingBox* leftboundingBox = adjustBoundingBox(leftRowIndicatorColumn, e);\r
164     if (e != BCExceptionNO) {\r
165         delete barcodeMetadata;\r
166         return NULL;\r
167     }\r
168     CBC_BoundingBox* rightboundingBox = adjustBoundingBox(rightRowIndicatorColumn, e);\r
169     if (e != BCExceptionNO) {\r
170         delete barcodeMetadata;\r
171         return NULL;\r
172     }\r
173     CBC_BoundingBox* boundingBox = CBC_BoundingBox::merge(leftboundingBox, rightboundingBox, e);\r
174     if (e != BCExceptionNO) {\r
175         delete barcodeMetadata;\r
176         return NULL;\r
177     }\r
178     CBC_DetectionResult* detectionresult = FX_NEW CBC_DetectionResult(barcodeMetadata, boundingBox);\r
179     return detectionresult;\r
180 }\r
181 CBC_BoundingBox* CBC_PDF417ScanningDecoder::adjustBoundingBox(CBC_DetectionResultRowIndicatorColumn* rowIndicatorColumn, int32_t &e)\r
182 {\r
183     if (rowIndicatorColumn == NULL) {\r
184         return NULL;\r
185     }\r
186     CFX_Int32Array* rowHeights = rowIndicatorColumn->getRowHeights(e);\r
187     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
188     int32_t maxRowHeight = getMax(*rowHeights);\r
189     int32_t missingStartRows = 0;\r
190     for (int32_t i = 0; i < rowHeights->GetSize(); i++) {\r
191         int32_t rowHeight = rowHeights->GetAt(i);\r
192         missingStartRows += maxRowHeight - rowHeight;\r
193         if (rowHeight > 0) {\r
194             break;\r
195         }\r
196     }\r
197     CFX_PtrArray* codewords = rowIndicatorColumn->getCodewords();\r
198     for (int32_t row = 0; missingStartRows > 0 && codewords->GetAt(row) == NULL; row++) {\r
199         missingStartRows--;\r
200     }\r
201     int32_t missingEndRows = 0;\r
202     for (int32_t row1 = rowHeights->GetSize() - 1; row1 >= 0; row1--) {\r
203         missingEndRows += maxRowHeight - rowHeights->GetAt(row1);\r
204         if (rowHeights->GetAt(row1) > 0) {\r
205             break;\r
206         }\r
207     }\r
208     for (int32_t row2 = codewords->GetSize() - 1; missingEndRows > 0 && codewords->GetAt(row2) == NULL; row2--) {\r
209         missingEndRows--;\r
210     }\r
211     CBC_BoundingBox* boundingBox = rowIndicatorColumn->getBoundingBox()->addMissingRows(missingStartRows, missingEndRows, rowIndicatorColumn->isLeft(), e);\r
212     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
213     return boundingBox;\r
214 }\r
215 int32_t CBC_PDF417ScanningDecoder::getMax(CFX_Int32Array& values)\r
216 {\r
217     int32_t maxValue = -1;\r
218     for (int32_t i = 0; i < values.GetSize(); i++) {\r
219         int32_t value = values.GetAt(i);\r
220         maxValue = maxValue > value ? maxValue : value;\r
221     }\r
222     return maxValue;\r
223 }\r
224 CBC_BarcodeMetadata* CBC_PDF417ScanningDecoder::getBarcodeMetadata(CBC_DetectionResultRowIndicatorColumn* leftRowIndicatorColumn,\r
225         CBC_DetectionResultRowIndicatorColumn* rightRowIndicatorColumn)\r
226 {\r
227     CBC_BarcodeMetadata* leftBarcodeMetadata = NULL;\r
228     CBC_BarcodeMetadata* rightBarcodeMetadata = NULL;\r
229     if (leftRowIndicatorColumn == NULL || (leftBarcodeMetadata = leftRowIndicatorColumn->getBarcodeMetadata()) == NULL) {\r
230         return rightRowIndicatorColumn == NULL ? NULL : rightRowIndicatorColumn->getBarcodeMetadata();\r
231     }\r
232     if (rightRowIndicatorColumn == NULL || (rightBarcodeMetadata = rightRowIndicatorColumn->getBarcodeMetadata()) == NULL) {\r
233         return leftRowIndicatorColumn == NULL ? NULL : leftRowIndicatorColumn->getBarcodeMetadata();\r
234     }\r
235     if (leftBarcodeMetadata->getColumnCount() != rightBarcodeMetadata->getColumnCount() &&\r
236             leftBarcodeMetadata->getErrorCorrectionLevel() != rightBarcodeMetadata->getErrorCorrectionLevel() &&\r
237             leftBarcodeMetadata->getRowCount() != rightBarcodeMetadata->getRowCount()) {\r
238         delete leftBarcodeMetadata;\r
239         delete rightBarcodeMetadata;\r
240         return NULL;\r
241     }\r
242     delete rightBarcodeMetadata;\r
243     return leftBarcodeMetadata;\r
244 }\r
245 CBC_DetectionResultRowIndicatorColumn* CBC_PDF417ScanningDecoder::getRowIndicatorColumn(CBC_CommonBitMatrix* image, CBC_BoundingBox* boundingBox, CBC_ResultPoint startPoint,\r
246         FX_BOOL leftToRight, int32_t minCodewordWidth, int32_t maxCodewordWidth)\r
247 {\r
248     CBC_DetectionResultRowIndicatorColumn* rowIndicatorColumn = FX_NEW CBC_DetectionResultRowIndicatorColumn(boundingBox, leftToRight);\r
249     for (int32_t i = 0; i < 2; i++) {\r
250         int32_t increment = i == 0 ? 1 : -1;\r
251         int32_t startColumn = (int32_t) startPoint.GetX();\r
252         for (int32_t imageRow = (int32_t) startPoint.GetY(); imageRow <= boundingBox->getMaxY() && imageRow >= boundingBox->getMinY(); imageRow += increment) {\r
253             CBC_Codeword* codeword = detectCodeword(image, 0, image->GetWidth(), leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth);\r
254             if (codeword != NULL) {\r
255                 rowIndicatorColumn->setCodeword(imageRow, codeword);\r
256                 if (leftToRight) {\r
257                     startColumn = codeword->getStartX();\r
258                 } else {\r
259                     startColumn = codeword->getEndX();\r
260                 }\r
261             }\r
262         }\r
263     }\r
264     return rowIndicatorColumn;\r
265 }\r
266 void CBC_PDF417ScanningDecoder::adjustCodewordCount(CBC_DetectionResult* detectionResult, CFX_PtrArray* barcodeMatrix, int32_t &e)\r
267 {\r
268     CFX_Int32Array* numberOfCodewords = ((CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(0))->GetAt(1))->getValue();\r
269     int32_t calculatedNumberOfCodewords = detectionResult->getBarcodeColumnCount() * detectionResult->getBarcodeRowCount() - getNumberOfECCodeWords(detectionResult->getBarcodeECLevel());\r
270     if (numberOfCodewords->GetSize() == 0) {\r
271         if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > CBC_PDF417Common::MAX_CODEWORDS_IN_BARCODE) {\r
272             e = BCExceptiontNotFoundInstance;\r
273             delete numberOfCodewords;\r
274             BC_EXCEPTION_CHECK_ReturnVoid(e);\r
275         }\r
276         ((CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(0))->GetAt(1))->setValue(calculatedNumberOfCodewords);\r
277     } else if (numberOfCodewords->GetAt(0) != calculatedNumberOfCodewords) {\r
278         ((CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(0))->GetAt(1))->setValue(calculatedNumberOfCodewords);\r
279     }\r
280     delete numberOfCodewords;\r
281 }\r
282 CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::createDecoderResult(CBC_DetectionResult* detectionResult, int32_t &e)\r
283 {\r
284     CFX_PtrArray* barcodeMatrix = createBarcodeMatrix(detectionResult);\r
285     adjustCodewordCount(detectionResult, barcodeMatrix, e);\r
286     if (e != BCExceptionNO) {\r
287         for (int32_t i = 0; i < barcodeMatrix->GetSize(); i++) {\r
288             CFX_PtrArray* temp = (CFX_PtrArray*)barcodeMatrix->GetAt(i);\r
289             for (int32_t j = 0; j < temp->GetSize(); j++) {\r
290                 delete (CBC_BarcodeValue*)temp->GetAt(j);\r
291             }\r
292             temp->RemoveAll();\r
293             delete temp;\r
294         }\r
295         barcodeMatrix->RemoveAll();\r
296         delete barcodeMatrix;\r
297         return NULL;\r
298     }\r
299     CFX_Int32Array erasures;\r
300     CFX_Int32Array codewords;\r
301     codewords.SetSize(detectionResult->getBarcodeRowCount() * detectionResult->getBarcodeColumnCount());\r
302     CFX_PtrArray ambiguousIndexValuesList;\r
303     CFX_Int32Array ambiguousIndexesList;\r
304     for (int32_t row = 0; row < detectionResult->getBarcodeRowCount(); row++) {\r
305         for (int32_t l = 0; l < detectionResult->getBarcodeColumnCount(); l++) {\r
306             CFX_Int32Array* values = ((CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(row))->GetAt(l + 1))->getValue();\r
307             int32_t codewordIndex = row * detectionResult->getBarcodeColumnCount() + l;\r
308             if (values->GetSize() == 0) {\r
309                 erasures.Add(codewordIndex);\r
310             } else if (values->GetSize() == 1) {\r
311                 codewords[codewordIndex] = values->GetAt(0);\r
312             } else {\r
313                 ambiguousIndexesList.Add(codewordIndex);\r
314                 ambiguousIndexValuesList.Add(values);\r
315             }\r
316         }\r
317     }\r
318     CFX_PtrArray ambiguousIndexValues;\r
319     ambiguousIndexValues.SetSize(ambiguousIndexValuesList.GetSize());\r
320     for (int32_t i = 0; i < ambiguousIndexValues.GetSize(); i++) {\r
321         ambiguousIndexValues.SetAt(i, ambiguousIndexValuesList.GetAt(i));\r
322     }\r
323     for (int32_t l = 0; l < barcodeMatrix->GetSize(); l++) {\r
324         CFX_PtrArray* temp = (CFX_PtrArray*)barcodeMatrix->GetAt(l);\r
325         for (int32_t j = 0; j < temp->GetSize(); j++) {\r
326             delete (CBC_BarcodeValue*)temp->GetAt(j);\r
327         }\r
328         temp->RemoveAll();\r
329         delete temp;\r
330     }\r
331     barcodeMatrix->RemoveAll();\r
332     delete barcodeMatrix;\r
333     CBC_CommonDecoderResult* decoderResult = createDecoderResultFromAmbiguousValues(detectionResult->getBarcodeECLevel(), codewords, erasures, ambiguousIndexesList, ambiguousIndexValues, e);\r
334     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
335     return decoderResult;\r
336 }\r
337 CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::createDecoderResultFromAmbiguousValues(int32_t ecLevel, CFX_Int32Array &codewords, CFX_Int32Array &erasureArray, CFX_Int32Array &ambiguousIndexes,\r
338         CFX_PtrArray& ambiguousIndexValues, int32_t &e)\r
339 {\r
340     CFX_Int32Array ambiguousIndexCount;\r
341     ambiguousIndexCount.SetSize(ambiguousIndexes.GetSize());\r
342     int32_t tries = 100;\r
343     while (tries-- > 0) {\r
344         for (int32_t l = 0; l < ambiguousIndexCount.GetSize(); l++) {\r
345             codewords[ambiguousIndexes[l]] = ((CFX_Int32Array*)ambiguousIndexValues.GetAt(l))->GetAt(ambiguousIndexCount[l]);\r
346         }\r
347         CBC_CommonDecoderResult* decoderResult = decodeCodewords(codewords, ecLevel, erasureArray, e);\r
348         if (e != BCExceptionNO) {\r
349             e = BCExceptionNO;\r
350             continue;\r
351         } else {\r
352             return decoderResult;\r
353         }\r
354         if (ambiguousIndexCount.GetSize() == 0) {\r
355             e = BCExceptionChecksumInstance;\r
356             return NULL;\r
357         }\r
358         for (int32_t i = 0; i < ambiguousIndexCount.GetSize(); i++) {\r
359             if (ambiguousIndexCount[i] < ((CFX_Int32Array*)(ambiguousIndexValues.GetAt(i)))->GetSize() - 1) {\r
360                 ambiguousIndexCount[i]++;\r
361                 break;\r
362             } else {\r
363                 ambiguousIndexCount[i] = 0;\r
364                 if (i == ambiguousIndexCount.GetSize() - 1) {\r
365                     e = BCExceptionChecksumInstance;\r
366                     return NULL;\r
367                 }\r
368             }\r
369         }\r
370     }\r
371     e = BCExceptionChecksumInstance;\r
372     return NULL;\r
373 }\r
374 CFX_PtrArray* CBC_PDF417ScanningDecoder::createBarcodeMatrix(CBC_DetectionResult* detectionResult)\r
375 {\r
376     CFX_PtrArray* barcodeMatrix = FX_NEW CFX_PtrArray;\r
377     barcodeMatrix->SetSize(detectionResult->getBarcodeRowCount());\r
378     CFX_PtrArray* temp = NULL;\r
379     int32_t colume = 0;\r
380     for (int32_t row = 0; row < barcodeMatrix->GetSize(); row++) {\r
381         temp = FX_NEW CFX_PtrArray;\r
382         temp->SetSize(detectionResult->getBarcodeColumnCount() + 2);\r
383         for (colume = 0; colume < detectionResult->getBarcodeColumnCount() + 2; colume++) {\r
384             temp->SetAt(colume, FX_NEW CBC_BarcodeValue());\r
385         }\r
386         barcodeMatrix->SetAt(row, temp);\r
387     }\r
388     colume = -1;\r
389     for (int32_t i = 0; i < detectionResult->getDetectionResultColumns().GetSize(); i++) {\r
390         CBC_DetectionResultColumn* detectionResultColumn = (CBC_DetectionResultColumn*) detectionResult->getDetectionResultColumns().GetAt(i);\r
391         colume++;\r
392         if (detectionResultColumn == NULL) {\r
393             continue;\r
394         }\r
395         CFX_PtrArray* temp = detectionResultColumn->getCodewords();\r
396         for (int32_t l = 0; l < temp->GetSize(); l++) {\r
397             CBC_Codeword* codeword = (CBC_Codeword*) temp->GetAt(l);\r
398             if (codeword == NULL || codeword->getRowNumber() == -1) {\r
399                 continue;\r
400             }\r
401             ((CBC_BarcodeValue*)((CFX_PtrArray*)barcodeMatrix->GetAt(codeword->getRowNumber()))->GetAt(colume))->setValue(codeword->getValue());\r
402         }\r
403     }\r
404     return barcodeMatrix;\r
405 }\r
406 FX_BOOL CBC_PDF417ScanningDecoder::isValidBarcodeColumn(CBC_DetectionResult* detectionResult, int32_t barcodeColumn)\r
407 {\r
408     return barcodeColumn >= 0 && barcodeColumn <= detectionResult->getBarcodeColumnCount() + 1;\r
409 }\r
410 int32_t CBC_PDF417ScanningDecoder::getStartColumn(CBC_DetectionResult* detectionResult, int32_t barcodeColumn, int32_t imageRow, FX_BOOL leftToRight)\r
411 {\r
412     int32_t offset = leftToRight ? 1 : -1;\r
413     CBC_Codeword* codeword = NULL;\r
414     if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) {\r
415         codeword = detectionResult->getDetectionResultColumn(barcodeColumn - offset)->getCodeword(imageRow);\r
416     }\r
417     if (codeword != NULL) {\r
418         return leftToRight ? codeword->getEndX() : codeword->getStartX();\r
419     }\r
420     codeword = detectionResult->getDetectionResultColumn(barcodeColumn)->getCodewordNearby(imageRow);\r
421     if (codeword != NULL) {\r
422         return leftToRight ? codeword->getStartX() : codeword->getEndX();\r
423     }\r
424     if (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) {\r
425         codeword = detectionResult->getDetectionResultColumn(barcodeColumn - offset)->getCodewordNearby(imageRow);\r
426     }\r
427     if (codeword != NULL) {\r
428         return leftToRight ? codeword->getEndX() : codeword->getStartX();\r
429     }\r
430     int32_t skippedColumns = 0;\r
431     while (isValidBarcodeColumn(detectionResult, barcodeColumn - offset)) {\r
432         barcodeColumn -= offset;\r
433         for (int32_t i = 0; i < detectionResult->getDetectionResultColumn(barcodeColumn)->getCodewords()->GetSize(); i++) {\r
434             CBC_Codeword* previousRowCodeword = (CBC_Codeword*) detectionResult->getDetectionResultColumn(barcodeColumn)->getCodewords()->GetAt(i);\r
435             if (previousRowCodeword != NULL) {\r
436                 return (leftToRight ? previousRowCodeword->getEndX() : previousRowCodeword->getStartX()) +\r
437                        offset * skippedColumns * (previousRowCodeword->getEndX() - previousRowCodeword->getStartX());\r
438             }\r
439         }\r
440         skippedColumns++;\r
441     }\r
442     return leftToRight ? detectionResult->getBoundingBox()->getMinX() : detectionResult->getBoundingBox()->getMaxX();\r
443 }\r
444 CBC_Codeword* CBC_PDF417ScanningDecoder::detectCodeword(CBC_CommonBitMatrix* image, int32_t minColumn, int32_t maxColumn, FX_BOOL leftToRight, int32_t startColumn,\r
445         int32_t imageRow, int32_t minCodewordWidth, int32_t maxCodewordWidth)\r
446 {\r
447     startColumn = adjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, startColumn, imageRow);\r
448     CFX_Int32Array* moduleBitCount = getModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow);\r
449     if (moduleBitCount == NULL) {\r
450         return NULL;\r
451     }\r
452     int32_t endColumn;\r
453     int32_t codewordBitCount = CBC_PDF417Common::getBitCountSum(*moduleBitCount);\r
454     if (leftToRight) {\r
455         endColumn = startColumn + codewordBitCount;\r
456     } else {\r
457         for (int32_t i = 0; i < moduleBitCount->GetSize() >> 1; i++) {\r
458             int32_t tmpCount = moduleBitCount->GetAt(i);\r
459             moduleBitCount->SetAt(i, moduleBitCount->GetAt(moduleBitCount->GetSize() - 1 - i));\r
460             moduleBitCount->SetAt(moduleBitCount->GetSize() - 1 - i, tmpCount);\r
461         }\r
462         endColumn = startColumn;\r
463         startColumn = endColumn - codewordBitCount;\r
464     }\r
465     int32_t decodedValue = CBC_PDF417CodewordDecoder::getDecodedValue(*moduleBitCount);\r
466     int32_t codeword = CBC_PDF417Common::getCodeword(decodedValue);\r
467     delete moduleBitCount;\r
468     if (codeword == -1) {\r
469         return NULL;\r
470     }\r
471     return FX_NEW CBC_Codeword(startColumn, endColumn, getCodewordBucketNumber(decodedValue), codeword);\r
472 }\r
473 CFX_Int32Array* CBC_PDF417ScanningDecoder::getModuleBitCount(CBC_CommonBitMatrix* image, int32_t minColumn, int32_t maxColumn, FX_BOOL leftToRight, int32_t startColumn, int32_t imageRow)\r
474 {\r
475     int32_t imageColumn = startColumn;\r
476     CFX_Int32Array* moduleBitCount = FX_NEW CFX_Int32Array;\r
477     moduleBitCount->SetSize(8);\r
478     int32_t moduleNumber = 0;\r
479     int32_t increment = leftToRight ? 1 : -1;\r
480     FX_BOOL previousPixelValue = leftToRight;\r
481     while (((leftToRight && imageColumn < maxColumn) || (!leftToRight && imageColumn >= minColumn)) && moduleNumber < moduleBitCount->GetSize()) {\r
482         if (image->Get(imageColumn, imageRow) == previousPixelValue) {\r
483             moduleBitCount->SetAt(moduleNumber, moduleBitCount->GetAt(moduleNumber) + 1);\r
484             imageColumn += increment;\r
485         } else {\r
486             moduleNumber++;\r
487             previousPixelValue = !previousPixelValue;\r
488         }\r
489     }\r
490     if (moduleNumber == moduleBitCount->GetSize() || (((leftToRight && imageColumn == maxColumn) || (!leftToRight && imageColumn == minColumn)) && moduleNumber == moduleBitCount->GetSize() - 1)) {\r
491         return moduleBitCount;\r
492     }\r
493     delete moduleBitCount;\r
494     return NULL;\r
495 }\r
496 int32_t CBC_PDF417ScanningDecoder::getNumberOfECCodeWords(int32_t barcodeECLevel)\r
497 {\r
498     return 2 << barcodeECLevel;\r
499 }\r
500 int32_t CBC_PDF417ScanningDecoder::adjustCodewordStartColumn(CBC_CommonBitMatrix* image, int32_t minColumn, int32_t maxColumn, FX_BOOL leftToRight, int32_t codewordStartColumn, int32_t imageRow)\r
501 {\r
502     int32_t correctedStartColumn = codewordStartColumn;\r
503     int32_t increment = leftToRight ? -1 : 1;\r
504     for (int32_t i = 0; i < 2; i++) {\r
505         FX_BOOL l = image->Get(correctedStartColumn, imageRow);\r
506         while (((leftToRight && correctedStartColumn >= minColumn) || (!leftToRight && correctedStartColumn < maxColumn)) && leftToRight == image->Get(correctedStartColumn, imageRow)) {\r
507             if (abs(codewordStartColumn - correctedStartColumn) > CODEWORD_SKEW_SIZE) {\r
508                 return codewordStartColumn;\r
509             }\r
510             correctedStartColumn += increment;\r
511         }\r
512         increment = -increment;\r
513         leftToRight = !leftToRight;\r
514     }\r
515     return correctedStartColumn;\r
516 }\r
517 FX_BOOL CBC_PDF417ScanningDecoder::checkCodewordSkew(int32_t codewordSize, int32_t minCodewordWidth, int32_t maxCodewordWidth)\r
518 {\r
519     return minCodewordWidth - CODEWORD_SKEW_SIZE <= codewordSize && codewordSize <= maxCodewordWidth + CODEWORD_SKEW_SIZE;\r
520 }\r
521 CBC_CommonDecoderResult* CBC_PDF417ScanningDecoder::decodeCodewords(CFX_Int32Array &codewords, int32_t ecLevel, CFX_Int32Array &erasures, int32_t &e)\r
522 {\r
523     if (codewords.GetSize() == 0) {\r
524         e = BCExceptionFormatInstance;\r
525         return NULL;\r
526     }\r
527     int32_t numECCodewords = 1 << (ecLevel + 1);\r
528     int32_t correctedErrorsCount = correctErrors(codewords, erasures, numECCodewords, e);\r
529     BC_EXCEPTION_CHECK_ReturnValue(e , NULL);\r
530     verifyCodewordCount(codewords, numECCodewords, e);\r
531     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
532     CFX_ByteString bytestring;\r
533     CBC_CommonDecoderResult* decoderResult = CBC_DecodedBitStreamPaser::decode(codewords, bytestring.FormatInteger(ecLevel), e);\r
534     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
535     return decoderResult;\r
536 }\r
537 int32_t CBC_PDF417ScanningDecoder::correctErrors(CFX_Int32Array &codewords, CFX_Int32Array &erasures, int32_t numECCodewords, int32_t &e)\r
538 {\r
539     if ((erasures.GetSize() != 0 && erasures.GetSize() > (numECCodewords / 2 + MAX_ERRORS)) || numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS) {\r
540         e = BCExceptionChecksumInstance;\r
541         return -1;\r
542     }\r
543     int32_t result = CBC_PDF417ECErrorCorrection::decode(codewords, numECCodewords, erasures, e);\r
544     BC_EXCEPTION_CHECK_ReturnValue(e, -1);\r
545     return result;\r
546 }\r
547 void CBC_PDF417ScanningDecoder::verifyCodewordCount(CFX_Int32Array &codewords, int32_t numECCodewords, int32_t &e)\r
548 {\r
549     if (codewords.GetSize() < 4) {\r
550         e = BCExceptionFormatInstance;\r
551         return;\r
552     }\r
553     int32_t numberOfCodewords = codewords.GetAt(0);\r
554     if (numberOfCodewords > codewords.GetSize()) {\r
555         e = BCExceptionFormatInstance;\r
556         return;\r
557     }\r
558     if (numberOfCodewords == 0) {\r
559         if (numECCodewords < codewords.GetSize()) {\r
560             codewords[0] = codewords.GetSize() - numECCodewords;\r
561         } else {\r
562             e = BCExceptionFormatInstance;\r
563             return;\r
564         }\r
565     }\r
566 }\r
567 CFX_Int32Array* CBC_PDF417ScanningDecoder::getBitCountForCodeword(int32_t codeword)\r
568 {\r
569     CFX_Int32Array* result = FX_NEW CFX_Int32Array;\r
570     result->SetSize(8);\r
571     int32_t previousValue = 0;\r
572     int32_t i = result->GetSize() - 1;\r
573     while (TRUE) {\r
574         if ((codeword & 0x1) != previousValue) {\r
575             previousValue = codeword & 0x1;\r
576             i--;\r
577             if (i < 0) {\r
578                 break;\r
579             }\r
580         }\r
581         result->SetAt(i, result->GetAt(i) + 1);\r
582         codeword >>= 1;\r
583     }\r
584     return result;\r
585 }\r
586 int32_t CBC_PDF417ScanningDecoder::getCodewordBucketNumber(int32_t codeword)\r
587 {\r
588     CFX_Int32Array* array = getBitCountForCodeword(codeword);\r
589     int32_t result = getCodewordBucketNumber(*array);\r
590     delete array;\r
591     return result;\r
592 }\r
593 int32_t CBC_PDF417ScanningDecoder::getCodewordBucketNumber(CFX_Int32Array& moduleBitCount)\r
594 {\r
595     return (moduleBitCount.GetAt(0) - moduleBitCount.GetAt(2) + moduleBitCount.GetAt(4) - moduleBitCount.GetAt(6) + 9) % 9;\r
596 }\r