You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.9 KiB
124 lines
3.9 KiB
// Copyright 2022 KURZ Digital Solutions GmbH |
|
// |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#import <CoreGraphics/CoreGraphics.h> |
|
#import "ZXIBarcodeWriter.h" |
|
#import "ZXIWriterOptions.h" |
|
#import "MultiFormatWriter.h" |
|
#import "BitMatrix.h" |
|
#import "BitMatrixIO.h" |
|
#import "ZXIFormatHelper.h" |
|
#import "ZXIErrors.h" |
|
#import <iostream> |
|
|
|
using namespace ZXing; |
|
|
|
std::wstring NSStringToStringW(NSString* str) { |
|
NSData* asData = [str dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE)]; |
|
return std::wstring((wchar_t*)[asData bytes], [asData length] / |
|
sizeof(wchar_t)); |
|
} |
|
|
|
std::wstring NSDataToStringW(NSData *data) { |
|
std::wstring s; |
|
const unsigned char *bytes = (const unsigned char *) [data bytes]; |
|
size_t len = [data length]; |
|
for (int i = 0; i < len; ++i) { |
|
s.push_back(bytes[i]); |
|
} |
|
return s; |
|
} |
|
|
|
@implementation ZXIBarcodeWriter |
|
|
|
- (instancetype)init { |
|
return [self initWithOptions: [[ZXIWriterOptions alloc] init]]; |
|
} |
|
|
|
- (instancetype)initWithOptions:(ZXIWriterOptions*)options{ |
|
self = [super init]; |
|
self.options = options; |
|
return self; |
|
} |
|
|
|
-(CGImageRef)writeData:(NSData *)data |
|
error:(NSError *__autoreleasing _Nullable *)error { |
|
return [self encode: NSDataToStringW(data) |
|
encoding: CharacterSet::BINARY |
|
format: self.options.format |
|
width: self.options.width |
|
height: self.options.height |
|
margin: self.options.margin |
|
ecLevel: self.options.ecLevel |
|
error: error]; |
|
} |
|
|
|
-(CGImageRef)writeString:(NSString *)contents |
|
error:(NSError *__autoreleasing _Nullable *)error { |
|
return [self encode: NSStringToStringW(contents) |
|
encoding: CharacterSet::UTF8 |
|
format: self.options.format |
|
width: self.options.width |
|
height: self.options.height |
|
margin: self.options.margin |
|
ecLevel: self.options.ecLevel |
|
error: error]; |
|
} |
|
|
|
-(CGImageRef)encode:(std::wstring)content |
|
encoding:(CharacterSet)encoding |
|
format:(ZXIFormat)format |
|
width:(int)width |
|
height:(int)height |
|
margin:(int)margin |
|
ecLevel:(int)ecLevel |
|
error:(NSError *__autoreleasing _Nullable *)error { |
|
MultiFormatWriter writer { BarcodeFormatFromZXIFormat(format) }; |
|
writer.setEncoding(encoding); |
|
writer.setMargin(margin); |
|
writer.setEccLevel(ecLevel); |
|
// Catch exception for invalid formats |
|
try { |
|
BitMatrix bitMatrix = writer.encode(content, width, height); |
|
return [self inflate:&bitMatrix]; |
|
} catch(std::exception &e) { |
|
SetNSError(error, ZXIWriterError, e.what()); |
|
return nil; |
|
} |
|
} |
|
|
|
-(CGImageRef)inflate:(BitMatrix *)bitMatrix { |
|
int realWidth = bitMatrix->width(); |
|
int realHeight = bitMatrix->height(); |
|
|
|
#ifdef DEBUG |
|
std::cout << ToString(*bitMatrix, 'X', ' ', false, false); |
|
#endif |
|
|
|
NSMutableData *resultAsNSData = [[NSMutableData alloc] initWithLength:realWidth * realHeight]; |
|
size_t index = 0; |
|
uint8_t *bytes = (uint8_t*)resultAsNSData.mutableBytes; |
|
for (int y = 0; y < realHeight; ++y) { |
|
for (int x = 0; x < realWidth; ++x) { |
|
bytes[index] = bitMatrix->get(x, y) ? 0 : 255; |
|
++index; |
|
} |
|
} |
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); |
|
|
|
return CGImageCreate(realWidth, |
|
realHeight, |
|
8, |
|
8, |
|
realWidth, |
|
colorSpace, |
|
kCGBitmapByteOrderDefault, |
|
CGDataProviderCreateWithCFData((CFDataRef)resultAsNSData), |
|
NULL, |
|
YES, |
|
kCGRenderingIntentDefault); |
|
} |
|
|
|
@end
|
|
|