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; 32 CBC_OneDReader::CBC_OneDReader() {} 33 CBC_OneDReader::~CBC_OneDReader() {} 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 } 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 } 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 } 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 } 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 } 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