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