Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_PDF417DetectionResultRowIndicatorColumn.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_ResultPoint.h"\r
9 #include "include/BC_PDF417BarcodeMetadata.h"\r
10 #include "include/BC_PDF417BoundingBox.h"\r
11 #include "include/BC_PDF417Codeword.h"\r
12 #include "include/BC_PDF417BarcodeValue.h"\r
13 #include "include/BC_PDF417Common.h"\r
14 #include "include/BC_PDF417DetectionResultColumn.h"\r
15 #include "include/BC_PDF417DetectionResultRowIndicatorColumn.h"\r
16 CBC_DetectionResultRowIndicatorColumn::CBC_DetectionResultRowIndicatorColumn(CBC_BoundingBox* boundingBox, FX_BOOL isLeft)\r
17     : CBC_DetectionResultColumn(boundingBox)\r
18 {\r
19     m_isLeft = isLeft;\r
20 }\r
21 CBC_DetectionResultRowIndicatorColumn::~CBC_DetectionResultRowIndicatorColumn()\r
22 {\r
23 }\r
24 void CBC_DetectionResultRowIndicatorColumn::setRowNumbers()\r
25 {\r
26     for (FX_INT32 i = 0; i < m_codewords->GetSize(); i++) {\r
27         CBC_Codeword * codeword = (CBC_Codeword*)m_codewords->GetAt(i);\r
28         if (codeword != NULL) {\r
29             codeword->setRowNumberAsRowIndicatorColumn();\r
30         }\r
31     }\r
32 }\r
33 FX_INT32 CBC_DetectionResultRowIndicatorColumn::adjustCompleteIndicatorColumnRowNumbers(CBC_BarcodeMetadata barcodeMetadata)\r
34 {\r
35     CFX_PtrArray* codewords = getCodewords();\r
36     setRowNumbers();\r
37     removeIncorrectCodewords(codewords, barcodeMetadata);\r
38     CBC_BoundingBox* boundingBox = getBoundingBox();\r
39     CBC_ResultPoint* top = m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight();\r
40     CBC_ResultPoint* bottom = m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight();\r
41     FX_INT32 firstRow = imageRowToCodewordIndex((FX_INT32) top->GetY());\r
42     FX_INT32 lastRow = imageRowToCodewordIndex((FX_INT32) bottom->GetY());\r
43     FX_FLOAT averageRowHeight = (lastRow - firstRow) / (FX_FLOAT) barcodeMetadata.getRowCount();\r
44     FX_INT32 barcodeRow = -1;\r
45     FX_INT32 maxRowHeight = 1;\r
46     FX_INT32 currentRowHeight = 0;\r
47     for (FX_INT32 codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) {\r
48         if (codewords->GetAt(codewordsRow) == NULL) {\r
49             continue;\r
50         }\r
51         CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordsRow);\r
52         FX_INT32 rowDifference = codeword->getRowNumber() - barcodeRow;\r
53         if (rowDifference == 0) {\r
54             currentRowHeight++;\r
55         } else if (rowDifference == 1) {\r
56             maxRowHeight = maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight;\r
57             currentRowHeight = 1;\r
58             barcodeRow = codeword->getRowNumber();\r
59         } else if (rowDifference < 0) {\r
60             codewords->SetAt(codewordsRow, NULL);\r
61         } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) {\r
62             codewords->SetAt(codewordsRow, NULL);\r
63         } else if (rowDifference > codewordsRow) {\r
64             codewords->SetAt(codewordsRow, NULL);\r
65         } else {\r
66             FX_INT32 checkedRows;\r
67             if (maxRowHeight > 2) {\r
68                 checkedRows = (maxRowHeight - 2) * rowDifference;\r
69             } else {\r
70                 checkedRows = rowDifference;\r
71             }\r
72             FX_BOOL closePreviousCodewordFound = checkedRows >= codewordsRow;\r
73             for (FX_INT32 i = 1; i <= checkedRows && !closePreviousCodewordFound; i++) {\r
74                 closePreviousCodewordFound = codewords->GetAt(codewordsRow - i) != NULL;\r
75             }\r
76             if (closePreviousCodewordFound) {\r
77                 codewords->SetAt(codewordsRow, NULL);\r
78             } else {\r
79                 barcodeRow = codeword->getRowNumber();\r
80                 currentRowHeight = 1;\r
81             }\r
82         }\r
83     }\r
84     return (FX_INT32) (averageRowHeight + 0.5);\r
85 }\r
86 CFX_Int32Array* CBC_DetectionResultRowIndicatorColumn::getRowHeights(FX_INT32 &e)\r
87 {\r
88     CBC_BarcodeMetadata* barcodeMetadata = getBarcodeMetadata();\r
89     if (barcodeMetadata == NULL) {\r
90         e = BCExceptionCannotMetadata;\r
91         return NULL;\r
92     }\r
93     adjustIncompleteIndicatorColumnRowNumbers(*barcodeMetadata);\r
94     CFX_Int32Array* result = FX_NEW CFX_Int32Array;\r
95     result->SetSize(barcodeMetadata->getRowCount());\r
96     for (FX_INT32 i = 0; i < getCodewords()->GetSize(); i++) {\r
97         CBC_Codeword* codeword = (CBC_Codeword*)getCodewords()->GetAt(i);\r
98         if (codeword != NULL) {\r
99             result->SetAt(codeword->getRowNumber(),  result->GetAt(codeword->getRowNumber()) + 1);\r
100         }\r
101     }\r
102     return result;\r
103 }\r
104 FX_INT32 CBC_DetectionResultRowIndicatorColumn::adjustIncompleteIndicatorColumnRowNumbers(CBC_BarcodeMetadata barcodeMetadata)\r
105 {\r
106     CBC_BoundingBox* boundingBox = getBoundingBox();\r
107     CBC_ResultPoint* top = m_isLeft ? boundingBox->getTopLeft() : boundingBox->getTopRight();\r
108     CBC_ResultPoint* bottom = m_isLeft ? boundingBox->getBottomLeft() : boundingBox->getBottomRight();\r
109     FX_INT32 firstRow = imageRowToCodewordIndex((FX_INT32) top->GetY());\r
110     FX_INT32 lastRow = imageRowToCodewordIndex((FX_INT32) bottom->GetY());\r
111     FX_FLOAT averageRowHeight = (lastRow - firstRow) / (FX_FLOAT) barcodeMetadata.getRowCount();\r
112     CFX_PtrArray* codewords = getCodewords();\r
113     FX_INT32 barcodeRow = -1;\r
114     FX_INT32 maxRowHeight = 1;\r
115     FX_INT32 currentRowHeight = 0;\r
116     for (FX_INT32 codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) {\r
117         if (codewords->GetAt(codewordsRow) == NULL) {\r
118             continue;\r
119         }\r
120         CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordsRow);\r
121         codeword->setRowNumberAsRowIndicatorColumn();\r
122         FX_INT32 rowDifference = codeword->getRowNumber() - barcodeRow;\r
123         if (rowDifference == 0) {\r
124             currentRowHeight++;\r
125         } else if (rowDifference == 1) {\r
126             maxRowHeight = maxRowHeight > currentRowHeight ? maxRowHeight : currentRowHeight;\r
127             currentRowHeight = 1;\r
128             barcodeRow = codeword->getRowNumber();\r
129         } else if (codeword->getRowNumber() >= barcodeMetadata.getRowCount()) {\r
130             codewords->SetAt(codewordsRow, NULL);\r
131         } else {\r
132             barcodeRow = codeword->getRowNumber();\r
133             currentRowHeight = 1;\r
134         }\r
135     }\r
136     return (FX_INT32) (averageRowHeight + 0.5);\r
137 }\r
138 CBC_BarcodeMetadata* CBC_DetectionResultRowIndicatorColumn::getBarcodeMetadata()\r
139 {\r
140     CFX_PtrArray* codewords = getCodewords();\r
141     CBC_BarcodeValue barcodeColumnCount;\r
142     CBC_BarcodeValue barcodeRowCountUpperPart;\r
143     CBC_BarcodeValue barcodeRowCountLowerPart;\r
144     CBC_BarcodeValue barcodeECLevel;\r
145     for (FX_INT32 i = 0; i < codewords->GetSize(); i++) {\r
146         CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(i);\r
147         if (codeword == NULL) {\r
148             continue;\r
149         }\r
150         codeword->setRowNumberAsRowIndicatorColumn();\r
151         FX_INT32 rowIndicatorValue = codeword->getValue() % 30;\r
152         FX_INT32 codewordRowNumber = codeword->getRowNumber();\r
153         if (!m_isLeft) {\r
154             codewordRowNumber += 2;\r
155         }\r
156         switch (codewordRowNumber % 3) {\r
157             case 0:\r
158                 barcodeRowCountUpperPart.setValue(rowIndicatorValue * 3 + 1);\r
159                 break;\r
160             case 1:\r
161                 barcodeECLevel.setValue(rowIndicatorValue / 3);\r
162                 barcodeRowCountLowerPart.setValue(rowIndicatorValue % 3);\r
163                 break;\r
164             case 2:\r
165                 barcodeColumnCount.setValue(rowIndicatorValue + 1);\r
166                 break;\r
167         }\r
168     }\r
169     if ((barcodeColumnCount.getValue()->GetSize() == 0) ||\r
170             (barcodeRowCountUpperPart.getValue()->GetSize() == 0) ||\r
171             (barcodeRowCountLowerPart.getValue()->GetSize() == 0) ||\r
172             (barcodeECLevel.getValue()->GetSize() == 0) ||\r
173             barcodeColumnCount.getValue()->GetAt(0) < 1 ||\r
174             barcodeRowCountUpperPart.getValue()->GetAt(0) + barcodeRowCountLowerPart.getValue()->GetAt(0) < CBC_PDF417Common::MIN_ROWS_IN_BARCODE ||\r
175             barcodeRowCountUpperPart.getValue()->GetAt(0) + barcodeRowCountLowerPart.getValue()->GetAt(0) > CBC_PDF417Common::MAX_ROWS_IN_BARCODE) {\r
176         return NULL;\r
177     }\r
178     CBC_BarcodeMetadata* barcodeMetadata = FX_NEW CBC_BarcodeMetadata(barcodeColumnCount.getValue()->GetAt(0), barcodeRowCountUpperPart.getValue()->GetAt(0), barcodeRowCountLowerPart.getValue()->GetAt(0), barcodeECLevel.getValue()->GetAt(0));\r
179     removeIncorrectCodewords(codewords, *barcodeMetadata);\r
180     return barcodeMetadata;\r
181 }\r
182 FX_BOOL CBC_DetectionResultRowIndicatorColumn::isLeft()\r
183 {\r
184     return m_isLeft;\r
185 }\r
186 CFX_ByteString CBC_DetectionResultRowIndicatorColumn::toString()\r
187 {\r
188     return (CFX_ByteString)"IsLeft: " + (CFX_ByteString)m_isLeft + '\n' + CBC_DetectionResultColumn::toString();\r
189 }\r
190 void CBC_DetectionResultRowIndicatorColumn::removeIncorrectCodewords(CFX_PtrArray* codewords, CBC_BarcodeMetadata barcodeMetadata)\r
191 {\r
192     for (FX_INT32 codewordRow = 0; codewordRow < codewords->GetSize(); codewordRow++) {\r
193         CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordRow);\r
194         if (codeword == NULL) {\r
195             continue;\r
196         }\r
197         FX_INT32 rowIndicatorValue = codeword->getValue() % 30;\r
198         FX_INT32 codewordRowNumber = codeword->getRowNumber();\r
199         if (codewordRowNumber > barcodeMetadata.getRowCount()) {\r
200             codewords->SetAt(codewordRow, NULL);\r
201             continue;\r
202         }\r
203         if (!m_isLeft) {\r
204             codewordRowNumber += 2;\r
205         }\r
206         switch (codewordRowNumber % 3) {\r
207             case 0:\r
208                 if (rowIndicatorValue * 3 + 1 != barcodeMetadata.getRowCountUpperPart()) {\r
209                     codewords->SetAt(codewordRow, NULL);\r
210                 }\r
211                 break;\r
212             case 1:\r
213                 if (rowIndicatorValue / 3 != barcodeMetadata.getErrorCorrectionLevel() ||\r
214                         rowIndicatorValue % 3 != barcodeMetadata.getRowCountLowerPart()) {\r
215                     codewords->SetAt(codewordRow, NULL);\r
216                 }\r
217                 break;\r
218             case 2:\r
219                 if (rowIndicatorValue + 1 != barcodeMetadata.getColumnCount()) {\r
220                     codewords->SetAt(codewordRow, NULL);\r
221                 }\r
222                 break;\r
223         }\r
224     }\r
225 }\r