Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ZXUPCEANReader.m 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright 2012 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "ZXBitArray.h"
  17. #import "ZXDecodeHints.h"
  18. #import "ZXEANManufacturerOrgSupport.h"
  19. #import "ZXErrors.h"
  20. #import "ZXIntArray.h"
  21. #import "ZXResult.h"
  22. #import "ZXResultPoint.h"
  23. #import "ZXResultPointCallback.h"
  24. #import "ZXUPCEANReader.h"
  25. #import "ZXUPCEANExtensionSupport.h"
  26. static float ZX_UPC_EAN_MAX_AVG_VARIANCE = 0.48f;
  27. static float ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE = 0.7f;
  28. /**
  29. * Start/end guard pattern.
  30. */
  31. const int ZX_UPC_EAN_START_END_PATTERN_LEN = 3;
  32. const int ZX_UPC_EAN_START_END_PATTERN[ZX_UPC_EAN_START_END_PATTERN_LEN] = {1, 1, 1};
  33. /**
  34. * Pattern marking the middle of a UPC/EAN pattern, separating the two halves.
  35. */
  36. const int ZX_UPC_EAN_MIDDLE_PATTERN_LEN = 5;
  37. const int ZX_UPC_EAN_MIDDLE_PATTERN[ZX_UPC_EAN_MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1};
  38. /**
  39. * "Odd", or "L" patterns used to encode UPC/EAN digits.
  40. */
  41. const int ZX_UPC_EAN_L_PATTERNS_LEN = 10;
  42. const int ZX_UPC_EAN_L_PATTERNS_SUB_LEN = 4;
  43. const int ZX_UPC_EAN_L_PATTERNS[ZX_UPC_EAN_L_PATTERNS_LEN][ZX_UPC_EAN_L_PATTERNS_SUB_LEN] = {
  44. {3, 2, 1, 1}, // 0
  45. {2, 2, 2, 1}, // 1
  46. {2, 1, 2, 2}, // 2
  47. {1, 4, 1, 1}, // 3
  48. {1, 1, 3, 2}, // 4
  49. {1, 2, 3, 1}, // 5
  50. {1, 1, 1, 4}, // 6
  51. {1, 3, 1, 2}, // 7
  52. {1, 2, 1, 3}, // 8
  53. {3, 1, 1, 2} // 9
  54. };
  55. /**
  56. * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits.
  57. */
  58. const int ZX_UPC_EAN_L_AND_G_PATTERNS_LEN = 20;
  59. const int ZX_UPC_EAN_L_AND_G_PATTERNS_SUB_LEN = 4;
  60. const int ZX_UPC_EAN_L_AND_G_PATTERNS[ZX_UPC_EAN_L_AND_G_PATTERNS_LEN][ZX_UPC_EAN_L_AND_G_PATTERNS_SUB_LEN] = {
  61. {3, 2, 1, 1}, // 0
  62. {2, 2, 2, 1}, // 1
  63. {2, 1, 2, 2}, // 2
  64. {1, 4, 1, 1}, // 3
  65. {1, 1, 3, 2}, // 4
  66. {1, 2, 3, 1}, // 5
  67. {1, 1, 1, 4}, // 6
  68. {1, 3, 1, 2}, // 7
  69. {1, 2, 1, 3}, // 8
  70. {3, 1, 1, 2}, // 9
  71. {1, 1, 2, 3}, // 10 reversed 0
  72. {1, 2, 2, 2}, // 11 reversed 1
  73. {2, 2, 1, 2}, // 12 reversed 2
  74. {1, 1, 4, 1}, // 13 reversed 3
  75. {2, 3, 1, 1}, // 14 reversed 4
  76. {1, 3, 2, 1}, // 15 reversed 5
  77. {4, 1, 1, 1}, // 16 reversed 6
  78. {2, 1, 3, 1}, // 17 reversed 7
  79. {3, 1, 2, 1}, // 18 reversed 8
  80. {2, 1, 1, 3} // 19 reversed 9
  81. };
  82. @interface ZXUPCEANReader ()
  83. @property (nonatomic, strong, readonly) NSMutableString *decodeRowNSMutableString;
  84. @property (nonatomic, strong, readonly) ZXUPCEANExtensionSupport *extensionReader;
  85. @property (nonatomic, strong, readonly) ZXEANManufacturerOrgSupport *eanManSupport;
  86. @end
  87. @implementation ZXUPCEANReader
  88. - (id)init {
  89. if (self = [super init]) {
  90. _decodeRowNSMutableString = [NSMutableString stringWithCapacity:20];
  91. _extensionReader = [[ZXUPCEANExtensionSupport alloc] init];
  92. _eanManSupport = [[ZXEANManufacturerOrgSupport alloc] init];
  93. }
  94. return self;
  95. }
  96. + (NSRange)findStartGuardPattern:(ZXBitArray *)row error:(NSError **)error {
  97. BOOL foundStart = NO;
  98. NSRange startRange = NSMakeRange(NSNotFound, 0);
  99. int nextStart = 0;
  100. ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:ZX_UPC_EAN_START_END_PATTERN_LEN];
  101. while (!foundStart) {
  102. [counters clear];
  103. startRange = [self findGuardPattern:row rowOffset:nextStart
  104. whiteFirst:NO
  105. pattern:ZX_UPC_EAN_START_END_PATTERN
  106. patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN
  107. counters:counters
  108. error:error];
  109. if (startRange.location == NSNotFound) {
  110. return startRange;
  111. }
  112. int start = (int)startRange.location;
  113. nextStart = (int)NSMaxRange(startRange);
  114. // Make sure there is a quiet zone at least as big as the start pattern before the barcode.
  115. // If this check would run off the left edge of the image, do not accept this barcode,
  116. // as it is very likely to be a false positive.
  117. int quietStart = start - (nextStart - start);
  118. if (quietStart >= 0) {
  119. foundStart = [row isRange:quietStart end:start value:NO];
  120. }
  121. }
  122. return startRange;
  123. }
  124. - (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error {
  125. return [self decodeRow:rowNumber row:row startGuardRange:[[self class] findStartGuardPattern:row error:error] hints:hints error:error];
  126. }
  127. - (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row startGuardRange:(NSRange)startGuardRange hints:(ZXDecodeHints *)hints error:(NSError **)error {
  128. id<ZXResultPointCallback> resultPointCallback = hints == nil ? nil : hints.resultPointCallback;
  129. if (resultPointCallback != nil) {
  130. [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:(startGuardRange.location + NSMaxRange(startGuardRange)) / 2.0f y:rowNumber]];
  131. }
  132. NSMutableString *result = [NSMutableString string];
  133. int endStart = [self decodeMiddle:row startRange:startGuardRange result:result error:error];
  134. if (endStart == -1) {
  135. return nil;
  136. }
  137. if (resultPointCallback != nil) {
  138. [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:endStart y:rowNumber]];
  139. }
  140. NSRange endRange = [self decodeEnd:row endStart:endStart error:error];
  141. if (endRange.location == NSNotFound) {
  142. return nil;
  143. }
  144. if (resultPointCallback != nil) {
  145. [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:(endRange.location + NSMaxRange(endRange)) / 2.0f y:rowNumber]];
  146. }
  147. // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The
  148. // spec might want more whitespace, but in practice this is the maximum we can count on.
  149. int end = (int)NSMaxRange(endRange);
  150. int quietEnd = end + (end - (int)endRange.location);
  151. if (quietEnd >= [row size] || ![row isRange:end end:quietEnd value:NO]) {
  152. if (error) *error = ZXNotFoundErrorInstance();
  153. return nil;
  154. }
  155. NSString *resultString = [result description];
  156. // UPC/EAN should never be less than 8 chars anyway
  157. if ([resultString length] < 8) {
  158. if (error) *error = ZXFormatErrorInstance();
  159. return nil;
  160. }
  161. if (![self checkChecksum:resultString error:error]) {
  162. if (error) *error = ZXChecksumErrorInstance();
  163. return nil;
  164. }
  165. float left = (float)(NSMaxRange(startGuardRange) + startGuardRange.location) / 2.0f;
  166. float right = (float)(NSMaxRange(endRange) + endRange.location) / 2.0f;
  167. ZXBarcodeFormat format = [self barcodeFormat];
  168. ZXResult *decodeResult = [ZXResult resultWithText:resultString
  169. rawBytes:nil
  170. resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]]
  171. format:format];
  172. int extensionLength = 0;
  173. ZXResult *extensionResult = [self.extensionReader decodeRow:rowNumber row:row rowOffset:(int)NSMaxRange(endRange) error:error];
  174. if (extensionResult) {
  175. [decodeResult putMetadata:kResultMetadataTypeUPCEANExtension value:extensionResult.text];
  176. [decodeResult putAllMetadata:[extensionResult resultMetadata]];
  177. [decodeResult addResultPoints:[extensionResult resultPoints]];
  178. extensionLength = (int)[extensionResult.text length];
  179. }
  180. ZXIntArray *allowedExtensions = hints == nil ? nil : hints.allowedEANExtensions;
  181. if (allowedExtensions != nil) {
  182. BOOL valid = NO;
  183. for (int i = 0; i < allowedExtensions.length; i++) {
  184. if (extensionLength == allowedExtensions.array[i]) {
  185. valid = YES;
  186. break;
  187. }
  188. }
  189. if (!valid) {
  190. if (error) *error = ZXNotFoundErrorInstance();
  191. return nil;
  192. }
  193. }
  194. if (format == kBarcodeFormatEan13 || format == kBarcodeFormatUPCA) {
  195. NSString *countryID = [self.eanManSupport lookupCountryIdentifier:resultString];
  196. if (countryID != nil) {
  197. [decodeResult putMetadata:kResultMetadataTypePossibleCountry value:countryID];
  198. }
  199. }
  200. return decodeResult;
  201. }
  202. - (BOOL)checkChecksum:(NSString *)s error:(NSError **)error {
  203. if ([[self class] checkStandardUPCEANChecksum:s]) {
  204. return YES;
  205. } else {
  206. if (error) *error = ZXFormatErrorInstance();
  207. return NO;
  208. }
  209. }
  210. + (BOOL)checkStandardUPCEANChecksum:(NSString *)s {
  211. int length = (int)[s length];
  212. if (length == 0) {
  213. return NO;
  214. }
  215. int sum = 0;
  216. for (int i = length - 2; i >= 0; i -= 2) {
  217. int digit = (int)[s characterAtIndex:i] - (int)'0';
  218. if (digit < 0 || digit > 9) {
  219. return NO;
  220. }
  221. sum += digit;
  222. }
  223. sum *= 3;
  224. for (int i = length - 1; i >= 0; i -= 2) {
  225. int digit = (int)[s characterAtIndex:i] - (int)'0';
  226. if (digit < 0 || digit > 9) {
  227. return NO;
  228. }
  229. sum += digit;
  230. }
  231. return sum % 10 == 0;
  232. }
  233. - (NSRange)decodeEnd:(ZXBitArray *)row endStart:(int)endStart error:(NSError **)error {
  234. return [[self class] findGuardPattern:row
  235. rowOffset:endStart
  236. whiteFirst:NO
  237. pattern:ZX_UPC_EAN_START_END_PATTERN
  238. patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN
  239. error:error];
  240. }
  241. + (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen error:(NSError **)error {
  242. ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:patternLen];
  243. return [self findGuardPattern:row rowOffset:rowOffset whiteFirst:whiteFirst pattern:pattern patternLen:patternLen counters:counters error:error];
  244. }
  245. + (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen counters:(ZXIntArray *)counters error:(NSError **)error {
  246. int patternLength = patternLen;
  247. int width = row.size;
  248. BOOL isWhite = whiteFirst;
  249. rowOffset = whiteFirst ? [row nextUnset:rowOffset] : [row nextSet:rowOffset];
  250. int counterPosition = 0;
  251. int patternStart = rowOffset;
  252. int32_t *array = counters.array;
  253. for (int x = rowOffset; x < width; x++) {
  254. if ([row get:x] ^ isWhite) {
  255. array[counterPosition]++;
  256. } else {
  257. if (counterPosition == patternLength - 1) {
  258. if ([self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE] < ZX_UPC_EAN_MAX_AVG_VARIANCE) {
  259. return NSMakeRange(patternStart, x - patternStart);
  260. }
  261. patternStart += array[0] + array[1];
  262. for (int y = 2; y < patternLength; y++) {
  263. array[y - 2] = array[y];
  264. }
  265. array[patternLength - 2] = 0;
  266. array[patternLength - 1] = 0;
  267. counterPosition--;
  268. } else {
  269. counterPosition++;
  270. }
  271. array[counterPosition] = 1;
  272. isWhite = !isWhite;
  273. }
  274. }
  275. if (error) *error = ZXNotFoundErrorInstance();
  276. return NSMakeRange(NSNotFound, 0);
  277. }
  278. /**
  279. * Attempts to decode a single UPC/EAN-encoded digit.
  280. */
  281. + (int)decodeDigit:(ZXBitArray *)row counters:(ZXIntArray *)counters rowOffset:(int)rowOffset patternType:(ZX_UPC_EAN_PATTERNS)patternType error:(NSError **)error {
  282. if (![self recordPattern:row start:rowOffset counters:counters]) {
  283. if (error) *error = ZXNotFoundErrorInstance();
  284. return -1;
  285. }
  286. float bestVariance = ZX_UPC_EAN_MAX_AVG_VARIANCE;
  287. int bestMatch = -1;
  288. int max = 0;
  289. switch (patternType) {
  290. case ZX_UPC_EAN_PATTERNS_L_PATTERNS:
  291. max = ZX_UPC_EAN_L_PATTERNS_LEN;
  292. for (int i = 0; i < max; i++) {
  293. int pattern[counters.length];
  294. for (int j = 0; j < counters.length; j++){
  295. pattern[j] = ZX_UPC_EAN_L_PATTERNS[i][j];
  296. }
  297. float variance = [self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE];
  298. if (variance < bestVariance) {
  299. bestVariance = variance;
  300. bestMatch = i;
  301. }
  302. }
  303. break;
  304. case ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS:
  305. max = ZX_UPC_EAN_L_AND_G_PATTERNS_LEN;
  306. for (int i = 0; i < max; i++) {
  307. int pattern[counters.length];
  308. for (int j = 0; j< counters.length; j++){
  309. pattern[j] = ZX_UPC_EAN_L_AND_G_PATTERNS[i][j];
  310. }
  311. float variance = [self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE];
  312. if (variance < bestVariance) {
  313. bestVariance = variance;
  314. bestMatch = i;
  315. }
  316. }
  317. break;
  318. default:
  319. break;
  320. }
  321. if (bestMatch >= 0) {
  322. return bestMatch;
  323. } else {
  324. if (error) *error = ZXNotFoundErrorInstance();
  325. return -1;
  326. }
  327. }
  328. - (ZXBarcodeFormat)barcodeFormat {
  329. @throw [NSException exceptionWithName:NSInternalInconsistencyException
  330. reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
  331. userInfo:nil];
  332. }
  333. - (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error {
  334. @throw [NSException exceptionWithName:NSInternalInconsistencyException
  335. reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
  336. userInfo:nil];
  337. }
  338. @end