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 "xfa/src/fxbarcode/barcode.h" 24 #include "xfa/src/fxbarcode/BC_Reader.h" 25 #include "xfa/src/fxbarcode/common/BC_CommonBitArray.h" 26 #include "BC_OneDReader.h" 27 #include "BC_OneDimReader.h" 28 const int32_t CBC_OneDimReader::MAX_AVG_VARIANCE = (int32_t)(256 * 0.48f); 29 const int32_t CBC_OneDimReader::MAX_INDIVIDUAL_VARIANCE = (int32_t)(256 * 0.7f); 30 const int32_t CBC_OneDimReader::START_END_PATTERN[3] = {1, 1, 1}; 31 const int32_t CBC_OneDimReader::MIDDLE_PATTERN[5] = {1, 1, 1, 1, 1}; 32 const int32_t CBC_OneDimReader::L_PATTERNS[10][4] = { 33 {3, 2, 1, 1}, {2, 2, 2, 1}, {2, 1, 2, 2}, {1, 4, 1, 1}, {1, 1, 3, 2}, 34 {1, 2, 3, 1}, {1, 1, 1, 4}, {1, 3, 1, 2}, {1, 2, 1, 3}, {3, 1, 1, 2}}; 35 const int32_t CBC_OneDimReader::L_AND_G_PATTERNS[20][4] = { 36 {3, 2, 1, 1}, {2, 2, 2, 1}, {2, 1, 2, 2}, {1, 4, 1, 1}, {1, 1, 3, 2}, 37 {1, 2, 3, 1}, {1, 1, 1, 4}, {1, 3, 1, 2}, {1, 2, 1, 3}, {3, 1, 1, 2}, 38 {1, 1, 2, 3}, {1, 2, 2, 2}, {2, 2, 1, 2}, {1, 1, 4, 1}, {2, 3, 1, 1}, 39 {1, 3, 2, 1}, {4, 1, 1, 1}, {2, 1, 3, 1}, {3, 1, 2, 1}, {2, 1, 1, 3}}; 40 CBC_OneDimReader::CBC_OneDimReader() {} 41 CBC_OneDimReader::~CBC_OneDimReader() {} 42 CFX_Int32Array* CBC_OneDimReader::FindStartGuardPattern(CBC_CommonBitArray* row, 43 int32_t& e) { 44 FX_BOOL foundStart = FALSE; 45 CFX_Int32Array* startRange = NULL; 46 CFX_Int32Array startEndPattern; 47 startEndPattern.SetSize(3); 48 startEndPattern[0] = START_END_PATTERN[0]; 49 startEndPattern[1] = START_END_PATTERN[1]; 50 startEndPattern[2] = START_END_PATTERN[2]; 51 int32_t nextStart = 0; 52 while (!foundStart) { 53 if (startRange != NULL) { 54 delete startRange; 55 startRange = NULL; 56 } 57 startRange = FindGuardPattern(row, nextStart, FALSE, &startEndPattern, e); 58 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 59 int32_t start = (*startRange)[0]; 60 nextStart = (*startRange)[1]; 61 if (start <= 1) { 62 break; 63 } 64 int32_t quietStart = start - (nextStart - start); 65 if (quietStart >= 0) { 66 FX_BOOL booT = row->IsRange(quietStart, start, FALSE, e); 67 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 68 foundStart = booT; 69 } 70 } 71 return startRange; 72 } 73 CFX_ByteString CBC_OneDimReader::DecodeRow(int32_t rowNumber, 74 CBC_CommonBitArray* row, 75 int32_t hints, 76 int32_t& e) { 77 CFX_Int32Array* StartPattern = FindStartGuardPattern(row, e); 78 BC_EXCEPTION_CHECK_ReturnValue(e, ""); 79 CBC_AutoPtr<CFX_Int32Array> result(StartPattern); 80 CFX_ByteString temp = DecodeRow(rowNumber, row, result.get(), hints, e); 81 BC_EXCEPTION_CHECK_ReturnValue(e, ""); 82 return temp; 83 } 84 CFX_ByteString CBC_OneDimReader::DecodeRow(int32_t rowNumber, 85 CBC_CommonBitArray* row, 86 CFX_Int32Array* startGuardRange, 87 int32_t hints, 88 int32_t& e) { 89 CFX_ByteString result; 90 DecodeMiddle(row, startGuardRange, result, e); 91 BC_EXCEPTION_CHECK_ReturnValue(e, ""); 92 FX_BOOL b = CheckChecksum(result, e); 93 BC_EXCEPTION_CHECK_ReturnValue(e, ""); 94 if (!b) { 95 e = BCExceptionChecksumException; 96 return ""; 97 } 98 return result; 99 } 100 FX_BOOL CBC_OneDimReader::CheckChecksum(CFX_ByteString& s, int32_t& e) { 101 FX_BOOL temp = CheckStandardUPCEANChecksum(s, e); 102 BC_EXCEPTION_CHECK_ReturnValue(e, FALSE); 103 return temp; 104 } 105 FX_BOOL CBC_OneDimReader::CheckStandardUPCEANChecksum(CFX_ByteString& s, 106 int32_t& e) { 107 int32_t length = s.GetLength(); 108 if (length == 0) { 109 return FALSE; 110 } 111 int32_t sum = 0; 112 for (int32_t i = length - 2; i >= 0; i -= 2) { 113 int32_t digit = (int32_t)s[i] - (int32_t)'0'; 114 if (digit < 0 || digit > 9) { 115 e = BCExceptionFormatException; 116 return FALSE; 117 } 118 sum += digit; 119 } 120 sum *= 3; 121 for (int32_t j = length - 1; j >= 0; j -= 2) { 122 int32_t digit = (int32_t)s[j] - (int32_t)'0'; 123 if (digit < 0 || digit > 9) { 124 e = BCExceptionFormatException; 125 return FALSE; 126 } 127 sum += digit; 128 } 129 return sum % 10 == 0; 130 } 131 CFX_Int32Array* CBC_OneDimReader::DecodeEnd(CBC_CommonBitArray* row, 132 int32_t endStart, 133 int32_t& e) { 134 CFX_Int32Array startEndPattern; 135 startEndPattern.Add(START_END_PATTERN[0]); 136 startEndPattern.Add(START_END_PATTERN[1]); 137 startEndPattern.Add(START_END_PATTERN[2]); 138 CFX_Int32Array* FindGuard = 139 FindGuardPattern(row, endStart, FALSE, &startEndPattern, e); 140 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 141 return FindGuard; 142 } 143 CFX_Int32Array* CBC_OneDimReader::FindGuardPattern(CBC_CommonBitArray* row, 144 int32_t rowOffset, 145 FX_BOOL whiteFirst, 146 CFX_Int32Array* pattern, 147 int32_t& e) { 148 int32_t patternLength = pattern->GetSize(); 149 CFX_Int32Array counters; 150 counters.SetSize(patternLength); 151 int32_t width = row->GetSize(); 152 FX_BOOL isWhite = FALSE; 153 while (rowOffset < width) { 154 isWhite = !row->Get(rowOffset); 155 if (whiteFirst == isWhite) { 156 break; 157 } 158 rowOffset++; 159 } 160 int32_t counterPosition = 0; 161 int32_t patternStart = rowOffset; 162 for (int32_t x = rowOffset; x < width; x++) { 163 FX_BOOL pixel = row->Get(x); 164 if (pixel ^ isWhite) { 165 counters[counterPosition]++; 166 } else { 167 if (counterPosition == patternLength - 1) { 168 if (PatternMatchVariance(&counters, &(*pattern)[0], 169 MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { 170 CFX_Int32Array* result = new CFX_Int32Array(); 171 result->SetSize(2); 172 (*result)[0] = patternStart; 173 (*result)[1] = x; 174 return result; 175 } 176 patternStart += counters[0] + counters[1]; 177 for (int32_t y = 2; y < patternLength; y++) { 178 counters[y - 2] = counters[y]; 179 } 180 counters[patternLength - 2] = 0; 181 counters[patternLength - 1] = 0; 182 counterPosition--; 183 } else { 184 counterPosition++; 185 } 186 counters[counterPosition] = 1; 187 isWhite = !isWhite; 188 } 189 } 190 e = BCExceptionNotFound; 191 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); 192 return NULL; 193 } 194 int32_t CBC_OneDimReader::DecodeDigit(CBC_CommonBitArray* row, 195 CFX_Int32Array* counters, 196 int32_t rowOffset, 197 const int32_t* patterns, 198 int32_t patternLength, 199 int32_t& e) { 200 RecordPattern(row, rowOffset, counters, e); 201 BC_EXCEPTION_CHECK_ReturnValue(e, 0); 202 int32_t bestVariance = MAX_AVG_VARIANCE; 203 int32_t bestMatch = -1; 204 int32_t max = patternLength; 205 for (int32_t i = 0; i < max; i++) { 206 int32_t variance = PatternMatchVariance(counters, &patterns[i * 4], 207 MAX_INDIVIDUAL_VARIANCE); 208 if (variance < bestVariance) { 209 bestVariance = variance; 210 bestMatch = i; 211 } 212 } 213 if (bestMatch >= 0) { 214 return bestMatch; 215 } else { 216 e = BCExceptionNotFound; 217 return 0; 218 } 219 return 0; 220 } 221