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