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 2008 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 <algorithm>
24
25 #include "xfa/src/fxbarcode/barcode.h"
26 #include "xfa/src/fxbarcode/BC_Reader.h"
27 #include "xfa/src/fxbarcode/BC_BinaryBitmap.h"
28 #include "xfa/src/fxbarcode/common/BC_CommonBitArray.h"
29 #include "BC_OneDReader.h"
30 const int32_t CBC_OneDReader::INTEGER_MATH_SHIFT = 8;
31 const int32_t CBC_OneDReader::PATTERN_MATCH_RESULT_SCALE_FACTOR = 1 << 8;
CBC_OneDReader()32 CBC_OneDReader::CBC_OneDReader() {}
~CBC_OneDReader()33 CBC_OneDReader::~CBC_OneDReader() {}
Decode(CBC_BinaryBitmap * image,int32_t & e)34 CFX_ByteString CBC_OneDReader::Decode(CBC_BinaryBitmap* image, int32_t& e) {
35 CFX_ByteString strtemp = Decode(image, 0, e);
36 BC_EXCEPTION_CHECK_ReturnValue(e, "");
37 return strtemp;
38 }
Decode(CBC_BinaryBitmap * image,int32_t hints,int32_t & e)39 CFX_ByteString CBC_OneDReader::Decode(CBC_BinaryBitmap* image,
40 int32_t hints,
41 int32_t& e) {
42 CFX_ByteString strtemp = DeDecode(image, hints, e);
43 BC_EXCEPTION_CHECK_ReturnValue(e, "");
44 return strtemp;
45 }
DeDecode(CBC_BinaryBitmap * image,int32_t hints,int32_t & e)46 CFX_ByteString CBC_OneDReader::DeDecode(CBC_BinaryBitmap* image,
47 int32_t hints,
48 int32_t& e) {
49 int32_t height = image->GetHeight();
50 CBC_CommonBitArray* row = NULL;
51 int32_t middle = height >> 1;
52 FX_BOOL tryHarder = FALSE;
53 int32_t rowStep = std::max(1, height >> (tryHarder ? 8 : 5));
54 int32_t maxLines;
55 if (tryHarder) {
56 maxLines = height;
57 } else {
58 maxLines = 15;
59 }
60 for (int32_t x = 0; x < maxLines; x++) {
61 int32_t rowStepsAboveOrBelow = (x + 1) >> 1;
62 FX_BOOL isAbove = (x & 0x01) == 0;
63 int32_t rowNumber =
64 middle +
65 rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
66 if (rowNumber < 0 || rowNumber >= height) {
67 break;
68 }
69 row = image->GetBlackRow(rowNumber, NULL, e);
70 if (e != BCExceptionNO) {
71 e = BCExceptionNO;
72 if (row != NULL) {
73 delete row;
74 row = NULL;
75 }
76 continue;
77 }
78 for (int32_t attempt = 0; attempt < 2; attempt++) {
79 if (attempt == 1) {
80 row->Reverse();
81 }
82 CFX_ByteString result = DecodeRow(rowNumber, row, hints, e);
83 if (e != BCExceptionNO) {
84 e = BCExceptionNO;
85 continue;
86 }
87 if (row != NULL) {
88 delete row;
89 row = NULL;
90 }
91 return result;
92 }
93 if (row != NULL) {
94 delete row;
95 row = NULL;
96 }
97 }
98 e = BCExceptionNotFound;
99 return "";
100 }
RecordPattern(CBC_CommonBitArray * row,int32_t start,CFX_Int32Array * counters,int32_t & e)101 void CBC_OneDReader::RecordPattern(CBC_CommonBitArray* row,
102 int32_t start,
103 CFX_Int32Array* counters,
104 int32_t& e) {
105 int32_t numCounters = counters->GetSize();
106 for (int32_t i = 0; i < numCounters; i++) {
107 (*counters)[i] = 0;
108 }
109 int32_t end = row->GetSize();
110 if (start >= end) {
111 e = BCExceptionNotFound;
112 return;
113 }
114 FX_BOOL isWhite = !row->Get(start);
115 int32_t counterPosition = 0;
116 int32_t j = start;
117 while (j < end) {
118 FX_BOOL pixel = row->Get(j);
119 if (pixel ^ isWhite) {
120 (*counters)[counterPosition]++;
121 } else {
122 counterPosition++;
123 if (counterPosition == numCounters) {
124 break;
125 } else {
126 (*counters)[counterPosition] = 1;
127 isWhite = !isWhite;
128 }
129 }
130 j++;
131 }
132 if (!(counterPosition == numCounters ||
133 (counterPosition == numCounters - 1 && j == end))) {
134 e = BCExceptionNotFound;
135 return;
136 }
137 }
RecordPatternInReverse(CBC_CommonBitArray * row,int32_t start,CFX_Int32Array * counters,int32_t & e)138 void CBC_OneDReader::RecordPatternInReverse(CBC_CommonBitArray* row,
139 int32_t start,
140 CFX_Int32Array* counters,
141 int32_t& e) {
142 int32_t numTransitionsLeft = counters->GetSize();
143 FX_BOOL last = row->Get(start);
144 while (start > 0 && numTransitionsLeft >= 0) {
145 if (row->Get(--start) != last) {
146 numTransitionsLeft--;
147 last = !last;
148 }
149 }
150 if (numTransitionsLeft >= 0) {
151 e = BCExceptionNotFound;
152 return;
153 }
154 RecordPattern(row, start + 1, counters, e);
155 BC_EXCEPTION_CHECK_ReturnVoid(e);
156 }
PatternMatchVariance(CFX_Int32Array * counters,const int32_t * pattern,int32_t maxIndividualVariance)157 int32_t CBC_OneDReader::PatternMatchVariance(CFX_Int32Array* counters,
158 const int32_t* pattern,
159 int32_t maxIndividualVariance) {
160 int32_t numCounters = counters->GetSize();
161 int32_t total = 0;
162 int32_t patternLength = 0;
163 for (int32_t i = 0; i < numCounters; i++) {
164 total += (*counters)[i];
165 patternLength += pattern[i];
166 }
167 if (total < patternLength) {
168 #undef max
169 return FXSYS_IntMax;
170 }
171 int32_t unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
172 maxIndividualVariance =
173 (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
174 int32_t totalVariance = 0;
175 for (int32_t x = 0; x < numCounters; x++) {
176 int32_t counter = (*counters)[x] << INTEGER_MATH_SHIFT;
177 int32_t scaledPattern = pattern[x] * unitBarWidth;
178 int32_t variance = counter > scaledPattern ? counter - scaledPattern
179 : scaledPattern - counter;
180 if (variance > maxIndividualVariance) {
181 #undef max
182 return FXSYS_IntMax;
183 }
184 totalVariance += variance;
185 }
186 return totalVariance / total;
187 }
188