/*
|
* 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
|