/* * Copyright 2012 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #import "ZXBoolArray.h" #import "ZXCode128Reader.h" #import "ZXCode128Writer.h" // Dummy characters used to specify control characters in input const unichar ZX_CODE128_ESCAPE_FNC_1 = L'\u00f1'; const unichar ZX_CODE128_ESCAPE_FNC_2 = L'\u00f2'; const unichar ZX_CODE128_ESCAPE_FNC_3 = L'\u00f3'; const unichar ZX_CODE128_ESCAPE_FNC_4 = L'\u00f4'; @implementation ZXCode128Writer - (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { if (format != kBarcodeFormatCode128) { [NSException raise:NSInvalidArgumentException format:@"Can only encode CODE_128"]; } return [super encode:contents format:format width:width height:height hints:hints error:error]; } - (ZXBoolArray *)encode:(NSString *)contents { int length = (int)[contents length]; // Check length if (length < 1 || length > 80) { [NSException raise:NSInvalidArgumentException format:@"Contents length should be between 1 and 80 characters, but got %d", length]; } // Check content for (int i = 0; i < length; i++) { unichar c = [contents characterAtIndex:i]; if (c < ' ' || c > '~') { switch (c) { case ZX_CODE128_ESCAPE_FNC_1: case ZX_CODE128_ESCAPE_FNC_2: case ZX_CODE128_ESCAPE_FNC_3: case ZX_CODE128_ESCAPE_FNC_4: break; default: [NSException raise:NSInvalidArgumentException format:@"Bad character in input: %C", c]; } } } NSMutableArray *patterns = [NSMutableArray array]; // temporary storage for patterns int checkSum = 0; int checkWeight = 1; int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C) int position = 0; // position in contents while (position < length) { //Select code to use int requiredDigitCount = codeSet == ZX_CODE128_CODE_CODE_C ? 2 : 4; int newCodeSet; if ([self isDigits:contents start:position length:requiredDigitCount]) { newCodeSet = ZX_CODE128_CODE_CODE_C; } else { newCodeSet = ZX_CODE128_CODE_CODE_B; } //Get the pattern index int patternIndex; if (newCodeSet == codeSet) { // Encode the current character // First handle escapes switch ([contents characterAtIndex:position]) { case ZX_CODE128_ESCAPE_FNC_1: patternIndex = ZX_CODE128_CODE_FNC_1; break; case ZX_CODE128_ESCAPE_FNC_2: patternIndex = ZX_CODE128_CODE_FNC_2; break; case ZX_CODE128_ESCAPE_FNC_3: patternIndex = ZX_CODE128_CODE_FNC_3; break; case ZX_CODE128_ESCAPE_FNC_4: patternIndex = ZX_CODE128_CODE_FNC_4_B; // FIXME if this ever outputs Code A break; default: // Then handle normal characters otherwise if (codeSet == ZX_CODE128_CODE_CODE_B) { patternIndex = [contents characterAtIndex:position] - ' '; } else { // CODE_CODE_C patternIndex = [[contents substringWithRange:NSMakeRange(position, 2)] intValue]; position++; // Also incremented below } } position++; } else { // Should we change the current code? // Do we have a code set? if (codeSet == 0) { // No, we don't have a code set if (newCodeSet == ZX_CODE128_CODE_CODE_B) { patternIndex = ZX_CODE128_CODE_START_B; } else { // CODE_CODE_C patternIndex = ZX_CODE128_CODE_START_C; } } else { // Yes, we have a code set patternIndex = newCodeSet; } codeSet = newCodeSet; } // Get the pattern NSMutableArray *pattern = [NSMutableArray array]; for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[patternIndex]) / sizeof(int); i++) { [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[patternIndex][i])]; } [patterns addObject:pattern]; // Compute checksum checkSum += patternIndex * checkWeight; if (position != 0) { checkWeight++; } } // Compute and append checksum checkSum %= 103; NSMutableArray *pattern = [NSMutableArray array]; for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[checkSum]) / sizeof(int); i++) { [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[checkSum][i])]; } [patterns addObject:pattern]; // Append stop code pattern = [NSMutableArray array]; for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP]) / sizeof(int); i++) { [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP][i])]; } [patterns addObject:pattern]; // Compute code width int codeWidth = 0; for (pattern in patterns) { for (int i = 0; i < pattern.count; i++) { codeWidth += [pattern[i] intValue]; } } // Compute result ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:codeWidth]; int pos = 0; for (NSArray *patternArray in patterns) { int patternLen = (int)[patternArray count]; int pattern[patternLen]; for (int i = 0; i < patternLen; i++) { pattern[i] = [patternArray[i] intValue]; } pos += [self appendPattern:result pos:pos pattern:pattern patternLen:patternLen startColor:YES]; } return result; } - (BOOL)isDigits:(NSString *)value start:(int)start length:(unsigned int)length { int end = start + length; int last = (int)[value length]; for (int i = start; i < end && i < last; i++) { unichar c = [value characterAtIndex:i]; if (c < '0' || c > '9') { if (c != ZX_CODE128_ESCAPE_FNC_1) { return NO; } end++; // ignore FNC_1 } } return end <= last; // end > last if we've run out of string } @end