One-D barcodes reader port on c++
[zxing.git] / cpp / core / src / zxing / oned / OneDReader.cpp
1 /*
2  *  OneDReader.cpp
3  *  ZXing
4  *
5  *  Created by Lukasz Warchol on 10-01-15.
6  *  Copyright 2010 ZXing authors All rights reserved.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include "OneDReader.h"
22 #include <zxing/ReaderException.h>
23 #include <math.h>
24
25 namespace zxing {
26         namespace oned {
27                 using namespace std;
28                 
29                 OneDReader::OneDReader() {
30                 }
31                 
32                 Ref<Result> OneDReader::decode(Ref<BinaryBitmap> image) {
33                         try {
34                                 return doDecode(image);
35                         }catch (ReaderException re) {
36                                 if (false /*tryHarder && image.isRotateSupported()*/) {
37                                         /*
38                                         BinaryBitmap rotatedImage = image.rotateCounterClockwise();
39                                         Result result = doDecode(rotatedImage, hints);
40                                         // Record that we found it rotated 90 degrees CCW / 270 degrees CW
41                                         Hashtable metadata = result.getResultMetadata();
42                                         int orientation = 270;
43                                         if (metadata != null && metadata.containsKey(ResultMetadataType.ORIENTATION)) {
44                                                 // But if we found it reversed in doDecode(), add in that result here:
45                                                 orientation = (orientation +
46                                                                            ((Integer) metadata.get(ResultMetadataType.ORIENTATION)).intValue()) % 360;
47                                         }
48                                         result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(orientation));
49                                         // Update result points
50                                         ResultPoint[] points = result.getResultPoints();
51                                         int height = rotatedImage.getHeight();
52                                         for (int i = 0; i < points.length; i++) {
53                                                 points[i] = new ResultPoint(height - points[i].getY() - 1, points[i].getX());
54                                         }
55                                         return result;
56                                         */
57                                 } else {
58                                         throw re;
59                                 }
60                         }
61                 }
62                 
63                 Ref<Result> OneDReader::doDecode(Ref<BinaryBitmap> image){
64                         int width = image->getWidth();
65                         int height = image->getHeight();
66                         Ref<BitArray> row(new BitArray(width));
67 //                      BitArray row = new BitArray(width);
68                         
69                         int middle = height >> 1;
70                         bool tryHarder = true;//hints != null && hints.containsKey(DecodeHintType.TRY_HARDER);
71                         int rowStep = (int)fmax(1, height >> (tryHarder ? 7 : 4));
72                         int maxLines;
73                         if (tryHarder) {
74                                 maxLines = height; // Look at the whole image, not just the center
75                         } else {
76                                 maxLines = 9; // Nine rows spaced 1/16 apart is roughly the middle half of the image
77                         }
78                         
79                         for (int x = 0; x < maxLines; x++) {
80                                 
81                                 // Scanning from the middle out. Determine which row we're looking at next:
82                                 int rowStepsAboveOrBelow = (x + 1) >> 1;
83                                 bool isAbove = (x & 0x01) == 0; // i.e. is x even?
84                                 int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
85                                 if (rowNumber < 0 || rowNumber >= height) {
86                                         // Oops, if we run off the top or bottom, stop
87                                         break;
88                                 }
89                                         
90                                 // Estimate black point for this row and load it:
91                                 try {
92                                         row = image->getBlackRow(rowNumber, row);
93                                 }catch (ReaderException re) {
94                                         continue;
95                                 }
96                                 
97                                 // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
98                                 // handle decoding upside down barcodes.
99                                 for (int attempt = 0; attempt < 2; attempt++) {
100                                         if (attempt == 1) { // trying again?
101                                                 row->reverse(); // reverse the row and continue
102                                         }
103                                         try {
104                                                 // Look for a barcode
105                                                 Ref<Result> result = decodeRow(rowNumber, row);
106                                                 // We found our barcode
107                                                 if (attempt == 1) {
108                                                         //                                              // But it was upside down, so note that
109                                                         //                                              result.putMetadata(ResultMetadataType.ORIENTATION, new Integer(180));
110                                                         //                                              // And remember to flip the result points horizontally.
111                                                         //                                              ResultPoint[] points = result.getResultPoints();
112                                                         //                                              points[0] = new ResultPoint(width - points[0].getX() - 1, points[0].getY());
113                                                         //                                              points[1] = new ResultPoint(width - points[1].getX() - 1, points[1].getY());
114                                                 }
115                                                 return result;
116                                         } catch (ReaderException re) {
117                                                 // continue -- just couldn't decode this row
118                                         }
119                                 }
120                         }
121                         throw ReaderException("");
122                 }
123                 
124                 int OneDReader::patternMatchVariance(int counters[], int countersSize, const int pattern[], int maxIndividualVariance) {
125                         int numCounters = countersSize;
126                         int total = 0;
127                         int patternLength = 0;
128                         for (int i = 0; i < numCounters; i++) {
129                                 total += counters[i];
130                                 patternLength += pattern[i];
131                         }
132                         if (total < patternLength) {
133                                 // If we don't even have one pixel per unit of bar width, assume this is too small
134                                 // to reliably match, so fail:
135                                 return INT_MAX;
136                         }
137                         // We're going to fake floating-point math in integers. We just need to use more bits.
138                         // Scale up patternLength so that intermediate values below like scaledCounter will have
139                         // more "significant digits"
140                         int unitBarWidth = (total << INTEGER_MATH_SHIFT) / patternLength;
141                         maxIndividualVariance = (maxIndividualVariance * unitBarWidth) >> INTEGER_MATH_SHIFT;
142                         
143                         int totalVariance = 0;
144                         for (int x = 0; x < numCounters; x++) {
145                                 int counter = counters[x] << INTEGER_MATH_SHIFT;
146                                 int scaledPattern = pattern[x] * unitBarWidth;
147                                 int variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
148                                 if (variance > maxIndividualVariance) {
149                                         return INT_MAX;
150                                 }
151                                 totalVariance += variance;
152                         }
153                         return totalVariance / total;
154                 }
155                 
156                 void OneDReader::recordPattern(Ref<BitArray> row, int start, int counters[], int countersCount){
157                         int numCounters = countersCount;//sizeof(counters) / sizeof(int);
158                         for (int i = 0; i < numCounters; i++) {
159                                 counters[i] = 0;
160                         }
161                         int end = row->getSize();
162                         if (start >= end) {
163                                 throw ReaderException("recordPattern: start >= end");
164                         }
165                         bool isWhite = !row->get(start);
166                         int counterPosition = 0;
167                         int i = start;
168                         while (i < end) {
169                                 bool pixel = row->get(i);
170                                 if (pixel ^ isWhite) { // that is, exactly one is true
171                                         counters[counterPosition]++;
172                                 } else {
173                                         counterPosition++;
174                                         if (counterPosition == numCounters) {
175                                                 break;
176                                         } else {
177                                                 counters[counterPosition] = 1;
178                                                 isWhite ^= true; // isWhite = !isWhite;
179                                         }
180                                 }
181                                 i++;
182                         }
183                         // If we read fully the last section of pixels and filled up our counters -- or filled
184                         // the last counter but ran off the side of the image, OK. Otherwise, a problem.
185                         if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) {
186                                 throw ReaderException("recordPattern");
187                         }
188                 }
189                 
190                 OneDReader::~OneDReader() {
191                 }
192         }
193 }