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