ZXIBarcodeWriter.mm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // Copyright 2022 KURZ Digital Solutions GmbH
  2. //
  3. // SPDX-License-Identifier: Apache-2.0
  4. #import <CoreGraphics/CoreGraphics.h>
  5. #import "ZXIBarcodeWriter.h"
  6. #import "ZXIWriterOptions.h"
  7. #import "MultiFormatWriter.h"
  8. #import "BitMatrix.h"
  9. #import "BitMatrixIO.h"
  10. #import "ZXIFormatHelper.h"
  11. #import "ZXIErrors.h"
  12. #import <iostream>
  13. using namespace ZXing;
  14. std::wstring NSStringToStringW(NSString* str) {
  15. NSData* asData = [str dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE)];
  16. return std::wstring((wchar_t*)[asData bytes], [asData length] /
  17. sizeof(wchar_t));
  18. }
  19. std::wstring NSDataToStringW(NSData *data) {
  20. std::wstring s;
  21. const unsigned char *bytes = (const unsigned char *) [data bytes];
  22. size_t len = [data length];
  23. for (int i = 0; i < len; ++i) {
  24. s.push_back(bytes[i]);
  25. }
  26. return s;
  27. }
  28. @implementation ZXIBarcodeWriter
  29. - (instancetype)init {
  30. return [self initWithOptions: [[ZXIWriterOptions alloc] init]];
  31. }
  32. - (instancetype)initWithOptions:(ZXIWriterOptions*)options{
  33. self = [super init];
  34. self.options = options;
  35. return self;
  36. }
  37. -(CGImageRef)writeData:(NSData *)data
  38. error:(NSError *__autoreleasing _Nullable *)error {
  39. return [self encode: NSDataToStringW(data)
  40. encoding: CharacterSet::BINARY
  41. format: self.options.format
  42. width: self.options.width
  43. height: self.options.height
  44. margin: self.options.margin
  45. ecLevel: self.options.ecLevel
  46. error: error];
  47. }
  48. -(CGImageRef)writeString:(NSString *)contents
  49. error:(NSError *__autoreleasing _Nullable *)error {
  50. return [self encode: NSStringToStringW(contents)
  51. encoding: CharacterSet::UTF8
  52. format: self.options.format
  53. width: self.options.width
  54. height: self.options.height
  55. margin: self.options.margin
  56. ecLevel: self.options.ecLevel
  57. error: error];
  58. }
  59. -(CGImageRef)encode:(std::wstring)content
  60. encoding:(CharacterSet)encoding
  61. format:(ZXIFormat)format
  62. width:(int)width
  63. height:(int)height
  64. margin:(int)margin
  65. ecLevel:(int)ecLevel
  66. error:(NSError *__autoreleasing _Nullable *)error {
  67. MultiFormatWriter writer { BarcodeFormatFromZXIFormat(format) };
  68. writer.setEncoding(encoding);
  69. writer.setMargin(margin);
  70. writer.setEccLevel(ecLevel);
  71. // Catch exception for invalid formats
  72. try {
  73. BitMatrix bitMatrix = writer.encode(content, width, height);
  74. return [self inflate:&bitMatrix];
  75. } catch(std::exception &e) {
  76. SetNSError(error, ZXIWriterError, e.what());
  77. return nil;
  78. }
  79. }
  80. -(CGImageRef)inflate:(BitMatrix *)bitMatrix {
  81. int realWidth = bitMatrix->width();
  82. int realHeight = bitMatrix->height();
  83. #ifdef DEBUG
  84. std::cout << ToString(*bitMatrix, 'X', ' ', false, false);
  85. #endif
  86. NSMutableData *resultAsNSData = [[NSMutableData alloc] initWithLength:realWidth * realHeight];
  87. size_t index = 0;
  88. uint8_t *bytes = (uint8_t*)resultAsNSData.mutableBytes;
  89. for (int y = 0; y < realHeight; ++y) {
  90. for (int x = 0; x < realWidth; ++x) {
  91. bytes[index] = bitMatrix->get(x, y) ? 0 : 255;
  92. ++index;
  93. }
  94. }
  95. CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
  96. return CGImageCreate(realWidth,
  97. realHeight,
  98. 8,
  99. 8,
  100. realWidth,
  101. colorSpace,
  102. kCGBitmapByteOrderDefault,
  103. CGDataProviderCreateWithCFData((CFDataRef)resultAsNSData),
  104. NULL,
  105. YES,
  106. kCGRenderingIntentDefault);
  107. }
  108. @end