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