blob: 9caae9c97b12faf6e6a99d938817986b1d15c851 [file] [log] [blame]
/*
* Copyright 2013 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 "ZXBitMatrix.h"
#import "ZXByteMatrix.h"
#import "ZXDataMatrixErrorCorrection.h"
#import "ZXDataMatrixWriter.h"
#import "ZXDefaultPlacement.h"
#import "ZXDimension.h"
#import "ZXEncodeHints.h"
#import "ZXHighLevelEncoder.h"
#import "ZXSymbolInfo.h"
#import "ZXSymbolShapeHint.h"
@implementation ZXDataMatrixWriter
- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error {
return [self encode:contents format:format width:width height:height hints:nil error:error];
}
- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error {
if (contents.length == 0) {
[NSException raise:NSInvalidArgumentException format:@"Found empty contents"];
}
if (format != kBarcodeFormatDataMatrix) {
[NSException raise:NSInvalidArgumentException format:@"Can only encode kBarcodeFormatDataMatrix"];
}
if (width < 0 || height < 0) {
[NSException raise:NSInvalidArgumentException
format:@"Requested dimensions are too small: %dx%d", width, height];
}
// Try to get force shape & min / max size
ZXSymbolShapeHint *shape = [ZXSymbolShapeHint forceNone];
ZXDimension *minSize = nil;
ZXDimension *maxSize = nil;
if (hints != nil) {
ZXSymbolShapeHint *requestedShape = hints.dataMatrixShape;
if (requestedShape != nil) {
shape = requestedShape;
}
ZXDimension *requestedMinSize = hints.minSize;
if (requestedMinSize != nil) {
minSize = requestedMinSize;
}
ZXDimension *requestedMaxSize = hints.maxSize;
if (requestedMaxSize != nil) {
maxSize = requestedMaxSize;
}
}
//1. step: Data encodation
NSString *encoded = [ZXHighLevelEncoder encodeHighLevel:contents shape:shape minSize:minSize maxSize:maxSize];
ZXSymbolInfo *symbolInfo = [ZXSymbolInfo lookup:(int)encoded.length shape:shape minSize:minSize maxSize:maxSize fail:YES];
//2. step: ECC generation
NSString *codewords = [ZXDataMatrixErrorCorrection encodeECC200:encoded symbolInfo:symbolInfo];
//3. step: Module placement in Matrix
ZXDefaultPlacement *placement = [[ZXDefaultPlacement alloc] initWithCodewords:codewords numcols:symbolInfo.symbolDataWidth numrows:symbolInfo.symbolDataHeight];
[placement place];
//4. step: low-level encoding
return [self encodeLowLevel:placement symbolInfo:symbolInfo];
}
/**
* Encode the given symbol info to a bit matrix.
*/
- (ZXBitMatrix *)encodeLowLevel:(ZXDefaultPlacement *)placement symbolInfo:(ZXSymbolInfo *)symbolInfo {
int symbolWidth = symbolInfo.symbolDataWidth;
int symbolHeight = symbolInfo.symbolDataHeight;
ZXByteMatrix *matrix = [[ZXByteMatrix alloc] initWithWidth:symbolInfo.symbolWidth height:symbolInfo.symbolHeight];
int matrixY = 0;
for (int y = 0; y < symbolHeight; y++) {
// Fill the top edge with alternate 0 / 1
int matrixX;
if ((y % symbolInfo.matrixHeight) == 0) {
matrixX = 0;
for (int x = 0; x < symbolInfo.symbolWidth; x++) {
[matrix setX:matrixX y:matrixY boolValue:(x % 2) == 0];
matrixX++;
}
matrixY++;
}
matrixX = 0;
for (int x = 0; x < symbolWidth; x++) {
// Fill the right edge with full 1
if ((x % symbolInfo.matrixWidth) == 0) {
[matrix setX:matrixX y:matrixY boolValue:YES];
matrixX++;
}
[matrix setX:matrixX y:matrixY boolValue:[placement bitAtCol:x row:y]];
matrixX++;
// Fill the right edge with alternate 0 / 1
if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1) {
[matrix setX:matrixX y:matrixY boolValue:(y % 2) == 0];
matrixX++;
}
}
matrixY++;
// Fill the bottom edge with full 1
if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1) {
matrixX = 0;
for (int x = 0; x < symbolInfo.symbolWidth; x++) {
[matrix setX:matrixX y:matrixY boolValue:YES];
matrixX++;
}
matrixY++;
}
}
return [self convertByteMatrixToBitMatrix:matrix];
}
/**
* Convert the ByteMatrix to BitMatrix.
*/
- (ZXBitMatrix *)convertByteMatrixToBitMatrix:(ZXByteMatrix *)matrix {
int matrixWidgth = matrix.width;
int matrixHeight = matrix.height;
ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:matrixWidgth height:matrixHeight];
[output clear];
for (int i = 0; i < matrixWidgth; i++) {
for (int j = 0; j < matrixHeight; j++) {
// Zero is white in the bytematrix
if ([matrix getX:i y:j] == 1) {
[output setX:i y:j];
}
}
}
return output;
}
@end