From 6dd5c5701717ddef1623025e4fd198a82e948969 Mon Sep 17 00:00:00 2001 From: Hendrik von Prince Date: Fri, 25 Feb 2022 10:23:42 +0100 Subject: [PATCH 01/88] Add iOS Wrapper Co-authored-by: Christian Braun --- core/CMakeLists.txt | 22 +++ wrappers/ios/Info.plist | Bin 0 -> 723 bytes wrappers/ios/README.md | 14 ++ .../Sources/Wrapper/Reader/ZXIBarcodeReader.h | 23 +++ .../Wrapper/Reader/ZXIBarcodeReader.mm | 112 +++++++++++++ .../Sources/Wrapper/Reader/ZXIDecodeHints.h | 21 +++ .../Sources/Wrapper/Reader/ZXIDecodeHints.mm | 20 +++ .../ios/Sources/Wrapper/Reader/ZXIResult.h | 23 +++ .../ios/Sources/Wrapper/Reader/ZXIResult.mm | 20 +++ wrappers/ios/Sources/Wrapper/UmbrellaHeader.h | 19 +++ .../Sources/Wrapper/Writer/ZXIBarcodeWriter.h | 30 ++++ .../Wrapper/Writer/ZXIBarcodeWriter.mm | 117 ++++++++++++++ .../ios/Sources/Wrapper/Writer/ZXICharset.h | 49 ++++++ .../Sources/Wrapper/Writer/ZXICharsetHelper.h | 17 ++ .../Wrapper/Writer/ZXICharsetHelper.mm | 148 ++++++++++++++++++ wrappers/ios/Sources/Wrapper/ZXIErrors.h | 21 +++ wrappers/ios/Sources/Wrapper/ZXIFormat.h | 18 +++ .../ios/Sources/Wrapper/ZXIFormatHelper.h | 16 ++ .../ios/Sources/Wrapper/ZXIFormatHelper.mm | 106 +++++++++++++ wrappers/ios/Sources/Wrapper/module.modulemap | 6 + wrappers/ios/build-release.sh | 36 +++++ 21 files changed, 838 insertions(+) create mode 100644 wrappers/ios/Info.plist create mode 100644 wrappers/ios/README.md create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm create mode 100644 wrappers/ios/Sources/Wrapper/UmbrellaHeader.h create mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h create mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm create mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h create mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h create mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm create mode 100644 wrappers/ios/Sources/Wrapper/ZXIErrors.h create mode 100644 wrappers/ios/Sources/Wrapper/ZXIFormat.h create mode 100644 wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h create mode 100644 wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm create mode 100644 wrappers/ios/Sources/Wrapper/module.modulemap create mode 100755 wrappers/ios/build-release.sh diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d52b08570d..9a710ad272 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -114,6 +114,7 @@ if (BUILD_READERS) src/Result.cpp src/ResultPoint.h src/ResultPoint.cpp + src/StructuredAppend.h src/TextDecoder.h src/TextDecoder.cpp src/ThresholdBinarizer.h @@ -462,6 +463,26 @@ if (PROJECT_VERSION) set_target_properties(ZXing PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) endif() +set(PUBLIC_HEADERS "${COMMON_FILES}") +list(FILTER PUBLIC_HEADERS INCLUDE REGEX "^.*\.h$") + +message(STATUS "PUBLIC HEADERS BE LIKE ${PUBLIC_HEADERS}") + +set_target_properties(ZXing PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION "C" + XCODE_ATTRIBUTE_DEFINES_MODULE YES + XCODE_ATTRIBUTE_BUILD_LIBRARY_FOR_DISTRIBUTION YES + XCODE_ATTRIBUTE_MODULEMAP_FILE "wrappers/ios/Sources/Wrapper/module.modulemap" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + MACOSX_FRAMEWORK_IDENTIFIER "com.zxing_cpp.ios" + CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO + #MACOSX_FRAMEWORK_INFO_PLIST Info.plist + PUBLIC_HEADER "${PUBLIC_HEADERS}" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" + XCODE_ATTRIBUTE_ENABLE_BITCODE "YES" +) + include (GNUInstallDirs) install ( @@ -469,6 +490,7 @@ install ( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} INCLUDES DESTINATION include ) diff --git a/wrappers/ios/Info.plist b/wrappers/ios/Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..0433f478b49fa21f43f38dbba7b6bc0a62542df1 GIT binary patch literal 723 zcmYjOyKWOf6x}<#5+2DWPJo02On3x{Sb4pPrO+VRYa=VNW4!Cwi9%N6-LXB&?1Ozo zc7B0^p3YxDO+|&M_y8(IK|_ORD4=0>V-u#i_ndpqoqK269-~2+$$Sy#0G&B|?)-&` z$%~gRUzwT~XJ%7#^H;B3Us$}cbn{mF_DcHB-Fx>}9~xpRA5msiu-T&y+13(dhzo^M zK5{HZRB}X^>)FH!>!eFv#}H@7wPK%`QHa}&{7058E~Onxd_!CwE6YyDRjCd-9coARwl*>!G|K$ts7XrLrfgt{OO0}!yo{(%tdl|kd$>&*4Jip4Sy|0xn?Yf-1mM>1VoI_~rQvFUjdbptIYW%N>|xurklXSm#=wVoUQ+N2?_#A?1cBNES& zwF8N^VcDj;mWOn4uVpiE~Q7?A6fi7=I>-%FA16@`WE>nuKtkh*?_&|i=qXzcv z+`2F!C_-5v!m;pLcq@DmJ`2BK3Kn1uo +#import +#import "ZXIResult.h" +#import "ZXIDecodeHints.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIBarcodeReader : NSObject +@property(nonatomic, strong) ZXIDecodeHints *hints; + +- (instancetype)initWithHints:(ZXIDecodeHints*)options; +- (nullable ZXIResult *)readCIImage:(nonnull CIImage *)image error:(NSError **)error; +- (nullable ZXIResult *)readCGImage:(nonnull CGImageRef)image error:(NSError **)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm new file mode 100644 index 0000000000..19537bbd55 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -0,0 +1,112 @@ +// +// BarcodeReader.m +// +// +// Created by Christian Braun on 22.02.22. +// + +#import "ZXIBarcodeReader.h" +#import "ZXIErrors.h" +#import "ZXing/ReadBarcode.h" +#import "ZXing/ImageView.h" +#import "ZXing/Result.h" +#import "ZXIFormatHelper.h" + +using namespace ZXing; + +@interface ZXIBarcodeReader() +@property (nonatomic, strong) CIContext* ciContext; +@end + +@implementation ZXIBarcodeReader + +- (instancetype)init { + return [self initWithHints: [[ZXIDecodeHints alloc]initWithTryHarder:NO tryRotate:NO formats:@[]]]; +} + +- (instancetype)initWithHints:(ZXIDecodeHints*)hints{ + self = [super init]; + self.ciContext = [CIContext new]; + self.hints = hints; + return self; +} + +- (nullable ZXIResult *)readCIImage:(nonnull CIImage *)image error:(NSError **)error { + CGImageRef cgImage = [self.ciContext createCGImage:image fromRect:image.extent]; + ZXIResult *result = [self readCGImage:cgImage error:error]; + CGImageRelease(cgImage); + return result; +} + +- (nullable ZXIResult *)readCGImage: (nonnull CGImageRef)image error:(NSError **)error { + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); + CGFloat cols = CGImageGetWidth(image); + CGFloat rows = CGImageGetHeight(image); + NSMutableData *data = [NSMutableData dataWithLength: cols * rows]; + + CGContextRef contextRef = CGBitmapContextCreate( + data.mutableBytes,// Pointer to backing data + cols, // Width of bitmap + rows, // Height of bitmap + 8, // Bits per component + cols, // Bytes per row + colorSpace, // Colorspace + kCGBitmapByteOrderDefault); // Bitmap info flags + + CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image); + CGContextRelease(contextRef); + + ImageView imageView = ImageView( + static_cast(data.bytes), + static_cast(cols), + static_cast(rows), + ImageFormat::Lum); + + Result result = ReadBarcode(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); + if(result.status() == DecodeStatus::NoError) { + const std::wstring &resultText = result.text(); + NSString *text = [[NSString alloc] initWithBytes:resultText.data() + length:resultText.size() * sizeof(wchar_t) + encoding:NSUTF32LittleEndianStringEncoding]; + + std::string s(resultText.begin(), resultText.end()); + NSData *rawBytes = [[NSData alloc] initWithBytes:s.c_str() length:s.size()]; + return [[ZXIResult alloc] init:text + format:ZXIFormatFromBarcodeFormat(result.format()) + rawBytes:rawBytes]; + } else { + if(error != nil) { + ZXIReaderError errorCode; + switch (result.status()) { + case ZXing::DecodeStatus::NoError: + // Can not happen + break; + case ZXing::DecodeStatus::NotFound: + errorCode = ZXIReaderError::ZXINotFoundError; + break; + case ZXing::DecodeStatus::FormatError: + errorCode = ZXIReaderError::ZXIFormatError; + break; + case ZXing::DecodeStatus::ChecksumError: + errorCode = ZXIReaderError::ZXIChecksumError; + break; + } + *error = [[NSError alloc] initWithDomain: ZXIErrorDomain code: errorCode userInfo:nil]; + } + return nil; + } +} + ++ (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { + DecodeHints resultingHints = DecodeHints(); + resultingHints.setTryRotate(hints.tryRotate); + resultingHints.setTryHarder(hints.tryHarder); + BarcodeFormats formats; + for(NSNumber* flag in hints.formats) { + formats.setFlag(BarcodeFormatFromZXIFormat((ZXIFormat)flag.integerValue)); + } + resultingHints.setFormats(formats); + return resultingHints; +} + +@end diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h new file mode 100644 index 0000000000..ce21914fb8 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h @@ -0,0 +1,21 @@ +// +// ZXIDecodeHints.h +// +// +// Created by Christian Braun on 25.02.22. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIDecodeHints : NSObject +@property(nonatomic) BOOL tryHarder; +@property(nonatomic) BOOL tryRotate; +/// An array of ZXIFormat +@property(nonatomic, strong) NSArray *formats; + +- (instancetype)initWithTryHarder:(BOOL)tryHarder tryRotate:(BOOL)tryRotate formats:(NSArray*)formats; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm new file mode 100644 index 0000000000..7972cbfbb3 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm @@ -0,0 +1,20 @@ +// +// ZXIDecodeHints.m +// +// +// Created by Christian Braun on 25.02.22. +// + +#import "ZXIDecodeHints.h" + +@implementation ZXIDecodeHints + +- (instancetype)initWithTryHarder:(BOOL)tryHarder tryRotate:(BOOL)tryRotate formats:(NSArray*)formats { + self = [super init]; + self.tryHarder = tryHarder; + self.tryRotate = tryRotate; + self.formats = formats; + return self; +} + +@end diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h new file mode 100644 index 0000000000..b3910be231 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h @@ -0,0 +1,23 @@ +// +// ZXIResult.h +// +// +// Created by Christian Braun on 25.02.22. +// + +#import +#import "ZXIFormat.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIResult : NSObject +@property(nonatomic, strong) NSString *text; +@property(nonatomic, strong) NSData *rawBytes; +@property(nonatomic) ZXIFormat format; + +- (instancetype)init:(NSString *)text + format:(ZXIFormat)format + rawBytes:(NSData *)rawBytes; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm new file mode 100644 index 0000000000..efaa4e3ba1 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm @@ -0,0 +1,20 @@ +// +// ZXIResult.m +// +// +// Created by Christian Braun on 25.02.22. +// + +#import "ZXIResult.h" + +@implementation ZXIResult +- (instancetype)init:(NSString *)text + format:(ZXIFormat)format + rawBytes:(NSData *)rawBytes { + self = [super init]; + self.text = text; + self.format = format; + self.rawBytes = rawBytes; + return self; +} +@end diff --git a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h new file mode 100644 index 0000000000..19cfaa6683 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h @@ -0,0 +1,19 @@ +// +// UmbrellaHeader.h +// +// +// Created by Christian Braun on 22.02.22. +// + +#ifndef UmbrellaHeader_h +#define UmbrellaHeader_h + +#import "Reader/ZXIBarcodeReader.h" +#import "Reader/ZXIResult.h" +#import "Reader/ZXIDecodeHints.h" +#import "Writer/ZXIBarcodeWriter.h" +#import "Writer/ZXICharset.h" +#import "ZXIErrors.h" +#import "ZXIFormat.h" + +#endif diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h new file mode 100644 index 0000000000..be50354b21 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h @@ -0,0 +1,30 @@ +// +// ZXIBarcodeWriter.h +// +// +// Created by Hendrik von Prince on 25.02.22. +// + +#import +#import "ZXIFormat.h" +#import "ZXICharset.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIBarcodeWriter : NSObject + +-(nullable CGImageRef)write:(NSString *)contents + width:(int)width + height:(int)height + format:(ZXIFormat)format + error:(NSError **)error; + +-(nullable CGImageRef)write:(NSString *)contents + width:(int)width + height:(int)height + format:(ZXIFormat)format + charset:(ZXICharset)charset + error:(NSError **)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm new file mode 100644 index 0000000000..1f57f496ea --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -0,0 +1,117 @@ +// +// ZXIBarcodeWriter.m +// +// +// Created by Hendrik von Prince on 25.02.22. +// + +#import +#import "ZXIBarcodeWriter.h" +#import "ZXing/MultiFormatWriter.h" +#import "ZXing/BitMatrix.h" +#import "ZXing/BitArray.h" +#import "ZXIFormatHelper.h" +#import "ZXICharsetHelper.h" +#import "ZXIErrors.h" +#import + +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)); +} + +#ifdef DEBUG +std::string ToString(const BitMatrix& matrix, char one, char zero, bool addSpace, bool printAsCString) +{ + std::string result; + result.reserve((addSpace ? 2 : 1) * (matrix.width() * matrix.height()) + matrix.height()); + for (int y = 0; y < matrix.height(); ++y) { + BitArray row; + matrix.getRow(y, row); + if (printAsCString) + result += '"'; + for (auto bit : row) { + result += bit ? one : zero; + if (addSpace) + result += ' '; + } + if (printAsCString) + result += "\\n\""; + result += '\n'; + } + return result; +} +#endif + + + +@implementation ZXIBarcodeWriter + +-(nullable CGImageRef)write:(nonnull NSString *)contents + width:(int)width + height:(int)height + format:(ZXIFormat)format + error:(NSError **)error { + return [self write:contents width:width height:height format:format charset:Unknown error:error]; +} + +-(CGImageRef)write:(NSString *)contents + width:(int)width + height:(int)height + format:(ZXIFormat)format + charset:(ZXICharset)charset + error:(NSError *__autoreleasing _Nullable *)error { + MultiFormatWriter writer { BarcodeFormatFromZXIFormat(format) }; + writer.setEncoding(CharsetFromZXICharset(charset)); + // Catch exception for invalid formats + try { + BitMatrix result = writer.encode(NSStringToStringW(contents), width, height); + int realWidth = result.width(); + int realHeight = result.height(); + + +#ifdef DEBUG + std::cout << ToString(result, '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) { + BitArray row; + result.getRow(y, row); + for (auto bit : row) { + bytes[index] = bit ? 0 : 255; + ++index; + } + } + + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); + + CGImageRef cgimage = CGImageCreate(realWidth, + realHeight, + 8, + 8, + realWidth, + colorSpace, + kCGBitmapByteOrderDefault, + CGDataProviderCreateWithCFData((CFDataRef)resultAsNSData), + NULL, + YES, + kCGRenderingIntentDefault); + return cgimage; + } catch(std::exception &e) { + if(error != nil) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: [[NSString alloc] initWithUTF8String:e.what()] + }; + *error = [[NSError alloc] initWithDomain:ZXIErrorDomain code:ZXIWriterError userInfo:userInfo]; + } + return nil; + } +} + +@end diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h new file mode 100644 index 0000000000..4728f26c57 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h @@ -0,0 +1,49 @@ +// +// Header.h +// +// +// Created by Hendrik von Prince on 25.03.22. +// + +#ifndef Header_h +#define Header_h + +#import + +typedef NS_ENUM(NSInteger, ZXICharset) { + Unknown, + ASCII, + ISO8859_1, + ISO8859_2, + ISO8859_3, + ISO8859_4, + ISO8859_5, + ISO8859_6, + ISO8859_7, + ISO8859_8, + ISO8859_9, + ISO8859_10, + ISO8859_11, + ISO8859_13, + ISO8859_14, + ISO8859_15, + ISO8859_16, + Cp437, + Cp1250, + Cp1251, + Cp1252, + Cp1256, + + Shift_JIS, + Big5, + GB2312, + GB18030, + EUC_JP, + EUC_KR, + UnicodeBig, + UTF8, + + BINARY +}; + +#endif /* Header_h */ diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h new file mode 100644 index 0000000000..527738ca8e --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h @@ -0,0 +1,17 @@ +// +// ZXICharsetHelper.h +// +// +// Created by Hendrik von Prince on 25.03.22. +// + +#import +#import "ZXing/CharacterSet.h" +#import "ZXICharset.h" + +NS_ASSUME_NONNULL_BEGIN + +ZXICharset ZXICharsetFromCharset(ZXing::CharacterSet charset); +ZXing::CharacterSet CharsetFromZXICharset(ZXICharset charset); + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm new file mode 100644 index 0000000000..c904af2f1a --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm @@ -0,0 +1,148 @@ +// +// ZXICharsetHelper.m +// +// +// Created by Hendrik von Prince on 25.03.22. +// + +#import "ZXICharsetHelper.h" + +ZXICharset ZXICharsetFromCharset(ZXing::CharacterSet charset) { + switch(charset) { + case ZXing::CharacterSet::Unknown: + return Unknown; + case ZXing::CharacterSet::ASCII: + return ASCII; + case ZXing::CharacterSet::ISO8859_1: + return ISO8859_1; + case ZXing::CharacterSet::ISO8859_2: + return ISO8859_2; + case ZXing::CharacterSet::ISO8859_3: + return ISO8859_3; + case ZXing::CharacterSet::ISO8859_4: + return ISO8859_4; + case ZXing::CharacterSet::ISO8859_5: + return ISO8859_5; + case ZXing::CharacterSet::ISO8859_6: + return ISO8859_6; + case ZXing::CharacterSet::ISO8859_7: + return ISO8859_7; + case ZXing::CharacterSet::ISO8859_8: + return ISO8859_8; + case ZXing::CharacterSet::ISO8859_9: + return ISO8859_9; + case ZXing::CharacterSet::ISO8859_10: + return ISO8859_10; + case ZXing::CharacterSet::ISO8859_11: + return ISO8859_11; + case ZXing::CharacterSet::ISO8859_13: + return ISO8859_13; + case ZXing::CharacterSet::ISO8859_14: + return ISO8859_14; + case ZXing::CharacterSet::ISO8859_15: + return ISO8859_15; + case ZXing::CharacterSet::ISO8859_16: + return ISO8859_16; + case ZXing::CharacterSet::Cp437: + return Cp437; + case ZXing::CharacterSet::Cp1250: + return Cp1250; + case ZXing::CharacterSet::Cp1251: + return Cp1251; + case ZXing::CharacterSet::Cp1252: + return Cp1252; + case ZXing::CharacterSet::Cp1256: + return Cp1256; + case ZXing::CharacterSet::Shift_JIS: + return Shift_JIS; + case ZXing::CharacterSet::Big5: + return Big5; + case ZXing::CharacterSet::GB2312: + return GB2312; + case ZXing::CharacterSet::GB18030: + return GB18030; + case ZXing::CharacterSet::EUC_JP: + return EUC_JP; + case ZXing::CharacterSet::EUC_KR: + return EUC_KR; + case ZXing::CharacterSet::UnicodeBig: + return UnicodeBig; + case ZXing::CharacterSet::UTF8: + return UTF8; + case ZXing::CharacterSet::BINARY: + return BINARY; + case ZXing::CharacterSet::CharsetCount: + return Unknown; + } + NSLog(@"ZXIWrapper: Received invalid CharacterSet, returning Unknown"); + return Unknown; +} + +ZXing::CharacterSet CharsetFromZXICharset(ZXICharset charset) { + switch(charset) { + case Unknown: + return ZXing::CharacterSet::Unknown; + case ASCII: + return ZXing::CharacterSet::ASCII; + case ISO8859_1: + return ZXing::CharacterSet::ISO8859_1; + case ISO8859_2: + return ZXing::CharacterSet::ISO8859_2; + case ISO8859_3: + return ZXing::CharacterSet::ISO8859_3; + case ISO8859_4: + return ZXing::CharacterSet::ISO8859_4; + case ISO8859_5: + return ZXing::CharacterSet::ISO8859_5; + case ISO8859_6: + return ZXing::CharacterSet::ISO8859_6; + case ISO8859_7: + return ZXing::CharacterSet::ISO8859_7; + case ISO8859_8: + return ZXing::CharacterSet::ISO8859_8; + case ISO8859_9: + return ZXing::CharacterSet::ISO8859_9; + case ISO8859_10: + return ZXing::CharacterSet::ISO8859_10; + case ISO8859_11: + return ZXing::CharacterSet::ISO8859_11; + case ISO8859_13: + return ZXing::CharacterSet::ISO8859_13; + case ISO8859_14: + return ZXing::CharacterSet::ISO8859_14; + case ISO8859_15: + return ZXing::CharacterSet::ISO8859_15; + case ISO8859_16: + return ZXing::CharacterSet::ISO8859_16; + case Cp437: + return ZXing::CharacterSet::Cp437; + case Cp1250: + return ZXing::CharacterSet::Cp1250; + case Cp1251: + return ZXing::CharacterSet::Cp1251; + case Cp1252: + return ZXing::CharacterSet::Cp1252; + case Cp1256: + return ZXing::CharacterSet::Cp1256; + case Shift_JIS: + return ZXing::CharacterSet::Shift_JIS; + case Big5: + return ZXing::CharacterSet::Big5; + case GB2312: + return ZXing::CharacterSet::GB2312; + case GB18030: + return ZXing::CharacterSet::GB18030; + case EUC_JP: + return ZXing::CharacterSet::EUC_JP; + case EUC_KR: + return ZXing::CharacterSet::EUC_KR; + case UnicodeBig: + return ZXing::CharacterSet::UnicodeBig; + case UTF8: + return ZXing::CharacterSet::UTF8; + case BINARY: + return ZXing::CharacterSet::BINARY; + } + NSLog(@"ZXIWrapper: Received invalid ZXIFormat, returning Unknown"); + return ZXing::CharacterSet::Unknown; +} diff --git a/wrappers/ios/Sources/Wrapper/ZXIErrors.h b/wrappers/ios/Sources/Wrapper/ZXIErrors.h new file mode 100644 index 0000000000..1480ff8dce --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/ZXIErrors.h @@ -0,0 +1,21 @@ +// +// ZXIErrors.h +// +// +// Created by Christian Braun on 25.02.22. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +#define ZXIErrorDomain @"ZXIErrorDomain" + +typedef NS_ENUM(NSInteger, ZXIReaderError) { + ZXINotFoundError = 1000, + ZXIChecksumError, + ZXIFormatError, + ZXIWriterError, +}; + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormat.h b/wrappers/ios/Sources/Wrapper/ZXIFormat.h new file mode 100644 index 0000000000..749a926568 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/ZXIFormat.h @@ -0,0 +1,18 @@ +// +// Header.h +// +// +// Created by Christian Braun on 25.03.22. +// + +#import +#ifndef ZXIFormat_h +#define ZXIFormat_h + +typedef NS_ENUM(NSInteger, ZXIFormat) { + NONE, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_BAR, DATA_BAR_EXPANDED, + DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, UPC_A, UPC_E, + ONE_D_CODES, TWO_D_CODES, MICRO_QR_CODE, ANY +}; + +#endif diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h new file mode 100644 index 0000000000..5b1c30c742 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h @@ -0,0 +1,16 @@ +// +// ZXIFormatHelper.h +// +// +// Created by Christian Braun on 25.03.22. +// + +#import +#import "ZXing/BarcodeFormat.h" +#import "ZXIFormat.h" + +NS_ASSUME_NONNULL_BEGIN + +ZXing::BarcodeFormat BarcodeFormatFromZXIFormat(ZXIFormat format); +ZXIFormat ZXIFormatFromBarcodeFormat(ZXing::BarcodeFormat format); +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm new file mode 100644 index 0000000000..c36f3ef6ed --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm @@ -0,0 +1,106 @@ +// +// ZXIFormatHelper.m +// +// +// Created by Christian Braun on 25.03.22. +// + +#import "ZXIFormatHelper.h" + +ZXing::BarcodeFormat BarcodeFormatFromZXIFormat(ZXIFormat format) { + switch (format) { + case ZXIFormat::ANY: + return ZXing::BarcodeFormat::Any; + case ZXIFormat::TWO_D_CODES: + return ZXing::BarcodeFormat::TwoDCodes; + case ZXIFormat::ONE_D_CODES: + return ZXing::BarcodeFormat::OneDCodes; + case ZXIFormat::UPC_E: + return ZXing::BarcodeFormat::UPCE; + case ZXIFormat::UPC_A: + return ZXing::BarcodeFormat::UPCA; + case ZXIFormat::QR_CODE: + return ZXing::BarcodeFormat::QRCode; + case ZXIFormat::PDF_417: + return ZXing::BarcodeFormat::PDF417; + case ZXIFormat::MAXICODE: + return ZXing::BarcodeFormat::MaxiCode; + case ZXIFormat::ITF: + return ZXing::BarcodeFormat::ITF; + case ZXIFormat::EAN_13: + return ZXing::BarcodeFormat::EAN13; + case ZXIFormat::EAN_8: + return ZXing::BarcodeFormat::EAN8; + case ZXIFormat::DATA_MATRIX: + return ZXing::BarcodeFormat::DataMatrix; + case ZXIFormat::DATA_BAR_EXPANDED: + return ZXing::BarcodeFormat::DataBarExpanded; + case ZXIFormat::DATA_BAR: + return ZXing::BarcodeFormat::DataBar; + case ZXIFormat::CODE_128: + return ZXing::BarcodeFormat::Code128; + case ZXIFormat::CODE_93: + return ZXing::BarcodeFormat::Code93; + case ZXIFormat::CODE_39: + return ZXing::BarcodeFormat::Code39; + case ZXIFormat::CODABAR: + return ZXing::BarcodeFormat::Codabar; + case ZXIFormat::AZTEC: + return ZXing::BarcodeFormat::Aztec; + case ZXIFormat::MICRO_QR_CODE: + return ZXing::BarcodeFormat::MicroQRCode; + case ZXIFormat::NONE: + return ZXing::BarcodeFormat::None; + } + NSLog(@"ZXIWrapper: Received invalid ZXIFormat, returning format: None"); + return ZXing::BarcodeFormat::None; +} + +ZXIFormat ZXIFormatFromBarcodeFormat(ZXing::BarcodeFormat format) { + switch (format) { + case ZXing::BarcodeFormat::None: + return ZXIFormat::NONE; + case ZXing::BarcodeFormat::Aztec: + return ZXIFormat::AZTEC; + case ZXing::BarcodeFormat::Codabar: + return ZXIFormat::CODABAR; + case ZXing::BarcodeFormat::Code39: + return ZXIFormat::CODE_39; + case ZXing::BarcodeFormat::Code93: + return ZXIFormat::CODE_93; + case ZXing::BarcodeFormat::Code128: + return ZXIFormat::CODE_128; + case ZXing::BarcodeFormat::DataBar: + return ZXIFormat::DATA_BAR; + case ZXing::BarcodeFormat::DataBarExpanded: + return ZXIFormat::DATA_BAR_EXPANDED; + case ZXing::BarcodeFormat::DataMatrix: + return ZXIFormat::DATA_MATRIX; + case ZXing::BarcodeFormat::EAN8: + return ZXIFormat::EAN_8; + case ZXing::BarcodeFormat::EAN13: + return ZXIFormat::EAN_13; + case ZXing::BarcodeFormat::ITF: + return ZXIFormat::ITF; + case ZXing::BarcodeFormat::MaxiCode: + return ZXIFormat::MAXICODE; + case ZXing::BarcodeFormat::PDF417: + return ZXIFormat::PDF_417; + case ZXing::BarcodeFormat::QRCode: + return ZXIFormat::QR_CODE; + case ZXing::BarcodeFormat::UPCA: + return ZXIFormat::UPC_A; + case ZXing::BarcodeFormat::UPCE: + return ZXIFormat::UPC_E; + case ZXing::BarcodeFormat::OneDCodes: + return ZXIFormat::ONE_D_CODES; + case ZXing::BarcodeFormat::TwoDCodes: + return ZXIFormat::TWO_D_CODES; + case ZXing::BarcodeFormat::MicroQRCode: + return ZXIFormat::MICRO_QR_CODE; + case ZXing::BarcodeFormat::Any: + return ZXIFormat::ANY; + } + NSLog(@"ZXIWrapper: Received invalid BarcodeFormat, returning format: None"); + return ZXIFormat::NONE; +} diff --git a/wrappers/ios/Sources/Wrapper/module.modulemap b/wrappers/ios/Sources/Wrapper/module.modulemap new file mode 100644 index 0000000000..5812eac363 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/module.modulemap @@ -0,0 +1,6 @@ +module ZXingWrapper { + umbrella header "UmbrellaHeader.h" + export * + module * { export * } +} + diff --git a/wrappers/ios/build-release.sh b/wrappers/ios/build-release.sh new file mode 100755 index 0000000000..63e02980c8 --- /dev/null +++ b/wrappers/ios/build-release.sh @@ -0,0 +1,36 @@ +echo ========= Remove previous builds +rm -rf _builds +rm -rf ZXing.xcframework + +echo ========= Create project structure +cmake -S../../ -B_builds -GXcode \ + -DCMAKE_SYSTEM_NAME=iOS \ + "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \ + -DCMAKE_INSTALL_PREFIX=`pwd`/_install \ + -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \ + -DBUILD_UNIT_TESTS=NO \ + -DBUILD_BLACKBOX_TESTS=NO \ + -DBUILD_EXAMPLES=NO + +echo ========= Build the sdk for simulators +xcodebuild -project _builds/ZXing.xcodeproj build \ + -target ZXing \ + -parallelizeTargets \ + -configuration Release \ + -hideShellScriptEnvironment \ + -sdk iphonesimulator + +echo ========= Build the sdk for iOS +xcodebuild -project _builds/ZXing.xcodeproj build \ + -target ZXing \ + -parallelizeTargets \ + -configuration Release \ + -hideShellScriptEnvironment \ + -sdk iphoneos + +echo ========= Create the xcframework +xcodebuild -create-xcframework \ + -framework ./_builds/core/Release-iphonesimulator/ZXing.framework \ + -framework ./_builds/core/Release-iphoneos/ZXing.framework \ + -output ZXing.xcframework From 9c7659d7bb729cfb661f41f57b51d4619266e900 Mon Sep 17 00:00:00 2001 From: Hendrik von Prince Date: Tue, 24 May 2022 11:47:30 +0200 Subject: [PATCH 02/88] Add a demo project --- wrappers/ios/Package.swift | 31 ++ wrappers/ios/demo/README.md | 5 + .../ios/demo/demo.xcodeproj/project.pbxproj | 399 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/demo.xcscheme | 90 ++++ wrappers/ios/demo/demo/AppDelegate.swift | 36 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 93 ++++ .../demo/demo/Assets.xcassets/Contents.json | 6 + .../demo/Base.lproj/LaunchScreen.storyboard | 25 ++ .../ios/demo/demo/Base.lproj/Main.storyboard | 24 ++ wrappers/ios/demo/demo/Info.plist | 25 ++ wrappers/ios/demo/demo/SceneDelegate.swift | 52 +++ wrappers/ios/demo/demo/ViewController.swift | 72 ++++ 15 files changed, 884 insertions(+) create mode 100644 wrappers/ios/Package.swift create mode 100644 wrappers/ios/demo/README.md create mode 100644 wrappers/ios/demo/demo.xcodeproj/project.pbxproj create mode 100644 wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 wrappers/ios/demo/demo.xcodeproj/xcshareddata/xcschemes/demo.xcscheme create mode 100644 wrappers/ios/demo/demo/AppDelegate.swift create mode 100644 wrappers/ios/demo/demo/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 wrappers/ios/demo/demo/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 wrappers/ios/demo/demo/Assets.xcassets/Contents.json create mode 100644 wrappers/ios/demo/demo/Base.lproj/LaunchScreen.storyboard create mode 100644 wrappers/ios/demo/demo/Base.lproj/Main.storyboard create mode 100644 wrappers/ios/demo/demo/Info.plist create mode 100644 wrappers/ios/demo/demo/SceneDelegate.swift create mode 100644 wrappers/ios/demo/demo/ViewController.swift diff --git a/wrappers/ios/Package.swift b/wrappers/ios/Package.swift new file mode 100644 index 0000000000..58c94ce0e1 --- /dev/null +++ b/wrappers/ios/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "ZXingWrapper", + platforms: [ + .iOS(.v13) + ], + products: [ + .library( + name: "ZXingWrapper", + type: .static, + targets: ["ZXingWrapper"]) + ], + targets: [ + .binaryTarget( + name: "ZXing", + path: "ZXing.xcframework" + ), + .target( + name: "ZXingWrapper", + dependencies: ["ZXing"], + path: "Sources/Wrapper", + publicHeadersPath: ".", + cxxSettings: [ + .unsafeFlags(["-stdlib=libc++"]), + .unsafeFlags(["-std=gnu++17"]) + ] + ) + ] +) diff --git a/wrappers/ios/demo/README.md b/wrappers/ios/demo/README.md new file mode 100644 index 0000000000..6d8a8ed41e --- /dev/null +++ b/wrappers/ios/demo/README.md @@ -0,0 +1,5 @@ +# ZXingWrapper Demo Project + +This demo-project sets up a basic `AVCaptureSession` and uses ZXing on the incoming frames. +You have to build the `ZXing.xcframework` before, by performing the `build-release.sh` script +in the parent-directory. diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..7abe431326 --- /dev/null +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -0,0 +1,399 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 388BF029283CC49D005CE271 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388BF028283CC49D005CE271 /* AppDelegate.swift */; }; + 388BF02B283CC49D005CE271 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388BF02A283CC49D005CE271 /* SceneDelegate.swift */; }; + 388BF02D283CC49D005CE271 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388BF02C283CC49D005CE271 /* ViewController.swift */; }; + 388BF030283CC49D005CE271 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 388BF02E283CC49D005CE271 /* Main.storyboard */; }; + 388BF032283CC49E005CE271 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388BF031283CC49E005CE271 /* Assets.xcassets */; }; + 388BF035283CC49E005CE271 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */; }; + 388BF042283CD908005CE271 /* ZXingWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 388BF041283CD908005CE271 /* ZXingWrapper */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 388BF025283CC49D005CE271 /* demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 388BF028283CC49D005CE271 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 388BF02A283CC49D005CE271 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 388BF02C283CC49D005CE271 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 388BF02F283CC49D005CE271 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 388BF031283CC49E005CE271 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 388BF034283CC49E005CE271 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 388BF036283CC49E005CE271 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 388BF03F283CD6C5005CE271 /* ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ios; path = ..; sourceTree = ""; }; + 388BF043283CE0AC005CE271 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 388BF022283CC49D005CE271 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 388BF042283CD908005CE271 /* ZXingWrapper in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 388BF01C283CC49D005CE271 = { + isa = PBXGroup; + children = ( + 388BF043283CE0AC005CE271 /* README.md */, + 388BF03E283CD6C5005CE271 /* Packages */, + 388BF027283CC49D005CE271 /* demo */, + 388BF026283CC49D005CE271 /* Products */, + 388BF040283CD908005CE271 /* Frameworks */, + ); + sourceTree = ""; + }; + 388BF026283CC49D005CE271 /* Products */ = { + isa = PBXGroup; + children = ( + 388BF025283CC49D005CE271 /* demo.app */, + ); + name = Products; + sourceTree = ""; + }; + 388BF027283CC49D005CE271 /* demo */ = { + isa = PBXGroup; + children = ( + 388BF028283CC49D005CE271 /* AppDelegate.swift */, + 388BF02A283CC49D005CE271 /* SceneDelegate.swift */, + 388BF02C283CC49D005CE271 /* ViewController.swift */, + 388BF02E283CC49D005CE271 /* Main.storyboard */, + 388BF031283CC49E005CE271 /* Assets.xcassets */, + 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */, + 388BF036283CC49E005CE271 /* Info.plist */, + ); + path = demo; + sourceTree = ""; + }; + 388BF03E283CD6C5005CE271 /* Packages */ = { + isa = PBXGroup; + children = ( + 388BF03F283CD6C5005CE271 /* ios */, + ); + name = Packages; + sourceTree = ""; + }; + 388BF040283CD908005CE271 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 388BF024283CC49D005CE271 /* demo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 388BF039283CC49E005CE271 /* Build configuration list for PBXNativeTarget "demo" */; + buildPhases = ( + 388BF021283CC49D005CE271 /* Sources */, + 388BF022283CC49D005CE271 /* Frameworks */, + 388BF023283CC49D005CE271 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = demo; + packageProductDependencies = ( + 388BF041283CD908005CE271 /* ZXingWrapper */, + ); + productName = demo; + productReference = 388BF025283CC49D005CE271 /* demo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 388BF01D283CC49D005CE271 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1340; + LastUpgradeCheck = 1340; + TargetAttributes = { + 388BF024283CC49D005CE271 = { + CreatedOnToolsVersion = 13.4; + }; + }; + }; + buildConfigurationList = 388BF020283CC49D005CE271 /* Build configuration list for PBXProject "demo" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 388BF01C283CC49D005CE271; + productRefGroup = 388BF026283CC49D005CE271 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 388BF024283CC49D005CE271 /* demo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 388BF023283CC49D005CE271 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 388BF035283CC49E005CE271 /* LaunchScreen.storyboard in Resources */, + 388BF032283CC49E005CE271 /* Assets.xcassets in Resources */, + 388BF030283CC49D005CE271 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 388BF021283CC49D005CE271 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 388BF02D283CC49D005CE271 /* ViewController.swift in Sources */, + 388BF029283CC49D005CE271 /* AppDelegate.swift in Sources */, + 388BF02B283CC49D005CE271 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 388BF02E283CC49D005CE271 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 388BF02F283CC49D005CE271 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 388BF034283CC49E005CE271 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 388BF037283CC49E005CE271 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 388BF038283CC49E005CE271 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 388BF03A283CC49E005CE271 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 25MXZ8DDDM; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = demo/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.zxing-cpp.ios.demo-${SAMPLE_CODE_DISAMBIGUATOR}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 388BF03B283CC49E005CE271 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 25MXZ8DDDM; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = demo/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.zxing-cpp.ios.demo-${SAMPLE_CODE_DISAMBIGUATOR}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 388BF020283CC49D005CE271 /* Build configuration list for PBXProject "demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 388BF037283CC49E005CE271 /* Debug */, + 388BF038283CC49E005CE271 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 388BF039283CC49E005CE271 /* Build configuration list for PBXNativeTarget "demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 388BF03A283CC49E005CE271 /* Debug */, + 388BF03B283CC49E005CE271 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCSwiftPackageProductDependency section */ + 388BF041283CD908005CE271 /* ZXingWrapper */ = { + isa = XCSwiftPackageProductDependency; + productName = ZXingWrapper; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 388BF01D283CC49D005CE271 /* Project object */; +} diff --git a/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/wrappers/ios/demo/demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/wrappers/ios/demo/demo.xcodeproj/xcshareddata/xcschemes/demo.xcscheme b/wrappers/ios/demo/demo.xcodeproj/xcshareddata/xcschemes/demo.xcscheme new file mode 100644 index 0000000000..45b72fe64f --- /dev/null +++ b/wrappers/ios/demo/demo.xcodeproj/xcshareddata/xcschemes/demo.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wrappers/ios/demo/demo/AppDelegate.swift b/wrappers/ios/demo/demo/AppDelegate.swift new file mode 100644 index 0000000000..3d0259a695 --- /dev/null +++ b/wrappers/ios/demo/demo/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// demo +// +// Created by Hendrik von Prince on 24.05.22. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/wrappers/ios/demo/demo/Assets.xcassets/AccentColor.colorset/Contents.json b/wrappers/ios/demo/demo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..eb87897008 --- /dev/null +++ b/wrappers/ios/demo/demo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wrappers/ios/demo/demo/Assets.xcassets/AppIcon.appiconset/Contents.json b/wrappers/ios/demo/demo/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..5a3257a7d0 --- /dev/null +++ b/wrappers/ios/demo/demo/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wrappers/ios/demo/demo/Assets.xcassets/Contents.json b/wrappers/ios/demo/demo/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/wrappers/ios/demo/demo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wrappers/ios/demo/demo/Base.lproj/LaunchScreen.storyboard b/wrappers/ios/demo/demo/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..865e9329f3 --- /dev/null +++ b/wrappers/ios/demo/demo/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wrappers/ios/demo/demo/Base.lproj/Main.storyboard b/wrappers/ios/demo/demo/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..25a763858e --- /dev/null +++ b/wrappers/ios/demo/demo/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wrappers/ios/demo/demo/Info.plist b/wrappers/ios/demo/demo/Info.plist new file mode 100644 index 0000000000..dd3c9afdae --- /dev/null +++ b/wrappers/ios/demo/demo/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/wrappers/ios/demo/demo/SceneDelegate.swift b/wrappers/ios/demo/demo/SceneDelegate.swift new file mode 100644 index 0000000000..93544179d5 --- /dev/null +++ b/wrappers/ios/demo/demo/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// demo +// +// Created by Hendrik von Prince on 24.05.22. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift new file mode 100644 index 0000000000..19bb1e8c8f --- /dev/null +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -0,0 +1,72 @@ +// +// ViewController.swift +// demo +// +// Created by Hendrik von Prince on 24.05.22. +// + +import UIKit +import AVFoundation +import ZXingWrapper + +class ViewController: UIViewController { + let captureSession = AVCaptureSession() + lazy var preview = AVCaptureVideoPreviewLayer(session: captureSession) + let queue = DispatchQueue(label: "com.zxing_cpp.ios.demo") + let reader = ZXIBarcodeReader() + let zxingLock = DispatchSemaphore(value: 1) + + override func viewDidLoad() { + super.viewDidLoad() + + self.preview.videoGravity = AVLayerVideoGravity.resizeAspectFill + self.preview.frame = self.view.layer.bounds + self.view.layer.addSublayer(self.preview) + + // setup camera session + self.requestAccess { + let discoverySession = AVCaptureDevice.DiscoverySession( + deviceTypes: [.builtInWideAngleCamera], + mediaType: AVMediaType.video, + position: .back) + + let device = discoverySession.devices.first! + let cameraInput = try! AVCaptureDeviceInput(device: device) + self.captureSession.beginConfiguration() + self.captureSession.addInput(cameraInput) + let videoDataOutput = AVCaptureVideoDataOutput() + videoDataOutput.setSampleBufferDelegate(self, queue: self.queue) + videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)] + videoDataOutput.alwaysDiscardsLateVideoFrames = true + self.captureSession.addOutput(videoDataOutput) + self.captureSession.commitConfiguration() + self.captureSession.startRunning() + } + } +} + +extension ViewController { + func requestAccess(_ completion: @escaping () -> Void) { + if AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == .notDetermined { + AVCaptureDevice.requestAccess(for: .video) { _ in + completion() + } + } else { + completion() + } + } +} + +extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { + func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { + guard self.zxingLock.wait(timeout: DispatchTime.now()) == .success else { + // The previous image is still processed, drop the new one to prevent too much pressure + return + } + let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! + if let result = try? reader.read(CIImage(cvPixelBuffer: imageBuffer)) { + print("Found barcode of format", result.format.rawValue, "with text", result.text) + } + self.zxingLock.signal() + } +} From cc699a8d9e8f2d7985fe7bfb9c79737e3c2b1079 Mon Sep 17 00:00:00 2001 From: Hendrik von Prince Date: Thu, 2 Jun 2022 09:48:53 +0200 Subject: [PATCH 03/88] Add SPDX-License-Identifier: Apache-2. to sources --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h | 1 + wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 1 + wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h | 1 + wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm | 1 + wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h | 1 + wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm | 1 + wrappers/ios/Sources/Wrapper/UmbrellaHeader.h | 1 + wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h | 1 + wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 1 + wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h | 1 + wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h | 1 + wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm | 1 + wrappers/ios/Sources/Wrapper/ZXIErrors.h | 1 + wrappers/ios/Sources/Wrapper/ZXIFormat.h | 1 + wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h | 1 + wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm | 1 + 16 files changed, 16 insertions(+) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h index 8419e3015e..011f85c20e 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 22.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 19537bbd55..70d05259b0 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -4,6 +4,7 @@ // // Created by Christian Braun on 22.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import "ZXIBarcodeReader.h" #import "ZXIErrors.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h index ce21914fb8..04a7c89b54 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm index 7972cbfbb3..c8511a269d 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import "ZXIDecodeHints.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h index b3910be231..1289e982ec 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXIFormat.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm index efaa4e3ba1..fb38bb41ba 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import "ZXIResult.h" diff --git a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h index 19cfaa6683..35a60be758 100644 --- a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h +++ b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 22.02.22. // +// SPDX-License-Identifier: Apache-2.0 #ifndef UmbrellaHeader_h #define UmbrellaHeader_h diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h index be50354b21..7f3bf3f27a 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h @@ -4,6 +4,7 @@ // // Created by Hendrik von Prince on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXIFormat.h" diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 1f57f496ea..9f789af5f5 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -4,6 +4,7 @@ // // Created by Hendrik von Prince on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXIBarcodeWriter.h" diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h index 4728f26c57..ff4618a527 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h @@ -4,6 +4,7 @@ // // Created by Hendrik von Prince on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #ifndef Header_h #define Header_h diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h index 527738ca8e..c5f9760a7c 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h @@ -4,6 +4,7 @@ // // Created by Hendrik von Prince on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXing/CharacterSet.h" diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm index c904af2f1a..a25efef4a1 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm @@ -4,6 +4,7 @@ // // Created by Hendrik von Prince on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #import "ZXICharsetHelper.h" diff --git a/wrappers/ios/Sources/Wrapper/ZXIErrors.h b/wrappers/ios/Sources/Wrapper/ZXIErrors.h index 1480ff8dce..b7b1bac47d 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIErrors.h +++ b/wrappers/ios/Sources/Wrapper/ZXIErrors.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.02.22. // +// SPDX-License-Identifier: Apache-2.0 #import diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormat.h b/wrappers/ios/Sources/Wrapper/ZXIFormat.h index 749a926568..dced8d27c6 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormat.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormat.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #import #ifndef ZXIFormat_h diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h index 5b1c30c742..687ceeeb91 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXing/BarcodeFormat.h" diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm index c36f3ef6ed..06c7276573 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm @@ -4,6 +4,7 @@ // // Created by Christian Braun on 25.03.22. // +// SPDX-License-Identifier: Apache-2.0 #import "ZXIFormatHelper.h" From b79fb7a24b1e2ebd98dee33e7a677dfa2b30b624 Mon Sep 17 00:00:00 2001 From: Hendrik von Prince Date: Thu, 2 Jun 2022 10:06:05 +0200 Subject: [PATCH 04/88] Update copyright comments --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h | 6 +----- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 6 +----- wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h | 6 +----- wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm | 6 +----- wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h | 6 +----- wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm | 6 +----- wrappers/ios/Sources/Wrapper/UmbrellaHeader.h | 6 +----- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h | 6 +----- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 6 +----- wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h | 6 +----- wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h | 6 +----- wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm | 6 +----- wrappers/ios/Sources/Wrapper/ZXIErrors.h | 6 +----- wrappers/ios/Sources/Wrapper/ZXIFormat.h | 6 +----- wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h | 6 +----- wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm | 6 +----- wrappers/ios/demo/demo/AppDelegate.swift | 4 +--- wrappers/ios/demo/demo/SceneDelegate.swift | 4 +--- wrappers/ios/demo/demo/ViewController.swift | 4 +--- 19 files changed, 19 insertions(+), 89 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h index 011f85c20e..b8e6d7295a 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h @@ -1,8 +1,4 @@ -// -// BarcodeReader.h -// -// -// Created by Christian Braun on 22.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 70d05259b0..be1a759949 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -1,8 +1,4 @@ -// -// BarcodeReader.m -// -// -// Created by Christian Braun on 22.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h index 04a7c89b54..1530178a9c 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h @@ -1,8 +1,4 @@ -// -// ZXIDecodeHints.h -// -// -// Created by Christian Braun on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm index c8511a269d..06c8b2daf4 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm @@ -1,8 +1,4 @@ -// -// ZXIDecodeHints.m -// -// -// Created by Christian Braun on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h index 1289e982ec..b21c352806 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h @@ -1,8 +1,4 @@ -// -// ZXIResult.h -// -// -// Created by Christian Braun on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm index fb38bb41ba..495a036f99 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm @@ -1,8 +1,4 @@ -// -// ZXIResult.m -// -// -// Created by Christian Braun on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h index 35a60be758..3a0ad9b132 100644 --- a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h +++ b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h @@ -1,8 +1,4 @@ -// -// UmbrellaHeader.h -// -// -// Created by Christian Braun on 22.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h index 7f3bf3f27a..be730365ef 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h @@ -1,8 +1,4 @@ -// -// ZXIBarcodeWriter.h -// -// -// Created by Hendrik von Prince on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 9f789af5f5..13b02e85a6 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -1,8 +1,4 @@ -// -// ZXIBarcodeWriter.m -// -// -// Created by Hendrik von Prince on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h index ff4618a527..d3005ede67 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h @@ -1,8 +1,4 @@ -// -// Header.h -// -// -// Created by Hendrik von Prince on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h index c5f9760a7c..517b4a1d82 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h @@ -1,8 +1,4 @@ -// -// ZXICharsetHelper.h -// -// -// Created by Hendrik von Prince on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm index a25efef4a1..e7dedc0b0b 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm @@ -1,8 +1,4 @@ -// -// ZXICharsetHelper.m -// -// -// Created by Hendrik von Prince on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/ZXIErrors.h b/wrappers/ios/Sources/Wrapper/ZXIErrors.h index b7b1bac47d..f24757999a 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIErrors.h +++ b/wrappers/ios/Sources/Wrapper/ZXIErrors.h @@ -1,8 +1,4 @@ -// -// ZXIErrors.h -// -// -// Created by Christian Braun on 25.02.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormat.h b/wrappers/ios/Sources/Wrapper/ZXIFormat.h index dced8d27c6..108abe2cf9 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormat.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormat.h @@ -1,8 +1,4 @@ -// -// Header.h -// -// -// Created by Christian Braun on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h index 687ceeeb91..29f90a03bf 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.h @@ -1,8 +1,4 @@ -// -// ZXIFormatHelper.h -// -// -// Created by Christian Braun on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm index 06c7276573..744f676a6f 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm @@ -1,8 +1,4 @@ -// -// ZXIFormatHelper.m -// -// -// Created by Christian Braun on 25.03.22. +// Copyright 2022 KURZ Digital Solutions GmbH // // SPDX-License-Identifier: Apache-2.0 diff --git a/wrappers/ios/demo/demo/AppDelegate.swift b/wrappers/ios/demo/demo/AppDelegate.swift index 3d0259a695..0625413105 100644 --- a/wrappers/ios/demo/demo/AppDelegate.swift +++ b/wrappers/ios/demo/demo/AppDelegate.swift @@ -1,8 +1,6 @@ -// -// AppDelegate.swift // demo // -// Created by Hendrik von Prince on 24.05.22. +// Copyright 2022 KURZ Digital Solutions GmbH // import UIKit diff --git a/wrappers/ios/demo/demo/SceneDelegate.swift b/wrappers/ios/demo/demo/SceneDelegate.swift index 93544179d5..d61cae806c 100644 --- a/wrappers/ios/demo/demo/SceneDelegate.swift +++ b/wrappers/ios/demo/demo/SceneDelegate.swift @@ -1,8 +1,6 @@ -// -// SceneDelegate.swift // demo // -// Created by Hendrik von Prince on 24.05.22. +// Copyright 2022 KURZ Digital Solutions GmbH // import UIKit diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index 19bb1e8c8f..d63ff2c635 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -1,8 +1,6 @@ -// -// ViewController.swift // demo // -// Created by Hendrik von Prince on 24.05.22. +// Copyright 2022 KURZ Digital Solutions GmbH // import UIKit From 707487185c1fc3d15ba18e6427d9b4daa533f57c Mon Sep 17 00:00:00 2001 From: axxel Date: Thu, 2 Jun 2022 01:57:16 +0200 Subject: [PATCH 05/88] ci: exclude test/samples from "Source code" release assets disable blackbox tests by default and tune ZXingReaderTest to not fail when samples folder is missing. This fixes #312. --- .gitattributes | 1 + .github/workflows/ci.yml | 2 +- CMakeLists.txt | 2 +- example/CMakeLists.txt | 15 +++++++-------- 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..482add0e9b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +test/samples export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79becdffc6..6858fb4f2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system shell: bash - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_UNIT_TESTS=ON -DBUILD_PYTHON_MODULE=ON + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_BLACKBOX_TESTS=ON -DBUILD_UNIT_TESTS=ON -DBUILD_PYTHON_MODULE=ON - name: Build working-directory: ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index b9052cac91..2e215cf44e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project (ZXing VERSION "1.3.0" LANGUAGES CXX) option (BUILD_WRITERS "Build with writer support (encoders)" ON) option (BUILD_READERS "Build with reader support (decoders)" ON) option (BUILD_EXAMPLES "Build the example barcode reader/writer applications" ON) -option (BUILD_BLACKBOX_TESTS "Build the black box reader/writer tests" ON) +option (BUILD_BLACKBOX_TESTS "Build the black box reader/writer tests" OFF) option (BUILD_UNIT_TESTS "Build the unit tests (don't enable for production builds)" OFF) option (BUILD_PYTHON_MODULE "Build the python module" OFF) set(BUILD_DEPENDENCIES "AUTO" CACHE STRING "Fetch from github or use locally installed (AUTO/GITHUB/LOCAL)") diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index ec593db9ae..471050dda5 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -3,14 +3,6 @@ set (CMAKE_CXX_STANDARD 11) zxing_add_package_stb() -if (BUILD_READERS) - add_executable (ZXingReader ZXingReader.cpp) - - target_link_libraries (ZXingReader ZXing::ZXing stb::stb) - - add_test(NAME ZXingReaderTest COMMAND ZXingReader -fast -format qrcode "${CMAKE_SOURCE_DIR}/test/samples/qrcode-1/1.png") -endif() - if (BUILD_WRITERS) add_executable (ZXingWriter ZXingWriter.cpp) @@ -19,6 +11,13 @@ if (BUILD_WRITERS) add_test(NAME ZXingWriterTest COMMAND ZXingWriter qrcode "I have the best words." test.png) endif() +if (BUILD_READERS) + add_executable (ZXingReader ZXingReader.cpp) + + target_link_libraries (ZXingReader ZXing::ZXing stb::stb) + + add_test(NAME ZXingReaderTest COMMAND ZXingReader -fast -format qrcode test.png) # see above +endif() if (BUILD_READERS) find_package(Qt5 COMPONENTS Gui Multimedia Quick) From 71adf1d7b5ab52dfbbccac9d96376a5e1fc5843a Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 10:16:32 +0200 Subject: [PATCH 06/88] example: install the ZXingReader and ZXingWriter Fixes #339. --- example/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 471050dda5..8cb2e1b4d8 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -3,12 +3,16 @@ set (CMAKE_CXX_STANDARD 11) zxing_add_package_stb() +include (GNUInstallDirs) + if (BUILD_WRITERS) add_executable (ZXingWriter ZXingWriter.cpp) target_link_libraries (ZXingWriter ZXing::ZXing stb::stb) add_test(NAME ZXingWriterTest COMMAND ZXingWriter qrcode "I have the best words." test.png) + + install(TARGETS ZXingWriter DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if (BUILD_READERS) @@ -17,6 +21,8 @@ if (BUILD_READERS) target_link_libraries (ZXingReader ZXing::ZXing stb::stb) add_test(NAME ZXingReaderTest COMMAND ZXingReader -fast -format qrcode test.png) # see above + + install(TARGETS ZXingReader DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() if (BUILD_READERS) From 109d81e2b2fddc5dfb76b15bcf886fe66c88a866 Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 17:11:01 +0200 Subject: [PATCH 07/88] CharacterSet: new CharacterSetFromString and deprecated CharacterSetECI Deprecate the namespace `CharacterSetECI` and header and use name consistent with `BarcodeFormatFromString()`. --- core/CMakeLists.txt | 2 +- .../{CharacterSetECI.cpp => CharacterSet.cpp} | 19 +++++++------------ core/src/CharacterSet.h | 4 ++++ core/src/CharacterSetECI.h | 4 +--- core/src/Content.cpp | 6 +++--- core/src/datamatrix/DMDecoder.cpp | 2 +- core/src/maxicode/MCDecoder.cpp | 2 +- core/src/pdf417/PDFDecodedBitStreamParser.cpp | 2 +- core/src/qrcode/QRDecoder.cpp | 1 - example/ZXingWriter.cpp | 4 ++-- test/unit/CharacterSetECITest.cpp | 2 -- 11 files changed, 21 insertions(+), 27 deletions(-) rename core/src/{CharacterSetECI.cpp => CharacterSet.cpp} (90%) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 9a710ad272..e303236d0c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -49,8 +49,8 @@ set (COMMON_FILES src/ByteArray.h src/ByteMatrix.h src/CharacterSet.h + src/CharacterSet.cpp src/CharacterSetECI.h - src/CharacterSetECI.cpp src/ConcentricFinder.h src/ConcentricFinder.cpp src/CustomData.h diff --git a/core/src/CharacterSetECI.cpp b/core/src/CharacterSet.cpp similarity index 90% rename from core/src/CharacterSetECI.cpp rename to core/src/CharacterSet.cpp index 95bff2f722..0badb9c7a6 100644 --- a/core/src/CharacterSetECI.cpp +++ b/core/src/CharacterSet.cpp @@ -4,18 +4,13 @@ */ // SPDX-License-Identifier: Apache-2.0 -#include "CharacterSetECI.h" - -#include "ECI.h" -#include "TextDecoder.h" +#include "CharacterSet.h" #include -#include #include -#include #include -namespace ZXing::CharacterSetECI { +namespace ZXing { struct CompareNoCase { bool operator ()(const char* a, const char* b) const { @@ -93,13 +88,13 @@ static const std::map ECI_NAME_TO_CHA {"BINARY", CharacterSet::BINARY}, }; -CharacterSet CharsetFromName(const char* name) +CharacterSet CharacterSetFromString(const std::string& name) { - auto it = ECI_NAME_TO_CHARSET.find(name); - if (it != ECI_NAME_TO_CHARSET.end()) { + auto it = ECI_NAME_TO_CHARSET.find(name.c_str()); + if (it != ECI_NAME_TO_CHARSET.end()) return it->second; - } + return CharacterSet::Unknown; } -} // namespace ZXing::CharacterSetECI +} // namespace ZXing diff --git a/core/src/CharacterSet.h b/core/src/CharacterSet.h index e078f1fa89..b26f4b23f2 100644 --- a/core/src/CharacterSet.h +++ b/core/src/CharacterSet.h @@ -5,6 +5,8 @@ #pragma once +#include + namespace ZXing { enum class CharacterSet @@ -46,4 +48,6 @@ enum class CharacterSet CharsetCount }; +CharacterSet CharacterSetFromString(const std::string& name); + } // ZXing diff --git a/core/src/CharacterSetECI.h b/core/src/CharacterSetECI.h index 249c729a74..e70f9dc3bc 100644 --- a/core/src/CharacterSetECI.h +++ b/core/src/CharacterSetECI.h @@ -8,8 +8,6 @@ #include "CharacterSet.h" -#include - namespace ZXing { /** @@ -24,7 +22,7 @@ namespace CharacterSetECI { * @return {@code CharacterSet} representing ECI of given value, or {@code CharacterSet::Unknown} if it is * unsupported */ -CharacterSet CharsetFromName(const char* name); +[[deprecated]] inline CharacterSet CharsetFromName(const char* name) { return CharacterSetFromString(name); } } // namespace CharacterSetECI } // namespace ZXing diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 1754e31fa0..c730e9ca03 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -5,7 +5,7 @@ #include "Content.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "TextDecoder.h" #include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" @@ -75,7 +75,7 @@ std::wstring Content::text() const if (!canProcess()) return {}; - auto fallbackCS = CharacterSetECI::CharsetFromName(hintedCharset.c_str()); + auto fallbackCS = CharacterSetFromString(hintedCharset); if (!hasECI && fallbackCS == CharacterSet::Unknown) fallbackCS = guessEncoding(); @@ -95,7 +95,7 @@ std::string Content::utf8Protocol() const std::wstring res = TextDecoder::FromLatin1(symbology.toString(true)); ECI lastECI = ECI::Unknown; - auto fallbackCS = CharacterSetECI::CharsetFromName(hintedCharset.c_str()); + auto fallbackCS = CharacterSetFromString(hintedCharset); if (!hasECI && fallbackCS == CharacterSet::Unknown) fallbackCS = guessEncoding(); diff --git a/core/src/datamatrix/DMDecoder.cpp b/core/src/datamatrix/DMDecoder.cpp index 87286c8300..a7303018a9 100644 --- a/core/src/datamatrix/DMDecoder.cpp +++ b/core/src/datamatrix/DMDecoder.cpp @@ -8,7 +8,7 @@ #include "BitMatrix.h" #include "BitSource.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DMBitLayout.h" #include "DMDataBlock.h" #include "DMVersion.h" diff --git a/core/src/maxicode/MCDecoder.cpp b/core/src/maxicode/MCDecoder.cpp index 76886ace7a..8d4be16bea 100644 --- a/core/src/maxicode/MCDecoder.cpp +++ b/core/src/maxicode/MCDecoder.cpp @@ -7,7 +7,7 @@ #include "MCDecoder.h" #include "ByteArray.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DecoderResult.h" #include "DecodeStatus.h" #include "GenericGF.h" diff --git a/core/src/pdf417/PDFDecodedBitStreamParser.cpp b/core/src/pdf417/PDFDecodedBitStreamParser.cpp index e3ebc2a8ff..515c066b1d 100644 --- a/core/src/pdf417/PDFDecodedBitStreamParser.cpp +++ b/core/src/pdf417/PDFDecodedBitStreamParser.cpp @@ -7,7 +7,7 @@ #include "PDFDecodedBitStreamParser.h" #include "ByteArray.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DecoderResult.h" #include "DecodeStatus.h" #include "PDFDecoderResultExtra.h" diff --git a/core/src/qrcode/QRDecoder.cpp b/core/src/qrcode/QRDecoder.cpp index 507666987d..703d28d941 100644 --- a/core/src/qrcode/QRDecoder.cpp +++ b/core/src/qrcode/QRDecoder.cpp @@ -9,7 +9,6 @@ #include "BitMatrix.h" #include "BitSource.h" #include "CharacterSet.h" -#include "CharacterSetECI.h" #include "DecodeStatus.h" #include "DecoderResult.h" #include "GenericGF.h" diff --git a/example/ZXingWriter.cpp b/example/ZXingWriter.cpp index 14934d62bf..80a62d5c58 100644 --- a/example/ZXingWriter.cpp +++ b/example/ZXingWriter.cpp @@ -6,9 +6,9 @@ #include "BarcodeFormat.h" #include "BitMatrix.h" #include "BitMatrixIO.h" +#include "CharacterSet.h" #include "MultiFormatWriter.h" #include "TextUtfEncoding.h" -#include "CharacterSetECI.h" #include #include @@ -73,7 +73,7 @@ static bool ParseOptions(int argc, char* argv[], int* width, int* height, int* m } else if (strcmp(argv[i], "-encoding") == 0) { if (++i == argc) return false; - *encoding = CharacterSetECI::CharsetFromName(argv[i]); + *encoding = CharacterSetFromString(argv[i]); } else if (nonOptArgCount == 0) { *format = BarcodeFormatFromString(argv[i]); if (*format == BarcodeFormat::None) { diff --git a/test/unit/CharacterSetECITest.cpp b/test/unit/CharacterSetECITest.cpp index aeef242add..2ff4dbf14d 100644 --- a/test/unit/CharacterSetECITest.cpp +++ b/test/unit/CharacterSetECITest.cpp @@ -3,14 +3,12 @@ */ // SPDX-License-Identifier: Apache-2.0 -#include "CharacterSetECI.h" #include "ECI.h" #include "gtest/gtest.h" #include "gmock/gmock.h" using namespace ZXing; -using namespace ZXing::CharacterSetECI; using namespace testing; TEST(CharacterSetECITest, Charset2ECI) From e4604f690a66e04a12a39e831f68972eaf969e6b Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 17:49:25 +0200 Subject: [PATCH 08/88] CharacterSet: introduce name normalization like in BarcodeFormatFromString --- core/src/CharacterSet.cpp | 58 +++++++++---------------------- test/unit/CharacterSetECITest.cpp | 10 ++++++ 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/core/src/CharacterSet.cpp b/core/src/CharacterSet.cpp index 0badb9c7a6..57ee86eb01 100644 --- a/core/src/CharacterSet.cpp +++ b/core/src/CharacterSet.cpp @@ -6,59 +6,34 @@ #include "CharacterSet.h" -#include -#include -#include +#include "ZXContainerAlgorithms.h" + +#include namespace ZXing { -struct CompareNoCase { - bool operator ()(const char* a, const char* b) const { - while (*a != '\0' && *b != '\0') { - auto ca = std::tolower(*a++); - auto cb = std::tolower(*b++); - if (ca < cb) { - return true; - } - else if (ca > cb) { - return false; - } - } - return *a == '\0' && *b != '\0'; - } +struct CharacterSetName +{ + const char* name; + CharacterSet cs; }; -static const std::map ECI_NAME_TO_CHARSET = { +static CharacterSetName NAME_TO_CHARSET[] = { {"Cp437", CharacterSet::Cp437}, - {"ISO8859_1", CharacterSet::ISO8859_1}, {"ISO-8859-1", CharacterSet::ISO8859_1}, - {"ISO8859_2", CharacterSet::ISO8859_2}, {"ISO-8859-2", CharacterSet::ISO8859_2}, - {"ISO8859_3", CharacterSet::ISO8859_3}, {"ISO-8859-3", CharacterSet::ISO8859_3}, - {"ISO8859_4", CharacterSet::ISO8859_4}, {"ISO-8859-4", CharacterSet::ISO8859_4}, - {"ISO8859_5", CharacterSet::ISO8859_5}, {"ISO-8859-5", CharacterSet::ISO8859_5}, - {"ISO8859_6", CharacterSet::ISO8859_6}, {"ISO-8859-6", CharacterSet::ISO8859_6}, - {"ISO8859_7", CharacterSet::ISO8859_7}, {"ISO-8859-7", CharacterSet::ISO8859_7}, - {"ISO8859_8", CharacterSet::ISO8859_8}, {"ISO-8859-8", CharacterSet::ISO8859_8}, - {"ISO8859_9", CharacterSet::ISO8859_9}, {"ISO-8859-9", CharacterSet::ISO8859_9}, - {"ISO8859_10", CharacterSet::ISO8859_10}, {"ISO-8859-10", CharacterSet::ISO8859_10}, - {"ISO8859_11", CharacterSet::ISO8859_11}, {"ISO-8859-11", CharacterSet::ISO8859_11}, - {"ISO8859_13", CharacterSet::ISO8859_13}, {"ISO-8859-13", CharacterSet::ISO8859_13}, - {"ISO8859_14", CharacterSet::ISO8859_14}, {"ISO-8859-14", CharacterSet::ISO8859_14}, - {"ISO8859_15", CharacterSet::ISO8859_15}, {"ISO-8859-15", CharacterSet::ISO8859_15}, - {"ISO8859_16", CharacterSet::ISO8859_16}, {"ISO-8859-16", CharacterSet::ISO8859_16}, {"SJIS", CharacterSet::Shift_JIS}, {"Shift_JIS", CharacterSet::Shift_JIS}, @@ -73,28 +48,29 @@ static const std::map ECI_NAME_TO_CHA {"UnicodeBigUnmarked", CharacterSet::UnicodeBig}, {"UTF-16BE", CharacterSet::UnicodeBig}, {"UnicodeBig", CharacterSet::UnicodeBig}, - {"UTF8", CharacterSet::UTF8}, {"UTF-8", CharacterSet::UTF8}, {"ASCII", CharacterSet::ASCII}, {"US-ASCII", CharacterSet::ASCII}, {"Big5", CharacterSet::Big5}, {"GB2312", CharacterSet::GB2312}, {"GB18030", CharacterSet::GB18030}, - {"EUC_CN", CharacterSet::GB18030}, {"EUC-CN", CharacterSet::GB18030}, {"GBK", CharacterSet::GB18030}, - {"EUC_KR", CharacterSet::EUC_KR}, {"EUC-KR", CharacterSet::EUC_KR}, {"BINARY", CharacterSet::BINARY}, }; -CharacterSet CharacterSetFromString(const std::string& name) +static std::string NormalizeName(std::string str) { - auto it = ECI_NAME_TO_CHARSET.find(name.c_str()); - if (it != ECI_NAME_TO_CHARSET.end()) - return it->second; + std::transform(str.begin(), str.end(), str.begin(), [](char c) { return (char)std::tolower(c); }); + str.erase(std::remove_if(str.begin(), str.end(), [](char c) { return Contains("_-[] ", c); }), str.end()); + return str; +} - return CharacterSet::Unknown; +CharacterSet CharacterSetFromString(const std::string& name) +{ + auto i = FindIf(NAME_TO_CHARSET, [str = NormalizeName(name)](auto& v) { return NormalizeName(v.name) == str; }); + return i == std::end(NAME_TO_CHARSET) ? CharacterSet::Unknown : i->cs; } } // namespace ZXing diff --git a/test/unit/CharacterSetECITest.cpp b/test/unit/CharacterSetECITest.cpp index 2ff4dbf14d..e34dd9640f 100644 --- a/test/unit/CharacterSetECITest.cpp +++ b/test/unit/CharacterSetECITest.cpp @@ -3,6 +3,7 @@ */ // SPDX-License-Identifier: Apache-2.0 +#include "CharacterSet.h" #include "ECI.h" #include "gtest/gtest.h" @@ -20,3 +21,12 @@ TEST(CharacterSetECITest, Charset2ECI) EXPECT_EQ(ToInt(ToECI(CharacterSet::BINARY)), 899); EXPECT_EQ(ToInt(ToECI(CharacterSet::Unknown)), -1); } + +TEST(CharacterSetECITest, CharacterSetFromString) +{ + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO-8859-1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO8859_1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO 8859-1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("iso88591")); + EXPECT_EQ(CharacterSet::Unknown, CharacterSetFromString("invalid-name")); +} From eea9ea09080a0292a432d05ffc6ca3f5290ad107 Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 18:45:53 +0200 Subject: [PATCH 09/88] ECI: remove the need to publish ECI.h (via Content.h -> Result.h) --- core/src/Content.cpp | 5 +++++ core/src/Content.h | 10 ++++++---- test/unit/ContentTest.cpp | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index c730e9ca03..e89c86a534 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -6,6 +6,7 @@ #include "Content.h" #include "CharacterSet.h" +#include "ECI.h" #include "TextDecoder.h" #include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" @@ -44,6 +45,10 @@ void Content::switchEncoding(ECI eci, bool isECI) hasECI |= isECI; } +Content::Content() : encodings({{ECI::Unknown, 0}}) {} + +Content::Content(ByteArray&& binary) : binary(std::move(binary)), encodings{{ECI::ISO8859_1, 0}} {} + void Content::switchEncoding(CharacterSet cs) { switchEncoding(ToECI(cs), false); diff --git a/core/src/Content.h b/core/src/Content.h index b786b88386..6b3e874545 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -6,10 +6,12 @@ #pragma once #include "ByteArray.h" -#include "ECI.h" namespace ZXing { +enum class ECI : int; +enum class CharacterSet; + enum class ContentType { Text, Binary, Mixed }; std::string ToString(ContentType type); @@ -40,14 +42,14 @@ class Content }; ByteArray binary; - std::vector encodings = {{ECI::Unknown, 0}}; + std::vector encodings; std::string hintedCharset; std::string applicationIndicator; SymbologyIdentifier symbology; bool hasECI = false; - Content() = default; - Content(ByteArray&& binary) : binary(std::move(binary)), encodings{{ECI::ISO8859_1, 0}} {} + Content(); + Content(ByteArray&& binary); void switchEncoding(ECI eci) { switchEncoding(eci, true); } void switchEncoding(CharacterSet cs); diff --git a/test/unit/ContentTest.cpp b/test/unit/ContentTest.cpp index 5b3129a4d2..b200f51530 100644 --- a/test/unit/ContentTest.cpp +++ b/test/unit/ContentTest.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "Content.h" +#include "ECI.h" #include "gtest/gtest.h" #include "gmock/gmock.h" From 305ef8ad0fa31a8590f45d6980a0a07041ae905b Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 18:51:45 +0200 Subject: [PATCH 10/88] cmake: only install minimal set of header files Fixes #168. This has been tested to work with the example applications. This is a pretty sharp "deprecation" of a whole lot of internal API and reduces the published interface to merely `ReadBarcode` and `MultiFormatWriter`. It is obviously somewhat risky but I see no other practical way of moving forward with limiting the API. --- CMakeLists.txt | 16 ----------- core/CMakeLists.txt | 69 ++++++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e215cf44e..50e2702c03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,22 +87,6 @@ install ( DESTINATION ${CMAKECONFIG_INSTALL_DIR} NAMESPACE ZXing:: ) -install ( - DIRECTORY core/src/ - DESTINATION include/ZXing - FILES_MATCHING PATTERN "*.h" -) - -configure_file ( - core/ZXVersion.h.in - ZXVersion.h -) - -install ( - FILES "${CMAKE_CURRENT_BINARY_DIR}/ZXVersion.h" - DESTINATION include/ZXing -) - # PC file generation. if (NOT DEFINED INSTALLDIR) set (INSTALLDIR ${CMAKE_INSTALL_PREFIX}) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e303236d0c..7b34509510 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -114,7 +114,6 @@ if (BUILD_READERS) src/Result.cpp src/ResultPoint.h src/ResultPoint.cpp - src/StructuredAppend.h src/TextDecoder.h src/TextDecoder.cpp src/ThresholdBinarizer.h @@ -134,6 +133,41 @@ if (BUILD_WRITERS) ) endif() +# define subset of public headers that get distributed with the binaries +set (PUBLIC_HEADERS + src/BarcodeFormat.h + src/BitHacks.h + src/ByteArray.h + src/CharacterSet.h + src/CharacterSetECI.h # deprecated + src/Flags.h + src/GTIN.h + src/TextUtfEncoding.h + src/ZXConfig.h + src/ZXContainerAlgorithms.h +) +if (BUILD_READERS) + set (PUBLIC_HEADERS ${PUBLIC_HEADERS} + src/Content.h + src/DecodeHints.h + src/DecodeStatus.h + src/ImageView.h + src/Point.h + src/Quadrilateral.h + src/ReadBarcode.h + src/Result.h + src/StructuredAppend.h + ) +endif() +if (BUILD_WRITERS) + set (PUBLIC_HEADERS ${PUBLIC_HEADERS} + src/BitMatrix.h + src/BitMatrixIO.h + src/Matrix.h + src/MultiFormatWriter.h + ) +endif() +# end of public header set set (AZTEC_FILES ) @@ -427,7 +461,7 @@ add_library (ZXing target_include_directories (ZXing PUBLIC "$" - INTERFACE "$" + INTERFACE "$" ) target_compile_options (ZXing @@ -463,25 +497,7 @@ if (PROJECT_VERSION) set_target_properties(ZXing PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) endif() -set(PUBLIC_HEADERS "${COMMON_FILES}") -list(FILTER PUBLIC_HEADERS INCLUDE REGEX "^.*\.h$") - -message(STATUS "PUBLIC HEADERS BE LIKE ${PUBLIC_HEADERS}") - -set_target_properties(ZXing PROPERTIES - FRAMEWORK TRUE - FRAMEWORK_VERSION "C" - XCODE_ATTRIBUTE_DEFINES_MODULE YES - XCODE_ATTRIBUTE_BUILD_LIBRARY_FOR_DISTRIBUTION YES - XCODE_ATTRIBUTE_MODULEMAP_FILE "wrappers/ios/Sources/Wrapper/module.modulemap" - XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES - MACOSX_FRAMEWORK_IDENTIFIER "com.zxing_cpp.ios" - CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO - #MACOSX_FRAMEWORK_INFO_PLIST Info.plist - PUBLIC_HEADER "${PUBLIC_HEADERS}" - XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" - XCODE_ATTRIBUTE_ENABLE_BITCODE "YES" -) +set_target_properties(ZXing PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") include (GNUInstallDirs) @@ -490,8 +506,15 @@ install ( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION include +# INCLUDES DESTINATION include + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ZXing" +) + +configure_file (ZXVersion.h.in ZXVersion.h) + +install ( + FILES "${CMAKE_CURRENT_BINARY_DIR}/ZXVersion.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ZXing" ) if(MSVC) From 798673c0eb1594709f614ba844e4286e8b6daa4a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 11:28:52 +0200 Subject: [PATCH 11/88] Add .gitignore --- _deps/fmtlib-src | 1 + wrappers/ios/.gitignore | 4 ++++ 2 files changed, 5 insertions(+) create mode 160000 _deps/fmtlib-src create mode 100644 wrappers/ios/.gitignore diff --git a/_deps/fmtlib-src b/_deps/fmtlib-src new file mode 160000 index 0000000000..d141cdbeb0 --- /dev/null +++ b/_deps/fmtlib-src @@ -0,0 +1 @@ +Subproject commit d141cdbeb0fb422a3fb7173b285fd38e0d1772dc diff --git a/wrappers/ios/.gitignore b/wrappers/ios/.gitignore new file mode 100644 index 0000000000..50f2f7a0d7 --- /dev/null +++ b/wrappers/ios/.gitignore @@ -0,0 +1,4 @@ +.swiftpm +_builds +ZXing.xcframework +xcuserdata From 4de75d7d9e2148a1b1813830928fa428c784da5a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 11:49:08 +0200 Subject: [PATCH 12/88] Add license comments --- wrappers/ios/demo/demo/AppDelegate.swift | 1 + wrappers/ios/demo/demo/SceneDelegate.swift | 1 + wrappers/ios/demo/demo/ViewController.swift | 1 + 3 files changed, 3 insertions(+) diff --git a/wrappers/ios/demo/demo/AppDelegate.swift b/wrappers/ios/demo/demo/AppDelegate.swift index 0625413105..1b46e39eae 100644 --- a/wrappers/ios/demo/demo/AppDelegate.swift +++ b/wrappers/ios/demo/demo/AppDelegate.swift @@ -2,6 +2,7 @@ // // Copyright 2022 KURZ Digital Solutions GmbH // +// SPDX-License-Identifier: Apache-2.0 import UIKit diff --git a/wrappers/ios/demo/demo/SceneDelegate.swift b/wrappers/ios/demo/demo/SceneDelegate.swift index d61cae806c..d307973059 100644 --- a/wrappers/ios/demo/demo/SceneDelegate.swift +++ b/wrappers/ios/demo/demo/SceneDelegate.swift @@ -2,6 +2,7 @@ // // Copyright 2022 KURZ Digital Solutions GmbH // +// SPDX-License-Identifier: Apache-2.0 import UIKit diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index d63ff2c635..2b26cc53c8 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -2,6 +2,7 @@ // // Copyright 2022 KURZ Digital Solutions GmbH // +// SPDX-License-Identifier: Apache-2.0 import UIKit import AVFoundation From 20cd0668156f64f874ff340fdd59a3bacb88759a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 14:41:58 +0200 Subject: [PATCH 13/88] Rename to ZXingCpp --- wrappers/ios/.gitignore | 1 - wrappers/ios/Package.swift | 14 +++++++------- wrappers/ios/README.md | 4 ++-- .../Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 15 ++++----------- wrappers/ios/Sources/Wrapper/module.modulemap | 2 +- wrappers/ios/build-release.sh | 4 ++-- wrappers/ios/demo/demo.xcodeproj/project.pbxproj | 14 +++++++------- wrappers/ios/demo/demo/ViewController.swift | 2 +- 8 files changed, 24 insertions(+), 32 deletions(-) diff --git a/wrappers/ios/.gitignore b/wrappers/ios/.gitignore index 50f2f7a0d7..184c93d996 100644 --- a/wrappers/ios/.gitignore +++ b/wrappers/ios/.gitignore @@ -1,4 +1,3 @@ .swiftpm _builds -ZXing.xcframework xcuserdata diff --git a/wrappers/ios/Package.swift b/wrappers/ios/Package.swift index 58c94ce0e1..b0dbe39bb3 100644 --- a/wrappers/ios/Package.swift +++ b/wrappers/ios/Package.swift @@ -2,24 +2,24 @@ import PackageDescription let package = Package( - name: "ZXingWrapper", + name: "ZXingCppWrapper", platforms: [ .iOS(.v13) ], products: [ .library( - name: "ZXingWrapper", + name: "ZXingCppWrapper", type: .static, - targets: ["ZXingWrapper"]) + targets: ["ZXingCppWrapper"]) ], targets: [ .binaryTarget( - name: "ZXing", - path: "ZXing.xcframework" + name: "ZXingCpp", + path: "ZXingCpp.xcframework" ), .target( - name: "ZXingWrapper", - dependencies: ["ZXing"], + name: "ZXingCppWrapper", + dependencies: ["ZXingCpp"], path: "Sources/Wrapper", publicHeadersPath: ".", cxxSettings: [ diff --git a/wrappers/ios/README.md b/wrappers/ios/README.md index afd83d7ac0..fc2c06fcf3 100644 --- a/wrappers/ios/README.md +++ b/wrappers/ios/README.md @@ -1,4 +1,4 @@ -# ZXing-C++ iOS Framework +# ZXingCpp iOS Framework To use the iOS (wrapper) framework in other apps, it is easiest to build the library project and include the resulting xcframework @@ -10,5 +10,5 @@ To build the xcframework: $ ./build-release.sh -Then copy `zxingcpp/wrappers/ios/ZXing.xcframework` into the +Then copy `zxingcpp/wrappers/ios/ZXingCpp.xcframework` into the frameworks-section of your app. diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 13b02e85a6..70b187ef77 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -6,7 +6,6 @@ #import "ZXIBarcodeWriter.h" #import "ZXing/MultiFormatWriter.h" #import "ZXing/BitMatrix.h" -#import "ZXing/BitArray.h" #import "ZXIFormatHelper.h" #import "ZXICharsetHelper.h" #import "ZXIErrors.h" @@ -26,12 +25,8 @@ std::string result; result.reserve((addSpace ? 2 : 1) * (matrix.width() * matrix.height()) + matrix.height()); for (int y = 0; y < matrix.height(); ++y) { - BitArray row; - matrix.getRow(y, row); - if (printAsCString) - result += '"'; - for (auto bit : row) { - result += bit ? one : zero; + for (int x = 0; x < matrix.width(); ++x) { + result += matrix.get(x, y) ? one : zero; if (addSpace) result += ' '; } @@ -78,10 +73,8 @@ -(CGImageRef)write:(NSString *)contents size_t index = 0; uint8_t *bytes = (uint8_t*)resultAsNSData.mutableBytes; for (int y = 0; y < realHeight; ++y) { - BitArray row; - result.getRow(y, row); - for (auto bit : row) { - bytes[index] = bit ? 0 : 255; + for (int x = 0; x < realWidth; ++x) { + bytes[index] = result.get(x, y) ? 0 : 255; ++index; } } diff --git a/wrappers/ios/Sources/Wrapper/module.modulemap b/wrappers/ios/Sources/Wrapper/module.modulemap index 5812eac363..f613294fc1 100644 --- a/wrappers/ios/Sources/Wrapper/module.modulemap +++ b/wrappers/ios/Sources/Wrapper/module.modulemap @@ -1,4 +1,4 @@ -module ZXingWrapper { +module ZXingCppWrapper { umbrella header "UmbrellaHeader.h" export * module * { export * } diff --git a/wrappers/ios/build-release.sh b/wrappers/ios/build-release.sh index 63e02980c8..e8180c3d08 100755 --- a/wrappers/ios/build-release.sh +++ b/wrappers/ios/build-release.sh @@ -1,6 +1,6 @@ echo ========= Remove previous builds rm -rf _builds -rm -rf ZXing.xcframework +rm -rf ZXingCpp.xcframework echo ========= Create project structure cmake -S../../ -B_builds -GXcode \ @@ -33,4 +33,4 @@ echo ========= Create the xcframework xcodebuild -create-xcframework \ -framework ./_builds/core/Release-iphonesimulator/ZXing.framework \ -framework ./_builds/core/Release-iphoneos/ZXing.framework \ - -output ZXing.xcframework + -output ZXingCpp.xcframework diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 7abe431326..682ced0199 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -13,7 +13,7 @@ 388BF030283CC49D005CE271 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 388BF02E283CC49D005CE271 /* Main.storyboard */; }; 388BF032283CC49E005CE271 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388BF031283CC49E005CE271 /* Assets.xcassets */; }; 388BF035283CC49E005CE271 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */; }; - 388BF042283CD908005CE271 /* ZXingWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 388BF041283CD908005CE271 /* ZXingWrapper */; }; + 9507445028609C0500E02D06 /* ZXingCppWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 9507444F28609C0500E02D06 /* ZXingCppWrapper */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -25,8 +25,8 @@ 388BF031283CC49E005CE271 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 388BF034283CC49E005CE271 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 388BF036283CC49E005CE271 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 388BF03F283CD6C5005CE271 /* ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ios; path = ..; sourceTree = ""; }; 388BF043283CE0AC005CE271 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 9550105328609B7900ED103F /* ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ios; path = ..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -34,7 +34,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 388BF042283CD908005CE271 /* ZXingWrapper in Frameworks */, + 9507445028609C0500E02D06 /* ZXingCppWrapper in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,7 +77,7 @@ 388BF03E283CD6C5005CE271 /* Packages */ = { isa = PBXGroup; children = ( - 388BF03F283CD6C5005CE271 /* ios */, + 9550105328609B7900ED103F /* ios */, ); name = Packages; sourceTree = ""; @@ -106,7 +106,7 @@ ); name = demo; packageProductDependencies = ( - 388BF041283CD908005CE271 /* ZXingWrapper */, + 9507444F28609C0500E02D06 /* ZXingCppWrapper */, ); productName = demo; productReference = 388BF025283CC49D005CE271 /* demo.app */; @@ -389,9 +389,9 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - 388BF041283CD908005CE271 /* ZXingWrapper */ = { + 9507444F28609C0500E02D06 /* ZXingCppWrapper */ = { isa = XCSwiftPackageProductDependency; - productName = ZXingWrapper; + productName = ZXingCppWrapper; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index 2b26cc53c8..a8d4645e28 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -6,7 +6,7 @@ import UIKit import AVFoundation -import ZXingWrapper +import ZXingCppWrapper class ViewController: UIViewController { let captureSession = AVCaptureSession() From fe75d0fa44db362e2a41e6f0b8550a69fd106020 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:03:16 +0200 Subject: [PATCH 14/88] Disable printing of written code in debug mode --- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 70b187ef77..31e713da68 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -66,7 +66,7 @@ -(CGImageRef)write:(NSString *)contents #ifdef DEBUG - std::cout << ToString(result, 'X', ' ', false, false); +// std::cout << ToString(result, 'X', ' ', false, false); #endif NSMutableData *resultAsNSData = [[NSMutableData alloc] initWithLength:realWidth * realHeight]; From 24044e31f64a9a7a197eff0dac82f8c3c85e5963 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:03:51 +0200 Subject: [PATCH 15/88] Add WriteViewController to demo project --- .../ios/demo/demo.xcodeproj/project.pbxproj | 4 + .../ios/demo/demo/Base.lproj/Main.storyboard | 89 +++++++++++++++++-- .../ios/demo/demo/WriteViewController.swift | 25 ++++++ 3 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 wrappers/ios/demo/demo/WriteViewController.swift diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 682ced0199..12eea52919 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 388BF032283CC49E005CE271 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388BF031283CC49E005CE271 /* Assets.xcassets */; }; 388BF035283CC49E005CE271 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */; }; 9507445028609C0500E02D06 /* ZXingCppWrapper in Frameworks */ = {isa = PBXBuildFile; productRef = 9507444F28609C0500E02D06 /* ZXingCppWrapper */; }; + 950744522860A3A300E02D06 /* WriteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950744512860A3A300E02D06 /* WriteViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -26,6 +27,7 @@ 388BF034283CC49E005CE271 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 388BF036283CC49E005CE271 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 388BF043283CE0AC005CE271 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 950744512860A3A300E02D06 /* WriteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteViewController.swift; sourceTree = ""; }; 9550105328609B7900ED103F /* ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ios; path = ..; sourceTree = ""; }; /* End PBXFileReference section */ @@ -66,6 +68,7 @@ 388BF028283CC49D005CE271 /* AppDelegate.swift */, 388BF02A283CC49D005CE271 /* SceneDelegate.swift */, 388BF02C283CC49D005CE271 /* ViewController.swift */, + 950744512860A3A300E02D06 /* WriteViewController.swift */, 388BF02E283CC49D005CE271 /* Main.storyboard */, 388BF031283CC49E005CE271 /* Assets.xcassets */, 388BF033283CC49E005CE271 /* LaunchScreen.storyboard */, @@ -165,6 +168,7 @@ files = ( 388BF02D283CC49D005CE271 /* ViewController.swift in Sources */, 388BF029283CC49D005CE271 /* AppDelegate.swift in Sources */, + 950744522860A3A300E02D06 /* WriteViewController.swift in Sources */, 388BF02B283CC49D005CE271 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/wrappers/ios/demo/demo/Base.lproj/Main.storyboard b/wrappers/ios/demo/demo/Base.lproj/Main.storyboard index 25a763858e..68bbd506cf 100644 --- a/wrappers/ios/demo/demo/Base.lproj/Main.storyboard +++ b/wrappers/ios/demo/demo/Base.lproj/Main.storyboard @@ -1,24 +1,101 @@ - + + - + + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wrappers/ios/demo/demo/WriteViewController.swift b/wrappers/ios/demo/demo/WriteViewController.swift new file mode 100644 index 0000000000..8f1e1f28e8 --- /dev/null +++ b/wrappers/ios/demo/demo/WriteViewController.swift @@ -0,0 +1,25 @@ +// +// demo +// +// Copyright 2022 KURZ Digital Solutions GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +import UIKit +import ZXingCppWrapper + +class WriteViewController: UIViewController { + @IBOutlet fileprivate var imageView: UIImageView! + + // MARK: - Actions + + @IBAction func textFieldChanged(_ sender: UITextField) { + guard let text = sender.text, + let image = try? ZXIBarcodeWriter().write(text, width: 200, height: 200, format: .QR_CODE) + else { + return + } + + imageView.image = UIImage(cgImage: image.takeRetainedValue()) + } +} From 82dceba9a6c2f09b8d99223fc83d0bec06186a4b Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:15:08 +0200 Subject: [PATCH 16/88] Use .binary() on result for reader --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index be1a759949..efb84b7fce 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -66,8 +66,8 @@ - (nullable ZXIResult *)readCGImage: (nonnull CGImageRef)image error:(NSError ** length:resultText.size() * sizeof(wchar_t) encoding:NSUTF32LittleEndianStringEncoding]; - std::string s(resultText.begin(), resultText.end()); - NSData *rawBytes = [[NSData alloc] initWithBytes:s.c_str() length:s.size()]; + auto binary = result.binary(); + NSData *rawBytes = [[NSData alloc] initWithBytes:binary.data() length:binary.size()]; return [[ZXIResult alloc] init:text format:ZXIFormatFromBarcodeFormat(result.format()) rawBytes:rawBytes]; From dd9831a31e2202f53d2341a2f3818b3357ff3d7c Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:17:41 +0200 Subject: [PATCH 17/88] Update .gitignore --- wrappers/ios/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/ios/.gitignore b/wrappers/ios/.gitignore index 184c93d996..272f06febd 100644 --- a/wrappers/ios/.gitignore +++ b/wrappers/ios/.gitignore @@ -1,3 +1,4 @@ .swiftpm _builds xcuserdata +ZXingCpp.xcframework From fd79e7a7b3d921bfdb0ab7f2225050ee0cac5a21 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:17:54 +0200 Subject: [PATCH 18/88] Make demo app only work in portrait --- wrappers/ios/demo/demo.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 12eea52919..46f114c04f 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -323,6 +323,7 @@ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -353,6 +354,7 @@ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( From 0840db601e9980e4a33ae6252426619b2fd2f777 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:19:48 +0200 Subject: [PATCH 19/88] Set demo development team to None --- wrappers/ios/demo/demo.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 46f114c04f..204cd12fe1 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -316,7 +316,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 25MXZ8DDDM; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; @@ -347,7 +347,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 25MXZ8DDDM; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; From b43cc2bc12946a0a9b09cd3f9b87963d3c272124 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:33:41 +0200 Subject: [PATCH 20/88] Remove whitelines --- wrappers/ios/demo/demo/SceneDelegate.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wrappers/ios/demo/demo/SceneDelegate.swift b/wrappers/ios/demo/demo/SceneDelegate.swift index d307973059..717ca0b219 100644 --- a/wrappers/ios/demo/demo/SceneDelegate.swift +++ b/wrappers/ios/demo/demo/SceneDelegate.swift @@ -10,7 +10,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. @@ -45,7 +44,4 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } - - } - From 23c20518e0fe37151ed16ac96fbd9b655a049d1e Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 15:39:18 +0200 Subject: [PATCH 21/88] Add maxSymbolNumber and downscale option to hints --- .../ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 10 ++++++---- wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h | 8 +++++++- wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm | 8 +++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index efb84b7fce..329c1f6f48 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -95,14 +95,16 @@ - (nullable ZXIResult *)readCGImage: (nonnull CGImageRef)image error:(NSError ** } + (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { - DecodeHints resultingHints = DecodeHints(); - resultingHints.setTryRotate(hints.tryRotate); - resultingHints.setTryHarder(hints.tryHarder); BarcodeFormats formats; for(NSNumber* flag in hints.formats) { formats.setFlag(BarcodeFormatFromZXIFormat((ZXIFormat)flag.integerValue)); } - resultingHints.setFormats(formats); + DecodeHints resultingHints = DecodeHints() + .setTryRotate(hints.tryRotate) + .setTryHarder(hints.tryHarder) + .setTryDownscale(hints.tryDownscale) + .setFormats(formats) + .setMaxNumberOfSymbols(hints.maxNumberOfSymbols); return resultingHints; } diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h index 1530178a9c..2481d40471 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h @@ -9,10 +9,16 @@ NS_ASSUME_NONNULL_BEGIN @interface ZXIDecodeHints : NSObject @property(nonatomic) BOOL tryHarder; @property(nonatomic) BOOL tryRotate; +@property(nonatomic) BOOL tryDownscale; +@property(nonatomic) BOOL maxNumberOfSymbols; /// An array of ZXIFormat @property(nonatomic, strong) NSArray *formats; -- (instancetype)initWithTryHarder:(BOOL)tryHarder tryRotate:(BOOL)tryRotate formats:(NSArray*)formats; +- (instancetype)initWithTryHarder:(BOOL)tryHarder + tryRotate:(BOOL)tryRotate + tryDownscale:(BOOL)tryDownscale + maxNumberOfSymbols:(NSInteger)maxNumberOfSymbol + formats:(NSArray*)formats; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm index 06c8b2daf4..4db2c06c6e 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm @@ -6,10 +6,16 @@ @implementation ZXIDecodeHints -- (instancetype)initWithTryHarder:(BOOL)tryHarder tryRotate:(BOOL)tryRotate formats:(NSArray*)formats { +- (instancetype)initWithTryHarder:(BOOL)tryHarder + tryRotate:(BOOL)tryRotate + tryDownscale:(BOOL)tryDownscale + maxNumberOfSymbols:(NSInteger)maxNumberOfSymbol + formats:(NSArray*)formats { self = [super init]; self.tryHarder = tryHarder; self.tryRotate = tryRotate; + self.tryDownscale = tryDownscale; + self.maxNumberOfSymbols = maxNumberOfSymbols; self.formats = formats; return self; } From 0c3e0977c9b944bf8cf85beb32bb17b2c5d7e92e Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 20 Jun 2022 16:04:12 +0200 Subject: [PATCH 22/88] WIP: Return multiple results --- .../Sources/Wrapper/Reader/ZXIBarcodeReader.h | 4 +- .../Wrapper/Reader/ZXIBarcodeReader.mm | 77 ++++++++++--------- .../Sources/Wrapper/Reader/ZXIDecodeHints.mm | 2 +- .../ios/demo/demo.xcodeproj/project.pbxproj | 4 +- wrappers/ios/demo/demo/ViewController.swift | 3 +- 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h index b8e6d7295a..bb4bf13d6c 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h @@ -13,8 +13,8 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong) ZXIDecodeHints *hints; - (instancetype)initWithHints:(ZXIDecodeHints*)options; -- (nullable ZXIResult *)readCIImage:(nonnull CIImage *)image error:(NSError **)error; -- (nullable ZXIResult *)readCGImage:(nonnull CGImageRef)image error:(NSError **)error; +- (nullable NSArray *)readCIImage:(nonnull CIImage *)image error:(NSError **)error; +- (nullable NSArray *)readCGImage:(nonnull CGImageRef)image error:(NSError **)error; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 329c1f6f48..49ac8e7cf4 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -18,7 +18,7 @@ @interface ZXIBarcodeReader() @implementation ZXIBarcodeReader - (instancetype)init { - return [self initWithHints: [[ZXIDecodeHints alloc]initWithTryHarder:NO tryRotate:NO formats:@[]]]; + return [self initWithHints: [[ZXIDecodeHints alloc]initWithTryHarder:NO tryRotate:NO tryDownscale:NO maxNumberOfSymbols:1 formats:@[]]]; } - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ @@ -28,14 +28,14 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return self; } -- (nullable ZXIResult *)readCIImage:(nonnull CIImage *)image error:(NSError **)error { +- (nullable NSArray *)readCIImage:(nonnull CIImage *)image error:(NSError **)error { CGImageRef cgImage = [self.ciContext createCGImage:image fromRect:image.extent]; - ZXIResult *result = [self readCGImage:cgImage error:error]; + auto results = [self readCGImage:cgImage error:error]; CGImageRelease(cgImage); - return result; + return results; } -- (nullable ZXIResult *)readCGImage: (nonnull CGImageRef)image error:(NSError **)error { +- (nullable NSArray *)readCGImage: (nonnull CGImageRef)image error:(NSError **)error { CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); CGFloat cols = CGImageGetWidth(image); CGFloat rows = CGImageGetHeight(image); @@ -59,39 +59,46 @@ - (nullable ZXIResult *)readCGImage: (nonnull CGImageRef)image error:(NSError ** static_cast(rows), ImageFormat::Lum); - Result result = ReadBarcode(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); - if(result.status() == DecodeStatus::NoError) { - const std::wstring &resultText = result.text(); - NSString *text = [[NSString alloc] initWithBytes:resultText.data() - length:resultText.size() * sizeof(wchar_t) - encoding:NSUTF32LittleEndianStringEncoding]; - - auto binary = result.binary(); - NSData *rawBytes = [[NSData alloc] initWithBytes:binary.data() length:binary.size()]; - return [[ZXIResult alloc] init:text - format:ZXIFormatFromBarcodeFormat(result.format()) - rawBytes:rawBytes]; - } else { - if(error != nil) { - ZXIReaderError errorCode; - switch (result.status()) { - case ZXing::DecodeStatus::NoError: - // Can not happen - break; - case ZXing::DecodeStatus::NotFound: - errorCode = ZXIReaderError::ZXINotFoundError; - break; - case ZXing::DecodeStatus::FormatError: - errorCode = ZXIReaderError::ZXIFormatError; - break; - case ZXing::DecodeStatus::ChecksumError: - errorCode = ZXIReaderError::ZXIChecksumError; - break; + Results results = ReadBarcodes(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); + + NSMutableArray* zxiResults = [NSMutableArray array]; + for (auto result: results) { + if(result.status() == DecodeStatus::NoError) { + const std::wstring &resultText = result.text(); + NSString *text = [[NSString alloc] initWithBytes:resultText.data() + length:resultText.size() * sizeof(wchar_t) + encoding:NSUTF32LittleEndianStringEncoding]; + + auto binary = result.binary(); + NSData *rawBytes = [[NSData alloc] initWithBytes:binary.data() length:binary.size()]; + [zxiResults addObject: + [[ZXIResult alloc] init:text + format:ZXIFormatFromBarcodeFormat(result.format()) + rawBytes:rawBytes] + ]; + } else { + if(error != nil) { + ZXIReaderError errorCode; + switch (result.status()) { + case ZXing::DecodeStatus::NoError: + // Can not happen + break; + case ZXing::DecodeStatus::NotFound: + errorCode = ZXIReaderError::ZXINotFoundError; + break; + case ZXing::DecodeStatus::FormatError: + errorCode = ZXIReaderError::ZXIFormatError; + break; + case ZXing::DecodeStatus::ChecksumError: + errorCode = ZXIReaderError::ZXIChecksumError; + break; + } + *error = [[NSError alloc] initWithDomain: ZXIErrorDomain code: errorCode userInfo:nil]; } - *error = [[NSError alloc] initWithDomain: ZXIErrorDomain code: errorCode userInfo:nil]; + return nil; } - return nil; } + return zxiResults; } + (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm index 4db2c06c6e..cd28dc40f8 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.mm @@ -9,7 +9,7 @@ @implementation ZXIDecodeHints - (instancetype)initWithTryHarder:(BOOL)tryHarder tryRotate:(BOOL)tryRotate tryDownscale:(BOOL)tryDownscale - maxNumberOfSymbols:(NSInteger)maxNumberOfSymbol + maxNumberOfSymbols:(NSInteger)maxNumberOfSymbols formats:(NSArray*)formats { self = [super init]; self.tryHarder = tryHarder; diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 204cd12fe1..46f114c04f 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -316,7 +316,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 25MXZ8DDDM; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; @@ -347,7 +347,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 25MXZ8DDDM; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index a8d4645e28..beabec5781 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -63,7 +63,8 @@ extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { return } let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! - if let result = try? reader.read(CIImage(cvPixelBuffer: imageBuffer)) { + if let results = try? reader.read(CIImage(cvPixelBuffer: imageBuffer)), + let result = results.first { print("Found barcode of format", result.format.rawValue, "with text", result.text) } self.zxingLock.signal() From 32e813be8ffec24a3187eec877de80ffc890e130 Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 22:45:59 +0200 Subject: [PATCH 23/88] CharacterSet: replace deprecated CharsetFromName in WASM wrapper --- wrappers/wasm/BarcodeWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/wasm/BarcodeWriter.cpp b/wrappers/wasm/BarcodeWriter.cpp index 209fec1a89..ed2a2b1663 100644 --- a/wrappers/wasm/BarcodeWriter.cpp +++ b/wrappers/wasm/BarcodeWriter.cpp @@ -6,7 +6,7 @@ #include "BarcodeFormat.h" #include "MultiFormatWriter.h" #include "BitMatrix.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include #include @@ -59,7 +59,7 @@ WriteResult generateBarcode(std::wstring text, std::string format, std::string e if (margin >= 0) writer.setMargin(margin); - CharacterSet charset = CharacterSetECI::CharsetFromName(encoding.c_str()); + CharacterSet charset = CharacterSetFromString(encoding); if (charset != CharacterSet::Unknown) writer.setEncoding(charset); From 6b7c7763e71ab58aa060cae42ad449e9adf9c147 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 6 Jun 2022 13:18:16 +0200 Subject: [PATCH 24/88] DMDecoder: set missing Result::applicationIndicator --- core/src/datamatrix/DMDecoder.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/datamatrix/DMDecoder.cpp b/core/src/datamatrix/DMDecoder.cpp index a7303018a9..efd6f1bea7 100644 --- a/core/src/datamatrix/DMDecoder.cpp +++ b/core/src/datamatrix/DMDecoder.cpp @@ -320,11 +320,11 @@ DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const b readerInit = true; break; case 235: upperShift.set = true; break; // Upper Shift (shift to Extended ASCII) - case 236: // 05 Macro + case 236: // ISO 15434 format "05" Macro result.append("[)>\x1E" "05\x1D"); resultTrailer.insert(0, "\x1E\x04"); break; - case 237: // 06 Macro + case 237: // ISO 15434 format "06" Macro result.append("[)>\x1E" "06\x1D"); resultTrailer.insert(0, "\x1E\x04"); break; @@ -357,6 +357,7 @@ DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const b } result.append(resultTrailer); + result.applicationIndicator = result.symbology.modifier == '2' ? "GS1" : ""; result.symbology.modifier += isDMRE * 6; return DecoderResult(std::move(bytes), {}, std::move(result)) From 8e64c308b75db211f3077d62df50872f77a6a0ca Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 6 Jun 2022 13:27:07 +0200 Subject: [PATCH 25/88] Result: add GS1, ISO15434 and UnknownECI ContentTypes Also tuned binary detection to possibly return true even if a 'text' ECI like latin1 was used (see https://github.com/nu-book/zxing-cpp/issues/334#issuecomment-1146083723) --- core/src/Content.cpp | 32 +++++++++++++++++++++++--------- core/src/Content.h | 2 +- core/src/TextDecoder.cpp | 4 ---- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index e89c86a534..c9482336e0 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -15,7 +15,7 @@ namespace ZXing { std::string ToString(ContentType type) { - const char* t2s[] = {"Text", "Binary", "Mixed"}; + const char* t2s[] = {"Text", "Binary", "Mixed", "GS1", "ISO15434", "UnknownECI"}; return t2s[static_cast(type)]; } @@ -166,21 +166,35 @@ CharacterSet Content::guessEncoding() const if (input.empty()) return CharacterSet::Unknown; - return TextDecoder::GuessEncoding(input.data(), input.size(), CharacterSet::BINARY); + return TextDecoder::GuessEncoding(input.data(), input.size(), CharacterSet::ISO8859_1); } ContentType Content::type() const { - auto isBinary = [](Encoding e) { return !IsText(e.eci); }; - auto es = encodings; + if (!canProcess()) + return ContentType::UnknownECI; + + if (applicationIndicator == "GS1") + return ContentType::GS1; + + // check for the absolut minimum of a ISO 15434 conforming message ("[)>" + RS + digit + digit) + if (binary.size() > 6 && binary.asString(0, 4) == "[)>\x1E" && std::isdigit(binary[4]) && std::isdigit(binary[5])) + return ContentType::ISO15434; - for (auto& e : es) - if (e.eci == ECI::Unknown) - e.eci = ToECI(guessEncoding()); + ECI fallback = ToECI(guessEncoding()); + std::vector binaryECIs; + ForEachECIBlock([&](ECI eci, int begin, int end) { + if (eci == ECI::Unknown) + eci = fallback; + binaryECIs.push_back((!IsText(eci) + || (ToInt(eci) > 0 && ToInt(eci) < 28 && ToInt(eci) != 25 + && std::any_of(binary.begin() + begin, binary.begin() + end, + [](auto c) { return c < 0x20 && c != 0xa && c != 0xd; })))); + }); - if (std::none_of(es.begin(), es.end(), isBinary)) + if (!Contains(binaryECIs, true)) return ContentType::Text; - if (std::all_of(es.begin(), es.end(), isBinary)) + if (!Contains(binaryECIs, false)) return ContentType::Binary; return ContentType::Mixed; diff --git a/core/src/Content.h b/core/src/Content.h index 6b3e874545..34aa6b92d7 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -12,7 +12,7 @@ namespace ZXing { enum class ECI : int; enum class CharacterSet; -enum class ContentType { Text, Binary, Mixed }; +enum class ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI }; std::string ToString(ContentType type); diff --git a/core/src/TextDecoder.cpp b/core/src/TextDecoder.cpp index 98677d63a4..4df8a65f14 100644 --- a/core/src/TextDecoder.cpp +++ b/core/src/TextDecoder.cpp @@ -402,10 +402,6 @@ TextDecoder::GuessEncoding(const uint8_t* bytes, size_t length, CharacterSet fal if (value > 0x7F && value < 0xA0) { canBeISO88591 = false; } - // treat all ANSI control characters as binary, except EOT, LF, CR, GS and RS (see ISO/IEC 15434) - else if (value < 0x20 && value != 0x04 && value != 0x0a && value != 0x0d && value != 0x1d && value != 0x1e) { - canBeISO88591 = false; - } else if (value > 0x9F) { if (value < 0xC0 || value == 0xD7 || value == 0xF7) { isoHighOther++; From 9aac5f650ae383792b48b0812546073f23761277 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 6 Jun 2022 17:41:39 +0200 Subject: [PATCH 26/88] Result: deprecate rawBytes and numBits --- core/src/Result.h | 12 +++++------- example/ZXingQtReader.h | 9 ++++----- test/blackbox/BlackboxTestRunner.cpp | 2 -- test/unit/aztec/AZDecoderTest.cpp | 5 ----- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/core/src/Result.h b/core/src/Result.h index f13afcc233..6f196fb198 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -24,10 +24,8 @@ class DecoderResult; using Position = QuadrilateralI; /** -*

Encapsulates the result of decoding a barcode within an image.

-* -* @author Sean Owen -*/ + * @brief The Result class encapsulates the result of decoding a barcode within an image. + */ class Result { public: @@ -66,9 +64,9 @@ class Result */ bool isMirrored() const { return _isMirrored; } - const ByteArray& rawBytes() const { return _rawBytes; } - - int numBits() const { return _numBits; } + /// see binary() above for a proper replacement of rawByes + [[deprecated]] const ByteArray& rawBytes() const { return _rawBytes; } + [[deprecated]] int numBits() const { return _numBits; } const std::wstring& ecLevel() const { return _ecLevel; } diff --git a/example/ZXingQtReader.h b/example/ZXingQtReader.h index 2a05bbf5d8..9db4a7c528 100644 --- a/example/ZXingQtReader.h +++ b/example/ZXingQtReader.h @@ -97,13 +97,13 @@ class Result : private ZXing::Result Q_PROPERTY(BarcodeFormat format READ format) Q_PROPERTY(QString formatName READ formatName) Q_PROPERTY(QString text READ text) - Q_PROPERTY(QByteArray rawBytes READ rawBytes) + Q_PROPERTY(QByteArray binary READ binary) Q_PROPERTY(bool isValid READ isValid) Q_PROPERTY(DecodeStatus status READ status) Q_PROPERTY(Position position READ position) QString _text; - QByteArray _rawBytes; + QByteArray _binary; Position _position; public: @@ -111,8 +111,7 @@ class Result : private ZXing::Result explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)) { _text = QString::fromWCharArray(ZXing::Result::text().c_str()); - _rawBytes = QByteArray(reinterpret_cast(ZXing::Result::rawBytes().data()), - Size(ZXing::Result::rawBytes())); + _binary = QByteArray(reinterpret_cast(ZXing::Result::binary().data()), Size(ZXing::Result::binary())); auto& pos = ZXing::Result::position(); auto qp = [&pos](int i) { return QPoint(pos[i].x, pos[i].y); }; _position = {qp(0), qp(1), qp(2), qp(3)}; @@ -124,7 +123,7 @@ class Result : private ZXing::Result DecodeStatus status() const { return static_cast(ZXing::Result::status()); } QString formatName() const { return QString::fromStdString(ZXing::ToString(ZXing::Result::format())); } const QString& text() const { return _text; } - const QByteArray& rawBytes() const { return _rawBytes; } + const QByteArray& binary() const { return _binary; } const Position& position() const { return _position; } // For debugging/development diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 9f16fa2aa3..8864d224a8 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -68,8 +68,6 @@ static std::string getResultValue(const Result& result, const std::string& key) return TextUtfEncoding::ToUtf8(result.ecLevel()); if (key == "orientation") return std::to_string(result.orientation()); - if (key == "numBits") - return std::to_string(result.numBits()); if (key == "symbologyIdentifier") return result.symbologyIdentifier(); if (key == "sequenceSize") diff --git a/test/unit/aztec/AZDecoderTest.cpp b/test/unit/aztec/AZDecoderTest.cpp index 523bb8b920..62d70977ff 100644 --- a/test/unit/aztec/AZDecoderTest.cpp +++ b/test/unit/aztec/AZDecoderTest.cpp @@ -60,11 +60,6 @@ TEST(AZDecoderTest, AztecResult) DecoderResult result = parse(std::move(bits), false, 30, 2); EXPECT_EQ(result.isValid(), true); EXPECT_EQ(result.text(), L"88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"); - EXPECT_EQ(result.rawBytes(), ByteArray({ - 0xf5, 0x55, 0x55, 0x75, 0x6b, 0x5a, 0xd6, 0xb5, 0xad, 0x6b, - 0x5a, 0xd6, 0xb5, 0xad, 0x6b, 0x5a, 0xd6, 0xb5, 0xad, 0x6b, - 0x5a, 0xd6, 0xb0 })); - EXPECT_EQ(result.numBits(), 180); EXPECT_EQ(result.symbologyIdentifier(), "]z0"); } From 72e8ae1cae1a02956129804f11098cf0d6a88a10 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 7 Jun 2022 12:24:40 +0200 Subject: [PATCH 27/88] Result: rename `binary` to `bytes` Originally the `binary` property was envisioned to contain only the binary parts (if present) of a barcode content. During the discussion, this has changed. Hence the name became misleading and should be changed before releasing it. Reasons for the choice `bytes`: * does not somehow imply that the content is 'binary' in nature * is closer to `rawBytes` which was there before with a similar intention * is used in Python as the name of the type this data would be stored in --- core/src/Content.cpp | 26 +++++++++++----------- core/src/Content.h | 16 ++++++------- core/src/Result.h | 6 ++--- core/src/aztec/AZDecoder.cpp | 20 ++++++++--------- core/src/maxicode/MCDecoder.cpp | 2 +- core/src/qrcode/QRDecoder.cpp | 2 +- example/ZXingQtReader.h | 8 +++---- example/ZXingReader.cpp | 6 ++--- test/blackbox/BlackboxTestRunner.cpp | 6 ++--- test/unit/ContentTest.cpp | 8 +++---- test/unit/aztec/AZEncodeDecodeTest.cpp | 4 ++-- test/unit/aztec/AZHighLevelEncoderTest.cpp | 2 +- test/unit/pdf417/PDF417DecoderTest.cpp | 2 +- 13 files changed, 54 insertions(+), 54 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index c9482336e0..90dd68d9f8 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -24,7 +24,7 @@ void Content::ForEachECIBlock(FUNC func) const { for (int i = 0; i < Size(encodings); ++i) { auto [eci, start] = encodings[i]; - int end = i + 1 == Size(encodings) ? Size(binary) : encodings[i + 1].pos; + int end = i + 1 == Size(encodings) ? Size(bytes) : encodings[i + 1].pos; if (start != end) func(eci, start, end); @@ -37,17 +37,17 @@ void Content::switchEncoding(ECI eci, bool isECI) if (isECI && !hasECI) encodings = {{ECI::ISO8859_1, 0}}; if (isECI || !hasECI) { - if (encodings.back().pos == Size(binary)) + if (encodings.back().pos == Size(bytes)) encodings.back().eci = eci; // no point in recording 0 length segments else - encodings.push_back({eci, Size(binary)}); + encodings.push_back({eci, Size(bytes)}); } hasECI |= isECI; } Content::Content() : encodings({{ECI::Unknown, 0}}) {} -Content::Content(ByteArray&& binary) : binary(std::move(binary)), encodings{{ECI::ISO8859_1, 0}} {} +Content::Content(ByteArray&& bytes) : bytes(std::move(bytes)), encodings{{ECI::ISO8859_1, 0}} {} void Content::switchEncoding(CharacterSet cs) { @@ -56,7 +56,7 @@ void Content::switchEncoding(CharacterSet cs) void Content::erase(int pos, int n) { - binary.erase(binary.begin() + pos, binary.begin() + pos + n); + bytes.erase(bytes.begin() + pos, bytes.begin() + pos + n); for (auto& e : encodings) if (e.pos > pos) pos -= n; @@ -64,7 +64,7 @@ void Content::erase(int pos, int n) void Content::insert(int pos, const std::string& str) { - binary.insert(binary.begin() + pos, str.begin(), str.end()); + bytes.insert(bytes.begin() + pos, str.begin(), str.end()); for (auto& e : encodings) if (e.pos > pos) pos += Size(str); @@ -88,7 +88,7 @@ std::wstring Content::text() const ForEachECIBlock([&](ECI eci, int begin, int end) { CharacterSet cs = eci == ECI::Unknown ? fallbackCS : ToCharacterSet(eci); - TextDecoder::Append(wstr, binary.data() + begin, end - begin, cs); + TextDecoder::Append(wstr, bytes.data() + begin, end - begin, cs); }); return wstr; } @@ -121,7 +121,7 @@ std::string Content::utf8Protocol() const lastECI = eci; std::wstring tmp; - TextDecoder::Append(tmp, binary.data() + begin, end - begin, cs); + TextDecoder::Append(tmp, bytes.data() + begin, end - begin, cs); for (auto c : tmp) { res += c; if (c == L'\\') // in the ECI protocol a '\' has to be doubled @@ -132,7 +132,7 @@ std::string Content::utf8Protocol() const return TextUtfEncoding::ToUtf8(res); } -ByteArray Content::binaryECI() const +ByteArray Content::bytesECI() const { if (empty()) return {}; @@ -144,7 +144,7 @@ ByteArray Content::binaryECI() const res += ToString(eci); for (int i = begin; i != end; ++i) { - char c = static_cast(binary[i]); + char c = static_cast(bytes[i]); res += c; if (c == '\\') // in the ECI protocol a '\' has to be doubled res += c; @@ -160,7 +160,7 @@ CharacterSet Content::guessEncoding() const ByteArray input; ForEachECIBlock([&](ECI eci, int begin, int end) { if (eci == ECI::Unknown) - input.insert(input.end(), binary.begin() + begin, binary.begin() + end); + input.insert(input.end(), bytes.begin() + begin, bytes.begin() + end); }); if (input.empty()) @@ -178,7 +178,7 @@ ContentType Content::type() const return ContentType::GS1; // check for the absolut minimum of a ISO 15434 conforming message ("[)>" + RS + digit + digit) - if (binary.size() > 6 && binary.asString(0, 4) == "[)>\x1E" && std::isdigit(binary[4]) && std::isdigit(binary[5])) + if (bytes.size() > 6 && bytes.asString(0, 4) == "[)>\x1E" && std::isdigit(bytes[4]) && std::isdigit(bytes[5])) return ContentType::ISO15434; ECI fallback = ToECI(guessEncoding()); @@ -188,7 +188,7 @@ ContentType Content::type() const eci = fallback; binaryECIs.push_back((!IsText(eci) || (ToInt(eci) > 0 && ToInt(eci) < 28 && ToInt(eci) != 25 - && std::any_of(binary.begin() + begin, binary.begin() + end, + && std::any_of(bytes.begin() + begin, bytes.begin() + end, [](auto c) { return c < 0x20 && c != 0xa && c != 0xd; })))); }); diff --git a/core/src/Content.h b/core/src/Content.h index 34aa6b92d7..a96113300e 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -41,7 +41,7 @@ class Content int pos; }; - ByteArray binary; + ByteArray bytes; std::vector encodings; std::string hintedCharset; std::string applicationIndicator; @@ -49,16 +49,16 @@ class Content bool hasECI = false; Content(); - Content(ByteArray&& binary); + Content(ByteArray&& bytes); void switchEncoding(ECI eci) { switchEncoding(eci, true); } void switchEncoding(CharacterSet cs); - void reserve(int count) { binary.reserve(binary.size() + count); } + void reserve(int count) { bytes.reserve(bytes.size() + count); } - void push_back(uint8_t val) { binary.push_back(val); } - void append(const std::string& str) { binary.insert(binary.end(), str.begin(), str.end()); } - void append(const ByteArray& bytes) { binary.insert(binary.end(), bytes.begin(), bytes.end()); } + void push_back(uint8_t val) { bytes.push_back(val); } + void append(const std::string& str) { bytes.insert(bytes.end(), str.begin(), str.end()); } + void append(const ByteArray& ba) { bytes.insert(bytes.end(), ba.begin(), ba.end()); } void operator+=(char val) { push_back(val); } void operator+=(const std::string& str) { append(str); } @@ -66,12 +66,12 @@ class Content void erase(int pos, int n); void insert(int pos, const std::string& str); - bool empty() const { return binary.empty(); } + bool empty() const { return bytes.empty(); } bool canProcess() const; std::wstring text() const; std::string utf8Protocol() const; - ByteArray binaryECI() const; + ByteArray bytesECI() const; CharacterSet guessEncoding() const; ContentType type() const; }; diff --git a/core/src/Result.h b/core/src/Result.h index 6f196fb198..17d969d5b3 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -46,8 +46,8 @@ class Result const std::wstring& text() const { return _text; } // WARNING: this is an experimental API and may change/disappear - const ByteArray& binary() const { return _content.binary; } - const ByteArray binaryECI() const { return _content.binaryECI(); } + const ByteArray& bytes() const { return _content.bytes; } + const ByteArray bytesECI() const { return _content.bytesECI(); } const std::string utf8Protocol() const { return _content.utf8Protocol(); } const std::string& applicationIndicator() const { return _content.applicationIndicator; } ContentType contentType() const { return _content.type(); } @@ -64,7 +64,7 @@ class Result */ bool isMirrored() const { return _isMirrored; } - /// see binary() above for a proper replacement of rawByes + /// see bytes() above for a proper replacement of rawByes [[deprecated]] const ByteArray& rawBytes() const { return _rawBytes; } [[deprecated]] int numBits() const { return _numBits; } diff --git a/core/src/aztec/AZDecoder.cpp b/core/src/aztec/AZDecoder.cpp index 7d0ad24dbe..b099e7434a 100644 --- a/core/src/aztec/AZDecoder.cpp +++ b/core/src/aztec/AZDecoder.cpp @@ -223,9 +223,9 @@ static ECI ParseECIValue(BitArray::Range& bits, const int flg) /** * See ISO/IEC 24778:2008 Section 8 */ -static StructuredAppendInfo ParseStructuredAppend(ByteArray& binary) +static StructuredAppendInfo ParseStructuredAppend(ByteArray& bytes) { - std::string text(binary.begin(), binary.end()); + std::string text(bytes.begin(), bytes.end()); StructuredAppendInfo sai; std::string::size_type i = 0; @@ -247,7 +247,7 @@ static StructuredAppendInfo ParseStructuredAppend(ByteArray& binary) sai.count = 0; // Choose to mark count as unknown text.erase(0, i + 2); // Remove - binary = ByteArray(text); + bytes = ByteArray(text); return sai; } @@ -314,32 +314,32 @@ DecoderResult Decode(const BitArray& bits, const std::string& characterSet) return DecodeStatus::FormatError; } - if (res.binary.empty()) + if (res.bytes.empty()) return DecodeStatus::FormatError; // Check for Structured Append - need 4 5-bit words, beginning with ML UL, ending with index and count bool haveStructuredAppend = Size(bits) > 20 && ToInt(bits, 0, 5) == 29 // latch to MIXED (from UPPER) && ToInt(bits, 5, 5) == 29; // latch back to UPPER (from MIXED) - StructuredAppendInfo sai = haveStructuredAppend ? ParseStructuredAppend(res.binary) : StructuredAppendInfo(); + StructuredAppendInfo sai = haveStructuredAppend ? ParseStructuredAppend(res.bytes) : StructuredAppendInfo(); // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using // modifiers that indicate ECI protocol (ISO/IEC 24778:2008 Annex F Table F.1) - if (res.binary[0] == 29) { + if (res.bytes[0] == 29) { res.symbology.modifier = '1'; // GS1 res.applicationIndicator = "GS1"; res.erase(0, 1); // Remove FNC1 - } else if (res.binary.size() > 2 && std::isupper(res.binary[0]) && res.binary[1] == 29) { + } else if (res.bytes.size() > 2 && std::isupper(res.bytes[0]) && res.bytes[1] == 29) { // FNC1 following single uppercase letter (the AIM Application Indicator) res.symbology.modifier = '2'; // AIM // TODO: remove the AI from the content? - res.applicationIndicator = res.binary.asString(0, 1); + res.applicationIndicator = res.bytes.asString(0, 1); res.erase(1, 1); // Remove FNC1, // The AIM Application Indicator character "A"-"Z" is left in the stream (ISO/IEC 24778:2008 16.2) - } else if (res.binary.size() > 3 && std::isdigit(res.binary[0]) && std::isdigit(res.binary[1]) && res.binary[2] == 29) { + } else if (res.bytes.size() > 3 && std::isdigit(res.bytes[0]) && std::isdigit(res.bytes[1]) && res.bytes[2] == 29) { // FNC1 following 2 digits (the AIM Application Indicator) res.symbology.modifier = '2'; // AIM - res.applicationIndicator = res.binary.asString(0, 2); + res.applicationIndicator = res.bytes.asString(0, 2); res.erase(2, 1); // Remove FNC1 // The AIM Application Indicator characters "00"-"99" are left in the stream (ISO/IEC 24778:2008 16.2) } diff --git a/core/src/maxicode/MCDecoder.cpp b/core/src/maxicode/MCDecoder.cpp index 8d4be16bea..16292730ae 100644 --- a/core/src/maxicode/MCDecoder.cpp +++ b/core/src/maxicode/MCDecoder.cpp @@ -281,7 +281,7 @@ DecoderResult Decode(ByteArray&& bytes, const int mode, const std::string& /*cha auto country = ToString(GetCountry(bytes), 3); auto service = ToString(GetServiceClass(bytes), 3); GetMessage(bytes, 10, 84, result, sai); - if (result.binary.asString().compare(0, 7, "[)>\u001E01\u001D") == 0) // "[)>" + RS + "01" + GS + if (result.bytes.asString().compare(0, 7, "[)>\u001E01\u001D") == 0) // "[)>" + RS + "01" + GS result.insert(9, postcode + GS + country + GS + service + GS); else result.insert(0, postcode + GS + country + GS + service + GS); diff --git a/core/src/qrcode/QRDecoder.cpp b/core/src/qrcode/QRDecoder.cpp index 703d28d941..e4ebed8192 100644 --- a/core/src/qrcode/QRDecoder.cpp +++ b/core/src/qrcode/QRDecoder.cpp @@ -292,7 +292,7 @@ DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCo result += static_cast(appInd - 100); else throw std::runtime_error("Invalid AIM Application Indicator"); - result.applicationIndicator = result.binary.asString(); // see also above + result.applicationIndicator = result.bytes.asString(); // see also above break; case CodecMode::STRUCTURED_APPEND: // sequence number and parity is added later to the result metadata diff --git a/example/ZXingQtReader.h b/example/ZXingQtReader.h index 9db4a7c528..7435e56c85 100644 --- a/example/ZXingQtReader.h +++ b/example/ZXingQtReader.h @@ -97,13 +97,13 @@ class Result : private ZXing::Result Q_PROPERTY(BarcodeFormat format READ format) Q_PROPERTY(QString formatName READ formatName) Q_PROPERTY(QString text READ text) - Q_PROPERTY(QByteArray binary READ binary) + Q_PROPERTY(QByteArray bytes READ bytes) Q_PROPERTY(bool isValid READ isValid) Q_PROPERTY(DecodeStatus status READ status) Q_PROPERTY(Position position READ position) QString _text; - QByteArray _binary; + QByteArray _bytes; Position _position; public: @@ -111,7 +111,7 @@ class Result : private ZXing::Result explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)) { _text = QString::fromWCharArray(ZXing::Result::text().c_str()); - _binary = QByteArray(reinterpret_cast(ZXing::Result::binary().data()), Size(ZXing::Result::binary())); + _bytes = QByteArray(reinterpret_cast(ZXing::Result::bytes().data()), Size(ZXing::Result::bytes())); auto& pos = ZXing::Result::position(); auto qp = [&pos](int i) { return QPoint(pos[i].x, pos[i].y); }; _position = {qp(0), qp(1), qp(2), qp(3)}; @@ -123,7 +123,7 @@ class Result : private ZXing::Result DecodeStatus status() const { return static_cast(ZXing::Result::status()); } QString formatName() const { return QString::fromStdString(ZXing::ToString(ZXing::Result::format())); } const QString& text() const { return _text; } - const QByteArray& binary() const { return _binary; } + const QByteArray& bytes() const { return _bytes; } const Position& position() const { return _position; } // For debugging/development diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 9baf5961f8..937da9077a 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -160,7 +160,7 @@ int main(int argc, char* argv[]) ret |= static_cast(result.status()); if (binaryOutput) { - std::cout.write(reinterpret_cast(result.binary().data()), result.binary().size()); + std::cout.write(reinterpret_cast(result.bytes().data()), result.bytes().size()); continue; } @@ -183,9 +183,9 @@ int main(int argc, char* argv[]) firstFile = false; } std::cout << "Text: \"" << ToUtf8(result.text(), angleEscape) << "\"\n" - << "Binary: \"" << ToHex(result.binary()) << "\"\n" + << "Bytes: \"" << ToHex(result.bytes()) << "\"\n" << "TextECI: \"" << result.utf8Protocol() << "\"\n" - << "BinaryECI: \"" << ToHex(result.binaryECI()) << "\"\n" + << "BytesECI: \"" << ToHex(result.bytesECI()) << "\"\n" << "Format: " << ToString(result.format()) << "\n" << "Identifier: " << result.symbologyIdentifier() << "\n" << "Content: " << ToString(result.contentType()) << "\n" diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 8864d224a8..108e91f9b8 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -141,8 +141,8 @@ static std::string checkResult(const fs::path& imgPath, std::string_view expecte if (auto expected = readFile(".bin")) { ByteArray binaryExpected(*expected); - return result.binary() != binaryExpected - ? fmt::format("Content mismatch: expected '{}' but got '{}'", ToHex(binaryExpected), ToHex(result.binary())) + return result.bytes() != binaryExpected + ? fmt::format("Content mismatch: expected '{}' but got '{}'", ToHex(binaryExpected), ToHex(result.bytes())) : ""; } @@ -266,7 +266,7 @@ static Result readMultiple(const std::vector& imgPaths, std::string_vi Content content; for (const auto& r : allResults) { text.append(r.text()); - content.append(r.binary()); + content.append(r.bytes()); } const auto& first = allResults.front(); diff --git a/test/unit/ContentTest.cpp b/test/unit/ContentTest.cpp index b200f51530..19c3a5f8b1 100644 --- a/test/unit/ContentTest.cpp +++ b/test/unit/ContentTest.cpp @@ -53,7 +53,7 @@ TEST(ContentTest, GuessEncoding) c.append(ByteArray{'A', 0xE9, 'Z'}); EXPECT_EQ(c.guessEncoding(), CharacterSet::ISO8859_1); EXPECT_EQ(c.text(), L"A\u00E9Z"); - EXPECT_EQ(c.binaryECI(), c.binary); + EXPECT_EQ(c.bytesECI(), c.bytes); } { // guess Shift_JIS @@ -73,7 +73,7 @@ TEST(ContentTest, ECI) c.append(ByteArray{'A', 0xE9, 'Z'}); EXPECT_TRUE(c.hasECI); EXPECT_EQ(c.text(), L"A\u00E9ZA\u0449Z"); - EXPECT_EQ(c.binaryECI().asString(), std::string_view("\\000003A\xE9Z\\000007A\xE9Z")); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\xE9Z\\000007A\xE9Z")); } { // switch ECI -> latin1 for unknown (instead of Shift_JIS) @@ -82,13 +82,13 @@ TEST(ContentTest, ECI) c.switchEncoding(ECI::ISO8859_5); c.append(ByteArray{'A', 0xE9, 'Z'}); EXPECT_EQ(c.text(), L"A\u0083\u0065ZA\u0449Z"); - EXPECT_EQ(c.binaryECI().asString(), std::string_view("\\000003A\x83\x65Z\\000007A\xE9Z")); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\x83\x65Z\\000007A\xE9Z")); } { // double '\' Content c; c.append("C:\\Test"); EXPECT_EQ(c.text(), L"C:\\Test"); - EXPECT_EQ(c.binaryECI().asString(), std::string_view("C:\\\\Test")); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("C:\\\\Test")); } } diff --git a/test/unit/aztec/AZEncodeDecodeTest.cpp b/test/unit/aztec/AZEncodeDecodeTest.cpp index 54c7d2fe7f..b28b9135e3 100644 --- a/test/unit/aztec/AZEncodeDecodeTest.cpp +++ b/test/unit/aztec/AZEncodeDecodeTest.cpp @@ -88,7 +88,7 @@ namespace { DecoderResult res = parse(matrix.copy(), aztec.compact, aztec.codeWords, aztec.layers); EXPECT_EQ(res.isValid(), true); - EXPECT_EQ(res.content().binary, ByteArray(textBytes)); + EXPECT_EQ(res.content().bytes, ByteArray(textBytes)); // Check error correction by introducing up to eccPercent/2 errors int ecWords = aztec.codeWords * eccPercent / 100 / 2; @@ -105,7 +105,7 @@ namespace { } res = parse(std::move(matrix), aztec.compact, aztec.codeWords, aztec.layers); EXPECT_EQ(res.isValid(), true); - EXPECT_EQ(res.content().binary, ByteArray(textBytes)); + EXPECT_EQ(res.content().bytes, ByteArray(textBytes)); } } diff --git a/test/unit/aztec/AZHighLevelEncoderTest.cpp b/test/unit/aztec/AZHighLevelEncoderTest.cpp index 7e80feb770..5f82f99d4a 100644 --- a/test/unit/aztec/AZHighLevelEncoderTest.cpp +++ b/test/unit/aztec/AZHighLevelEncoderTest.cpp @@ -38,7 +38,7 @@ namespace { BitArray bits = Aztec::HighLevelEncoder::Encode(s); int receivedBitCount = Size(Utility::ToString(bits)); EXPECT_EQ(receivedBitCount, expectedReceivedBits) << "highLevelEncode() failed for input string: " + s; - EXPECT_EQ(ByteArray(s), Aztec::Decode(bits).content().binary); + EXPECT_EQ(ByteArray(s), Aztec::Decode(bits).content().bytes); } } diff --git a/test/unit/pdf417/PDF417DecoderTest.cpp b/test/unit/pdf417/PDF417DecoderTest.cpp index 5b3668843b..2df84c85db 100644 --- a/test/unit/pdf417/PDF417DecoderTest.cpp +++ b/test/unit/pdf417/PDF417DecoderTest.cpp @@ -509,7 +509,7 @@ TEST(PDF417DecoderTest, ECIMultipleNumeric) TEST(PDF417DecoderTest, ECIInvalid) { EXPECT_EQ(decode({ 4, 927, 901, 0 }), L""); // non-charset ECI > 899 -> empty text result - EXPECT_EQ(parse({4, 927, 901, 0}).content().binary, ByteArray("AA")); // non-charset ECI > 899 -> ignored in binary result + EXPECT_EQ(parse({4, 927, 901, 0}).content().bytes, ByteArray("AA")); // non-charset ECI > 899 -> ignored in binary result EXPECT_EQ(decode({ 3, 0, 927 }), L"AA"); // Malformed ECI at end silently ignored } From 27ef8f64ab278c75d7e23b910516a11c4bdd8094 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 7 Jun 2022 12:29:29 +0200 Subject: [PATCH 28/88] python: add the `bytes` property to the Result struct --- wrappers/python/test.py | 1 + wrappers/python/zxing.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/wrappers/python/test.py b/wrappers/python/test.py index 350d08cd0e..8f37dbce59 100644 --- a/wrappers/python/test.py +++ b/wrappers/python/test.py @@ -23,6 +23,7 @@ def check_res(self, res, format, text): self.assertTrue(res.valid) self.assertEqual(res.format, format) self.assertEqual(res.text, text) + self.assertEqual(res.bytes, bytes(text, 'utf-8')) self.assertEqual(res.orientation, 0) def test_write_read_cycle(self): diff --git a/wrappers/python/zxing.cpp b/wrappers/python/zxing.cpp index 60db5387a2..72336d5c0c 100644 --- a/wrappers/python/zxing.cpp +++ b/wrappers/python/zxing.cpp @@ -205,6 +205,9 @@ PYBIND11_MODULE(zxingcpp, m) .def_property_readonly("text", &Result::text, ":return: text of the decoded symbol\n" ":rtype: str") + .def_property_readonly("bytes", [](const Result& res) { return py::bytes(res.bytes().asString()); }, + ":return: uninterpreted bytes of the decoded symbol\n" + ":rtype: bytes") .def_property_readonly("format", &Result::format, ":return: decoded symbol format\n" ":rtype: zxing.BarcodeFormat") From 97adf175361d8db90de48c7cb4d30024a38c1d4e Mon Sep 17 00:00:00 2001 From: axxel Date: Wed, 8 Jun 2022 10:27:29 +0200 Subject: [PATCH 29/88] Result: add MergeStructuredAppendResults() --- core/src/Content.cpp | 7 +++++++ core/src/Content.h | 1 + core/src/Result.cpp | 23 +++++++++++++++++++++++ core/src/Result.h | 7 +++++++ test/blackbox/BlackboxTestRunner.cpp | 27 ++------------------------- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 90dd68d9f8..15ad8787d5 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -54,6 +54,13 @@ void Content::switchEncoding(CharacterSet cs) switchEncoding(ToECI(cs), false); } +void Content::append(const Content& other) +{ + for (auto& e : other.encodings) + encodings.push_back({e.eci, Size(bytes) + e.pos}); + append(other.bytes); +} + void Content::erase(int pos, int n) { bytes.erase(bytes.begin() + pos, bytes.begin() + pos + n); diff --git a/core/src/Content.h b/core/src/Content.h index a96113300e..f429286d9f 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -59,6 +59,7 @@ class Content void push_back(uint8_t val) { bytes.push_back(val); } void append(const std::string& str) { bytes.insert(bytes.end(), str.begin(), str.end()); } void append(const ByteArray& ba) { bytes.insert(bytes.end(), ba.begin(), ba.end()); } + void append(const Content& other); void operator+=(char val) { push_back(val); } void operator+=(const std::string& str) { append(str); } diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 9d3c417868..6850dd167e 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -10,6 +10,7 @@ #include "TextDecoder.h" #include +#include #include namespace ZXing { @@ -69,4 +70,26 @@ bool Result::operator==(const Result& o) const return std::min(dTop, dBot) < length / 2; } +Result MergeStructuredAppendResults(const Results& results) +{ + if (results.empty()) + return Result(DecodeStatus::NotFound); + + std::list allResults(results.begin(), results.end()); + allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); }); + + if (allResults.back().sequenceSize() != Size(allResults) || + !std::all_of(allResults.begin(), allResults.end(), + [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); })) + return Result(DecodeStatus::FormatError); + + Result res = allResults.front(); + for (auto i = std::next(allResults.begin()); i != allResults.end(); ++i) + res._content.append(i->_content); + + res._text = res._content.text(); + + return res; +} + } // ZXing diff --git a/core/src/Result.h b/core/src/Result.h index 17d969d5b3..13ce7f2bb8 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -114,6 +114,8 @@ class Result bool operator==(const Result& o) const; + friend Result MergeStructuredAppendResults(const std::vector& results); + private: DecodeStatus _status = DecodeStatus::NoError; BarcodeFormat _format = BarcodeFormat::None; @@ -132,4 +134,9 @@ class Result using Results = std::vector; +/** + * @brief Merge a list of Results from one Structured Append set to a single result + */ +Result MergeStructuredAppendResults(const Results& results); + } // ZXing diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 108e91f9b8..4fff96eb5d 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -245,37 +245,14 @@ static void doRunTests(const fs::path& directory, std::string_view format, int t static Result readMultiple(const std::vector& imgPaths, std::string_view format) { - std::list allResults; + Results allResults; for (const auto& imgPath : imgPaths) { auto results = ReadBarcodes(ImageLoader::load(imgPath), DecodeHints().setFormats(BarcodeFormatFromString(format.data())).setTryDownscale(false)); allResults.insert(allResults.end(), results.begin(), results.end()); } - if (allResults.empty()) - return Result(DecodeStatus::NotFound); - - allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); }); - - if (allResults.back().sequenceSize() != Size(allResults) || - !std::all_of(allResults.begin(), allResults.end(), - [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); })) - return Result(DecodeStatus::FormatError); - - std::wstring text; - Content content; - for (const auto& r : allResults) { - text.append(r.text()); - content.append(r.bytes()); - } - - const auto& first = allResults.front(); - return {DecoderResult({}, std::move(text), std::move(content)) - .setStructuredAppend({first.sequenceIndex(), first.sequenceSize(), first.sequenceId()}) - .setSymbologyIdentifier(first.symbologyIdentifier()) - .setReaderInit(first.readerInit()), - {}, - first.format()}; + return MergeStructuredAppendResults(allResults); } static void doRunStructuredAppendTest(const fs::path& directory, std::string_view format, int totalTests, From e6b8558b6a713f622fb1c2a264fc5e73734dacbc Mon Sep 17 00:00:00 2001 From: axxel Date: Wed, 8 Jun 2022 10:59:36 +0200 Subject: [PATCH 30/88] DecoderResult: remove `text` and `symbologyIdentifier` member variables This further consolidates the internal structure with respect to the new `Content` class and its application. --- core/src/Content.cpp | 4 ++- core/src/Content.h | 2 +- core/src/DecoderResult.h | 26 ++++--------------- core/src/Result.cpp | 6 ++--- core/src/aztec/AZDecoder.cpp | 2 +- core/src/datamatrix/DMDecoder.cpp | 2 +- core/src/maxicode/MCDecoder.cpp | 2 +- core/src/oned/ODDataBarExpandedReader.cpp | 5 ++-- core/src/oned/ODDataBarReader.cpp | 3 +-- core/src/pdf417/PDFDecodedBitStreamParser.cpp | 2 +- core/src/qrcode/QRDecoder.cpp | 2 +- 11 files changed, 20 insertions(+), 36 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 15ad8787d5..14fddaad2d 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -47,7 +47,9 @@ void Content::switchEncoding(ECI eci, bool isECI) Content::Content() : encodings({{ECI::Unknown, 0}}) {} -Content::Content(ByteArray&& bytes) : bytes(std::move(bytes)), encodings{{ECI::ISO8859_1, 0}} {} +Content::Content(ByteArray&& bytes, SymbologyIdentifier si) + : bytes(std::move(bytes)), encodings{{ECI::ISO8859_1, 0}}, symbology(si) +{} void Content::switchEncoding(CharacterSet cs) { diff --git a/core/src/Content.h b/core/src/Content.h index f429286d9f..5d1f982069 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -49,7 +49,7 @@ class Content bool hasECI = false; Content(); - Content(ByteArray&& bytes); + Content(ByteArray&& bytes, SymbologyIdentifier si); void switchEncoding(ECI eci) { switchEncoding(eci, true); } void switchEncoding(CharacterSet cs); diff --git a/core/src/DecoderResult.h b/core/src/DecoderResult.h index 8714396f29..a6ce5e6ab3 100644 --- a/core/src/DecoderResult.h +++ b/core/src/DecoderResult.h @@ -20,25 +20,16 @@ namespace ZXing { class CustomData; -/** -*

Encapsulates the result of decoding a matrix of bits. This typically -* applies to 2D barcode formats. For now it contains the raw bytes obtained, -* as well as a string interpretation of those bytes, if applicable.

-* -* @author Sean Owen -*/ class DecoderResult { DecodeStatus _status = DecodeStatus::NoError; ByteArray _rawBytes; Content _content; int _numBits = 0; - std::wstring _text; std::string _ecLevel; int _errorsCorrected = -1; int _erasures = -1; int _lineCount = 0; - std::string _symbologyIdentifier; StructuredAppendInfo _structuredAppend; bool _isMirrored = false; bool _readerInit = false; @@ -49,17 +40,9 @@ class DecoderResult public: DecoderResult(DecodeStatus status) : _status(status) {} - DecoderResult(ByteArray&& rawBytes, std::wstring&& text, Content&& binary = {}) - : _rawBytes(std::move(rawBytes)), _content(std::move(binary)), _text(std::move(text)) + DecoderResult(ByteArray&& rawBytes, Content&& bytes = {}) : _rawBytes(std::move(rawBytes)), _content(std::move(bytes)) { _numBits = 8 * Size(_rawBytes); - if (_text.empty()) - _text = _content.text(); - // provide some best guess fallback for barcodes not, yet supporting the content info - if (_content.empty() && std::all_of(_text.begin(), _text.end(), [](auto c) { return c < 256; })) - std::for_each(_text.begin(), _text.end(), [this](wchar_t c) { _content += static_cast(c); }); - if (_content.symbology.code != 0) - _symbologyIdentifier = _content.symbology.toString(); } DecoderResult() = default; @@ -71,11 +54,13 @@ class DecoderResult const ByteArray& rawBytes() const & { return _rawBytes; } ByteArray&& rawBytes() && { return std::move(_rawBytes); } - const std::wstring& text() const & { return _text; } - std::wstring&& text() && { return std::move(_text); } const Content& content() const & { return _content; } Content&& content() && { return std::move(_content); } + // to keep the unit tests happy for now: + std::wstring text() const { return _content.text(); } + std::string symbologyIdentifier() const { return _content.symbology.toString(false); } + // Simple macro to set up getter/setter methods that save lots of boilerplate. // It sets up a standard 'const & () const', 2 setters for setting lvalues via // copy and 2 for setting rvalues via move. They are provided each to work @@ -96,7 +81,6 @@ class DecoderResult ZX_PROPERTY(int, errorsCorrected, setErrorsCorrected) ZX_PROPERTY(int, erasures, setErasures) ZX_PROPERTY(int, lineCount, setLineCount) - ZX_PROPERTY(std::string, symbologyIdentifier, setSymbologyIdentifier) ZX_PROPERTY(StructuredAppendInfo, structuredAppend, setStructuredAppend) ZX_PROPERTY(bool, isMirrored, setIsMirrored) ZX_PROPERTY(bool, readerInit, setReaderInit) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 6850dd167e..b4948f3721 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -19,7 +19,7 @@ Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFor SymbologyIdentifier si, ByteArray&& rawBytes, const bool readerInit) : _format(format), - _content({ByteArray(text)}), + _content({ByteArray(text)}, si), _text(TextDecoder::FromLatin1(text)), _position(Line(y, xStart, xStop)), _rawBytes(std::move(rawBytes)), @@ -33,12 +33,12 @@ Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat : _status(decodeResult.errorCode()), _format(format), _content(std::move(decodeResult).content()), - _text(std::move(decodeResult).text()), + _text(_content.text()), _position(std::move(position)), _rawBytes(std::move(decodeResult).rawBytes()), _numBits(decodeResult.numBits()), _ecLevel(TextDecoder::FromLatin1(decodeResult.ecLevel())), - _symbologyIdentifier(decodeResult.symbologyIdentifier()), + _symbologyIdentifier(_content.symbology.toString(false)), _sai(decodeResult.structuredAppend()), _isMirrored(decodeResult.isMirrored()), _readerInit(decodeResult.readerInit()), diff --git a/core/src/aztec/AZDecoder.cpp b/core/src/aztec/AZDecoder.cpp index b099e7434a..86b802c532 100644 --- a/core/src/aztec/AZDecoder.cpp +++ b/core/src/aztec/AZDecoder.cpp @@ -347,7 +347,7 @@ DecoderResult Decode(const BitArray& bits, const std::string& characterSet) if (sai.index != -1) res.symbology.modifier += 6; // TODO: this is wrong as long as we remove the sai info from the content in ParseStructuredAppend - return DecoderResult(bits.toBytes(), {}, std::move(res)).setNumBits(Size(bits)).setStructuredAppend(sai); + return DecoderResult(bits.toBytes(), std::move(res)).setNumBits(Size(bits)).setStructuredAppend(sai); } DecoderResult Decode(const DetectorResult& detectorResult, const std::string& characterSet) diff --git a/core/src/datamatrix/DMDecoder.cpp b/core/src/datamatrix/DMDecoder.cpp index efd6f1bea7..1b1f5a785d 100644 --- a/core/src/datamatrix/DMDecoder.cpp +++ b/core/src/datamatrix/DMDecoder.cpp @@ -360,7 +360,7 @@ DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const b result.applicationIndicator = result.symbology.modifier == '2' ? "GS1" : ""; result.symbology.modifier += isDMRE * 6; - return DecoderResult(std::move(bytes), {}, std::move(result)) + return DecoderResult(std::move(bytes), std::move(result)) .setStructuredAppend(sai) .setReaderInit(readerInit); } diff --git a/core/src/maxicode/MCDecoder.cpp b/core/src/maxicode/MCDecoder.cpp index 16292730ae..e3a781f2bb 100644 --- a/core/src/maxicode/MCDecoder.cpp +++ b/core/src/maxicode/MCDecoder.cpp @@ -292,7 +292,7 @@ DecoderResult Decode(ByteArray&& bytes, const int mode, const std::string& /*cha case 5: GetMessage(bytes, 1, 77, result, sai); break; } - return DecoderResult(std::move(bytes), {}, std::move(result)) + return DecoderResult(std::move(bytes), std::move(result)) .setEcLevel(std::to_string(mode)) .setStructuredAppend(sai) .setReaderInit(mode == 6); diff --git a/core/src/oned/ODDataBarExpandedReader.cpp b/core/src/oned/ODDataBarExpandedReader.cpp index 42fed5a6fa..2260931761 100644 --- a/core/src/oned/ODDataBarExpandedReader.cpp +++ b/core/src/oned/ODDataBarExpandedReader.cpp @@ -375,9 +375,8 @@ Result DataBarExpandedReader::decodePattern(int rowNumber, PatternView& view, // TODO: EstimatePosition misses part of the symbol in the stacked case where the last row contains less pairs than // the first - return {DecoderResult({}, TextDecoder::FromLatin1(txt)) - .setSymbologyIdentifier("]e0") // ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 - .setLineCount(EstimateLineCount(pairs.front(), pairs.back())), + // Symbology identifier: ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 + return {DecoderResult({}, Content(ByteArray(txt), {'e', '0'})).setLineCount(EstimateLineCount(pairs.front(), pairs.back())), EstimatePosition(pairs.front(), pairs.back()), BarcodeFormat::DataBarExpanded}; } diff --git a/core/src/oned/ODDataBarReader.cpp b/core/src/oned/ODDataBarReader.cpp index b9f4fa9601..a39ec9f741 100644 --- a/core/src/oned/ODDataBarReader.cpp +++ b/core/src/oned/ODDataBarReader.cpp @@ -198,8 +198,7 @@ Result DataBarReader::decodePattern(int rowNumber, PatternView& next, for (const auto& rightPair : prevState->rightPairs) if (ChecksumIsValid(leftPair, rightPair)) { // Symbology identifier ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 - Result res{DecoderResult({}, TextDecoder::FromLatin1(ConstructText(leftPair, rightPair))) - .setSymbologyIdentifier("]e0") + Result res{DecoderResult({}, Content(ByteArray(ConstructText(leftPair, rightPair)), {'e', '0'})) .setLineCount(EstimateLineCount(leftPair, rightPair)), EstimatePosition(leftPair, rightPair), BarcodeFormat::DataBar}; diff --git a/core/src/pdf417/PDFDecodedBitStreamParser.cpp b/core/src/pdf417/PDFDecodedBitStreamParser.cpp index 515c066b1d..6f7a835309 100644 --- a/core/src/pdf417/PDFDecodedBitStreamParser.cpp +++ b/core/src/pdf417/PDFDecodedBitStreamParser.cpp @@ -791,7 +791,7 @@ DecodedBitStreamParser::Decode(const std::vector& codewords, int ecLevel, c sai.id = resultMetadata->fileId(); } - return DecoderResult(ByteArray(), {}, std::move(result)) + return DecoderResult({}, std::move(result)) .setEcLevel(std::to_string(ecLevel)) .setStructuredAppend(sai) .setReaderInit(readerInit) diff --git a/core/src/qrcode/QRDecoder.cpp b/core/src/qrcode/QRDecoder.cpp index e4ebed8192..29d35f0ac3 100644 --- a/core/src/qrcode/QRDecoder.cpp +++ b/core/src/qrcode/QRDecoder.cpp @@ -338,7 +338,7 @@ DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCo return DecodeStatus::FormatError; } - return DecoderResult(std::move(bytes), {}, std::move(result)) + return DecoderResult(std::move(bytes), std::move(result)) .setEcLevel(ToString(ecLevel)) .setStructuredAppend(structuredAppend); } From 9633b25c4244c3f06ee700a8db1df0bb1ac51fd8 Mon Sep 17 00:00:00 2001 From: axxel Date: Wed, 8 Jun 2022 11:50:33 +0200 Subject: [PATCH 31/88] TextDecoder: non-printable ASCII control chars -> probably not Shift_JIS This fixes a regression with some Aztec binary symbols reported by @vkrause. --- core/src/TextDecoder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/TextDecoder.cpp b/core/src/TextDecoder.cpp index 4df8a65f14..b9835c77ad 100644 --- a/core/src/TextDecoder.cpp +++ b/core/src/TextDecoder.cpp @@ -426,6 +426,9 @@ TextDecoder::GuessEncoding(const uint8_t* bytes, size_t length, CharacterSet fal else if (value == 0x80 || value == 0xA0 || value > 0xEF) { canBeShiftJIS = false; } + else if (value < 0x20 && value != 0xa && value != 0xd) { + canBeShiftJIS = false; // use non-printable ASCII as indication for binary content + } else if (value > 0xA0 && value < 0xE0) { sjisKatakanaChars++; sjisCurDoubleBytesWordLength = 0; From 84ec5b971907fb584da2a2aa312ffcee8fa61a2d Mon Sep 17 00:00:00 2001 From: axxel Date: Thu, 9 Jun 2022 12:53:47 +0200 Subject: [PATCH 32/88] ECI: change handling of pseudo-ECIs to fix MergeStructuredAppendResults This fixes the cross symbol ECI sample discussed in https://github.com/nu-book/zxing-cpp/issues/334#issuecomment-1150297982 --- core/src/Content.cpp | 34 ++++++++++++++++----------- test/blackbox/BlackboxTestRunner.cpp | 4 ++-- test/samples/pdf417-4/03-01.png | Bin 0 -> 583 bytes test/samples/pdf417-4/03.txt | 1 + 4 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 test/samples/pdf417-4/03-01.png create mode 100644 test/samples/pdf417-4/03.txt diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 14fddaad2d..21fde3c976 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -22,6 +22,12 @@ std::string ToString(ContentType type) template void Content::ForEachECIBlock(FUNC func) const { + ECI defaultECI = hasECI ? ECI::ISO8859_1 : ECI::Unknown; + if (encodings.empty()) + func(defaultECI, 0, Size(bytes)); + else if (encodings.front().pos != 0) + func(defaultECI, 0, encodings.front().pos); + for (int i = 0; i < Size(encodings); ++i) { auto [eci, start] = encodings[i]; int end = i + 1 == Size(encodings) ? Size(bytes) : encodings[i + 1].pos; @@ -33,23 +39,18 @@ void Content::ForEachECIBlock(FUNC func) const void Content::switchEncoding(ECI eci, bool isECI) { - // replace all non-ECI entries on first ECI entry with default ECI + // remove all non-ECI entries on first ECI entry if (isECI && !hasECI) - encodings = {{ECI::ISO8859_1, 0}}; - if (isECI || !hasECI) { - if (encodings.back().pos == Size(bytes)) - encodings.back().eci = eci; // no point in recording 0 length segments - else - encodings.push_back({eci, Size(bytes)}); - } + encodings.clear(); + if (isECI || !hasECI) + encodings.push_back({eci, Size(bytes)}); + hasECI |= isECI; } -Content::Content() : encodings({{ECI::Unknown, 0}}) {} +Content::Content() {} -Content::Content(ByteArray&& bytes, SymbologyIdentifier si) - : bytes(std::move(bytes)), encodings{{ECI::ISO8859_1, 0}}, symbology(si) -{} +Content::Content(ByteArray&& bytes, SymbologyIdentifier si) : bytes(std::move(bytes)), symbology(si) {} void Content::switchEncoding(CharacterSet cs) { @@ -58,9 +59,14 @@ void Content::switchEncoding(CharacterSet cs) void Content::append(const Content& other) { - for (auto& e : other.encodings) - encodings.push_back({e.eci, Size(bytes) + e.pos}); + if (!hasECI && other.hasECI) + encodings.clear(); + if (other.hasECI || !hasECI) + for (auto& e : other.encodings) + encodings.push_back({e.eci, Size(bytes) + e.pos}); append(other.bytes); + + hasECI |= other.hasECI; } void Content::erase(int pos, int n) diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 4fff96eb5d..2d7fe005dd 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -615,8 +615,8 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set { 7, 0, pure }, }); - runStructuredAppendTest("pdf417-4", "PDF417", 2, { - { 2, 2, 0 }, + runStructuredAppendTest("pdf417-4", "PDF417", 3, { + { 3, 3, 0 }, }); runTests("falsepositives-1", "None", 26, { diff --git a/test/samples/pdf417-4/03-01.png b/test/samples/pdf417-4/03-01.png new file mode 100644 index 0000000000000000000000000000000000000000..3e54a6e9e2b882192aa8601545b77df60e4d388d GIT binary patch literal 583 zcmV-N0=WH&P)Px#22e~?MF0Q*|NsA`*`M7200G}gL_t(o!|m6xswOcA z1z^Ee@Kpp`!B-d327DDEt&q)s*=n1u7S_w1YA|0DGEB~a`?sfI7->Lt)VNE8iYNEuj}jBVf%#~nhIgCc5eK>;hcb9J0l^)@r=1O5n8IK*p|~DiOMzAw zoJG-hGy#RRe8X`Lq74okdoRpCh5~pGHp}^sU>g;Sh*NPe{ zbrp^#T6e9?R<7&=#c#k<$@fb^Kja^i0M%0CRt)#kopQNQ!GJn#DuLaEo-VL`UC~EY zPbNphJ2Tui-U!9|{N6?rK`^`a@>}>SXW1B|Nh!9W)cqV|B(B<=J({49z3`SCY|*dI zDd=c&jDN>9-yHh7s>YuuJ&P3Drz9i;ZGQQ!WrNHnZ`B~irtPyBWq3^(@Rov~Ci- zB(HWylbvwO0^jQLPxjbZJen-wmz Date: Thu, 9 Jun 2022 12:55:00 +0200 Subject: [PATCH 33/88] Result: clear position and structuredAppendIndex in merged result --- core/src/Result.cpp | 2 ++ core/src/Result.h | 2 +- test/samples/qrcode-7/01.result.txt | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index b4948f3721..a516f9087b 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -88,6 +88,8 @@ Result MergeStructuredAppendResults(const Results& results) res._content.append(i->_content); res._text = res._content.text(); + res._position = {}; + res._sai.index = -1; return res; } diff --git a/core/src/Result.h b/core/src/Result.h index 13ce7f2bb8..f52d41e0b6 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -99,7 +99,7 @@ class Result const std::string& sequenceId() const { return _sai.id; } bool isLastInSequence() const { return sequenceSize() == sequenceIndex() + 1; } - bool isPartOfSequence() const { return sequenceSize() > -1; } + bool isPartOfSequence() const { return sequenceSize() > -1 && sequenceIndex() > -1; } /** * @brief readerInit Set if Reader Initialisation/Programming symbol. diff --git a/test/samples/qrcode-7/01.result.txt b/test/samples/qrcode-7/01.result.txt index 7867b23fec..0631ce5a33 100644 --- a/test/samples/qrcode-7/01.result.txt +++ b/test/samples/qrcode-7/01.result.txt @@ -1,6 +1,6 @@ symbologyIdentifier=]Q1 # ecLevel not set when "runStructuredAppendTest" sequenceSize=4 -# sequenceIndex set to first when "runStructuredAppendTest" -sequenceIndex=0 +# sequenceIndex set to -1 in MergeStructuredAppendResults +sequenceIndex=-1 sequenceId=95 From 69576e3e9654c1497a167869b38fecca6ac6d60b Mon Sep 17 00:00:00 2001 From: axxel Date: Thu, 9 Jun 2022 13:43:38 +0200 Subject: [PATCH 34/88] Result: add MergeStructuredAppendSequences for automatically merging Add some automatic structured append sequence merging to ZXingReader. All merged sequences are reported under the last file name (for now). --- core/src/Result.cpp | 21 ++++++++++++++++++++- core/src/Result.h | 11 ++++++++--- example/ZXingReader.cpp | 11 +++++++++++ test/blackbox/BlackboxTestRunner.cpp | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index a516f9087b..b077830286 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -11,6 +11,7 @@ #include #include +#include #include namespace ZXing { @@ -70,7 +71,7 @@ bool Result::operator==(const Result& o) const return std::min(dTop, dBot) < length / 2; } -Result MergeStructuredAppendResults(const Results& results) +Result MergeStructuredAppendSequence(const Results& results) { if (results.empty()) return Result(DecodeStatus::NotFound); @@ -94,4 +95,22 @@ Result MergeStructuredAppendResults(const Results& results) return res; } +Results MergeStructuredAppendSequences(const Results& results) +{ + std::map sas; + for (auto& res : results) { + if (res.isPartOfSequence()) + sas[res.sequenceId()].push_back(res); + } + + Results saiResults; + for (auto& [id, seq] : sas) { + auto res = MergeStructuredAppendSequence(seq); + if (res.isValid()) + saiResults.push_back(std::move(res)); + } + + return saiResults; +} + } // ZXing diff --git a/core/src/Result.h b/core/src/Result.h index f52d41e0b6..8a07381e1c 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -114,7 +114,7 @@ class Result bool operator==(const Result& o) const; - friend Result MergeStructuredAppendResults(const std::vector& results); + friend Result MergeStructuredAppendSequence(const std::vector& results); private: DecodeStatus _status = DecodeStatus::NoError; @@ -135,8 +135,13 @@ class Result using Results = std::vector; /** - * @brief Merge a list of Results from one Structured Append set to a single result + * @brief Merge a list of Results from one Structured Append sequence to a single result */ -Result MergeStructuredAppendResults(const Results& results); +Result MergeStructuredAppendSequence(const Results& results); + +/** + * @brief Automatically merge all structured append sequences found in the given results + */ +Results MergeStructuredAppendSequences(const Results& results); } // ZXing diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 937da9077a..578e7714c6 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -115,6 +115,7 @@ int main(int argc, char* argv[]) { DecodeHints hints; std::vector filePaths; + Results allResults; std::string outPath; bool oneLine = false; bool angleEscape = false; @@ -152,6 +153,13 @@ int main(int argc, char* argv[]) if (results.empty()) results.emplace_back(DecodeStatus::NotFound); + allResults.insert(allResults.end(), results.begin(), results.end()); + if (filePath == filePaths.back()) { + auto merged = MergeStructuredAppendSequences(allResults); + // report all merged sequences as part of the last file to make the logic not overly complicated here + results.insert(results.end(), merged.begin(), merged.end()); + } + for (auto&& result : results) { if (!outPath.empty()) @@ -219,6 +227,9 @@ int main(int argc, char* argv[]) if (result.isPartOfSequence()) std::cout << "Structured Append: symbol " << result.sequenceIndex() + 1 << " of " << result.sequenceSize() << " (parity/id: '" << result.sequenceId() << "')\n"; + else if (result.sequenceSize() > 0) + std::cout << "Structured Append: merged result from " << result.sequenceSize() << " symbols (parity/id: '" + << result.sequenceId() << "')\n"; if (result.readerInit()) std::cout << "Reader Initialisation/Programming\n"; diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 2d7fe005dd..085bb41d95 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -252,7 +252,7 @@ static Result readMultiple(const std::vector& imgPaths, std::string_vi allResults.insert(allResults.end(), results.begin(), results.end()); } - return MergeStructuredAppendResults(allResults); + return MergeStructuredAppendSequence(allResults); } static void doRunStructuredAppendTest(const fs::path& directory, std::string_view format, int totalTests, From d0a8b9f47fa434f827dff37034c4ff2780e887f7 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 13 Jun 2022 18:37:49 +0200 Subject: [PATCH 35/88] example: port ZXingQtReader to Qt6 Note: to compile it with qt6, increase c++ standard to 17 and replace `find_package(Qt5 ...` with `ind_package(Qt6 ...`. The overlay drawing feature is missing due to a removed `videoOutput.mapPointToItem()` function. The default video resolution is different and the `Q_ENUM_NS` macros don't work correct (int value instead of string in GUI). --- example/CMakeLists.txt | 8 +- ...gQtCamReader.qml => ZXingQt5CamReader.qml} | 22 +-- example/ZXingQt6CamReader.qml | 148 ++++++++++++++++++ example/ZXingQtCamReader.cpp | 8 +- example/ZXingQtCamReader.qrc | 3 +- example/ZXingQtReader.h | 138 +++++++++++----- 6 files changed, 265 insertions(+), 62 deletions(-) rename example/{ZXingQtCamReader.qml => ZXingQt5CamReader.qml} (87%) create mode 100644 example/ZXingQt6CamReader.qml diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 8cb2e1b4d8..36d663a67f 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -30,14 +30,14 @@ if (BUILD_READERS) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) - if (TARGET Qt5::Gui) + if (TARGET Qt::Gui) add_executable (ZXingQtReader ZXingQtReader.cpp ZXingQtReader.h) - target_link_libraries(ZXingQtReader ZXing::ZXing Qt5::Gui) + target_link_libraries(ZXingQtReader ZXing::ZXing Qt::Gui) endif() - if (TARGET Qt5::Multimedia) + if (TARGET Qt::Multimedia AND TARGET Qt::Quick) add_executable(ZXingQtCamReader ZXingQtCamReader.cpp ZXingQtCamReader.qrc ZXingQtReader.h) - target_link_libraries(ZXingQtCamReader ZXing::ZXing Qt5::Gui Qt5::Multimedia Qt5::Quick) + target_link_libraries(ZXingQtCamReader ZXing::ZXing Qt::Gui Qt::Multimedia Qt::Quick) endif() find_package(OpenCV) diff --git a/example/ZXingQtCamReader.qml b/example/ZXingQt5CamReader.qml similarity index 87% rename from example/ZXingQtCamReader.qml rename to example/ZXingQt5CamReader.qml index 9a90cf20d6..bf3f8d3ed2 100644 --- a/example/ZXingQtCamReader.qml +++ b/example/ZXingQt5CamReader.qml @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser - * - * 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. */ +// SPDX-License-Identifier: Apache-2.0 import QtQuick 2.12 import QtQuick.Window 2.12 @@ -36,12 +25,13 @@ Window { interval: 2000 } - VideoFilter { - id: zxingFilter + BarcodeReader { + id: barcodeReader formats: (oneDSwitch.checked ? (ZXing.OneDCodes) : ZXing.None) | (twoDSwitch.checked ? (ZXing.TwoDCodes) : ZXing.None) tryRotate: tryRotateSwitch.checked tryHarder: tryHarderSwitch.checked + tryDownscale: tryDownscaleSwitch.checked // callback with parameter 'result', called for every successfully processed frame // onFoundBarcode: {} @@ -100,7 +90,7 @@ Window { id: videoOutput Layout.fillHeight: true Layout.fillWidth: true - filters: [zxingFilter] + filters: [barcodeReader] source: camera autoOrientation: true @@ -144,9 +134,11 @@ Window { ColumnLayout { anchors.right: parent.right + anchors.bottom: parent.bottom Switch {id: tryRotateSwitch; text: qsTr("Try Rotate"); checked: true } Switch {id: tryHarderSwitch; text: qsTr("Try Harder"); checked: true } + Switch {id: tryDownscaleSwitch; text: qsTr("Try Downscale"); checked: true } Switch {id: oneDSwitch; text: qsTr("1D Codes"); checked: true } Switch {id: twoDSwitch; text: qsTr("2D Codes"); checked: true } } diff --git a/example/ZXingQt6CamReader.qml b/example/ZXingQt6CamReader.qml new file mode 100644 index 0000000000..7c80e77855 --- /dev/null +++ b/example/ZXingQt6CamReader.qml @@ -0,0 +1,148 @@ +/* + * Copyright 2022 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Shapes +import QtMultimedia +import ZXing + +Window { + visible: true + width: 640 + height: 480 + title: Qt.application.name + + property var nullPoints: [Qt.point(0,0), Qt.point(0,0), Qt.point(0,0), Qt.point(0,0)] + property var points: nullPoints + + Timer { + id: resetInfo + interval: 2000 + } + + BarcodeReader { + id: barcodeReader + videoSink: videoOutput.videoSink + + formats: (oneDSwitch.checked ? (ZXing.OneDCodes) : ZXing.None) | (twoDSwitch.checked ? (ZXing.TwoDCodes) : ZXing.None) + tryRotate: tryRotateSwitch.checked + tryHarder: tryHarderSwitch.checked + tryDownscale: tryDownscaleSwitch.checked + + // callback with parameter 'result', called for every successfully processed frame + // onFoundBarcode: {} + + // callback with parameter 'result', called for every processed frame + onNewResult: { + points = result.isValid + ? [result.position.topLeft, result.position.topRight, result.position.bottomRight, result.position.bottomLeft] + : nullPoints + + if (result.isValid) + resetInfo.restart() + + if (result.isValid || !resetInfo.running) + info.text = qsTr("Format: \t %1 \nText: \t %2 \nError: \t %3 \nTime: \t %4 ms").arg(result.formatName).arg(result.text).arg(result.status).arg(result.runTime) + +// console.log(result) + } + } + + MediaDevices { + id: devices + } + + Camera { + id: camera + cameraDevice: devices.videoInputs[camerasComboBox.currentIndex] ? devices.videoInputs[camerasComboBox.currentIndex] : devices.defaultVideoInput + focusMode: Camera.FocusModeAutoNear + onErrorOccurred: console.log("camera error:" + errorString) + } + + CaptureSession { + id: captureSession + camera: camera + videoOutput: videoOutput + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + visible: devices.videoInputs.length > 1 + Label { + text: qsTr("Camera: ") + Layout.fillWidth: false + } + ComboBox { + id: camerasComboBox + Layout.fillWidth: true + model: devices.videoInputs + textRole: "displayName" + currentIndex: 0 + } + } + + VideoOutput { + id: videoOutput + Layout.fillHeight: true + Layout.fillWidth: true + +// Shape { +// id: polygon +// anchors.fill: parent +// visible: points.length == 4 +// ShapePath { +// strokeWidth: 3 +// strokeColor: "red" +// strokeStyle: ShapePath.SolidLine +// fillColor: "transparent" +// //TODO: really? I don't know qml... +// startX: videoOutput.mapPointToItem(points[3]).x +// startY: videoOutput.mapPointToItem(points[3]).y +// PathLine { +// x: videoOutput.mapPointToItem(points[0]).x +// y: videoOutput.mapPointToItem(points[0]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[1]).x +// y: videoOutput.mapPointToItem(points[1]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[2]).x +// y: videoOutput.mapPointToItem(points[2]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[3]).x +// y: videoOutput.mapPointToItem(points[3]).y +// } +// } +// } + + Label { + id: info + color: "white" + padding: 10 + background: Rectangle { color: "#80808080" } + } + + ColumnLayout { + anchors.right: parent.right + anchors.bottom: parent.bottom + + Switch {id: tryRotateSwitch; text: qsTr("Try Rotate"); checked: true } + Switch {id: tryHarderSwitch; text: qsTr("Try Harder"); checked: true } + Switch {id: tryDownscaleSwitch; text: qsTr("Try Downscale"); checked: true } + Switch {id: oneDSwitch; text: qsTr("1D Codes"); checked: true } + Switch {id: twoDSwitch; text: qsTr("2D Codes"); checked: true } + } + } + } +} diff --git a/example/ZXingQtCamReader.cpp b/example/ZXingQtCamReader.cpp index 102312e0e6..3815bfe43b 100644 --- a/example/ZXingQtCamReader.cpp +++ b/example/ZXingQtCamReader.cpp @@ -10,14 +10,20 @@ int main(int argc, char *argv[]) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif ZXingQt::registerQmlAndMetaTypes(); QGuiApplication app(argc, argv); app.setApplicationName("ZXingQtCamReader"); QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/ZXingQtCamReader.qml"))); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + engine.load(QUrl(QStringLiteral("qrc:/ZXingQt5CamReader.qml"))); +#else + engine.load(QUrl(QStringLiteral("qrc:/ZXingQt6CamReader.qml"))); +#endif if (engine.rootObjects().isEmpty()) return -1; diff --git a/example/ZXingQtCamReader.qrc b/example/ZXingQtCamReader.qrc index 967e6ec7d1..b6b772c75c 100644 --- a/example/ZXingQtCamReader.qrc +++ b/example/ZXingQtCamReader.qrc @@ -1,5 +1,6 @@ - ZXingQtCamReader.qml + ZXingQt5CamReader.qml + ZXingQt6CamReader.qml diff --git a/example/ZXingQtReader.h b/example/ZXingQtReader.h index 7435e56c85..07effc10d0 100644 --- a/example/ZXingQtReader.h +++ b/example/ZXingQtReader.h @@ -12,7 +12,12 @@ #include #ifdef QT_MULTIMEDIA_LIB +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include +#else +#include +#include +#endif #include #endif @@ -154,7 +159,7 @@ inline Result ReadBarcode(const QImage& img, const DecodeHints& hints = {}) auto exec = [&](const QImage& img) { return Result(ZXing::ReadBarcode( - {img.bits(), img.width(), img.height(), ImgFmtFromQImg(img), img.bytesPerLine()}, hints)); + {img.bits(), img.width(), img.height(), ImgFmtFromQImg(img), static_cast(img.bytesPerLine())}, hints)); }; return ImgFmtFromQImg(img) == ImageFormat::None ? exec(img.convertToFormat(QImage::Format_Grayscale8)) : exec(img); @@ -166,7 +171,11 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { using namespace ZXing; auto img = frame; // shallow copy just get access to non-const map() function +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (!frame.isValid() || !img.map(QAbstractVideoBuffer::ReadOnly)){ +#else + if (!frame.isValid() || !img.map(QVideoFrame::ReadOnly)){ +#endif qWarning() << "invalid QVideoFrame: could not map memory"; return {}; } @@ -176,10 +185,18 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { int pixStride = 0; int pixOffset = 0; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#define FORMAT(F5, F6) QVideoFrame::Format_##F5 +#define FIRST_PLANE +#else +#define FORMAT(F5, F6) QVideoFrameFormat::Format_##F6 +#define FIRST_PLANE 0 +#endif + switch (img.pixelFormat()) { - case QVideoFrame::Format_ARGB32: - case QVideoFrame::Format_ARGB32_Premultiplied: - case QVideoFrame::Format_RGB32: + case FORMAT(ARGB32, ARGB8888): + case FORMAT(ARGB32_Premultiplied, ARGB8888_Premultiplied): + case FORMAT(RGB32, RGBX8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::BGRX; #else @@ -187,11 +204,9 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; - case QVideoFrame::Format_RGB24: fmt = ImageFormat::RGB; break; - - case QVideoFrame::Format_BGRA32: - case QVideoFrame::Format_BGRA32_Premultiplied: - case QVideoFrame::Format_BGR32: + case FORMAT(BGRA32, BGRA8888): + case FORMAT(BGRA32_Premultiplied, BGRA8888_Premultiplied): + case FORMAT(BGR32, BGRX8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::RGBX; #else @@ -199,10 +214,17 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + case QVideoFrame::Format_RGB24: fmt = ImageFormat::RGB; break; case QVideoFrame::Format_BGR24: fmt = ImageFormat::BGR; break; + case QVideoFrame::Format_YUV444: fmt = ImageFormat::Lum, pixStride = 3; break; +#else + case QVideoFrameFormat::Format_P010: + case QVideoFrameFormat::Format_P016: fmt = ImageFormat::Lum, pixStride = 1; break; +#endif - case QVideoFrame::Format_AYUV444: - case QVideoFrame::Format_AYUV444_Premultiplied: + case FORMAT(AYUV444, AYUV): + case FORMAT(AYUV444_Premultiplied, AYUV_Premultiplied): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::Lum, pixStride = 4, pixOffset = 3; #else @@ -210,23 +232,22 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; - case QVideoFrame::Format_YUV444: fmt = ImageFormat::Lum, pixStride = 3; break; - case QVideoFrame::Format_YUV420P: - case QVideoFrame::Format_NV12: - case QVideoFrame::Format_NV21: - case QVideoFrame::Format_IMC1: - case QVideoFrame::Format_IMC2: - case QVideoFrame::Format_IMC3: - case QVideoFrame::Format_IMC4: - case QVideoFrame::Format_YV12: fmt = ImageFormat::Lum; break; - case QVideoFrame::Format_UYVY: fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; - case QVideoFrame::Format_YUYV: fmt = ImageFormat::Lum, pixStride = 2; break; - - case QVideoFrame::Format_Y8: fmt = ImageFormat::Lum; break; - case QVideoFrame::Format_Y16: fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; + case FORMAT(YUV420P, YUV420P): + case FORMAT(NV12, NV12): + case FORMAT(NV21, NV21): + case FORMAT(IMC1, IMC1): + case FORMAT(IMC2, IMC2): + case FORMAT(IMC3, IMC3): + case FORMAT(IMC4, IMC4): + case FORMAT(YV12, YV12): fmt = ImageFormat::Lum; break; + case FORMAT(UYVY, UYVY): fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; + case FORMAT(YUYV, YUYV): fmt = ImageFormat::Lum, pixStride = 2; break; + + case FORMAT(Y8, Y8): fmt = ImageFormat::Lum; break; + case FORMAT(Y16, Y16): fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; #if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - case QVideoFrame::Format_ABGR32: + case FORMAT(ABGR32, ABGR8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::RGBX; #else @@ -235,19 +256,22 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { break; #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) - case QVideoFrame::Format_YUV422P: fmt = ImageFormat::Lum; break; + case FORMAT(YUV422P, YUV422P): fmt = ImageFormat::Lum; break; #endif default: break; } Result res; if (fmt != ImageFormat::None) { - res = Result( - ZXing::ReadBarcode({img.bits() + pixOffset, img.width(), img.height(), fmt, img.bytesPerLine(), pixStride}, - hints)); + res = Result(ZXing::ReadBarcode( + {img.bits(FIRST_PLANE) + pixOffset, img.width(), img.height(), fmt, img.bytesPerLine(FIRST_PLANE), pixStride}, hints)); } else { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (QVideoFrame::imageFormatFromPixelFormat(img.pixelFormat()) != QImage::Format_Invalid) res = ReadBarcode(img.image(), hints); +#else + res = ReadBarcode(img.toImage(), hints); +#endif } img.unmap(); @@ -268,14 +292,21 @@ public: \ } \ Q_SIGNAL void name##Changed(); -class VideoFilter : public QAbstractVideoFilter, private DecodeHints + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +class BarcodeReader : public QAbstractVideoFilter, private DecodeHints +#else +class BarcodeReader : public QObject, private DecodeHints +#endif { Q_OBJECT public: - VideoFilter(QObject* parent = nullptr) : QAbstractVideoFilter(parent) {} - - QVideoFilterRunnable* createFilterRunnable() override; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + BarcodeReader(QObject* parent = nullptr) : QAbstractVideoFilter(parent) {} +#else + BarcodeReader(QObject* parent = nullptr) : QObject(parent) {} +#endif // TODO: find out how to properly expose QFlags to QML // simply using ZQ_PROPERTY(BarcodeFormats, formats, setFormats) @@ -298,9 +329,10 @@ class VideoFilter : public QAbstractVideoFilter, private DecodeHints ZQ_PROPERTY(bool, tryRotate, setTryRotate) ZQ_PROPERTY(bool, tryHarder, setTryHarder) + ZQ_PROPERTY(bool, tryDownscale, setTryDownscale) public slots: - Result process(const QVideoFrame& image) + ZXingQt::Result process(const QVideoFrame& image) { QElapsedTimer t; t.start(); @@ -316,18 +348,41 @@ public slots: } signals: - void newResult(Result result); - void foundBarcode(Result result); + void newResult(ZXingQt::Result result); + void foundBarcode(ZXingQt::Result result); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +public: + QVideoFilterRunnable *createFilterRunnable() override; +#else +private: + QVideoSink *_sink = nullptr; + +public: + void setVideoSink(QVideoSink* sink) { + if (_sink == sink) + return; + + if (_sink) + disconnect(_sink, nullptr, this, nullptr); + + _sink = sink; + connect(_sink, &QVideoSink::videoFrameChanged, this, &BarcodeReader::process); + } + Q_PROPERTY(QVideoSink* videoSink WRITE setVideoSink) +#endif + }; #undef ZX_PROPERTY +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) class VideoFilterRunnable : public QVideoFilterRunnable { - VideoFilter* _filter = nullptr; + BarcodeReader* _filter = nullptr; public: - explicit VideoFilterRunnable(VideoFilter* filter) : _filter(filter) {} + explicit VideoFilterRunnable(BarcodeReader* filter) : _filter(filter) {} QVideoFrame run(QVideoFrame* input, const QVideoSurfaceFormat& /*surfaceFormat*/, RunFlags /*flags*/) override { @@ -336,10 +391,11 @@ class VideoFilterRunnable : public QVideoFilterRunnable } }; -inline QVideoFilterRunnable* VideoFilter::createFilterRunnable() +inline QVideoFilterRunnable* BarcodeReader::createFilterRunnable() { return new VideoFilterRunnable(this); } +#endif #endif // QT_MULTIMEDIA_LIB @@ -367,7 +423,7 @@ inline void registerQmlAndMetaTypes() qmlRegisterUncreatableMetaObject( ZXingQt::staticMetaObject, "ZXing", 1, 0, "ZXing", "Access to enums & flags only"); - qmlRegisterType("ZXing", 1, 0, "VideoFilter"); + qmlRegisterType("ZXing", 1, 0, "BarcodeReader"); } } // namespace ZXingQt From 5bd41cdd7d5a821ba7e857f41204334f964492c3 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 13 Jun 2022 19:03:41 +0200 Subject: [PATCH 36/88] cmake: revert breaking change of `INTERFACE "$"` The change was deliberate but ill advised. Need a different solution to make the examples compile with the installed includes. --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7b34509510..e6c4d1a07f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -461,7 +461,7 @@ add_library (ZXing target_include_directories (ZXing PUBLIC "$" - INTERFACE "$" + INTERFACE "$" ) target_compile_options (ZXing From 9df7ef5a02c80e8f2913675041bce6b8e9e8fdb1 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 14 Jun 2022 13:29:25 +0200 Subject: [PATCH 37/88] API: improve a few comments for public symbols --- core/src/DecodeHints.h | 8 ++------ core/src/ReadBarcode.h | 8 +++++++- core/src/Result.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/DecodeHints.h b/core/src/DecodeHints.h index 68ffe031b9..26813d387e 100644 --- a/core/src/DecodeHints.h +++ b/core/src/DecodeHints.h @@ -109,7 +109,7 @@ class DecodeHints /// The maximum number of symbols (barcodes) to detect / look for in the image with ReadBarcodes ZX_PROPERTY(uint8_t, maxNumberOfSymbols, setMaxNumberOfSymbols) - /// Specifies what character encoding to use when decoding, where applicable. + /// Specifies fallback character set to use instead of auto-detecting it (when applicable) ZX_PROPERTY(std::string, characterSet, setCharacterSet) /// Allowed lengths of encoded data -- reject anything else.. @@ -124,11 +124,7 @@ class DecodeHints /// Assume ITF codes employ a GS1 check digit and validate it. ZX_PROPERTY(bool, validateITFCheckSum, setValidateITFCheckSum) - /** - * If true, return the start and end digits in a Codabar barcode instead of stripping them. They - * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them - * to not be. - */ + /// If true, return the start and end chars in a Codabar barcode instead of stripping them. ZX_PROPERTY(bool, returnCodabarStartEnd, setReturnCodabarStartEnd) /// Specify whether to ignore, read or require EAN-2/5 add-on symbols while scanning EAN/UPC codes diff --git a/core/src/ReadBarcode.h b/core/src/ReadBarcode.h index a76d60c31b..5b73d16913 100644 --- a/core/src/ReadBarcode.h +++ b/core/src/ReadBarcode.h @@ -20,7 +20,13 @@ namespace ZXing { */ Result ReadBarcode(const ImageView& buffer, const DecodeHints& hints = {}); -// WARNING: this API is experimental and may change/disappear +/** + * Read barcodes from an ImageView + * + * @param buffer view of the image data including layout and format + * @param hints optional DecodeHints to parameterize / speed up decoding + * @return #Results list of results found, may be empty + */ Results ReadBarcodes(const ImageView& buffer, const DecodeHints& hints = {}); } // ZXing diff --git a/core/src/Result.h b/core/src/Result.h index 8a07381e1c..c0a27513d7 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -140,7 +140,7 @@ using Results = std::vector; Result MergeStructuredAppendSequence(const Results& results); /** - * @brief Automatically merge all structured append sequences found in the given results + * @brief Automatically merge all Structured Append sequences found in the given results */ Results MergeStructuredAppendSequences(const Results& results); From 29388dbf429a4dd9266fd46183423aa5d3abd35b Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 14 Jun 2022 13:31:34 +0200 Subject: [PATCH 38/88] Result: remove applicationIndicator property (for now) --- core/src/Result.h | 1 - example/ZXingReader.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/core/src/Result.h b/core/src/Result.h index c0a27513d7..7f6db93e59 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -49,7 +49,6 @@ class Result const ByteArray& bytes() const { return _content.bytes; } const ByteArray bytesECI() const { return _content.bytesECI(); } const std::string utf8Protocol() const { return _content.utf8Protocol(); } - const std::string& applicationIndicator() const { return _content.applicationIndicator; } ContentType contentType() const { return _content.type(); } bool hasECI() const { return _content.hasECI; } // END WARNING diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 578e7714c6..56f6759491 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -209,7 +209,6 @@ int main(int argc, char* argv[]) }; printOptional("EC Level: ", ToUtf8(result.ecLevel())); - printOptional("App-Ind.: ", result.applicationIndicator()); if (result.lineCount()) std::cout << "Lines: " << result.lineCount() << "\n"; From f4c18c11f4a832674a798928e6fbd7288dcad726 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 14 Jun 2022 13:46:44 +0200 Subject: [PATCH 39/88] Result: increase API resilience against future ABI breakages (de-inlining) --- core/src/Result.cpp | 55 ++++++++++++++++++++++++++++++++++++++++----- core/src/Result.h | 24 ++++++++++---------- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index b077830286..72c995e0f5 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -21,11 +21,9 @@ Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFor : _format(format), _content({ByteArray(text)}, si), - _text(TextDecoder::FromLatin1(text)), _position(Line(y, xStart, xStop)), _rawBytes(std::move(rawBytes)), _numBits(Size(_rawBytes) * 8), - _symbologyIdentifier(si.toString()), _readerInit(readerInit), _lineCount(0) {} @@ -34,12 +32,10 @@ Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat : _status(decodeResult.errorCode()), _format(format), _content(std::move(decodeResult).content()), - _text(_content.text()), _position(std::move(position)), _rawBytes(std::move(decodeResult).rawBytes()), _numBits(decodeResult.numBits()), _ecLevel(TextDecoder::FromLatin1(decodeResult.ecLevel())), - _symbologyIdentifier(_content.symbology.toString(false)), _sai(decodeResult.structuredAppend()), _isMirrored(decodeResult.isMirrored()), _readerInit(decodeResult.readerInit()), @@ -48,12 +44,62 @@ Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat // TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra()) } +std::wstring Result::text() const +{ + return _content.text(); +} + +const ByteArray& Result::bytes() const +{ + return _content.bytes; +} + +ByteArray Result::bytesECI() const +{ + return _content.bytesECI(); +} + +std::string Result::utf8Protocol() const +{ + return _content.utf8Protocol(); +} + +ContentType Result::contentType() const +{ + return _content.type(); +} + +bool Result::hasECI() const +{ + return _content.hasECI; +} + int Result::orientation() const { constexpr auto std_numbers_pi_v = 3.14159265358979323846; // TODO: c++20 return std::lround(_position.orientation() * 180 / std_numbers_pi_v); } +std::string Result::symbologyIdentifier() const +{ + return _content.symbology.toString(); +} + +int Result::sequenceSize() const +{ + return _sai.count; +} + +int Result::sequenceIndex() const +{ + return _sai.index; +} + +std::string Result::sequenceId() const +{ + return _sai.id; +} + bool Result::operator==(const Result& o) const { if (format() != o.format() || text() != o.text()) @@ -88,7 +134,6 @@ Result MergeStructuredAppendSequence(const Results& results) for (auto i = std::next(allResults.begin()); i != allResults.end(); ++i) res._content.append(i->_content); - res._text = res._content.text(); res._position = {}; res._sai.index = -1; diff --git a/core/src/Result.h b/core/src/Result.h index 7f6db93e59..6a8ae00000 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -43,14 +43,14 @@ class Result BarcodeFormat format() const { return _format; } - const std::wstring& text() const { return _text; } + std::wstring text() const; // WARNING: this is an experimental API and may change/disappear - const ByteArray& bytes() const { return _content.bytes; } - const ByteArray bytesECI() const { return _content.bytesECI(); } - const std::string utf8Protocol() const { return _content.utf8Protocol(); } - ContentType contentType() const { return _content.type(); } - bool hasECI() const { return _content.hasECI; } + const ByteArray& bytes() const; + ByteArray bytesECI() const; + std::string utf8Protocol() const; + ContentType contentType() const; + bool hasECI() const; // END WARNING const Position& position() const { return _position; } @@ -72,7 +72,7 @@ class Result /** * @brief symbologyIdentifier Symbology identifier "]cm" where "c" is symbology code character, "m" the modifier. */ - const std::string& symbologyIdentifier() const { return _symbologyIdentifier; } + std::string symbologyIdentifier() const; /** * @brief sequenceSize number of symbols in a structured append sequence. @@ -81,12 +81,12 @@ class Result * If it is a structured append symbol but the total number of symbols is unknown, the * returned value is 0 (see PDF417 if optional "Segment Count" not given). */ - int sequenceSize() const { return _sai.count; } + int sequenceSize() const; /** * @brief sequenceIndex the 0-based index of this symbol in a structured append sequence. */ - int sequenceIndex() const { return _sai.index; } + int sequenceIndex() const; /** * @brief sequenceId id to check if a set of symbols belongs to the same structured append sequence. @@ -95,7 +95,7 @@ class Result * For QR Code, this is the parity integer converted to a string. * For PDF417 and DataMatrix, this is the "fileId". */ - const std::string& sequenceId() const { return _sai.id; } + std::string sequenceId() const; bool isLastInSequence() const { return sequenceSize() == sequenceIndex() + 1; } bool isPartOfSequence() const { return sequenceSize() > -1 && sequenceIndex() > -1; } @@ -109,6 +109,8 @@ class Result * @brief How many lines have been detected with this code (applies only to 1D symbologies) */ int lineCount() const { return _lineCount; } + + // only for internal use void incrementLineCount() { ++_lineCount; } bool operator==(const Result& o) const; @@ -119,12 +121,10 @@ class Result DecodeStatus _status = DecodeStatus::NoError; BarcodeFormat _format = BarcodeFormat::None; Content _content; - std::wstring _text; Position _position; ByteArray _rawBytes; int _numBits = 0; std::wstring _ecLevel; - std::string _symbologyIdentifier; StructuredAppendInfo _sai; bool _isMirrored = false; bool _readerInit = false; From 0a3f16903e9302e9356d26873db56fa9e22ecad2 Mon Sep 17 00:00:00 2001 From: axxel Date: Sat, 18 Jun 2022 15:42:50 +0200 Subject: [PATCH 40/88] GridSampler: support multi-symbol debugging --- core/src/GridSampler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/GridSampler.cpp b/core/src/GridSampler.cpp index b612f3a5ef..9bc3490212 100644 --- a/core/src/GridSampler.cpp +++ b/core/src/GridSampler.cpp @@ -22,7 +22,8 @@ DetectorResult SampleGrid(const BitMatrix& image, int width, int height, const P { #ifdef PRINT_DEBUG LogMatrix log; - LogMatrixWriter lmw(log, image, 5, "grid.pnm"); + static int i = 0; + LogMatrixWriter lmw(log, image, 5, "grid" + std::to_string(i++) + ".pnm"); #endif if (width <= 0 || height <= 0 || !mod2Pix.isValid()) return {}; From 9760a0ba6e420c59e7340120d5364ef757367caf Mon Sep 17 00:00:00 2001 From: axxel Date: Sat, 18 Jun 2022 15:47:18 +0200 Subject: [PATCH 41/88] QRCode: detect mirrored symbols directly from FormatInfo bits Also prepares MicroQRCode improvement based on hamming distance info in FormatInfo --- core/src/qrcode/QRBitMatrixParser.cpp | 41 +++++++------- core/src/qrcode/QRBitMatrixParser.h | 4 +- core/src/qrcode/QRDecoder.cpp | 21 +++----- core/src/qrcode/QRDetector.cpp | 2 +- core/src/qrcode/QRFormatInformation.cpp | 56 +++++++++----------- core/src/qrcode/QRFormatInformation.h | 34 ++++-------- test/unit/qrcode/QRBitMatrixParserTest.cpp | 8 +-- test/unit/qrcode/QRFormatInformationTest.cpp | 8 +-- 8 files changed, 73 insertions(+), 101 deletions(-) diff --git a/core/src/qrcode/QRBitMatrixParser.cpp b/core/src/qrcode/QRBitMatrixParser.cpp index ed614fe9a3..7cdb3e7529 100644 --- a/core/src/qrcode/QRBitMatrixParser.cpp +++ b/core/src/qrcode/QRBitMatrixParser.cpp @@ -17,7 +17,7 @@ namespace ZXing::QRCode { -static bool getBit(const BitMatrix& bitMatrix, int x, int y, bool mirrored) +static bool getBit(const BitMatrix& bitMatrix, int x, int y, bool mirrored = false) { return mirrored ? bitMatrix.get(y, x) : bitMatrix.get(x, y); } @@ -60,7 +60,7 @@ const Version* ReadVersion(const BitMatrix& bitMatrix) return nullptr; } -FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrored, bool isMicro) +FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool isMicro) { if (!hasValidDimension(bitMatrix, isMicro)) return {}; @@ -69,9 +69,9 @@ FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrore // Read top-left format info bits int formatInfoBits = 0; for (int x = 1; x < 9; x++) - AppendBit(formatInfoBits, getBit(bitMatrix, x, 8, mirrored)); + AppendBit(formatInfoBits, getBit(bitMatrix, x, 8)); for (int y = 7; y >= 1; y--) - AppendBit(formatInfoBits, getBit(bitMatrix, 8, y, mirrored)); + AppendBit(formatInfoBits, getBit(bitMatrix, 8, y)); return FormatInformation::DecodeMQR(formatInfoBits); } @@ -79,27 +79,27 @@ FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrore // Read top-left format info bits int formatInfoBits1 = 0; for (int x = 0; x < 6; x++) - AppendBit(formatInfoBits1, getBit(bitMatrix, x, 8, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, x, 8)); // .. and skip a bit in the timing pattern ... - AppendBit(formatInfoBits1, getBit(bitMatrix, 7, 8, mirrored)); - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 8, mirrored)); - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 7, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 7, 8)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 8)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 7)); // .. and skip a bit in the timing pattern ... for (int y = 5; y >= 0; y--) - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, y, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, y)); // Read the top-right/bottom-left pattern too int dimension = bitMatrix.height(); int formatInfoBits2 = 0; for (int y = dimension - 1; y >= dimension - 7; y--) - AppendBit(formatInfoBits2, getBit(bitMatrix, 8, y, mirrored)); + AppendBit(formatInfoBits2, getBit(bitMatrix, 8, y)); for (int x = dimension - 8; x < dimension; x++) - AppendBit(formatInfoBits2, getBit(bitMatrix, x, 8, mirrored)); + AppendBit(formatInfoBits2, getBit(bitMatrix, x, 8)); return FormatInformation::DecodeQR(formatInfoBits1, formatInfoBits2); } -static ByteArray ReadQRCodewords(const BitMatrix& bitMatrix, const Version& version, int maskIndex, bool mirrored) +static ByteArray ReadQRCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo) { BitMatrix functionPattern = version.buildFunctionPattern(); @@ -122,7 +122,8 @@ static ByteArray ReadQRCodewords(const BitMatrix& bitMatrix, const Version& vers // Ignore bits covered by the function pattern if (!functionPattern.get(xx, y)) { // Read a bit - AppendBit(currentByte, GetDataMaskBit(maskIndex, xx, y) != getBit(bitMatrix, xx, y, mirrored)); + AppendBit(currentByte, + GetDataMaskBit(formatInfo.dataMask, xx, y) != getBit(bitMatrix, xx, y, formatInfo.isMirrored)); // If we've made a whole byte, save it off if (++bitsRead % 8 == 0) result.push_back(std::exchange(currentByte, 0)); @@ -137,8 +138,7 @@ static ByteArray ReadQRCodewords(const BitMatrix& bitMatrix, const Version& vers return result; } -static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Version& version, - const FormatInformation& formatInformation, bool mirrored) +static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Version& version, const FormatInformation& formatInfo) { BitMatrix functionPattern = version.buildFunctionPattern(); @@ -147,7 +147,7 @@ static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Vers // See ISO 18004:2006 6.7.3. bool hasD4mBlock = version.versionNumber() % 2 == 1; int d4mBlockIndex = - version.versionNumber() == 1 ? 3 : (formatInformation.errorCorrectionLevel() == QRCode::ErrorCorrectionLevel::Low ? 11 : 9); + version.versionNumber() == 1 ? 3 : (formatInfo.ecLevel == QRCode::ErrorCorrectionLevel::Low ? 11 : 9); ByteArray result; result.reserve(version.totalCodewords()); @@ -166,7 +166,7 @@ static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Vers if (!functionPattern.get(xx, y)) { // Read a bit AppendBit(currentByte, - GetDataMaskBit(formatInformation.dataMask(), xx, y, true) != getBit(bitMatrix, xx, y, mirrored)); + GetDataMaskBit(formatInfo.dataMask, xx, y, true) != getBit(bitMatrix, xx, y, formatInfo.isMirrored)); ++bitsRead; // If we've made a whole byte, save it off; save early if 2x2 data block. if (bitsRead == 8 || (bitsRead == 4 && hasD4mBlock && Size(result) == d4mBlockIndex - 1)) { @@ -184,14 +184,13 @@ static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Vers return result; } -ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInformation, - bool mirrored) +ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo) { if (!hasValidDimension(bitMatrix, version.isMicroQRCode())) return {}; - return version.isMicroQRCode() ? ReadMQRCodewords(bitMatrix, version, formatInformation, mirrored) - : ReadQRCodewords(bitMatrix, version, formatInformation.dataMask(), mirrored); + return version.isMicroQRCode() ? ReadMQRCodewords(bitMatrix, version, formatInfo) + : ReadQRCodewords(bitMatrix, version, formatInfo); } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRBitMatrixParser.h b/core/src/qrcode/QRBitMatrixParser.h index cabb260210..0f070c8403 100644 --- a/core/src/qrcode/QRBitMatrixParser.h +++ b/core/src/qrcode/QRBitMatrixParser.h @@ -27,13 +27,13 @@ const Version* ReadVersion(const BitMatrix& bitMatrix); * @return {@link FormatInformation} encapsulating the QR Code's format info, result is invalid if both format * information locations cannot be parsed as the valid encoding of format information */ -FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrored, bool isMicro); +FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool isMicro); /** * @brief Reads the codewords from the BitMatrix. * @return bytes encoded within the QR Code or empty array if the exact number of bytes expected is not read */ -ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInformation, bool mirrored); +ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo); } // QRCode } // ZXing diff --git a/core/src/qrcode/QRDecoder.cpp b/core/src/qrcode/QRDecoder.cpp index 29d35f0ac3..f454b012fc 100644 --- a/core/src/qrcode/QRDecoder.cpp +++ b/core/src/qrcode/QRDecoder.cpp @@ -343,19 +343,19 @@ DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCo .setStructuredAppend(structuredAppend); } -static DecoderResult DoDecode(const BitMatrix& bits, const Version& version, const std::string& hintedCharset, bool mirrored) +static DecoderResult DoDecode(const BitMatrix& bits, const Version& version, const std::string& hintedCharset) { - auto formatInfo = ReadFormatInformation(bits, mirrored, version.isMicroQRCode()); + auto formatInfo = ReadFormatInformation(bits, version.isMicroQRCode()); if (!formatInfo.isValid()) return DecodeStatus::FormatError; // Read codewords - ByteArray codewords = ReadCodewords(bits, version, formatInfo, mirrored); + ByteArray codewords = ReadCodewords(bits, version, formatInfo); if (codewords.empty()) return DecodeStatus::FormatError; // Separate into data blocks - std::vector dataBlocks = DataBlock::GetDataBlocks(codewords, version, formatInfo.errorCorrectionLevel()); + std::vector dataBlocks = DataBlock::GetDataBlocks(codewords, version, formatInfo.ecLevel); if (dataBlocks.empty()) return DecodeStatus::FormatError; @@ -378,7 +378,7 @@ static DecoderResult DoDecode(const BitMatrix& bits, const Version& version, con } // Decode the contents of that stream of bytes - return DecodeBitStream(std::move(resultBytes), version, formatInfo.errorCorrectionLevel(), hintedCharset); + return DecodeBitStream(std::move(resultBytes), version, formatInfo.ecLevel, hintedCharset).setIsMirrored(formatInfo.isMirrored); } DecoderResult Decode(const BitMatrix& bits, const std::string& hintedCharset) @@ -387,16 +387,7 @@ DecoderResult Decode(const BitMatrix& bits, const std::string& hintedCharset) if (!version) return DecodeStatus::FormatError; - auto res = DoDecode(bits, *version, hintedCharset, false); - if (res.isValid()) - return res; - - if (auto resMirrored = DoDecode(bits, *version, hintedCharset, true); resMirrored.isValid()) { - resMirrored.setIsMirrored(true); - return resMirrored; - } - - return res; + return DoDecode(bits, *version, hintedCharset); } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRDetector.cpp b/core/src/qrcode/QRDetector.cpp index 3b0ea99766..1fdaa431ce 100644 --- a/core/src/qrcode/QRDetector.cpp +++ b/core/src/qrcode/QRDetector.cpp @@ -432,7 +432,7 @@ DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp) if (!fi.isValid()) continue; - const int dim = Version::DimensionOfVersion(fi.microVersion(), true); + const int dim = Version::DimensionOfVersion(fi.microVersion, true); // check that we are in fact not looking at a corner of a non-micro QRCode symbol // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2). diff --git a/core/src/qrcode/QRFormatInformation.cpp b/core/src/qrcode/QRFormatInformation.cpp index 44db397c06..7f4cba4aa8 100644 --- a/core/src/qrcode/QRFormatInformation.cpp +++ b/core/src/qrcode/QRFormatInformation.cpp @@ -87,64 +87,60 @@ static const std::array, 32> FORMAT_INFO_DECODE_LOOKUP_MICRO {0x3BBA, 0x1F}, }}; -static int FindBestFormatInfo(int mask, const std::array, 32> lookup, const std::vector& bits) +static FormatInformation FindBestFormatInfo(int mask, const std::array, 32> lookup, + const std::vector& bits) { - // Find the int in lookup with fewest bits differing - int bestDifference = 32; - int bestFormatInfo = -1; + FormatInformation fi; // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. - // TODO: test for mirrored format for (auto mask : {0, mask}) for (uint32_t bits : bits) - for (const auto& [pattern, decodedInfo] : lookup) - if (int bitsDifference = BitHacks::CountBitsSet((bits ^ mask) ^ pattern); bitsDifference < bestDifference) { - bestFormatInfo = decodedInfo; - bestDifference = bitsDifference; + for (bool mirror : {false, true}) + for (const auto& [pattern, index] : lookup) { + if (mirror) + bits = BitHacks::Reverse(bits) >> 17; + // Find the int in lookup with fewest bits differing + if (int hammingDist = BitHacks::CountBitsSet((bits ^ mask) ^ pattern); hammingDist < fi.hammingDistance) { + fi.index = index; + fi.hammingDistance = hammingDist; + fi.isMirrored = mirror; + } } - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits - // differing means we found a match - if (bestDifference <= 3) - return bestFormatInfo; - - return -1; + return fi; } /** * @param formatInfoBits1 format info indicator, with mask still applied -* @param formatInfoBits2 second copy of same info; both are checked at the same time -* to establish best match -* @return information about the format it specifies, or {@code null} -* if doesn't seem to match any known pattern +* @param formatInfoBits2 second copy of same info; both are checked at the same time to establish best match */ FormatInformation FormatInformation::DecodeQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2) { - int bestFormatInfo = FindBestFormatInfo(FORMAT_INFO_MASK_QR, FORMAT_INFO_DECODE_LOOKUP, {formatInfoBits1, formatInfoBits2}); - if (bestFormatInfo < 0) - return {}; + auto fi = FindBestFormatInfo(FORMAT_INFO_MASK_QR, FORMAT_INFO_DECODE_LOOKUP, {formatInfoBits1, formatInfoBits2}); // Use bits 3/4 for error correction, and 0-2 for mask. - return {ECLevelFromBits((bestFormatInfo >> 3) & 0x03), static_cast(bestFormatInfo & 0x07)}; + fi.ecLevel = ECLevelFromBits((fi.index >> 3) & 0x03); + fi.dataMask = static_cast(fi.index & 0x07); + + return fi; } /** * @param formatInfoBits format info indicator, with mask still applied - * @return information about the format it specifies, or {@code null} - * if doesn't seem to match any known pattern */ FormatInformation FormatInformation::DecodeMQR(uint32_t formatInfoBits) { // We don't use the additional masking (with 0x4445) to work around potentially non complying MircoQRCode encoders - int bestFormatInfo = FindBestFormatInfo(0, FORMAT_INFO_DECODE_LOOKUP_MICRO, {formatInfoBits}); - if (bestFormatInfo < 0) - return {}; + auto fi = FindBestFormatInfo(0, FORMAT_INFO_DECODE_LOOKUP_MICRO, {formatInfoBits}); constexpr uint8_t BITS_TO_VERSION[] = {1, 2, 2, 3, 3, 4, 4, 4}; // Bits 2/3/4 contain both error correction level and version, 0/1 contain mask. - return {ECLevelFromBits((bestFormatInfo >> 2) & 0x07, true), static_cast(bestFormatInfo & 0x03), - BITS_TO_VERSION[(bestFormatInfo >> 2) & 0x07]}; + fi.ecLevel = ECLevelFromBits((fi.index >> 2) & 0x07, true); + fi.dataMask = static_cast(fi.index & 0x03); + fi.microVersion = BITS_TO_VERSION[(fi.index >> 2) & 0x07]; + + return fi; } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRFormatInformation.h b/core/src/qrcode/QRFormatInformation.h index e83775b0fc..d7d59a2d9d 100644 --- a/core/src/qrcode/QRFormatInformation.h +++ b/core/src/qrcode/QRFormatInformation.h @@ -13,42 +13,28 @@ namespace ZXing { namespace QRCode { -/** -*

Encapsulates a QR Code's format information, including the data mask used and -* error correction level.

-* -* @author Sean Owen -* @see DataMask -* @see ErrorCorrectionLevel -*/ class FormatInformation { public: + uint8_t index = 255; + uint8_t hammingDistance = 255; + bool isMirrored = false; + uint8_t dataMask = 0; + uint8_t microVersion = 0; + ErrorCorrectionLevel ecLevel = ErrorCorrectionLevel::Invalid; + FormatInformation() = default; static FormatInformation DecodeQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2); static FormatInformation DecodeMQR(uint32_t formatInfoBits); - ErrorCorrectionLevel errorCorrectionLevel() const { return _errorCorrectionLevel; } - - uint8_t dataMask() const { return _dataMask; } - uint8_t microVersion() const { return _microVersion; } - - bool isValid() const { return _errorCorrectionLevel != ErrorCorrectionLevel::Invalid; } + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match + bool isValid() const { return hammingDistance <= 3; } bool operator==(const FormatInformation& other) const { - return _dataMask == other._dataMask && _errorCorrectionLevel == other._errorCorrectionLevel; + return dataMask == other.dataMask && ecLevel == other.ecLevel; } - -private: - ErrorCorrectionLevel _errorCorrectionLevel = ErrorCorrectionLevel::Invalid; - uint8_t _dataMask = 0; - uint8_t _microVersion = 0; - - FormatInformation(const ErrorCorrectionLevel& errorCorrectionLevel, uint8_t dataMask, uint8_t microVersion = 0) - : _errorCorrectionLevel(errorCorrectionLevel), _dataMask(dataMask), _microVersion(microVersion) - {} }; } // QRCode diff --git a/test/unit/qrcode/QRBitMatrixParserTest.cpp b/test/unit/qrcode/QRBitMatrixParserTest.cpp index 2cd7a9c5cf..f8c5a93a0d 100644 --- a/test/unit/qrcode/QRBitMatrixParserTest.cpp +++ b/test/unit/qrcode/QRBitMatrixParserTest.cpp @@ -37,8 +37,8 @@ TEST(QRBitMatrixParserTest, MQRCodeM3L) const auto version = ReadVersion(bitMatrix); EXPECT_EQ(3, version->versionNumber()); - const auto format = ReadFormatInformation(bitMatrix, false, true); - const auto codewords = ReadCodewords(bitMatrix, *version, format, false); + const auto format = ReadFormatInformation(bitMatrix, true); + const auto codewords = ReadCodewords(bitMatrix, *version, format); EXPECT_EQ(17, codewords.size()); EXPECT_EQ(0x0, codewords[10]); EXPECT_EQ(0xd1, codewords[11]); @@ -65,8 +65,8 @@ TEST(QRBitMatrixParserTest, MQRCodeM3M) const auto version = ReadVersion(bitMatrix); EXPECT_EQ(3, version->versionNumber()); - const auto format = ReadFormatInformation(bitMatrix, false, true); - const auto codewords = ReadCodewords(bitMatrix, *version, format, false); + const auto format = ReadFormatInformation(bitMatrix, true); + const auto codewords = ReadCodewords(bitMatrix, *version, format); EXPECT_EQ(17, codewords.size()); EXPECT_EQ(0x0, codewords[8]); EXPECT_EQ(0x89, codewords[9]); diff --git a/test/unit/qrcode/QRFormatInformationTest.cpp b/test/unit/qrcode/QRFormatInformationTest.cpp index 959f5ae42e..0dffa5ea27 100644 --- a/test/unit/qrcode/QRFormatInformationTest.cpp +++ b/test/unit/qrcode/QRFormatInformationTest.cpp @@ -20,8 +20,8 @@ static void DoFormatInformationTest(const int formatInfo, const uint8_t expected { FormatInformation parsedFormat = FormatInformation::DecodeMQR(formatInfo); EXPECT_TRUE(parsedFormat.isValid()); - EXPECT_EQ(expectedMask, parsedFormat.dataMask()); - EXPECT_EQ(expectedECL, parsedFormat.errorCorrectionLevel()); + EXPECT_EQ(expectedMask, parsedFormat.dataMask); + EXPECT_EQ(expectedECL, parsedFormat.ecLevel); } TEST(QRFormatInformationTest, Decode) @@ -29,8 +29,8 @@ TEST(QRFormatInformationTest, Decode) // Normal case FormatInformation expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); EXPECT_TRUE(expected.isValid()); - EXPECT_EQ(0x07, expected.dataMask()); - EXPECT_EQ(ErrorCorrectionLevel::Quality, expected.errorCorrectionLevel()); + EXPECT_EQ(0x07, expected.dataMask); + EXPECT_EQ(ErrorCorrectionLevel::Quality, expected.ecLevel); // where the code forgot the mask! EXPECT_EQ(expected, FormatInformation::DecodeQR(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO)); } From 2de960583b6bf54ef8a7918a559f12d274ab0dd8 Mon Sep 17 00:00:00 2001 From: axxel Date: Sat, 18 Jun 2022 16:01:52 +0200 Subject: [PATCH 42/88] MicoQRCode: choose orientation with the lowest hamming distance FormatInfo This fixes #344. --- core/src/PerspectiveTransform.h | 1 + core/src/qrcode/QRDetector.cpp | 36 +++++++++++++++++++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/core/src/PerspectiveTransform.h b/core/src/PerspectiveTransform.h index 0e99c3c101..c2f5043e18 100644 --- a/core/src/PerspectiveTransform.h +++ b/core/src/PerspectiveTransform.h @@ -34,6 +34,7 @@ class PerspectiveTransform static PerspectiveTransform UnitSquareTo(const QuadrilateralF& q); public: + PerspectiveTransform() = default; PerspectiveTransform(const QuadrilateralF& src, const QuadrilateralF& dst); /// Project from the destination space (grid of modules) into the image space (bit matrix) diff --git a/core/src/qrcode/QRDetector.cpp b/core/src/qrcode/QRDetector.cpp index 1fdaa431ce..5fdad20b89 100644 --- a/core/src/qrcode/QRDetector.cpp +++ b/core/src/qrcode/QRDetector.cpp @@ -412,6 +412,9 @@ DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp) constexpr PointI FORMAT_INFO_COORDS[] = {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {6, 8}, {7, 8}, {8, 8}, {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {8, 0}}; + FormatInformation bestFI; + PerspectiveTransform bestPT; + for (int i = 0; i < 4; ++i) { auto mod2Pix = PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, i)); @@ -429,26 +432,29 @@ DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp) AppendBit(formatInfoBits, image.get(mod2Pix(centered(FORMAT_INFO_COORDS[i])))); auto fi = FormatInformation::DecodeMQR(formatInfoBits); - if (!fi.isValid()) - continue; + if (fi.hammingDistance < bestFI.hammingDistance) { + bestFI = fi; + bestPT = mod2Pix; + } + } - const int dim = Version::DimensionOfVersion(fi.microVersion, true); + if (!bestFI.isValid()) + return {}; - // check that we are in fact not looking at a corner of a non-micro QRCode symbol - // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2). - int blackPixels = 0; - for (int i = 0; i < dim; ++i) { - auto px = mod2Pix(centered(PointI{i, dim})); - auto py = mod2Pix(centered(PointI{dim, i})); - blackPixels += (image.isIn(px) && image.get(px)) + (image.isIn(py) && image.get(py)); - } - if (blackPixels > 2 * dim / 3) - continue; + const int dim = Version::DimensionOfVersion(bestFI.microVersion, true); - return SampleGrid(image, dim, dim, mod2Pix); + // check that we are in fact not looking at a corner of a non-micro QRCode symbol + // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2). + int blackPixels = 0; + for (int i = 0; i < dim; ++i) { + auto px = bestPT(centered(PointI{i, dim})); + auto py = bestPT(centered(PointI{dim, i})); + blackPixels += (image.isIn(px) && image.get(px)) + (image.isIn(py) && image.get(py)); } + if (blackPixels > 2 * dim / 3) + return {}; - return {}; + return SampleGrid(image, dim, dim, bestPT); } } // namespace ZXing::QRCode From 78f2b4ecd8644b700e80847407de42ae193459e3 Mon Sep 17 00:00:00 2001 From: axxel Date: Sun, 19 Jun 2022 01:08:54 +0200 Subject: [PATCH 43/88] Result: compare bytes instead of text in opoerator== (performance) --- core/src/Result.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 72c995e0f5..3e0f62e38a 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -102,7 +102,7 @@ std::string Result::sequenceId() const bool Result::operator==(const Result& o) const { - if (format() != o.format() || text() != o.text()) + if (format() != o.format() || bytes() != o.bytes()) return false; if (BarcodeFormats(BarcodeFormat::TwoDCodes).testFlag(format())) From ad70b4038f342d15250ef79b5b933c2dba9dd228 Mon Sep 17 00:00:00 2001 From: axxel Date: Sun, 19 Jun 2022 01:14:32 +0200 Subject: [PATCH 44/88] Result: rename utf8Protocol -> utf8ECI --- core/src/Content.cpp | 2 +- core/src/Content.h | 2 +- core/src/Result.cpp | 4 ++-- core/src/Result.h | 2 +- example/ZXingReader.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 21fde3c976..f5b4e1a852 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -108,7 +108,7 @@ std::wstring Content::text() const return wstr; } -std::string Content::utf8Protocol() const +std::string Content::utf8ECI() const { if (empty() || !canProcess()) return {}; diff --git a/core/src/Content.h b/core/src/Content.h index 5d1f982069..756d8b72fe 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -71,7 +71,7 @@ class Content bool canProcess() const; std::wstring text() const; - std::string utf8Protocol() const; + std::string utf8ECI() const; ByteArray bytesECI() const; CharacterSet guessEncoding() const; ContentType type() const; diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 3e0f62e38a..15399dea0a 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -59,9 +59,9 @@ ByteArray Result::bytesECI() const return _content.bytesECI(); } -std::string Result::utf8Protocol() const +std::string Result::utf8ECI() const { - return _content.utf8Protocol(); + return _content.utf8ECI(); } ContentType Result::contentType() const diff --git a/core/src/Result.h b/core/src/Result.h index 6a8ae00000..0bad7c7f03 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -48,7 +48,7 @@ class Result // WARNING: this is an experimental API and may change/disappear const ByteArray& bytes() const; ByteArray bytesECI() const; - std::string utf8Protocol() const; + std::string utf8ECI() const; ContentType contentType() const; bool hasECI() const; // END WARNING diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 56f6759491..d8bf8fbd99 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -192,7 +192,7 @@ int main(int argc, char* argv[]) } std::cout << "Text: \"" << ToUtf8(result.text(), angleEscape) << "\"\n" << "Bytes: \"" << ToHex(result.bytes()) << "\"\n" - << "TextECI: \"" << result.utf8Protocol() << "\"\n" + << "TextECI: \"" << result.utf8ECI() << "\"\n" << "BytesECI: \"" << ToHex(result.bytesECI()) << "\"\n" << "Format: " << ToString(result.format()) << "\n" << "Identifier: " << result.symbologyIdentifier() << "\n" From c4748b13806381ca2880f10683cc7a4357331c1a Mon Sep 17 00:00:00 2001 From: axxel Date: Sun, 19 Jun 2022 23:14:21 +0200 Subject: [PATCH 45/88] GTIN: parse the `bytes()` instead of `text()` in `EanAddOn()` --- core/src/GTIN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/GTIN.cpp b/core/src/GTIN.cpp index 4231597aa8..252393dcbb 100644 --- a/core/src/GTIN.cpp +++ b/core/src/GTIN.cpp @@ -205,9 +205,9 @@ std::string EanAddOn(const Result& result) if (!(BarcodeFormat::EAN13 | BarcodeFormat::UPCA | BarcodeFormat::UPCE | BarcodeFormat::EAN8) .testFlag(result.format())) return {}; - auto txt = result.text(); - auto pos = txt.find(L' '); - return pos != std::wstring::npos ? TextUtfEncoding::ToUtf8(txt.substr(pos + 1)) : std::string(); + auto txt = result.bytes().asString(); + auto pos = txt.find(' '); + return pos != std::string::npos ? std::string(txt.substr(pos + 1)) : std::string(); } std::string IssueNr(const std::string& ean2AddOn) From fdca0b6f2a277b5a0cc62e0f4c7ab3ce4a43978a Mon Sep 17 00:00:00 2001 From: axxel Date: Sun, 19 Jun 2022 23:27:52 +0200 Subject: [PATCH 46/88] example: don't double quote the `bytes` result in ZXingReader output --- example/ZXingReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index d8bf8fbd99..206c400bcb 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -191,9 +191,9 @@ int main(int argc, char* argv[]) firstFile = false; } std::cout << "Text: \"" << ToUtf8(result.text(), angleEscape) << "\"\n" - << "Bytes: \"" << ToHex(result.bytes()) << "\"\n" + << "Bytes: " << ToHex(result.bytes()) << "\n" << "TextECI: \"" << result.utf8ECI() << "\"\n" - << "BytesECI: \"" << ToHex(result.bytesECI()) << "\"\n" + << "BytesECI: " << ToHex(result.bytesECI()) << "\n" << "Format: " << ToString(result.format()) << "\n" << "Identifier: " << result.symbologyIdentifier() << "\n" << "Content: " << ToString(result.contentType()) << "\n" From 805c7935e207d572ff37be3a4bb343edfac25b96 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 20 Jun 2022 09:04:11 +0200 Subject: [PATCH 47/88] example: use new Result::utf8() --- example/ZXingReader.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 206c400bcb..64f91e1701 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -111,6 +111,11 @@ void drawRect(const ImageView& image, const Position& pos) drawLine(image, pos[i], pos[(i + 1) % 4]); } +std::string escapeNonGraphical(const std::string& str) +{ + return ToUtf8(FromUtf8(str), true); +} + int main(int argc, char* argv[]) { DecodeHints hints; @@ -130,9 +135,6 @@ int main(int argc, char* argv[]) hints.setEanAddOnSymbol(EanAddOnSymbol::Read); - if (oneLine) - angleEscape = true; - if (angleEscape) std::setlocale(LC_CTYPE, "en_US.UTF-8"); // Needed so `std::iswgraph()` in `ToUtf8(angleEscape)` does not 'swallow' all printable non-ascii utf8 chars @@ -175,7 +177,7 @@ int main(int argc, char* argv[]) if (oneLine) { std::cout << filePath << " " << ToString(result.format()); if (result.isValid()) - std::cout << " \"" << ToUtf8(result.text(), angleEscape) << "\""; + std::cout << " \"" << escapeNonGraphical(result.utf8()) << "\""; else if (result.format() != BarcodeFormat::None) std::cout << " " << ToString(result.status()); std::cout << "\n"; @@ -190,9 +192,9 @@ int main(int argc, char* argv[]) std::cout << "File: " << filePath << "\n"; firstFile = false; } - std::cout << "Text: \"" << ToUtf8(result.text(), angleEscape) << "\"\n" - << "Bytes: " << ToHex(result.bytes()) << "\n" + std::cout << "Text: \"" << (angleEscape ? escapeNonGraphical(result.utf8()) : result.utf8()) << "\"\n" << "TextECI: \"" << result.utf8ECI() << "\"\n" + << "Bytes: " << ToHex(result.bytes()) << "\n" << "BytesECI: " << ToHex(result.bytesECI()) << "\n" << "Format: " << ToString(result.format()) << "\n" << "Identifier: " << result.symbologyIdentifier() << "\n" From 46186893204429a3712e372d36c95d5e01237be6 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 20 Jun 2022 09:06:37 +0200 Subject: [PATCH 48/88] Result: add new `utf8` property (forgot in last commit) --- core/src/Result.cpp | 6 ++++++ core/src/Result.h | 1 + 2 files changed, 7 insertions(+) diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 15399dea0a..fc1a86656a 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -8,6 +8,7 @@ #include "DecoderResult.h" #include "TextDecoder.h" +#include "TextUtfEncoding.h" #include #include @@ -59,6 +60,11 @@ ByteArray Result::bytesECI() const return _content.bytesECI(); } +std::string Result::utf8() const +{ + return TextUtfEncoding::ToUtf8(_content.text()); +} + std::string Result::utf8ECI() const { return _content.utf8ECI(); diff --git a/core/src/Result.h b/core/src/Result.h index 0bad7c7f03..24238bcee8 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -48,6 +48,7 @@ class Result // WARNING: this is an experimental API and may change/disappear const ByteArray& bytes() const; ByteArray bytesECI() const; + std::string utf8() const; std::string utf8ECI() const; ContentType contentType() const; bool hasECI() const; From feba841deec1041e1e2a394afb79122b5e818094 Mon Sep 17 00:00:00 2001 From: axxel Date: Mon, 20 Jun 2022 10:00:04 +0200 Subject: [PATCH 49/88] Writers: add utf8 overload for `encode()` functions To prevent a blatant inconsistency between writing and reading with regards to utf8 vs utf16 input/output... --- core/src/MultiFormatWriter.cpp | 6 ++++++ core/src/MultiFormatWriter.h | 1 + core/src/aztec/AZWriter.cpp | 6 ++++++ core/src/aztec/AZWriter.h | 1 + core/src/datamatrix/DMWriter.cpp | 6 ++++++ core/src/datamatrix/DMWriter.h | 1 + core/src/oned/ODCodabarWriter.cpp | 6 ++++++ core/src/oned/ODCodabarWriter.h | 1 + core/src/oned/ODCode128Writer.cpp | 6 ++++++ core/src/oned/ODCode128Writer.h | 1 + core/src/oned/ODCode39Writer.cpp | 6 ++++++ core/src/oned/ODCode39Writer.h | 1 + core/src/oned/ODCode93Writer.cpp | 6 ++++++ core/src/oned/ODCode93Writer.h | 1 + core/src/oned/ODEAN13Writer.cpp | 6 ++++++ core/src/oned/ODEAN13Writer.h | 1 + core/src/oned/ODEAN8Writer.cpp | 6 ++++++ core/src/oned/ODEAN8Writer.h | 1 + core/src/oned/ODITFWriter.cpp | 6 ++++++ core/src/oned/ODITFWriter.h | 1 + core/src/oned/ODUPCAWriter.cpp | 6 ++++++ core/src/oned/ODUPCAWriter.h | 1 + core/src/oned/ODUPCEWriter.cpp | 6 ++++++ core/src/oned/ODUPCEWriter.h | 1 + core/src/pdf417/PDFWriter.cpp | 6 ++++++ core/src/pdf417/PDFWriter.h | 1 + core/src/qrcode/QRWriter.cpp | 6 ++++++ core/src/qrcode/QRWriter.h | 1 + test/blackbox/TestWriterMain.cpp | 4 ++-- test/unit/oned/ODCodaBarWriterTest.cpp | 17 +++++++++-------- test/unit/oned/ODCode128WriterTest.cpp | 16 ++++++++-------- test/unit/oned/ODCode39ExtendedModeTest.cpp | 12 ++++++------ test/unit/oned/ODEAN13WriterTest.cpp | 8 ++++---- test/unit/oned/ODEAN8WriterTest.cpp | 8 ++++---- test/unit/oned/ODUPCAWriterTest.cpp | 6 +++--- test/unit/oned/ODUPCEWriterTest.cpp | 10 +++++----- 36 files changed, 139 insertions(+), 40 deletions(-) diff --git a/core/src/MultiFormatWriter.cpp b/core/src/MultiFormatWriter.cpp index 464dbc8054..5a03a6a4b3 100644 --- a/core/src/MultiFormatWriter.cpp +++ b/core/src/MultiFormatWriter.cpp @@ -20,6 +20,7 @@ #include "pdf417/PDFWriter.h" #include "qrcode/QRErrorCorrectionLevel.h" #include "qrcode/QRWriter.h" +#include "TextUtfEncoding.h" #include @@ -66,4 +67,9 @@ MultiFormatWriter::encode(const std::wstring& contents, int width, int height) c } } +BitMatrix MultiFormatWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // ZXing diff --git a/core/src/MultiFormatWriter.h b/core/src/MultiFormatWriter.h index 88b1c61591..f63ca03edb 100644 --- a/core/src/MultiFormatWriter.h +++ b/core/src/MultiFormatWriter.h @@ -50,6 +50,7 @@ class MultiFormatWriter } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: BarcodeFormat _format; diff --git a/core/src/aztec/AZWriter.cpp b/core/src/aztec/AZWriter.cpp index b41a15a62a..6e6b0ad0d7 100644 --- a/core/src/aztec/AZWriter.cpp +++ b/core/src/aztec/AZWriter.cpp @@ -9,6 +9,7 @@ #include "AZEncoder.h" #include "CharacterSet.h" #include "TextEncoder.h" +#include "TextUtfEncoding.h" #include @@ -29,4 +30,9 @@ Writer::encode(const std::wstring& contents, int width, int height) const return Inflate(std::move(aztec.matrix), width, height, _margin); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::Aztec diff --git a/core/src/aztec/AZWriter.h b/core/src/aztec/AZWriter.h index 1a41f6267e..aa80d46a30 100644 --- a/core/src/aztec/AZWriter.h +++ b/core/src/aztec/AZWriter.h @@ -41,6 +41,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: CharacterSet _encoding; diff --git a/core/src/datamatrix/DMWriter.cpp b/core/src/datamatrix/DMWriter.cpp index a95f5ad8a2..8c8f7bd3d3 100644 --- a/core/src/datamatrix/DMWriter.cpp +++ b/core/src/datamatrix/DMWriter.cpp @@ -13,6 +13,7 @@ #include "DMHighLevelEncoder.h" #include "DMSymbolInfo.h" #include "DMSymbolShape.h" +#include "TextUtfEncoding.h" #include #include @@ -110,4 +111,9 @@ Writer::encode(const std::wstring& contents, int width, int height) const return Inflate(std::move(result), width, height, _quietZone); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::DataMatrix diff --git a/core/src/datamatrix/DMWriter.h b/core/src/datamatrix/DMWriter.h index 61b0caba2a..f126e6eb35 100644 --- a/core/src/datamatrix/DMWriter.h +++ b/core/src/datamatrix/DMWriter.h @@ -44,6 +44,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: SymbolShape _shapeHint; diff --git a/core/src/oned/ODCodabarWriter.cpp b/core/src/oned/ODCodabarWriter.cpp index 1d74711299..25c42edbfc 100644 --- a/core/src/oned/ODCodabarWriter.cpp +++ b/core/src/oned/ODCodabarWriter.cpp @@ -7,6 +7,7 @@ #include "ODCodabarWriter.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" #include @@ -126,4 +127,9 @@ CodabarWriter::encode(const std::wstring& contents_, int width, int height) cons return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix CodabarWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCodabarWriter.h b/core/src/oned/ODCodabarWriter.h index 7304d49efc..10914313a7 100644 --- a/core/src/oned/ODCodabarWriter.h +++ b/core/src/oned/ODCodabarWriter.h @@ -24,6 +24,7 @@ class CodabarWriter public: CodabarWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode128Writer.cpp b/core/src/oned/ODCode128Writer.cpp index 2325376d5e..b737af2fca 100644 --- a/core/src/oned/ODCode128Writer.cpp +++ b/core/src/oned/ODCode128Writer.cpp @@ -8,6 +8,7 @@ #include "ODCode128Patterns.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -252,4 +253,9 @@ Code128Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code128Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode128Writer.h b/core/src/oned/ODCode128Writer.h index 5e517a66a6..386bf5cefc 100644 --- a/core/src/oned/ODCode128Writer.h +++ b/core/src/oned/ODCode128Writer.h @@ -24,6 +24,7 @@ class Code128Writer public: Code128Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode39Writer.cpp b/core/src/oned/ODCode39Writer.cpp index e05faa661f..d6732cd801 100644 --- a/core/src/oned/ODCode39Writer.cpp +++ b/core/src/oned/ODCode39Writer.cpp @@ -9,6 +9,7 @@ #include "CharacterSet.h" #include "ODWriterHelper.h" #include "TextEncoder.h" +#include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" #include @@ -167,4 +168,9 @@ Code39Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code39Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode39Writer.h b/core/src/oned/ODCode39Writer.h index 3342490301..20194b572f 100644 --- a/core/src/oned/ODCode39Writer.h +++ b/core/src/oned/ODCode39Writer.h @@ -24,6 +24,7 @@ class Code39Writer public: Code39Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode93Writer.cpp b/core/src/oned/ODCode93Writer.cpp index f84693ffce..fb2c26157c 100644 --- a/core/src/oned/ODCode93Writer.cpp +++ b/core/src/oned/ODCode93Writer.cpp @@ -7,6 +7,7 @@ #include "ODCode93Writer.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" #include "ZXTestSupport.h" @@ -183,4 +184,9 @@ Code93Writer::encode(const std::wstring& contents_, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code93Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode93Writer.h b/core/src/oned/ODCode93Writer.h index e33f4f512b..40654c8ccf 100644 --- a/core/src/oned/ODCode93Writer.h +++ b/core/src/oned/ODCode93Writer.h @@ -22,6 +22,7 @@ class Code93Writer public: Code93Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODEAN13Writer.cpp b/core/src/oned/ODEAN13Writer.cpp index 156ac51999..cf99be12cc 100644 --- a/core/src/oned/ODEAN13Writer.cpp +++ b/core/src/oned/ODEAN13Writer.cpp @@ -8,6 +8,7 @@ #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -53,4 +54,9 @@ EAN13Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix EAN13Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODEAN13Writer.h b/core/src/oned/ODEAN13Writer.h index bfed737bc1..c9086941d6 100644 --- a/core/src/oned/ODEAN13Writer.h +++ b/core/src/oned/ODEAN13Writer.h @@ -24,6 +24,7 @@ class EAN13Writer public: EAN13Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODEAN8Writer.cpp b/core/src/oned/ODEAN8Writer.cpp index f659a1cb18..652c26f719 100644 --- a/core/src/oned/ODEAN8Writer.cpp +++ b/core/src/oned/ODEAN8Writer.cpp @@ -8,6 +8,7 @@ #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include @@ -42,4 +43,9 @@ EAN8Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix EAN8Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODEAN8Writer.h b/core/src/oned/ODEAN8Writer.h index 2bbabd265a..8c42ea969c 100644 --- a/core/src/oned/ODEAN8Writer.h +++ b/core/src/oned/ODEAN8Writer.h @@ -24,6 +24,7 @@ class EAN8Writer public: EAN8Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODITFWriter.cpp b/core/src/oned/ODITFWriter.cpp index 27b8f58e58..1f3e6f611d 100644 --- a/core/src/oned/ODITFWriter.cpp +++ b/core/src/oned/ODITFWriter.cpp @@ -7,6 +7,7 @@ #include "ODITFWriter.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -69,4 +70,9 @@ ITFWriter::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix ITFWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODITFWriter.h b/core/src/oned/ODITFWriter.h index de837dd3a5..f4cab9bb39 100644 --- a/core/src/oned/ODITFWriter.h +++ b/core/src/oned/ODITFWriter.h @@ -24,6 +24,7 @@ class ITFWriter public: ITFWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODUPCAWriter.cpp b/core/src/oned/ODUPCAWriter.cpp index 0a789b6e95..16574022fb 100644 --- a/core/src/oned/ODUPCAWriter.cpp +++ b/core/src/oned/ODUPCAWriter.cpp @@ -8,6 +8,7 @@ #include "BitMatrix.h" #include "ODEAN13Writer.h" +#include "TextUtfEncoding.h" #include @@ -24,4 +25,9 @@ UPCAWriter::encode(const std::wstring& contents, int width, int height) const return EAN13Writer().setMargin(_sidesMargin).encode(L'0' + contents, width, height); } +BitMatrix UPCAWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODUPCAWriter.h b/core/src/oned/ODUPCAWriter.h index 467fbf0682..22dacdac20 100644 --- a/core/src/oned/ODUPCAWriter.h +++ b/core/src/oned/ODUPCAWriter.h @@ -24,6 +24,7 @@ class UPCAWriter public: UPCAWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODUPCEWriter.cpp b/core/src/oned/ODUPCEWriter.cpp index 5adf99cc4f..ea23e32290 100644 --- a/core/src/oned/ODUPCEWriter.cpp +++ b/core/src/oned/ODUPCEWriter.cpp @@ -8,6 +8,7 @@ #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -47,4 +48,9 @@ UPCEWriter::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix UPCEWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODUPCEWriter.h b/core/src/oned/ODUPCEWriter.h index 6e48975970..90fd7b0b8c 100644 --- a/core/src/oned/ODUPCEWriter.h +++ b/core/src/oned/ODUPCEWriter.h @@ -24,6 +24,7 @@ class UPCEWriter public: UPCEWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/pdf417/PDFWriter.cpp b/core/src/pdf417/PDFWriter.cpp index 19543119d6..400208eb50 100644 --- a/core/src/pdf417/PDFWriter.cpp +++ b/core/src/pdf417/PDFWriter.cpp @@ -7,6 +7,7 @@ #include "PDFWriter.h" #include "PDFEncoder.h" #include "BitMatrix.h" +#include "TextUtfEncoding.h" #include @@ -111,6 +112,11 @@ Writer::encode(const std::wstring& contents, int width, int height) const } } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + Writer::Writer() { _encoder.reset(new Encoder); diff --git a/core/src/pdf417/PDFWriter.h b/core/src/pdf417/PDFWriter.h index a9e01c943b..b9bf3c3606 100644 --- a/core/src/pdf417/PDFWriter.h +++ b/core/src/pdf417/PDFWriter.h @@ -60,6 +60,7 @@ class Writer BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _margin = -1; diff --git a/core/src/qrcode/QRWriter.cpp b/core/src/qrcode/QRWriter.cpp index 63a161150e..8f0597cab3 100644 --- a/core/src/qrcode/QRWriter.cpp +++ b/core/src/qrcode/QRWriter.cpp @@ -11,6 +11,7 @@ #include "QREncodeResult.h" #include "QREncoder.h" #include "QRErrorCorrectionLevel.h" +#include "TextUtfEncoding.h" #include #include @@ -42,4 +43,9 @@ BitMatrix Writer::encode(const std::wstring& contents, int width, int height) co return Inflate(std::move(code.matrix), width, height, _margin); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRWriter.h b/core/src/qrcode/QRWriter.h index 5aef3b70b8..d088c8bc20 100644 --- a/core/src/qrcode/QRWriter.h +++ b/core/src/qrcode/QRWriter.h @@ -58,6 +58,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _margin; diff --git a/test/blackbox/TestWriterMain.cpp b/test/blackbox/TestWriterMain.cpp index cb8e728198..420f0bf6ca 100644 --- a/test/blackbox/TestWriterMain.cpp +++ b/test/blackbox/TestWriterMain.cpp @@ -23,7 +23,7 @@ void savePng(const BitMatrix& matrix, BarcodeFormat format) int main() { - std::wstring text = L"http://www.google.com/"; + std::string text = "http://www.google.com/"; for (auto format : { BarcodeFormat::Aztec, BarcodeFormat::DataMatrix, @@ -33,7 +33,7 @@ int main() savePng(MultiFormatWriter(format).encode(text, 200, 200), format); } - text = L"012345678901234567890123456789"; + text = "012345678901234567890123456789"; using FormatSpecs = std::vector>; for (const auto& [format, length] : FormatSpecs({ {BarcodeFormat::Codabar, 0}, diff --git a/test/unit/oned/ODCodaBarWriterTest.cpp b/test/unit/oned/ODCodaBarWriterTest.cpp index f4071c33b7..f8662491fa 100644 --- a/test/unit/oned/ODCodaBarWriterTest.cpp +++ b/test/unit/oned/ODCodaBarWriterTest.cpp @@ -10,6 +10,7 @@ #include "DecodeHints.h" #include "Result.h" #include "oned/ODCodabarReader.h" +#include "TextUtfEncoding.h" #include "gtest/gtest.h" #include @@ -18,7 +19,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(CodabarWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -27,7 +28,7 @@ namespace { TEST(ODCodaBarWriterTest, Encode) { - EXPECT_EQ(Encode(L"B515-3/B"), + EXPECT_EQ(Encode("B515-3/B"), "00000" "1001001011" "0110101001" "0101011001" "0110101001" "0101001101" "0110010101" "01101101011" "01001001011" @@ -36,7 +37,7 @@ TEST(ODCodaBarWriterTest, Encode) TEST(ODCodaBarWriterTest, Encode2) { - EXPECT_EQ(Encode(L"T123T"), + EXPECT_EQ(Encode("T123T"), "00000" "1011001001" "0101011001" "0101001011" "0110010101" "01011001001" "00000"); @@ -44,20 +45,20 @@ TEST(ODCodaBarWriterTest, Encode2) TEST(ODCodaBarWriterTest, AltStartEnd) { - EXPECT_EQ(Encode(L"T123456789-$T"), Encode(L"A123456789-$A")); + EXPECT_EQ(Encode("T123456789-$T"), Encode("A123456789-$A")); } TEST(ODCodaBarWriterTest, FullCircle) { - std::wstring text = L"A0123456789-$:/.+A"; + std::string text = "A0123456789-$:/.+A"; BitArray row; CodabarWriter().encode(text, 0, 0).getRow(0, row); Result res = CodabarReader(DecodeHints().setReturnCodabarStartEnd(true)).decodeSingleRow(0, row); - EXPECT_EQ(text, res.text()); + EXPECT_EQ(text, res.utf8()); } TEST(ODCodaBarWriterTest, InvalidChars) { - EXPECT_THROW({Encode(L"AxA");}, std::invalid_argument ); - EXPECT_THROW({Encode(L"a0a");}, std::invalid_argument ); + EXPECT_THROW({Encode("AxA");}, std::invalid_argument ); + EXPECT_THROW({Encode("a0a");}, std::invalid_argument ); } diff --git a/test/unit/oned/ODCode128WriterTest.cpp b/test/unit/oned/ODCode128WriterTest.cpp index 010854357f..0d25f605d4 100644 --- a/test/unit/oned/ODCode128WriterTest.cpp +++ b/test/unit/oned/ODCode128WriterTest.cpp @@ -92,11 +92,11 @@ TEST(ODCode128Writer, EncodeWithFncsAndNumberInCodesetA) TEST(ODCode128Writer, RoundtripGS1) { auto toEncode = L"\xf1" "10958" "\xf1" "17160526"; - auto expected = L"10958\u001D17160526"; + auto expected = "10958\u001D17160526"; auto encResult = Code128Writer().encode(toEncode, 0, 0); auto decResult = Decode(encResult); - auto actual = decResult.text(); + auto actual = decResult.utf8(); EXPECT_EQ(actual, expected); EXPECT_EQ(decResult.symbologyIdentifier(), "]C1"); } @@ -104,11 +104,11 @@ TEST(ODCode128Writer, RoundtripGS1) TEST(ODCode128Writer, RoundtripFNC1) { auto toEncode = L"1\xf1" "0958" "\xf1" "17160526"; - auto expected = L"1\u001D0958\u001D17160526"; + auto expected = "1\u001D0958\u001D17160526"; auto encResult = Code128Writer().encode(toEncode, 0, 0); auto decResult = Decode(encResult); - auto actual = decResult.text(); + auto actual = decResult.utf8(); EXPECT_EQ(actual, expected); EXPECT_EQ(decResult.symbologyIdentifier(), "]C0"); } @@ -116,7 +116,7 @@ TEST(ODCode128Writer, RoundtripFNC1) TEST(ODCode128Writer, EncodeSwitchCodesetFromAToB) { // start with A switch to B and back to A - auto toEncode = std::wstring(L"\0ABab\u0010", 6); + auto toEncode = std::string("\0ABab\u0010", 6); // "\0" "A" "B" Switch to B "a" "b" Switch to A "\u0010" check digit auto expected = QUIET_SPACE + START_CODE_A + "10100001100" + "10100011000" + "10001011000" + SWITCH_CODE_B + "10010110000" + "10010000110" + SWITCH_CODE_A + "10100111100" + "11001110100" + STOP + QUIET_SPACE; @@ -124,14 +124,14 @@ TEST(ODCode128Writer, EncodeSwitchCodesetFromAToB) auto actual = LineMatrixToString(encoded); EXPECT_EQ(actual, expected); - auto actualRoundTrip = Decode(encoded).text(); + auto actualRoundTrip = Decode(encoded).utf8(); EXPECT_EQ(actualRoundTrip, toEncode); } TEST(ODCode128Writer, EncodeSwitchCodesetFromBToA) { // start with B switch to A and back to B - auto toEncode = std::wstring(L"ab\0ab", 5); + auto toEncode = std::string("ab\0ab", 5); // "a" "b" Switch to A "\0 "Switch to B" "a" "b" check digit auto expected = QUIET_SPACE + START_CODE_B + "10010110000" + "10010000110" + SWITCH_CODE_A + "10100001100" + SWITCH_CODE_B + "10010110000" + "10010000110" + "11010001110" + STOP + QUIET_SPACE; @@ -139,6 +139,6 @@ TEST(ODCode128Writer, EncodeSwitchCodesetFromBToA) auto actual = LineMatrixToString(encoded); EXPECT_EQ(actual, expected); - auto actualRoundTrip = Decode(encoded).text(); + auto actualRoundTrip = Decode(encoded).utf8(); EXPECT_EQ(actualRoundTrip, toEncode); } diff --git a/test/unit/oned/ODCode39ExtendedModeTest.cpp b/test/unit/oned/ODCode39ExtendedModeTest.cpp index 0c256971a4..ca172b4ec1 100644 --- a/test/unit/oned/ODCode39ExtendedModeTest.cpp +++ b/test/unit/oned/ODCode39ExtendedModeTest.cpp @@ -15,12 +15,12 @@ using namespace ZXing; using namespace ZXing::OneD; -static std::wstring Decode(std::string_view encoded) +static std::string Decode(std::string_view encoded) { Code39Reader sut(DecodeHints().setTryCode39ExtendedMode(true)); BitArray row = Utility::ParseBitArray(encoded, '1'); Result result = sut.decodeSingleRow(0, row); - return result.text(); + return result.utf8(); } TEST(ODCode39ExtendedModeTest, Decode) @@ -37,7 +37,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10100100100101010010110101101001001001010110010110101010010010010101001101101010" "10100100100101101010010110101001001001010110100101101010010010010110110100101010" "1001001001010101100101101010010010010110101100101010010110110100000"), - std::wstring(L"\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 0x20)); + std::string("\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 0x20)); EXPECT_EQ(Decode( "00000100101101101010011010110101001001010010110101001011010010010100101011010010" @@ -49,7 +49,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10101010100101101101101001011010101100101101010010010100101001101101010101001001" "00101011011001010101001001001010101001101101010010010010110101001101010100100100" "1010110100110101010010010010101011001101010010110110100000"), - L" !\"#$%&'()*+,-./0123456789:;<=>?"); + " !\"#$%&'()*+,-./0123456789:;<=>?"); EXPECT_EQ(Decode( "00001001011011010101001001001010011010101101101010010110101101001011011011010010" @@ -59,7 +59,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10101011011001101010101001011010110110010110101010011011010101010010010010110101" "01001101010010010010101101010011010100100100101101101010010101001001001010101101" "001101010010010010110101101001010010110110100000"), - L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"); + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"); EXPECT_EQ(Decode( "00000100101101101010100100100101100110101010100101001001011010100101101001010010" @@ -73,5 +73,5 @@ TEST(ODCode39ExtendedModeTest, Decode) "10100101001001010010110101101001010010010110010110101010010100100101001101101010" "10100100100101011011010010101001001001010101011001101010010010010110101011001010" "1001001001010110101100101010010010010101011011001010010110110100000"), - L"`abcdefghijklmnopqrstuvwxyz{|}~"); + "`abcdefghijklmnopqrstuvwxyz{|}~"); } diff --git a/test/unit/oned/ODEAN13WriterTest.cpp b/test/unit/oned/ODEAN13WriterTest.cpp index 22cfd92da9..c1bd1deee4 100644 --- a/test/unit/oned/ODEAN13WriterTest.cpp +++ b/test/unit/oned/ODEAN13WriterTest.cpp @@ -14,7 +14,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(EAN13Writer().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -23,19 +23,19 @@ namespace { TEST(ODEAN13WriterTest, Encode1) { - std::wstring toEncode = L"5901234123457"; + std::string toEncode = "5901234123457"; std::string expected = "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN13WriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"590123412345"; + std::string toEncode = "590123412345"; std::string expected = "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN13WriterTest, EncodeIllegalCharacters) { - EXPECT_THROW({ Encode(L"5901234123abc"); }, std::invalid_argument); + EXPECT_THROW({ Encode("5901234123abc"); }, std::invalid_argument); } diff --git a/test/unit/oned/ODEAN8WriterTest.cpp b/test/unit/oned/ODEAN8WriterTest.cpp index c2bebf5d54..6df37af6c9 100644 --- a/test/unit/oned/ODEAN8WriterTest.cpp +++ b/test/unit/oned/ODEAN8WriterTest.cpp @@ -13,7 +13,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(EAN8Writer().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -22,19 +22,19 @@ namespace { TEST(ODEAN8WriterTest, Encode1) { - std::wstring toEncode = L"96385074"; + std::string toEncode = "96385074"; std::string expected = "0000101000101101011110111101011011101010100111011100101000100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN8WriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"9638507"; + std::string toEncode = "9638507"; std::string expected = "0000101000101101011110111101011011101010100111011100101000100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN8WriterTest, EncodeIllegalCharacters) { - EXPECT_THROW({ Encode(L"96385abc"); }, std::invalid_argument); + EXPECT_THROW({ Encode("96385abc"); }, std::invalid_argument); } diff --git a/test/unit/oned/ODUPCAWriterTest.cpp b/test/unit/oned/ODUPCAWriterTest.cpp index f015c6cfbc..66e02f3f78 100644 --- a/test/unit/oned/ODUPCAWriterTest.cpp +++ b/test/unit/oned/ODUPCAWriterTest.cpp @@ -13,7 +13,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(UPCAWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -22,14 +22,14 @@ namespace { TEST(ODUPCAWriterTest, Encode1) { - std::wstring toEncode = L"485963095124"; + std::string toEncode = "485963095124"; std::string expected = "00001010100011011011101100010001011010111101111010101011100101110100100111011001101101100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCAWriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"12345678901"; + std::string toEncode = "12345678901"; std::string expected = "00001010011001001001101111010100011011000101011110101010001001001000111010011100101100110110110010100000"; EXPECT_EQ(Encode(toEncode), expected); } diff --git a/test/unit/oned/ODUPCEWriterTest.cpp b/test/unit/oned/ODUPCEWriterTest.cpp index 9db92ee6cd..271a817ced 100644 --- a/test/unit/oned/ODUPCEWriterTest.cpp +++ b/test/unit/oned/ODUPCEWriterTest.cpp @@ -14,7 +14,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(UPCEWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -23,26 +23,26 @@ namespace { TEST(ODUPCEWriterTest, Encode1) { - std::wstring toEncode = L"05096893"; + std::string toEncode = "05096893"; std::string expected = "000010101110010100111000101101011110110111001011101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, EncodeSystem1) { - std::wstring toEncode = L"12345670"; + std::string toEncode = "12345670"; std::string expected = "000010100100110111101010001101110010000101001000101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"0509689"; + std::string toEncode = "0509689"; std::string expected = "000010101110010100111000101101011110110111001011101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, EncodeIllegalCharacters) { - EXPECT_THROW(Encode(L"05096abc"), std::invalid_argument); + EXPECT_THROW(Encode("05096abc"), std::invalid_argument); } From 6284572d96c0162453d714f5c4d42797dbd9e019 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 00:18:27 +0200 Subject: [PATCH 50/88] Content: cleanup text/utf8/utf16 situation and remove code duplication --- core/src/Content.cpp | 71 ++++++++++--------- core/src/Content.h | 4 +- core/src/DecoderResult.h | 2 +- core/src/Result.cpp | 2 +- core/src/pdf417/PDFDecodedBitStreamParser.cpp | 4 +- test/unit/ContentTest.cpp | 16 ++--- 6 files changed, 52 insertions(+), 47 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index f5b4e1a852..c7fe98a619 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -90,30 +90,14 @@ bool Content::canProcess() const return std::all_of(encodings.begin(), encodings.end(), [](Encoding e) { return CanProcess(e.eci); }); } -std::wstring Content::text() const -{ - if (!canProcess()) - return {}; - - auto fallbackCS = CharacterSetFromString(hintedCharset); - if (!hasECI && fallbackCS == CharacterSet::Unknown) - fallbackCS = guessEncoding(); - - std::wstring wstr; - ForEachECIBlock([&](ECI eci, int begin, int end) { - CharacterSet cs = eci == ECI::Unknown ? fallbackCS : ToCharacterSet(eci); - - TextDecoder::Append(wstr, bytes.data() + begin, end - begin, cs); - }); - return wstr; -} - -std::string Content::utf8ECI() const +std::wstring Content::render(bool withECI) const { if (empty() || !canProcess()) return {}; - std::wstring res = TextDecoder::FromLatin1(symbology.toString(true)); + std::wstring res; + if (withECI) + res = TextDecoder::FromLatin1(symbology.toString(true)); ECI lastECI = ECI::Unknown; auto fallbackCS = CharacterSetFromString(hintedCharset); if (!hasECI && fallbackCS == CharacterSet::Unknown) @@ -125,26 +109,45 @@ std::string Content::utf8ECI() const // * if !IsText(eci) the ToCharcterSet(eci) will return Unknown and we decode as binary CharacterSet cs = eci == ECI::Unknown ? fallbackCS : ToCharacterSet(eci); - // then find the eci to report back in the ECI designator - if (IsText(ToECI(cs))) // everything decoded as text is reported as utf8 - eci = ECI::UTF8; - else if (eci == ECI::Unknown) // implies !hasECI and fallbackCS is Unknown or Binary - eci = ECI::Binary; + if (withECI) { + // then find the eci to report back in the ECI designator + if (IsText(ToECI(cs))) // everything decoded as text is reported as utf8 + eci = ECI::UTF8; + else if (eci == ECI::Unknown) // implies !hasECI and fallbackCS is Unknown or Binary + eci = ECI::Binary; - if (lastECI != eci) - TextDecoder::AppendLatin1(res, ToString(eci)); - lastECI = eci; + if (lastECI != eci) + TextDecoder::AppendLatin1(res, ToString(eci)); + lastECI = eci; - std::wstring tmp; - TextDecoder::Append(tmp, bytes.data() + begin, end - begin, cs); - for (auto c : tmp) { - res += c; - if (c == L'\\') // in the ECI protocol a '\' has to be doubled + std::wstring tmp; + TextDecoder::Append(tmp, bytes.data() + begin, end - begin, cs); + for (auto c : tmp) { res += c; + if (c == L'\\') // in the ECI protocol a '\' has to be doubled + res += c; + } + } else { + TextDecoder::Append(res, bytes.data() + begin, end - begin, cs); } }); - return TextUtfEncoding::ToUtf8(res); + return res; +} + +std::wstring Content::utf16() const +{ + return render(false); +} + +std::string Content::utf8() const +{ + return TextUtfEncoding::ToUtf8(render(false)); +} + +std::string Content::utf8ECI() const +{ + return TextUtfEncoding::ToUtf8(render(true)); } ByteArray Content::bytesECI() const diff --git a/core/src/Content.h b/core/src/Content.h index 756d8b72fe..022cdc9569 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -33,6 +33,7 @@ class Content void ForEachECIBlock(FUNC f) const; void switchEncoding(ECI eci, bool isECI); + std::wstring render(bool withECI) const; public: struct Encoding @@ -70,7 +71,8 @@ class Content bool empty() const { return bytes.empty(); } bool canProcess() const; - std::wstring text() const; + std::wstring utf16() const; + std::string utf8() const; std::string utf8ECI() const; ByteArray bytesECI() const; CharacterSet guessEncoding() const; diff --git a/core/src/DecoderResult.h b/core/src/DecoderResult.h index a6ce5e6ab3..9908d1121c 100644 --- a/core/src/DecoderResult.h +++ b/core/src/DecoderResult.h @@ -58,7 +58,7 @@ class DecoderResult Content&& content() && { return std::move(_content); } // to keep the unit tests happy for now: - std::wstring text() const { return _content.text(); } + std::wstring text() const { return _content.utf16(); } std::string symbologyIdentifier() const { return _content.symbology.toString(false); } // Simple macro to set up getter/setter methods that save lots of boilerplate. diff --git a/core/src/Result.cpp b/core/src/Result.cpp index fc1a86656a..1e6a7e8bcb 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -62,7 +62,7 @@ ByteArray Result::bytesECI() const std::string Result::utf8() const { - return TextUtfEncoding::ToUtf8(_content.text()); + return _content.utf8(); } std::string Result::utf8ECI() const diff --git a/core/src/pdf417/PDFDecodedBitStreamParser.cpp b/core/src/pdf417/PDFDecodedBitStreamParser.cpp index 6f7a835309..3a5cc5eef8 100644 --- a/core/src/pdf417/PDFDecodedBitStreamParser.cpp +++ b/core/src/pdf417/PDFDecodedBitStreamParser.cpp @@ -569,7 +569,7 @@ static int DecodeMacroOptionalTextField(DecodeStatus& status, const std::vector< codeIndex = TextCompaction(status, codewords, codeIndex, result); // Converting to UTF-8 (backward-incompatible change for non-ASCII chars) - TextUtfEncoding::ToUtf8(result.text(), field); + field = result.utf8(); return codeIndex; } @@ -587,7 +587,7 @@ static int DecodeMacroOptionalNumericField(DecodeStatus& status, const std::vect codeIndex = NumericCompaction(status, codewords, codeIndex, result); - field = std::stoll(result.text()); + field = std::stoll(result.utf8()); return codeIndex; } diff --git a/test/unit/ContentTest.cpp b/test/unit/ContentTest.cpp index 19c3a5f8b1..39fa72ba25 100644 --- a/test/unit/ContentTest.cpp +++ b/test/unit/ContentTest.cpp @@ -25,14 +25,14 @@ TEST(ContentTest, Base) Content c; c.switchEncoding(CharacterSet::ISO8859_1); c.append(ByteArray{'A', 0xE9, 'Z'}); - EXPECT_EQ(c.text(), L"A\u00E9Z"); + EXPECT_EQ(c.utf16(), L"A\u00E9Z"); } { // set CharacterSet::ISO8859_5 Content c; c.switchEncoding(CharacterSet::ISO8859_5); c.append(ByteArray{'A', 0xE9, 'Z'}); - EXPECT_EQ(c.text(), L"A\u0449Z"); + EXPECT_EQ(c.utf16(), L"A\u0449Z"); } { // switch to CharacterSet::ISO8859_5 @@ -42,7 +42,7 @@ TEST(ContentTest, Base) c.switchEncoding(CharacterSet::ISO8859_5); EXPECT_FALSE(c.hasECI); c.append(ByteArray{'A', 0xE9, 'Z'}); - EXPECT_EQ(c.text(), L"A\u00E9ZA\u0449Z"); + EXPECT_EQ(c.utf16(), L"A\u00E9ZA\u0449Z"); } } @@ -52,7 +52,7 @@ TEST(ContentTest, GuessEncoding) Content c; c.append(ByteArray{'A', 0xE9, 'Z'}); EXPECT_EQ(c.guessEncoding(), CharacterSet::ISO8859_1); - EXPECT_EQ(c.text(), L"A\u00E9Z"); + EXPECT_EQ(c.utf16(), L"A\u00E9Z"); EXPECT_EQ(c.bytesECI(), c.bytes); } @@ -60,7 +60,7 @@ TEST(ContentTest, GuessEncoding) Content c; c.append(ByteArray{'A', 0x83, 0x65, 'Z'}); EXPECT_EQ(c.guessEncoding(), CharacterSet::Shift_JIS); - EXPECT_EQ(c.text(), L"A\u30C6Z"); + EXPECT_EQ(c.utf16(), L"A\u30C6Z"); } } @@ -72,7 +72,7 @@ TEST(ContentTest, ECI) c.switchEncoding(ECI::ISO8859_5); c.append(ByteArray{'A', 0xE9, 'Z'}); EXPECT_TRUE(c.hasECI); - EXPECT_EQ(c.text(), L"A\u00E9ZA\u0449Z"); + EXPECT_EQ(c.utf16(), L"A\u00E9ZA\u0449Z"); EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\xE9Z\\000007A\xE9Z")); } @@ -81,14 +81,14 @@ TEST(ContentTest, ECI) c.append(ByteArray{'A', 0x83, 0x65, 'Z'}); c.switchEncoding(ECI::ISO8859_5); c.append(ByteArray{'A', 0xE9, 'Z'}); - EXPECT_EQ(c.text(), L"A\u0083\u0065ZA\u0449Z"); + EXPECT_EQ(c.utf16(), L"A\u0083\u0065ZA\u0449Z"); EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\x83\x65Z\\000007A\xE9Z")); } { // double '\' Content c; c.append("C:\\Test"); - EXPECT_EQ(c.text(), L"C:\\Test"); + EXPECT_EQ(c.utf16(), L"C:\\Test"); EXPECT_EQ(c.bytesECI().asString(), std::string_view("C:\\\\Test")); } } From 48ec1947cd969de0a8b8f789eb87070da5ba4cb8 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 01:18:29 +0200 Subject: [PATCH 51/88] Result: #define ZX_USE_UTF8 to transition from std::wstring to std::string See https://github.com/nu-book/zxing-cpp/issues/338 for more information * Change the return type of `text()` and `ecLevel()` based on ZX_USE_UTF8. * Introduce `utf16()` as a (temporary?) backend for `text()`. * Add documentation. * Update examples, wrappers and testing code to use ZX_USE_UTF8. --- core/CMakeLists.txt | 1 + core/src/Result.cpp | 12 ++--- core/src/Result.h | 50 ++++++++++++++++--- example/ZXingOpenCV.h | 6 +-- example/ZXingQtReader.h | 4 +- example/ZXingReader.cpp | 17 ++++--- test/blackbox/BlackboxTestRunner.cpp | 5 +- test/blackbox/CMakeLists.txt | 1 + test/blackbox/TestReaderMain.cpp | 5 +- test/unit/CMakeLists.txt | 1 + test/unit/ThresholdBinarizerTest.cpp | 2 +- test/unit/oned/ODCode128ReaderTest.cpp | 18 +++---- test/unit/oned/ODCode39ReaderTest.cpp | 14 +++--- test/unit/oned/ODCode93ReaderTest.cpp | 6 +-- .../zxingcpp/src/main/cpp/CMakeLists.txt | 1 + .../zxingcpp/src/main/cpp/JNIUtils.cpp | 4 +- wrappers/python/zxing.cpp | 2 + wrappers/wasm/BarcodeReader.cpp | 16 +++--- wrappers/winrt/BarcodeReader.cpp | 4 +- 19 files changed, 107 insertions(+), 62 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e6c4d1a07f..655d569305 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -19,6 +19,7 @@ set (ZXING_CORE_LOCAL_DEFINES $<$:-DZXING_BUILD_READERS> $<$:-DZXING_BUILD_WRITERS> $<$:-DZXING_BUILD_FOR_TEST> + -DZX_USE_UTF8 # silence deprecation warning in Result.h ) if (MSVC) set (ZXING_CORE_LOCAL_DEFINES ${ZXING_CORE_LOCAL_DEFINES} diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 1e6a7e8bcb..9539e273fc 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -36,7 +36,7 @@ Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat _position(std::move(position)), _rawBytes(std::move(decodeResult).rawBytes()), _numBits(decodeResult.numBits()), - _ecLevel(TextDecoder::FromLatin1(decodeResult.ecLevel())), + _ecLevel(decodeResult.ecLevel()), _sai(decodeResult.structuredAppend()), _isMirrored(decodeResult.isMirrored()), _readerInit(decodeResult.readerInit()), @@ -45,11 +45,6 @@ Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat // TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra()) } -std::wstring Result::text() const -{ - return _content.text(); -} - const ByteArray& Result::bytes() const { return _content.bytes; @@ -65,6 +60,11 @@ std::string Result::utf8() const return _content.utf8(); } +std::wstring Result::utf16() const +{ + return _content.utf16(); +} + std::string Result::utf8ECI() const { return _content.utf8ECI(); diff --git a/core/src/Result.h b/core/src/Result.h index 24238bcee8..74dcb5f411 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -43,21 +43,57 @@ class Result BarcodeFormat format() const { return _format; } - std::wstring text() const; - - // WARNING: this is an experimental API and may change/disappear + /** + * @brief bytes is the raw / standard content without any modifications like character set conversions + */ const ByteArray& bytes() const; + + /** + * @brief bytesECI is the raw / standard content following the ECI protocol + */ ByteArray bytesECI() const; + + /** + * @brief utf8/utf16 is the bytes() content converted to utf8/16 based on ECI or guessed character set information + * + * Note: these two properties might only be available while transitioning text() from std::wstring to std::string. time will tell. + * see https://github.com/nu-book/zxing-cpp/issues/338 for a background discussion on the issue. + */ std::string utf8() const; + std::wstring utf16() const; + +#ifdef ZX_USE_UTF8 + std::string text() const { return utf8(); } + std::string ecLevel() const { return _ecLevel; } +#else +#pragma message( \ + "Warning: the return type of text() and ecLevel() will change to std::string. Please #define ZX_USE_UTF8 to transition before the next release.") + std::wstring text() const { return utf16(); } + std::wstring ecLevel() const { return {_ecLevel.begin(), _ecLevel.end()}; } +#endif + + /** + * @brief utf8ECI is the standard content following the ECI protocol with every character set ECI segment transcoded to utf8 + */ std::string utf8ECI() const; + + /** + * @brief contentType gives a hint to the type of content found (Text/Binary/GS1/etc.) + */ ContentType contentType() const; + + /** + * @brief hasECI specifies wheter or not an ECI tag was found + */ bool hasECI() const; - // END WARNING const Position& position() const { return _position; } void setPosition(Position pos) { _position = pos; } - int orientation() const; //< orientation of barcode in degree, see also Position::orientation() + /** + * @brief orientation of barcode in degree, see also Position::orientation() + */ + int orientation() const; /** * @brief isMirrored is the symbol mirrored (currently only supported by QRCode and DataMatrix) @@ -68,8 +104,6 @@ class Result [[deprecated]] const ByteArray& rawBytes() const { return _rawBytes; } [[deprecated]] int numBits() const { return _numBits; } - const std::wstring& ecLevel() const { return _ecLevel; } - /** * @brief symbologyIdentifier Symbology identifier "]cm" where "c" is symbology code character, "m" the modifier. */ @@ -125,7 +159,7 @@ class Result Position _position; ByteArray _rawBytes; int _numBits = 0; - std::wstring _ecLevel; + std::string _ecLevel; StructuredAppendInfo _sai; bool _isMirrored = false; bool _readerInit = false; diff --git a/example/ZXingOpenCV.h b/example/ZXingOpenCV.h index bf9cca06e7..8dbfb2545d 100644 --- a/example/ZXingOpenCV.h +++ b/example/ZXingOpenCV.h @@ -5,8 +5,9 @@ #pragma once +#define ZX_USE_UTF8 1 // see Result.h + #include "ReadBarcode.h" -#include "TextUtfEncoding.h" #include @@ -41,6 +42,5 @@ inline void DrawResult(cv::Mat& img, ZXing::Result res) int npts = contour.size(); cv::polylines(img, &pts, &npts, 1, true, CV_RGB(0, 255, 0)); - cv::putText(img, ZXing::TextUtfEncoding::ToUtf8(res.text()), cv::Point(10, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, - CV_RGB(0, 255, 0)); + cv::putText(img, res.text(), cv::Point(10, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, CV_RGB(0, 255, 0)); } diff --git a/example/ZXingQtReader.h b/example/ZXingQtReader.h index 07effc10d0..675b2d0205 100644 --- a/example/ZXingQtReader.h +++ b/example/ZXingQtReader.h @@ -5,6 +5,8 @@ #pragma once +#define ZX_USE_UTF8 1 // see Result.h + #include "ReadBarcode.h" #include @@ -115,7 +117,7 @@ class Result : private ZXing::Result Result() : ZXing::Result(ZXing::DecodeStatus::NotFound) {} // required for qmetatype machinery explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)) { - _text = QString::fromWCharArray(ZXing::Result::text().c_str()); + _text = QString::fromStdString(ZXing::Result::text()); _bytes = QByteArray(reinterpret_cast(ZXing::Result::bytes().data()), Size(ZXing::Result::bytes())); auto& pos = ZXing::Result::position(); auto qp = [&pos](int i) { return QPoint(pos[i].x, pos[i].y); }; diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 64f91e1701..db7ac9239f 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -4,6 +4,8 @@ */ // SPDX-License-Identifier: Apache-2.0 +#define ZX_USE_UTF8 1 // see Result.h + #include "ReadBarcode.h" #include "TextUtfEncoding.h" #include "GTIN.h" @@ -23,7 +25,6 @@ #include using namespace ZXing; -using namespace TextUtfEncoding; static void PrintUsage(const char* exePath) { @@ -113,7 +114,7 @@ void drawRect(const ImageView& image, const Position& pos) std::string escapeNonGraphical(const std::string& str) { - return ToUtf8(FromUtf8(str), true); + return TextUtfEncoding::ToUtf8(TextUtfEncoding::FromUtf8(str), true); } int main(int argc, char* argv[]) @@ -177,7 +178,7 @@ int main(int argc, char* argv[]) if (oneLine) { std::cout << filePath << " " << ToString(result.format()); if (result.isValid()) - std::cout << " \"" << escapeNonGraphical(result.utf8()) << "\""; + std::cout << " \"" << escapeNonGraphical(result.text()) << "\""; else if (result.format() != BarcodeFormat::None) std::cout << " " << ToString(result.status()); std::cout << "\n"; @@ -192,7 +193,7 @@ int main(int argc, char* argv[]) std::cout << "File: " << filePath << "\n"; firstFile = false; } - std::cout << "Text: \"" << (angleEscape ? escapeNonGraphical(result.utf8()) : result.utf8()) << "\"\n" + std::cout << "Text: \"" << (angleEscape ? escapeNonGraphical(result.text()) : result.text()) << "\"\n" << "TextECI: \"" << result.utf8ECI() << "\"\n" << "Bytes: " << ToHex(result.bytes()) << "\n" << "BytesECI: " << ToHex(result.bytesECI()) << "\n" @@ -210,19 +211,19 @@ int main(int argc, char* argv[]) std::cout << key << v << "\n"; }; - printOptional("EC Level: ", ToUtf8(result.ecLevel())); + printOptional("EC Level: ", result.ecLevel()); if (result.lineCount()) std::cout << "Lines: " << result.lineCount() << "\n"; if ((BarcodeFormat::EAN13 | BarcodeFormat::EAN8 | BarcodeFormat::UPCA | BarcodeFormat::UPCE) .testFlag(result.format())) { - printOptional("Country: ", GTIN::LookupCountryIdentifier(ToUtf8(result.text()), result.format())); + printOptional("Country: ", GTIN::LookupCountryIdentifier(result.text(), result.format())); printOptional("Add-On: ", GTIN::EanAddOn(result)); printOptional("Price: ", GTIN::Price(GTIN::EanAddOn(result))); printOptional("Issue #: ", GTIN::IssueNr(GTIN::EanAddOn(result))); - } else if (result.format() == BarcodeFormat::ITF && result.text().length() == 14) { - printOptional("Country: ", GTIN::LookupCountryIdentifier(ToUtf8(result.text()), result.format())); + } else if (result.format() == BarcodeFormat::ITF && Size(result.bytes()) == 14) { + printOptional("Country: ", GTIN::LookupCountryIdentifier(result.text(), result.format())); } if (result.isPartOfSequence()) diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 085bb41d95..e28f3a1e02 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -9,7 +9,6 @@ #include "DecoderResult.h" #include "ImageLoader.h" #include "ReadBarcode.h" -#include "TextUtfEncoding.h" #include "ThresholdBinarizer.h" #include "ZXContainerAlgorithms.h" #include "pdf417/PDFReader.h" @@ -65,7 +64,7 @@ namespace { static std::string getResultValue(const Result& result, const std::string& key) { if (key == "ecLevel") - return TextUtfEncoding::ToUtf8(result.ecLevel()); + return result.ecLevel(); if (key == "orientation") return std::to_string(result.orientation()); if (key == "symbologyIdentifier") @@ -135,7 +134,7 @@ static std::string checkResult(const fs::path& imgPath, std::string_view expecte } if (auto expected = readFile(".txt")) { - auto utf8Result = TextUtfEncoding::ToUtf8(result.text()); + auto utf8Result = result.utf8(); return utf8Result != *expected ? fmt::format("Content mismatch: expected '{}' but got '{}'", *expected, utf8Result) : ""; } diff --git a/test/blackbox/CMakeLists.txt b/test/blackbox/CMakeLists.txt index f20f4127c7..2d7d9e3036 100644 --- a/test/blackbox/CMakeLists.txt +++ b/test/blackbox/CMakeLists.txt @@ -15,6 +15,7 @@ if (BUILD_READERS) ZXing::ZXing fmt::fmt stb::stb $<$,$,9.0>>:stdc++fs> ) + target_compile_definitions(ReaderTest PRIVATE ZX_USE_UTF8) add_test(NAME ReaderTest COMMAND ReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/../samples) endif() diff --git a/test/blackbox/TestReaderMain.cpp b/test/blackbox/TestReaderMain.cpp index 4aad4905cc..ebc4ed972e 100644 --- a/test/blackbox/TestReaderMain.cpp +++ b/test/blackbox/TestReaderMain.cpp @@ -6,7 +6,6 @@ #include "BlackboxTestRunner.h" #include "ImageLoader.h" -#include "TextUtfEncoding.h" #include "ZXContainerAlgorithms.h" #include "ZXFilesystem.h" @@ -44,12 +43,12 @@ int main(int argc, char** argv) Result result = ReadBarcode(ImageLoader::load(argv[i]).rotated(rotation), hints); std::cout << argv[i] << ": "; if (result.isValid()) - std::cout << ToString(result.format()) << ": " << TextUtfEncoding::ToUtf8(result.text()) << "\n"; + std::cout << ToString(result.format()) << ": " << result.text() << "\n"; else std::cout << "FAILED\n"; if (result.isValid() && getenv("WRITE_TEXT")) { std::ofstream f(fs::path(argv[i]).replace_extension(".txt")); - f << TextUtfEncoding::ToUtf8(result.text()); + f << result.text(); } } return 0; diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 9bd281796d..96ddb9b60e 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -65,5 +65,6 @@ add_executable (UnitTest target_include_directories (UnitTest PRIVATE .) target_link_libraries (UnitTest ZXing::ZXing GTest::gtest_main GTest::gmock) +target_compile_definitions(UnitTest PRIVATE ZX_USE_UTF8) add_test(NAME UnitTest COMMAND UnitTest) diff --git a/test/unit/ThresholdBinarizerTest.cpp b/test/unit/ThresholdBinarizerTest.cpp index ae6449f8dd..aee132bdcc 100644 --- a/test/unit/ThresholdBinarizerTest.cpp +++ b/test/unit/ThresholdBinarizerTest.cpp @@ -100,5 +100,5 @@ TEST(ThresholdBinarizerTest, PatternRowClear) result = reader.decode(ThresholdBinarizer(getImageView(buf, bits), 0x7F)); EXPECT_TRUE(result.isValid()); - EXPECT_EQ(result.text(), L"(91)12345678901234567890123456789012345678901234567890123456789012345678"); + EXPECT_EQ(result.text(), "(91)12345678901234567890123456789012345678901234567890123456789012345678"); } diff --git a/test/unit/oned/ODCode128ReaderTest.cpp b/test/unit/oned/ODCode128ReaderTest.cpp index ed37bcf79c..c22f655333 100644 --- a/test/unit/oned/ODCode128ReaderTest.cpp +++ b/test/unit/oned/ODCode128ReaderTest.cpp @@ -37,7 +37,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 2, 1, 2, 3, 1, 2, 2, 2, 1, 2, 2, 3, 1, 1, 2, 2, 2 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C0"); - EXPECT_EQ(result.text(), L"2001"); + EXPECT_EQ(result.utf8(), "2001"); } { @@ -45,7 +45,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 4, 1, 1, 1, 3, 1, 2, 2, 1, 2, 3, 1, 2, 2, 2, 1, 2, 2, 1, 3, 2, 1, 3, 1 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C1"); - EXPECT_EQ(result.text(), L"2001"); + EXPECT_EQ(result.utf8(), "2001"); } { @@ -53,7 +53,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 1, 1, 1, 3, 2, 3, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 2, 1, 2, 3, 2, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"AB"); + EXPECT_EQ(result.utf8(), "AB"); } { @@ -61,7 +61,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 4, 1, 2, 1, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 4, 2, 1, 2, 1, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"zB"); + EXPECT_EQ(result.utf8(), "zB"); } { @@ -69,7 +69,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 1, 1, 3, 1, 4, 1, 4, 1, 1, 1, 3, 1, 1, 1, 4, 1, 3, 1, 1, 1, 1, 3, 2, 3, 1, 2, 3, 1, 2, 2 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"99A"); + EXPECT_EQ(result.utf8(), "99A"); } { @@ -77,7 +77,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 2, 3, 2, 1, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 3, 2, 2, 2, 1, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C0"); // Just ignoring, not giving FormatError - EXPECT_EQ(result.text(), L"?\u001DB"); + EXPECT_EQ(result.utf8(), "?\u001DB"); } } @@ -88,7 +88,7 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 1, 1, 1, 1, 4, 3, 1, 3, 1, 1, 4, 1 }); auto result = parse('C', row); EXPECT_FALSE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.utf8(), "92"); } { @@ -96,7 +96,7 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 1, 1, 4, 3, 1, 1, 1, 1, 3, 1, 4, 1, 1, 1, 1, 1, 4, 3, 3, 3, 1, 1, 2, 1 }); auto result = parse('B', row); EXPECT_TRUE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.utf8(), "92"); } { @@ -104,6 +104,6 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 3, 2, 1, 1, 2, 2, 1, 1, 4, 3, 1, 1, 2, 2, 3, 2, 1, 1, 1, 2, 1, 4, 2, 1 }); auto result = parse('B', row); EXPECT_TRUE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.utf8(), "92"); } } diff --git a/test/unit/oned/ODCode39ReaderTest.cpp b/test/unit/oned/ODCode39ReaderTest.cpp index 42da6c6ce0..893c2a008c 100644 --- a/test/unit/oned/ODCode39ReaderTest.cpp +++ b/test/unit/oned/ODCode39ReaderTest.cpp @@ -33,39 +33,39 @@ TEST(ODCode39ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"A"); + EXPECT_EQ(result.utf8(), "A"); } { // "A" with checksum PatternRow row({ 2, 1, 1, 1, 1, 2, 1, 1, 2, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row, DecodeHints().setValidateCode39CheckSum(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A3"); - EXPECT_EQ(result.text(), L"A"); + EXPECT_EQ(result.utf8(), "A"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"AA"); + EXPECT_EQ(result.utf8(), "AA"); } { // Extended "a" PatternRow row({ 1, 2, 1, 1, 1, 2, 1, 2, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row, DecodeHints().setTryCode39ExtendedMode(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A4"); - EXPECT_EQ(result.text(), L"a"); + EXPECT_EQ(result.utf8(), "a"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"+A"); + EXPECT_EQ(result.utf8(), "+A"); } { // Extended "a" with checksum PatternRow row({ 1, 2, 1, 1, 1, 2, 1, 2, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2, 0, 2, 1, 1, 2, 1, 1, 2, 1, 1 }); auto result = parse(row, DecodeHints().setTryCode39ExtendedMode(true).setValidateCode39CheckSum(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A7"); - EXPECT_EQ(result.text(), L"a"); + EXPECT_EQ(result.utf8(), "a"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"+A8"); + EXPECT_EQ(result.utf8(), "+A8"); } } diff --git a/test/unit/oned/ODCode93ReaderTest.cpp b/test/unit/oned/ODCode93ReaderTest.cpp index 221d37d957..b037f1acbc 100644 --- a/test/unit/oned/ODCode93ReaderTest.cpp +++ b/test/unit/oned/ODCode93ReaderTest.cpp @@ -14,17 +14,17 @@ using namespace ZXing; using namespace ZXing::OneD; -static std::wstring Decode(std::string_view input) +static std::string Decode(std::string_view input) { Code93Reader sut; auto row = Utility::ParseBitArray(input, '1'); auto result = sut.decodeSingleRow(0, row); - return result.text(); + return result.utf8(); } TEST(ODCode93ReaderTest, Decode) { - auto expected = std::wstring(L"Code93!\n$%/+ :\x1b;[{\x7f\x00@`\x7f\x7f\x7f", 25); + auto expected = std::string("Code93!\n$%/+ :\x1b;[{\x7f\x00@`\x7f\x7f\x7f", 25); auto decoded = Decode( "00000010101111011010001010011001010010110010011001011001010010011001011001001010" "00010101010000101110101101101010001001001101001101001110010101101011101011011101" diff --git a/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt b/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt index e49d0b61e5..8d28b221a2 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt +++ b/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt @@ -12,5 +12,6 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../core ZXing EXCLUD add_library(zxing_android SHARED BarcodeReader.cpp JNIUtils.cpp) +target_compile_definitions(zxing_android PRIVATE -DZX_USE_UTF8) target_link_libraries(zxing_android PRIVATE ZXing::ZXing log jnigraphics) diff --git a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp index 6ae1333f12..85d1717f92 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp +++ b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "JNIUtils.h" -#include "TextDecoder.h" +#include "TextUtfEncoding.h" #include #include @@ -55,7 +55,7 @@ jstring C2JString(JNIEnv* env, const std::wstring& str) jstring C2JString(JNIEnv* env, const std::string& str) { - return C2JString(env, ZXing::TextDecoder::FromLatin1(str)); + return C2JString(env, ZXing::TextUtfEncoding::FromUtf8(str)); } std::string J2CString(JNIEnv* env, jstring str) diff --git a/wrappers/python/zxing.cpp b/wrappers/python/zxing.cpp index 72336d5c0c..17c79e80df 100644 --- a/wrappers/python/zxing.cpp +++ b/wrappers/python/zxing.cpp @@ -7,6 +7,8 @@ #include "BarcodeFormat.h" +#define ZX_USE_UTF8 1 // see Result.h + // Reader #include "ReadBarcode.h" diff --git a/wrappers/wasm/BarcodeReader.cpp b/wrappers/wasm/BarcodeReader.cpp index eb6e437b5a..7efee44486 100644 --- a/wrappers/wasm/BarcodeReader.cpp +++ b/wrappers/wasm/BarcodeReader.cpp @@ -3,6 +3,8 @@ */ // SPDX-License-Identifier: Apache-2.0 +#define ZX_USE_UTF8 1 // see Result.h + #include "ReadBarcode.h" #include @@ -16,7 +18,7 @@ struct ReadResult { std::string format; - std::wstring text; + std::string text; std::string error; ZXing::Position position; }; @@ -37,7 +39,7 @@ ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, &channels, 4), stbi_image_free); if (buffer == nullptr) { - return { "", L"", "Error loading image" }; + return { "", "", "Error loading image" }; } auto result = ReadBarcode({buffer.get(), width, height, ImageFormat::RGBX}, hints); @@ -46,10 +48,10 @@ ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, } } catch (const std::exception& e) { - return { "", L"", e.what() }; + return { "", "", e.what() }; } catch (...) { - return { "", L"", "Unknown error" }; + return { "", "", "Unknown error" }; } return {}; } @@ -72,10 +74,10 @@ ReadResult readBarcodeFromPixmap(int bufferPtr, int imgWidth, int imgHeight, boo } } catch (const std::exception& e) { - return { "", L"", e.what() }; + return { "", "", e.what() }; } catch (...) { - return { "", L"", "Unknown error" }; + return { "", "", "Unknown error" }; } return {}; } @@ -106,7 +108,7 @@ EMSCRIPTEN_BINDINGS(BarcodeReader) function("readBarcodeFromImage", &readBarcodeFromImage); function("readBarcodeFromPixmap", &readBarcodeFromPixmap); - // obsoletes + // obsoletes [[deprecated]] function("readBarcode", &readBarcodeFromImage); function("readBarcodeFromPng", &readBarcodeFromImage); } diff --git a/wrappers/winrt/BarcodeReader.cpp b/wrappers/winrt/BarcodeReader.cpp index 9695d26400..7080be6241 100644 --- a/wrappers/winrt/BarcodeReader.cpp +++ b/wrappers/winrt/BarcodeReader.cpp @@ -21,6 +21,8 @@ #include "BarcodeReader.h" +#define ZX_USE_UTF8 1 // silence deprecation warning in Result.h + #include "BarcodeFormat.h" #include "DecodeHints.h" #include "ReadBarcode.h" @@ -202,7 +204,7 @@ BarcodeReader::Read(SoftwareBitmap^ bitmap, int cropWidth, int cropHeight) auto result = ReadBarcode(img, *m_hints); if (result.isValid()) { - return ref new ReadResult(ToPlatformString(ZXing::ToString(result.format())), ToPlatformString(result.text()), ConvertNativeToRuntime(result.format())); + return ref new ReadResult(ToPlatformString(ZXing::ToString(result.format())), ToPlatformString(result.utf16()), ConvertNativeToRuntime(result.format())); } } else { throw std::runtime_error("Failed to read bitmap's data"); From 1a27185543095cf7921b32642bd7b6f18a576163 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 01:21:55 +0200 Subject: [PATCH 52/88] License: add overlooked SPDX-License-Identifier in 2 files --- core/ZXVersion.h.in | 16 +++------------- wrappers/winrt/BarcodeReader.cpp | 13 +------------ 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/core/ZXVersion.h.in b/core/ZXVersion.h.in index 8e2151f629..78fde4106a 100644 --- a/core/ZXVersion.h.in +++ b/core/ZXVersion.h.in @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2019 Nu-book Inc. -* -* 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. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once // Version numbering #define ZXING_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ diff --git a/wrappers/winrt/BarcodeReader.cpp b/wrappers/winrt/BarcodeReader.cpp index 7080be6241..5d3360985e 100644 --- a/wrappers/winrt/BarcodeReader.cpp +++ b/wrappers/winrt/BarcodeReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Nu-book Inc. -* -* 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. */ +// SPDX-License-Identifier: Apache-2.0 #if (_MSC_VER >= 1915) #define no_init_all deprecated From c44da705cc092be78f79165051ebe52c507ec512 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:05:02 +0200 Subject: [PATCH 53/88] Use .bytes() instead of .binary() on Result --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 49ac8e7cf4..b50fa31676 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -69,8 +69,8 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ length:resultText.size() * sizeof(wchar_t) encoding:NSUTF32LittleEndianStringEncoding]; - auto binary = result.binary(); - NSData *rawBytes = [[NSData alloc] initWithBytes:binary.data() length:binary.size()]; + auto bytes = result.bytes(); + NSData *rawBytes = [[NSData alloc] initWithBytes:bytes.data() length:bytes.size()]; [zxiResults addObject: [[ZXIResult alloc] init:text format:ZXIFormatFromBarcodeFormat(result.format()) From 7a2335570575de35bd3261fdd76cc209fabf80bd Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:07:37 +0200 Subject: [PATCH 54/88] Use NSInteger for maxNumberOfSymbols Fixing a stupid copy paste mistake done by me... --- wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h index 2481d40471..6a113f94e5 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIDecodeHints.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic) BOOL tryHarder; @property(nonatomic) BOOL tryRotate; @property(nonatomic) BOOL tryDownscale; -@property(nonatomic) BOOL maxNumberOfSymbols; +@property(nonatomic) NSInteger maxNumberOfSymbols; /// An array of ZXIFormat @property(nonatomic, strong) NSArray *formats; From 82ec9c96bf062205792cf6f906bf4e1ae2698cbe Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:09:47 +0200 Subject: [PATCH 55/88] Renaming rawBytes to bytes on Result --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 2 +- wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h | 4 ++-- wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index b50fa31676..98f8d0b660 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -74,7 +74,7 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ [zxiResults addObject: [[ZXIResult alloc] init:text format:ZXIFormatFromBarcodeFormat(result.format()) - rawBytes:rawBytes] + bytes:rawBytes] ]; } else { if(error != nil) { diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h index b21c352806..291c48eff9 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h @@ -9,12 +9,12 @@ NS_ASSUME_NONNULL_BEGIN @interface ZXIResult : NSObject @property(nonatomic, strong) NSString *text; -@property(nonatomic, strong) NSData *rawBytes; +@property(nonatomic, strong) NSData *bytes; @property(nonatomic) ZXIFormat format; - (instancetype)init:(NSString *)text format:(ZXIFormat)format - rawBytes:(NSData *)rawBytes; + bytes:(NSData *)bytes; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm index 495a036f99..0c9962673a 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm @@ -7,11 +7,11 @@ @implementation ZXIResult - (instancetype)init:(NSString *)text format:(ZXIFormat)format - rawBytes:(NSData *)rawBytes { + bytes:(NSData *)bytes { self = [super init]; self.text = text; self.format = format; - self.rawBytes = rawBytes; + self.bytes = bytes; return self; } @end From 403337e62da5a64ee075384fcf9df56ca11cd3f9 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:13:59 +0200 Subject: [PATCH 56/88] Move MicroQRCode next to QRCode in ZXIFormat --- wrappers/ios/Sources/Wrapper/ZXIFormat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormat.h b/wrappers/ios/Sources/Wrapper/ZXIFormat.h index 108abe2cf9..e43c39f570 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormat.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormat.h @@ -8,8 +8,8 @@ typedef NS_ENUM(NSInteger, ZXIFormat) { NONE, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_BAR, DATA_BAR_EXPANDED, - DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, UPC_A, UPC_E, - ONE_D_CODES, TWO_D_CODES, MICRO_QR_CODE, ANY + DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, MICRO_QR_CODE, UPC_A, UPC_E, + ONE_D_CODES, TWO_D_CODES, ANY }; #endif From d843be15956cd0569af1f14cfae805bd2e2113b3 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:59:24 +0200 Subject: [PATCH 57/88] Remove errors from reader Now that we are returning an array of results I had to think about how to handle possible errors when decoding the codes. Since I don't know of any case where the user of the lib is interested in the specific error, I decided not to return the error bound to a result. If a code cannot be read, I simply don't return a result at all. --- .../Sources/Wrapper/Reader/ZXIBarcodeReader.h | 4 +-- .../Wrapper/Reader/ZXIBarcodeReader.mm | 27 +++---------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h index bb4bf13d6c..bb41ae2d8e 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h @@ -13,8 +13,8 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong) ZXIDecodeHints *hints; - (instancetype)initWithHints:(ZXIDecodeHints*)options; -- (nullable NSArray *)readCIImage:(nonnull CIImage *)image error:(NSError **)error; -- (nullable NSArray *)readCGImage:(nonnull CGImageRef)image error:(NSError **)error; +- (NSArray *)readCIImage:(nonnull CIImage *)image; +- (NSArray *)readCGImage:(nonnull CGImageRef)image; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 98f8d0b660..a3a73b107c 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 #import "ZXIBarcodeReader.h" -#import "ZXIErrors.h" #import "ZXing/ReadBarcode.h" #import "ZXing/ImageView.h" #import "ZXing/Result.h" @@ -28,14 +27,14 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return self; } -- (nullable NSArray *)readCIImage:(nonnull CIImage *)image error:(NSError **)error { +- (NSArray *)readCIImage:(nonnull CIImage *)image { CGImageRef cgImage = [self.ciContext createCGImage:image fromRect:image.extent]; - auto results = [self readCGImage:cgImage error:error]; + auto results = [self readCGImage:cgImage]; CGImageRelease(cgImage); return results; } -- (nullable NSArray *)readCGImage: (nonnull CGImageRef)image error:(NSError **)error { +- (NSArray *)readCGImage: (nonnull CGImageRef)image { CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); CGFloat cols = CGImageGetWidth(image); CGFloat rows = CGImageGetHeight(image); @@ -76,26 +75,6 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ format:ZXIFormatFromBarcodeFormat(result.format()) bytes:rawBytes] ]; - } else { - if(error != nil) { - ZXIReaderError errorCode; - switch (result.status()) { - case ZXing::DecodeStatus::NoError: - // Can not happen - break; - case ZXing::DecodeStatus::NotFound: - errorCode = ZXIReaderError::ZXINotFoundError; - break; - case ZXing::DecodeStatus::FormatError: - errorCode = ZXIReaderError::ZXIFormatError; - break; - case ZXing::DecodeStatus::ChecksumError: - errorCode = ZXIReaderError::ZXIChecksumError; - break; - } - *error = [[NSError alloc] initWithDomain: ZXIErrorDomain code: errorCode userInfo:nil]; - } - return nil; } } return zxiResults; From da3a9c6823b6dc00784a763c302503b191d5756a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 12:59:43 +0200 Subject: [PATCH 58/88] Update ZXIErrors --- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 2 -- wrappers/ios/Sources/Wrapper/ZXIErrors.h | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 31e713da68..6a749094ec 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -38,8 +38,6 @@ } #endif - - @implementation ZXIBarcodeWriter -(nullable CGImageRef)write:(nonnull NSString *)contents diff --git a/wrappers/ios/Sources/Wrapper/ZXIErrors.h b/wrappers/ios/Sources/Wrapper/ZXIErrors.h index f24757999a..7f1ebb6e26 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIErrors.h +++ b/wrappers/ios/Sources/Wrapper/ZXIErrors.h @@ -8,10 +8,7 @@ NS_ASSUME_NONNULL_BEGIN #define ZXIErrorDomain @"ZXIErrorDomain" -typedef NS_ENUM(NSInteger, ZXIReaderError) { - ZXINotFoundError = 1000, - ZXIChecksumError, - ZXIFormatError, +typedef NS_ENUM(NSInteger, ZXIBarcodeWriterError) { ZXIWriterError, }; From 222841cf1a5a9ace0721f2b9a0b1a3481ae7a84f Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 13:00:37 +0200 Subject: [PATCH 59/88] Update demo project for new read api --- wrappers/ios/demo/demo/ViewController.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index beabec5781..b84de21af5 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -63,8 +63,7 @@ extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { return } let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! - if let results = try? reader.read(CIImage(cvPixelBuffer: imageBuffer)), - let result = results.first { + if let result = reader.read(CIImage(cvPixelBuffer: imageBuffer)).first { print("Found barcode of format", result.format.rawValue, "with text", result.text) } self.zxingLock.signal() From f6090cc1111b53fac0693657ff8207e89d9dbf31 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 13:15:33 +0200 Subject: [PATCH 60/88] Remove whiteline --- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 6a749094ec..02d04f3581 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -62,7 +62,6 @@ -(CGImageRef)write:(NSString *)contents int realWidth = result.width(); int realHeight = result.height(); - #ifdef DEBUG // std::cout << ToString(result, 'X', ' ', false, false); #endif From ec22310604d1732c6b89d1ab24411a482f9d3192 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 16:51:26 +0200 Subject: [PATCH 61/88] Add position to ZXIResult --- .../Wrapper/Reader/ZXIBarcodeReader.mm | 10 +++++--- .../ios/Sources/Wrapper/Reader/ZXIPoint.h | 19 ++++++++++++++ .../ios/Sources/Wrapper/Reader/ZXIPoint.m | 18 +++++++++++++ .../Wrapper/Reader/ZXIPosition+Helper.h | 18 +++++++++++++ .../Wrapper/Reader/ZXIPosition+Helper.mm | 19 ++++++++++++++ .../ios/Sources/Wrapper/Reader/ZXIPosition.h | 25 +++++++++++++++++++ .../ios/Sources/Wrapper/Reader/ZXIPosition.m | 22 ++++++++++++++++ .../ios/Sources/Wrapper/Reader/ZXIResult.h | 5 +++- .../ios/Sources/Wrapper/Reader/ZXIResult.mm | 4 ++- 9 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h create mode 100644 wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index a3a73b107c..0c45ee3286 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -7,6 +7,7 @@ #import "ZXing/ImageView.h" #import "ZXing/Result.h" #import "ZXIFormatHelper.h" +#import "ZXIPosition+Helper.h" using namespace ZXing; @@ -71,10 +72,11 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ auto bytes = result.bytes(); NSData *rawBytes = [[NSData alloc] initWithBytes:bytes.data() length:bytes.size()]; [zxiResults addObject: - [[ZXIResult alloc] init:text - format:ZXIFormatFromBarcodeFormat(result.format()) - bytes:rawBytes] - ]; + [[ZXIResult alloc] init:text + format:ZXIFormatFromBarcodeFormat(result.format()) + bytes:rawBytes + position:[[ZXIPosition alloc]initWithPosition: result.position()] + ]]; } } return zxiResults; diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h new file mode 100644 index 0000000000..e9bcf816e8 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h @@ -0,0 +1,19 @@ +// +// ZXIPoint.h +// +// +// Created by Christian Braun on 21.06.22. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIPoint : NSObject +@property(nonatomic) NSInteger x; +@property(nonatomic) NSInteger y; + +- (instancetype)initWithX:(NSInteger)x y:(NSInteger)y; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m new file mode 100644 index 0000000000..bb91f68387 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m @@ -0,0 +1,18 @@ +// +// ZXIPoint.m +// +// +// Created by Christian Braun on 21.06.22. +// + +#import "ZXIPoint.h" + +@implementation ZXIPoint + +- (instancetype)initWithX:(NSInteger)x y:(NSInteger)y { + self = [super init]; + self.x = x; + self.y = y; + return self; +} +@end diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h new file mode 100644 index 0000000000..f725eb1bb9 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h @@ -0,0 +1,18 @@ +// +// ZXIPositionHelper.h +// +// +// Created by Christian Braun on 21.06.22. +// + +#import +#import "ZXIPosition.h" +#import "ZXing/Result.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIPosition(Helper) +- (instancetype)initWithPosition:(ZXing::Position)position; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm new file mode 100644 index 0000000000..ef4175954b --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm @@ -0,0 +1,19 @@ +// +// ZXIPositionHelper.m +// +// +// Created by Christian Braun on 21.06.22. +// + +#import "ZXIPosition+Helper.h" +#import "ZXIPoint.h" + +@implementation ZXIPosition(Helper) +-(instancetype)initWithPosition:(ZXing::Position)position { + return [self initWithTopLeft:[[ZXIPoint alloc] initWithX:position.topLeft().x y:position.topLeft().y] + topRight:[[ZXIPoint alloc] initWithX:position.topRight().x y:position.topRight().y] + bottomRight:[[ZXIPoint alloc] initWithX:position.bottomRight().x y:position.bottomRight().y] + bottomLeft:[[ZXIPoint alloc] initWithX:position.bottomLeft().x y:position.bottomLeft().y]]; +} + +@end diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h new file mode 100644 index 0000000000..13d463a618 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h @@ -0,0 +1,25 @@ +// +// ZXIPosition.h +// +// +// Created by Christian Braun on 21.06.22. +// + +#import +#import "ZXIPoint.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ZXIPosition : NSObject +@property(nonatomic, nonnull)ZXIPoint *topLeft; +@property(nonatomic, nonnull)ZXIPoint *topRight; +@property(nonatomic, nonnull)ZXIPoint *bottomRight; +@property(nonatomic, nonnull)ZXIPoint *bottomLeft; + +- (instancetype)initWithTopLeft:(ZXIPoint *)topLeft + topRight:(ZXIPoint *)topRight + bottomRight:(ZXIPoint *)bottomRight + bottomLeft:(ZXIPoint *)bottomLeft; +@end + +NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m new file mode 100644 index 0000000000..bbc18bd372 --- /dev/null +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m @@ -0,0 +1,22 @@ +// +// ZXIPosition.m +// +// +// Created by Christian Braun on 21.06.22. +// + +#import "ZXIPosition.h" + +@implementation ZXIPosition +- (instancetype)initWithTopLeft:(ZXIPoint *)topLeft + topRight:(ZXIPoint *)topRight + bottomRight:(ZXIPoint *)bottomRight + bottomLeft:(ZXIPoint *)bottomLeft { + self = [super init]; + self.topLeft = topLeft; + self.topRight = topRight; + self.bottomRight = bottomRight; + self.bottomLeft = bottomLeft; + return self; +} +@end diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h index 291c48eff9..83d8a4cffc 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.h @@ -4,17 +4,20 @@ #import #import "ZXIFormat.h" +#import "ZXIPosition.h" NS_ASSUME_NONNULL_BEGIN @interface ZXIResult : NSObject @property(nonatomic, strong) NSString *text; @property(nonatomic, strong) NSData *bytes; +@property(nonatomic, strong) ZXIPosition *position; @property(nonatomic) ZXIFormat format; - (instancetype)init:(NSString *)text format:(ZXIFormat)format - bytes:(NSData *)bytes; + bytes:(NSData *)bytes + position:(ZXIPosition *)position; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm index 0c9962673a..b84267d2a0 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIResult.mm @@ -7,11 +7,13 @@ @implementation ZXIResult - (instancetype)init:(NSString *)text format:(ZXIFormat)format - bytes:(NSData *)bytes { + bytes:(NSData *)bytes + position:(ZXIPosition *)position { self = [super init]; self.text = text; self.format = format; self.bytes = bytes; + self.position = position; return self; } @end From febea8dd492de9864377a25aa675f4b98637c363 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 16:52:39 +0200 Subject: [PATCH 62/88] Update umbrella header --- wrappers/ios/Sources/Wrapper/UmbrellaHeader.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h index 3a0ad9b132..b890d2313f 100644 --- a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h +++ b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h @@ -7,6 +7,8 @@ #import "Reader/ZXIBarcodeReader.h" #import "Reader/ZXIResult.h" +#import "Reader/ZXIPosition.h" +#import "Reader/ZXIPoint.h" #import "Reader/ZXIDecodeHints.h" #import "Writer/ZXIBarcodeWriter.h" #import "Writer/ZXICharset.h" From ba8def7d64f77df25c29a70dbfa6b5ba23a03a44 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 12:32:35 +0200 Subject: [PATCH 63/88] android: add `bytes` and `contentType` members to `Result` Use in demo app to show hex coded binary content. --- .../com/example/zxingcppdemo/MainActivity.kt | 4 ++- .../zxingcpp/src/main/cpp/BarcodeReader.cpp | 29 +++++++++++++++++++ .../main/java/com/zxingcpp/BarcodeReader.kt | 5 ++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt b/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt index d023a70676..82cf02fd9e 100644 --- a/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt +++ b/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt @@ -166,7 +166,9 @@ class MainActivity : AppCompatActivity() { p.toPointF() } } - (result?.let { "${it.format}: ${it.text}" } ?: "") + (result?.let { "${it.format} (${it.contentType}):" + + "${if (it.contentType != BarcodeReader.ContentType.BINARY) it.text else it.bytes!!.joinToString(separator = "") { v -> "%02x".format(v) }}" } + ?: "") } catch (e: Throwable) { e.message ?: "Error" } diff --git a/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp b/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp index ce37a1ecde..571434cff1 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp +++ b/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp @@ -39,6 +39,20 @@ static const char* JavaBarcodeFormatName(BarcodeFormat format) } } +static const char* JavaContentTypeName(ContentType contentType) +{ + // These have to be the names of the enum constants in the kotlin code. + switch (contentType) { + case ContentType::Text: return "TEXT"; + case ContentType::Binary: return "BINARY"; + case ContentType::Mixed: return "MIXED"; + case ContentType::GS1: return "GS1"; + case ContentType::ISO15434: return "ISO15434"; + case ContentType::UnknownECI: return "UNKNOWN_ECI"; + default: throw std::invalid_argument("Invalid contentType"); + } +} + static jstring ThrowJavaException(JNIEnv* env, const char* message) { // if (env->ExceptionCheck()) @@ -48,6 +62,13 @@ static jstring ThrowJavaException(JNIEnv* env, const char* message) return nullptr; } +static jobject CreateContentType(JNIEnv* env, ContentType contentType) +{ + jclass cls = env->FindClass("com/zxingcpp/BarcodeReader$ContentType"); + jfieldID fidCT = env->GetStaticFieldID(cls , JavaContentTypeName(contentType), "Lcom/zxingcpp/BarcodeReader$ContentType;"); + return env->GetStaticObjectField(cls, fidCT); +} + static jobject CreateAndroidPoint(JNIEnv* env, const PointT& point) { jclass cls = env->FindClass("android/graphics/Point"); @@ -99,9 +120,17 @@ jstring Read(JNIEnv *env, ImageView image, jstring formats, jboolean tryHarder, env->SetObjectField(result, fidTime, C2JString(env, time)); if (res.isValid()) { + jbyteArray jByteArray = env->NewByteArray(res.bytes().size()); + env->SetByteArrayRegion(jByteArray, 0, res.bytes().size(), (jbyte*)res.bytes().data()); + jfieldID fidBytes = env->GetFieldID(clResult, "bytes", "[B"); + env->SetObjectField(result, fidBytes, jByteArray); + jfieldID fidText = env->GetFieldID(clResult, "text", "Ljava/lang/String;"); env->SetObjectField(result, fidText, C2JString(env, res.text())); + jfieldID fidContentType = env->GetFieldID(clResult , "contentType", "Lcom/zxingcpp/BarcodeReader$ContentType;"); + env->SetObjectField(result, fidContentType, CreateContentType(env, res.contentType())); + jfieldID fidPosition = env->GetFieldID(clResult, "position", "Lcom/zxingcpp/BarcodeReader$Position;"); env->SetObjectField(result, fidPosition, CreatePosition(env, res.position())); diff --git a/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt b/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt index 6dbddecdac..8f5745976d 100644 --- a/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt +++ b/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt @@ -32,6 +32,9 @@ class BarcodeReader { NONE, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_BAR, DATA_BAR_EXPANDED, DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, MICRO_QR_CODE, UPC_A, UPC_E } + enum class ContentType { + TEXT, BINARY, MIXED, GS1, ISO15434, UNKNOWN_ECI + } data class Options( val formats: Set = setOf(), @@ -50,8 +53,10 @@ class BarcodeReader { data class Result( val format: Format = Format.NONE, + val bytes: ByteArray? = null, val text: String? = null, val time: String? = null, // for development/debug purposes only + val contentType: ContentType = ContentType.TEXT, val position: Position? = null, val orientation: Int = 0, val ecLevel: String? = null, From a4f359f8070accb30b24972c9eb5f22a91ecfd5e Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 12:33:28 +0200 Subject: [PATCH 64/88] python: add `content_type` property in Result --- wrappers/python/zxing.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wrappers/python/zxing.cpp b/wrappers/python/zxing.cpp index 17c79e80df..59be2d6e24 100644 --- a/wrappers/python/zxing.cpp +++ b/wrappers/python/zxing.cpp @@ -175,6 +175,14 @@ PYBIND11_MODULE(zxingcpp, m) .value("Read", EanAddOnSymbol::Read) .value("Require", EanAddOnSymbol::Require) .export_values(); + py::enum_(m, "ContentType", "Enumeration of content types") + .value("Text", ContentType::Text) + .value("Binary", ContentType::Binary) + .value("Mixed", ContentType::Mixed) + .value("GS1", ContentType::GS1) + .value("ISO15434", ContentType::ISO15434) + .value("UnknownECI", ContentType::UnknownECI) + .export_values(); py::class_(m, "Point", "Represents the coordinates of a point in an image") .def_readonly("x", &PointI::x, ":return: horizontal coordinate of the point\n" @@ -216,6 +224,9 @@ PYBIND11_MODULE(zxingcpp, m) .def_property_readonly("symbology_identifier", &Result::symbologyIdentifier, ":return: decoded symbology idendifier\n" ":rtype: str") + .def_property_readonly("content_type", &Result::contentType, + ":return: content type of symbol\n" + ":rtype: zxing.ContentType") .def_property_readonly("position", &Result::position, ":return: position of the decoded symbol\n" ":rtype: zxing.Position") From 2b03796d636d6a1bc9df464b438bfc112f40abd1 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 13:33:19 +0200 Subject: [PATCH 65/88] Code128: properly report contentType GS1 --- core/src/Content.cpp | 4 +++- core/src/Content.h | 2 +- core/src/Result.cpp | 4 ++-- core/src/Result.h | 4 ++-- core/src/oned/ODCode128Reader.cpp | 9 ++++++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index c7fe98a619..16f290044d 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -50,7 +50,9 @@ void Content::switchEncoding(ECI eci, bool isECI) Content::Content() {} -Content::Content(ByteArray&& bytes, SymbologyIdentifier si) : bytes(std::move(bytes)), symbology(si) {} +Content::Content(ByteArray&& bytes, SymbologyIdentifier si, std::string ai) + : bytes(std::move(bytes)), applicationIndicator(std::move(ai)), symbology(si) +{} void Content::switchEncoding(CharacterSet cs) { diff --git a/core/src/Content.h b/core/src/Content.h index 022cdc9569..13e5e7c365 100644 --- a/core/src/Content.h +++ b/core/src/Content.h @@ -50,7 +50,7 @@ class Content bool hasECI = false; Content(); - Content(ByteArray&& bytes, SymbologyIdentifier si); + Content(ByteArray&& bytes, SymbologyIdentifier si, std::string ai = {}); void switchEncoding(ECI eci) { switchEncoding(eci, true); } void switchEncoding(CharacterSet cs); diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 9539e273fc..8e3ed62867 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -18,10 +18,10 @@ namespace ZXing { Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, - SymbologyIdentifier si, ByteArray&& rawBytes, const bool readerInit) + SymbologyIdentifier si, ByteArray&& rawBytes, bool readerInit, const std::string& ai) : _format(format), - _content({ByteArray(text)}, si), + _content({ByteArray(text)}, si, ai), _position(Line(y, xStart, xStop)), _rawBytes(std::move(rawBytes)), _numBits(Size(_rawBytes) * 8), diff --git a/core/src/Result.h b/core/src/Result.h index 74dcb5f411..735f2f2d23 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -32,8 +32,8 @@ class Result explicit Result(DecodeStatus status) : _status(status) {} // 1D convenience constructor - Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, - SymbologyIdentifier si, ByteArray&& rawBytes = {}, const bool readerInit = false); + Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, SymbologyIdentifier si, + ByteArray&& rawBytes = {}, bool readerInit = false, const std::string& ai = {}); Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format); diff --git a/core/src/oned/ODCode128Reader.cpp b/core/src/oned/ODCode128Reader.cpp index a9e55b7f5d..be000e4f7b 100644 --- a/core/src/oned/ODCode128Reader.cpp +++ b/core/src/oned/ODCode128Reader.cpp @@ -43,6 +43,7 @@ class Raw2TxtDecoder int codeSet = 0; SymbologyIdentifier _symbologyIdentifier = {'C', '0'}; // ISO/IEC 15417:2007 Annex C Table C.1 bool _readerInit = false; + std::string _applicationIndicator; std::string txt; size_t lastTxtSize = 0; @@ -59,6 +60,7 @@ class Raw2TxtDecoder // GS1 General Specifications Section 5.4.6.4 // "Transmitted data ... is prefixed by the symbology identifier ]C1, if used." // Choosing not to use symbology identifier, i.e. to not prefix to data. + _applicationIndicator = "GS1"; } else if ((isCodeSetC && txt.size() == 2 && txt[0] >= '0' && txt[0] <= '9' && txt[1] >= '0' && txt[1] <= '9') || (!isCodeSetC && txt.size() == 1 && ((txt[0] >= 'A' && txt[0] <= 'Z') @@ -66,6 +68,7 @@ class Raw2TxtDecoder // ISO/IEC 15417:2007 Annex B.2 // FNC1 in second position following Code Set C "00-99" or Code Set A/B "A-Za-z" - AIM _symbologyIdentifier.modifier = '2'; + _applicationIndicator = txt; } else { // ISO/IEC 15417:2007 Annex B.3. Otherwise FNC1 is returned as ASCII 29 (GS) @@ -154,7 +157,7 @@ class Raw2TxtDecoder } SymbologyIdentifier symbologyIdentifier() const { return _symbologyIdentifier; } - + std::string applicationIndicator() const { return _applicationIndicator; } bool readerInit() const { return _readerInit; } }; @@ -268,13 +271,13 @@ Result Code128Reader::decodePattern(int rowNumber, PatternView& next, std::uniqu int checksum = rawCodes.front(); for (int i = 1; i < Size(rawCodes) - 1; ++i) checksum += i * rawCodes[i]; - // the second last code is the checksum (last one is the stop code): + // the last code is the checksum: if (checksum % 103 != rawCodes.back()) return Result(DecodeStatus::ChecksumError); int xStop = next.pixelsTillEnd(); return Result(raw2txt.text(), rowNumber, xStart, xStop, BarcodeFormat::Code128, raw2txt.symbologyIdentifier(), - std::move(rawCodes), raw2txt.readerInit()); + std::move(rawCodes), raw2txt.readerInit(), raw2txt.applicationIndicator()); } } // namespace ZXing::OneD From 4122e14387cc29c329541b891f002a61b9e9ecda Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 13:34:16 +0200 Subject: [PATCH 66/88] Result: report (empty) NotFound results as ContentType::Text --- core/src/Content.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/Content.cpp b/core/src/Content.cpp index 16f290044d..280c3e41ee 100644 --- a/core/src/Content.cpp +++ b/core/src/Content.cpp @@ -191,6 +191,9 @@ CharacterSet Content::guessEncoding() const ContentType Content::type() const { + if (empty()) + return ContentType::Text; + if (!canProcess()) return ContentType::UnknownECI; From 509a4ab0e81d5075b52907b22c477a4a708c2dd9 Mon Sep 17 00:00:00 2001 From: axxel Date: Tue, 21 Jun 2022 13:35:22 +0200 Subject: [PATCH 67/88] test: add a few checks for contentType to black box tests --- test/blackbox/BlackboxTestRunner.cpp | 2 ++ test/samples/code128-1/1.result.txt | 1 + test/samples/datamatrix-1/eci-mixed.result.txt | 2 ++ test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt | 1 + test/samples/datamatrix-3/dm-c.result.txt | 1 + 5 files changed, 7 insertions(+) create mode 100644 test/samples/datamatrix-1/eci-mixed.result.txt create mode 100644 test/samples/datamatrix-3/dm-c.result.txt diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index e28f3a1e02..7f9a1d7ab9 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -63,6 +63,8 @@ namespace { // Helper for `compareResult()` - map `key` to Result property, converting value to std::string static std::string getResultValue(const Result& result, const std::string& key) { + if (key == "contentType") + return ToString(result.contentType()); if (key == "ecLevel") return result.ecLevel(); if (key == "orientation") diff --git a/test/samples/code128-1/1.result.txt b/test/samples/code128-1/1.result.txt index 90af6c5d09..ec5103cdec 100644 --- a/test/samples/code128-1/1.result.txt +++ b/test/samples/code128-1/1.result.txt @@ -1 +1,2 @@ symbologyIdentifier=]C1 +contentType=GS1 diff --git a/test/samples/datamatrix-1/eci-mixed.result.txt b/test/samples/datamatrix-1/eci-mixed.result.txt new file mode 100644 index 0000000000..352fff3edf --- /dev/null +++ b/test/samples/datamatrix-1/eci-mixed.result.txt @@ -0,0 +1,2 @@ +symbologyIdentifier=]d1 +contentType=UnknownECI diff --git a/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt b/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt index c31c096dbb..1edb45e39f 100644 --- a/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt +++ b/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt @@ -1 +1,2 @@ symbologyIdentifier=]d2 +contentType=GS1 diff --git a/test/samples/datamatrix-3/dm-c.result.txt b/test/samples/datamatrix-3/dm-c.result.txt new file mode 100644 index 0000000000..d0aaba1474 --- /dev/null +++ b/test/samples/datamatrix-3/dm-c.result.txt @@ -0,0 +1 @@ +contentType=Binary From 520bc1249d410c517dd0ef73eae75c0d9d410489 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 17:46:07 +0200 Subject: [PATCH 68/88] Rename local variable to bytes --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 0c45ee3286..2e81514ffc 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -69,12 +69,11 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ length:resultText.size() * sizeof(wchar_t) encoding:NSUTF32LittleEndianStringEncoding]; - auto bytes = result.bytes(); - NSData *rawBytes = [[NSData alloc] initWithBytes:bytes.data() length:bytes.size()]; + NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; [zxiResults addObject: [[ZXIResult alloc] init:text format:ZXIFormatFromBarcodeFormat(result.format()) - bytes:rawBytes + bytes:bytes position:[[ZXIPosition alloc]initWithPosition: result.position()] ]]; } From 25393b5f3af72aedfcafc264b5cf93cfce1ff04a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 21 Jun 2022 17:52:35 +0200 Subject: [PATCH 69/88] Add correct license header --- wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h | 8 +++----- wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m | 8 +++----- wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h | 7 ++----- wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm | 8 +++----- wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h | 8 +++----- wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m | 8 +++----- 6 files changed, 17 insertions(+), 30 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h index e9bcf816e8..5ce37c125b 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.h @@ -1,9 +1,7 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPoint.h -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 + #import diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m index bb91f68387..3a303c3bae 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPoint.m @@ -1,9 +1,7 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPoint.m -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 + #import "ZXIPoint.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h index f725eb1bb9..5224ea8d9c 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.h @@ -1,9 +1,6 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPositionHelper.h -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 #import #import "ZXIPosition.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm index ef4175954b..94404b5136 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition+Helper.mm @@ -1,9 +1,7 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPositionHelper.m -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 + #import "ZXIPosition+Helper.h" #import "ZXIPoint.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h index 13d463a618..1aa44dd56b 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.h @@ -1,9 +1,7 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPosition.h -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 + #import #import "ZXIPoint.h" diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m index bbc18bd372..17432026c5 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIPosition.m @@ -1,9 +1,7 @@ +// Copyright 2022 KURZ Digital Solutions GmbH // -// ZXIPosition.m -// -// -// Created by Christian Braun on 21.06.22. -// +// SPDX-License-Identifier: Apache-2.0 + #import "ZXIPosition.h" From 1fcd508f4f5d75edc704a7ccde78e449c3ddf899 Mon Sep 17 00:00:00 2001 From: axxel Date: Fri, 3 Jun 2022 22:28:18 +0200 Subject: [PATCH 70/88] Merge branch 'master' into ios_wrapper # Conflicts: # core/CMakeLists.txt # core/src/Content.cpp # core/src/Content.h --- core/CMakeLists.txt | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 655d569305..0cf10348d1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -462,7 +462,7 @@ add_library (ZXing target_include_directories (ZXing PUBLIC "$" - INTERFACE "$" + INTERFACE "$" ) target_compile_options (ZXing @@ -500,6 +500,23 @@ endif() set_target_properties(ZXing PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") +if (APPLE) + set_target_properties(ZXing PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION "C" + XCODE_ATTRIBUTE_DEFINES_MODULE YES + XCODE_ATTRIBUTE_BUILD_LIBRARY_FOR_DISTRIBUTION YES + XCODE_ATTRIBUTE_MODULEMAP_FILE "wrappers/ios/Sources/Wrapper/module.modulemap" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + MACOSX_FRAMEWORK_IDENTIFIER "com.zxing_cpp.ios" + CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO + #MACOSX_FRAMEWORK_INFO_PLIST Info.plist + PUBLIC_HEADER "${PUBLIC_HEADERS}" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" + XCODE_ATTRIBUTE_ENABLE_BITCODE "YES" + ) +endif() + include (GNUInstallDirs) install ( @@ -507,6 +524,7 @@ install ( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} # INCLUDES DESTINATION include PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ZXing" ) From d5183d1ae3d3a072d1e79efdf5261f00f7602610 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Wed, 22 Jun 2022 13:36:46 +0200 Subject: [PATCH 71/88] Add StructuredAppend.h to common files again If removed the StructuredAppend.h file is missing from the ZXing.xcframework and therefore the iOS Wrapper can not be built. --- core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 0cf10348d1..22f2b84926 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -115,6 +115,7 @@ if (BUILD_READERS) src/Result.cpp src/ResultPoint.h src/ResultPoint.cpp + src/StructuredAppend.h src/TextDecoder.h src/TextDecoder.cpp src/ThresholdBinarizer.h From 8fbe696037920773fc21177f0b3d1fb53f202351 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Wed, 22 Jun 2022 14:27:58 +0200 Subject: [PATCH 72/88] Update README.md --- wrappers/ios/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrappers/ios/README.md b/wrappers/ios/README.md index fc2c06fcf3..44aae4bf41 100644 --- a/wrappers/ios/README.md +++ b/wrappers/ios/README.md @@ -9,6 +9,6 @@ file in your app. To build the xcframework: $ ./build-release.sh - -Then copy `zxingcpp/wrappers/ios/ZXingCpp.xcframework` into the -frameworks-section of your app. + +Then you can add the iOS Wrapper as a local Swift Package by adding it as a dependency to your app. +Don't forget to add the wrapper to the `Frameworks, Libraries, and Embedded Content` section within the `General` tab. From 7f6256f32f58d362f4a0029e713a905ef9af9fa6 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Wed, 22 Jun 2022 14:30:26 +0200 Subject: [PATCH 73/88] Set team to None --- wrappers/ios/demo/demo.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj index 46f114c04f..204cd12fe1 100644 --- a/wrappers/ios/demo/demo.xcodeproj/project.pbxproj +++ b/wrappers/ios/demo/demo.xcodeproj/project.pbxproj @@ -316,7 +316,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 25MXZ8DDDM; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; @@ -347,7 +347,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 25MXZ8DDDM; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = demo/Info.plist; INFOPLIST_KEY_NSCameraUsageDescription = "Test ZXing"; From 81d67460f20673a6b7911fbf3d8398400c5a4817 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 28 Jun 2022 14:30:20 +0200 Subject: [PATCH 74/88] Add api to work directly with CVPixelBuffer This should improve performance when the pixel buffers pixel format is one of the supported luminance based ones. In this case we just hand over the luminance plane directly to ZXing without any color space conversion. For all other color spaces we keep on doing the color space conversion and call the CIImage api. --- .../Sources/Wrapper/Reader/ZXIBarcodeReader.h | 1 + .../Wrapper/Reader/ZXIBarcodeReader.mm | 55 ++++++++++++++++++- wrappers/ios/demo/demo/ViewController.swift | 4 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h index bb41ae2d8e..f2cca0ba21 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.h @@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithHints:(ZXIDecodeHints*)options; - (NSArray *)readCIImage:(nonnull CIImage *)image; - (NSArray *)readCGImage:(nonnull CGImageRef)image; +- (NSArray *)readCVPixelBuffer:(nonnull CVPixelBufferRef)pixelBuffer; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 2e81514ffc..7bbf9a931f 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -28,6 +28,36 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return self; } +- (NSArray *)readCVPixelBuffer:(nonnull CVPixelBufferRef)pixelBuffer { + OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer); + + // We tried to work with all luminance based formats listed in kCVPixelFormatType + // but only the following ones seem to be supported on iOS. + switch (pixelFormat) { + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: + case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: + NSInteger cols = CVPixelBufferGetWidth(pixelBuffer); + NSInteger rows = CVPixelBufferGetHeight(pixelBuffer); + NSInteger bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0); + CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); + const uint8_t * bytes = static_cast(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)); + ImageView imageView = ImageView( + static_cast(bytes), + static_cast(cols), + static_cast(rows), + ImageFormat::Lum, + static_cast(bytesPerRow), + 0); + NSArray* results = [self readImageView:imageView]; + CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly); + return results; + } + + // If given pixel format is not a supported type with a luminance channel we just use the + // default method + return [self readCIImage:[[CIImage alloc] initWithCVImageBuffer:pixelBuffer]]; +} + - (NSArray *)readCIImage:(nonnull CIImage *)image { CGImageRef cgImage = [self.ciContext createCGImage:image fromRect:image.extent]; auto results = [self readCGImage:cgImage]; @@ -35,12 +65,36 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return results; } +- (NSArray *)readImageView: (ImageView)imageView { + Results results = ReadBarcodes(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); + + NSMutableArray* zxiResults = [NSMutableArray array]; + for (auto result: results) { + if(result.status() == DecodeStatus::NoError) { + const std::wstring &resultText = result.text(); + NSString *text = [[NSString alloc] initWithBytes:resultText.data() + length:resultText.size() * sizeof(wchar_t) + encoding:NSUTF32LittleEndianStringEncoding]; + + NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; + [zxiResults addObject: + [[ZXIResult alloc] init:text + format:ZXIFormatFromBarcodeFormat(result.format()) + bytes:bytes + position:[[ZXIPosition alloc]initWithPosition: result.position()] + ]]; + } + } + return zxiResults; +} + - (NSArray *)readCGImage: (nonnull CGImageRef)image { CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); CGFloat cols = CGImageGetWidth(image); CGFloat rows = CGImageGetHeight(image); NSMutableData *data = [NSMutableData dataWithLength: cols * rows]; + CGContextRef contextRef = CGBitmapContextCreate( data.mutableBytes,// Pointer to backing data cols, // Width of bitmap @@ -49,7 +103,6 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ cols, // Bytes per row colorSpace, // Colorspace kCGBitmapByteOrderDefault); // Bitmap info flags - CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image); CGContextRelease(contextRef); diff --git a/wrappers/ios/demo/demo/ViewController.swift b/wrappers/ios/demo/demo/ViewController.swift index b84de21af5..4b4dd1e245 100644 --- a/wrappers/ios/demo/demo/ViewController.swift +++ b/wrappers/ios/demo/demo/ViewController.swift @@ -35,7 +35,7 @@ class ViewController: UIViewController { self.captureSession.addInput(cameraInput) let videoDataOutput = AVCaptureVideoDataOutput() videoDataOutput.setSampleBufferDelegate(self, queue: self.queue) - videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)] + videoDataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)] videoDataOutput.alwaysDiscardsLateVideoFrames = true self.captureSession.addOutput(videoDataOutput) self.captureSession.commitConfiguration() @@ -63,7 +63,7 @@ extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { return } let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)! - if let result = reader.read(CIImage(cvPixelBuffer: imageBuffer)).first { + if let result = reader.read(imageBuffer).first { print("Found barcode of format", result.format.rawValue, "with text", result.text) } self.zxingLock.signal() From 57a223a974455ec3ddb91dc5f3534270d301d55a Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 28 Jun 2022 14:33:35 +0200 Subject: [PATCH 75/88] Update .gitignore --- wrappers/ios/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/wrappers/ios/.gitignore b/wrappers/ios/.gitignore index 272f06febd..be5558caa1 100644 --- a/wrappers/ios/.gitignore +++ b/wrappers/ios/.gitignore @@ -1,4 +1,5 @@ .swiftpm _builds +.build xcuserdata ZXingCpp.xcframework From 399b3a054f449c0b1152f07f82dea4333a181e77 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Fri, 1 Jul 2022 11:48:57 +0200 Subject: [PATCH 76/88] Create build-ios.yml --- .github/workflows/build-ios.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/build-ios.yml diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml new file mode 100644 index 0000000000..d0aa8dbe17 --- /dev/null +++ b/.github/workflows/build-ios.yml @@ -0,0 +1,13 @@ +name: build-ios +on: push + +jobs: + build: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + + - name: Build + shell: bash + working-directory: ${{runner.workspace}}/wrappers/ios + run: ./build-release From 2c099919d4d3d80120134c3bc40896ffd301a83e Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Fri, 1 Jul 2022 11:54:50 +0200 Subject: [PATCH 77/88] Revert "Create build-ios.yml" This reverts commit 399b3a054f449c0b1152f07f82dea4333a181e77. --- .github/workflows/build-ios.yml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .github/workflows/build-ios.yml diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml deleted file mode 100644 index d0aa8dbe17..0000000000 --- a/.github/workflows/build-ios.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: build-ios -on: push - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - name: Build - shell: bash - working-directory: ${{runner.workspace}}/wrappers/ios - run: ./build-release From be84df6dcf82a63dbf967518210549dfcca1a56e Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Fri, 1 Jul 2022 14:32:59 +0200 Subject: [PATCH 78/88] Add ci for iOS wrapper --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6858fb4f2e..23bf7aec08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,29 @@ jobs: # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -V -C $BUILD_TYPE + + build-ios: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{github.ref}} + + - name: Build the ZXingCpp.xcframework + shell: sh + working-directory: ${{runner.workspace}}/${{github.event.repository.name}}/wrappers/ios + run: ./build-release.sh + + - name: Upload .xcframework + uses: actions/upload-artifact@v3 + with: + name: ios-artifacts + path: ${{runner.workspace}}/${{github.event.repository.name}}/wrappers/ios/ZXingCpp.xcframework + + - name: Build the demo app + shell: sh + working-directory: ${{runner.workspace}}/${{github.event.repository.name}}/wrappers/ios/demo + run: xcodebuild build -scheme demo -sdk "iphonesimulator" build-android: runs-on: ubuntu-latest From 42fa8ea6596d051e8fb13d0e4f08685b4861ab8f Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 5 Jul 2022 19:57:39 +0200 Subject: [PATCH 79/88] Remove fmtlib-src --- _deps/fmtlib-src | 1 - 1 file changed, 1 deletion(-) delete mode 160000 _deps/fmtlib-src diff --git a/_deps/fmtlib-src b/_deps/fmtlib-src deleted file mode 160000 index d141cdbeb0..0000000000 --- a/_deps/fmtlib-src +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d141cdbeb0fb422a3fb7173b285fd38e0d1772dc From 19556e3e8ae481e3639a94d811ad721049404fd5 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 5 Jul 2022 20:13:13 +0200 Subject: [PATCH 80/88] Use readImageView to remove code duplication --- .../Wrapper/Reader/ZXIBarcodeReader.mm | 56 ++++++------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 7bbf9a931f..25d209b4ef 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -65,29 +65,6 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return results; } -- (NSArray *)readImageView: (ImageView)imageView { - Results results = ReadBarcodes(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); - - NSMutableArray* zxiResults = [NSMutableArray array]; - for (auto result: results) { - if(result.status() == DecodeStatus::NoError) { - const std::wstring &resultText = result.text(); - NSString *text = [[NSString alloc] initWithBytes:resultText.data() - length:resultText.size() * sizeof(wchar_t) - encoding:NSUTF32LittleEndianStringEncoding]; - - NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; - [zxiResults addObject: - [[ZXIResult alloc] init:text - format:ZXIFormatFromBarcodeFormat(result.format()) - bytes:bytes - position:[[ZXIPosition alloc]initWithPosition: result.position()] - ]]; - } - } - return zxiResults; -} - - (NSArray *)readCGImage: (nonnull CGImageRef)image { CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); CGFloat cols = CGImageGetWidth(image); @@ -111,12 +88,29 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ static_cast(cols), static_cast(rows), ImageFormat::Lum); + return [self readImageView:imageView]; +} + ++ (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { + BarcodeFormats formats; + for(NSNumber* flag in hints.formats) { + formats.setFlag(BarcodeFormatFromZXIFormat((ZXIFormat)flag.integerValue)); + } + DecodeHints resultingHints = DecodeHints() + .setTryRotate(hints.tryRotate) + .setTryHarder(hints.tryHarder) + .setTryDownscale(hints.tryDownscale) + .setFormats(formats) + .setMaxNumberOfSymbols(hints.maxNumberOfSymbols); + return resultingHints; +} +- (NSArray *)readImageView: (ImageView)imageView { Results results = ReadBarcodes(imageView, [ZXIBarcodeReader DecodeHintsFromZXIOptions:self.hints]); NSMutableArray* zxiResults = [NSMutableArray array]; for (auto result: results) { - if(result.status() == DecodeStatus::NoError) { + if(result.error() == Error::None) { const std::wstring &resultText = result.text(); NSString *text = [[NSString alloc] initWithBytes:resultText.data() length:resultText.size() * sizeof(wchar_t) @@ -134,18 +128,4 @@ - (instancetype)initWithHints:(ZXIDecodeHints*)hints{ return zxiResults; } -+ (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { - BarcodeFormats formats; - for(NSNumber* flag in hints.formats) { - formats.setFlag(BarcodeFormatFromZXIFormat((ZXIFormat)flag.integerValue)); - } - DecodeHints resultingHints = DecodeHints() - .setTryRotate(hints.tryRotate) - .setTryHarder(hints.tryHarder) - .setTryDownscale(hints.tryDownscale) - .setFormats(formats) - .setMaxNumberOfSymbols(hints.maxNumberOfSymbols); - return resultingHints; -} - @end From 48c93152f6b7079eb8088f2b4d10a0efbc332779 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 5 Jul 2022 20:19:19 +0200 Subject: [PATCH 81/88] Remove ZXing from target include directory path --- core/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index fd32f7113a..39510068ea 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -454,7 +454,7 @@ add_library (ZXing target_include_directories (ZXing PUBLIC "$" - INTERFACE "$" + INTERFACE "$" ) target_compile_options (ZXing From 9c9d2571da326569dc832b217d18bc0796656987 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Tue, 5 Jul 2022 20:26:26 +0200 Subject: [PATCH 82/88] Add #define ZX_USE_UTF8 to get utf8 std::string --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 25d209b4ef..1e363cef39 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 +#define ZX_USE_UTF8 #import "ZXIBarcodeReader.h" #import "ZXing/ReadBarcode.h" #import "ZXing/ImageView.h" @@ -111,10 +112,7 @@ + (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { NSMutableArray* zxiResults = [NSMutableArray array]; for (auto result: results) { if(result.error() == Error::None) { - const std::wstring &resultText = result.text(); - NSString *text = [[NSString alloc] initWithBytes:resultText.data() - length:resultText.size() * sizeof(wchar_t) - encoding:NSUTF32LittleEndianStringEncoding]; + NSString *text = [NSString stringWithUTF8String:result.text().c_str()]; NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; [zxiResults addObject: From 4250ba4769ba80c00dbaf88eb40974e6d7e96736 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Wed, 6 Jul 2022 11:13:31 +0200 Subject: [PATCH 83/88] Rename 1D and 2D codes to linear and matrix --- wrappers/ios/Sources/Wrapper/ZXIFormat.h | 2 +- wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormat.h b/wrappers/ios/Sources/Wrapper/ZXIFormat.h index e43c39f570..157ac227cf 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormat.h +++ b/wrappers/ios/Sources/Wrapper/ZXIFormat.h @@ -9,7 +9,7 @@ typedef NS_ENUM(NSInteger, ZXIFormat) { NONE, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_BAR, DATA_BAR_EXPANDED, DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, MICRO_QR_CODE, UPC_A, UPC_E, - ONE_D_CODES, TWO_D_CODES, ANY + LINEAR_CODES, MATRIX_CODES, ANY }; #endif diff --git a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm index 744f676a6f..457c6e551f 100644 --- a/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm +++ b/wrappers/ios/Sources/Wrapper/ZXIFormatHelper.mm @@ -8,10 +8,10 @@ switch (format) { case ZXIFormat::ANY: return ZXing::BarcodeFormat::Any; - case ZXIFormat::TWO_D_CODES: - return ZXing::BarcodeFormat::TwoDCodes; - case ZXIFormat::ONE_D_CODES: - return ZXing::BarcodeFormat::OneDCodes; + case ZXIFormat::MATRIX_CODES: + return ZXing::BarcodeFormat::MatrixCodes; + case ZXIFormat::LINEAR_CODES: + return ZXing::BarcodeFormat::LinearCodes; case ZXIFormat::UPC_E: return ZXing::BarcodeFormat::UPCE; case ZXIFormat::UPC_A: @@ -89,10 +89,10 @@ ZXIFormat ZXIFormatFromBarcodeFormat(ZXing::BarcodeFormat format) { return ZXIFormat::UPC_A; case ZXing::BarcodeFormat::UPCE: return ZXIFormat::UPC_E; - case ZXing::BarcodeFormat::OneDCodes: - return ZXIFormat::ONE_D_CODES; - case ZXing::BarcodeFormat::TwoDCodes: - return ZXIFormat::TWO_D_CODES; + case ZXing::BarcodeFormat::LinearCodes: + return ZXIFormat::LINEAR_CODES; + case ZXing::BarcodeFormat::MatrixCodes: + return ZXIFormat::MATRIX_CODES; case ZXing::BarcodeFormat::MicroQRCode: return ZXIFormat::MICRO_QR_CODE; case ZXing::BarcodeFormat::Any: From 9cbe49f292e7c65d39992cc68351e9a45e3c5f2e Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Wed, 6 Jul 2022 19:40:04 +0200 Subject: [PATCH 84/88] Remove error check for result --- .../Wrapper/Reader/ZXIBarcodeReader.mm | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 1e363cef39..7fc278d1f0 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -111,17 +111,15 @@ + (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { NSMutableArray* zxiResults = [NSMutableArray array]; for (auto result: results) { - if(result.error() == Error::None) { - NSString *text = [NSString stringWithUTF8String:result.text().c_str()]; - - NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; - [zxiResults addObject: - [[ZXIResult alloc] init:text - format:ZXIFormatFromBarcodeFormat(result.format()) - bytes:bytes - position:[[ZXIPosition alloc]initWithPosition: result.position()] - ]]; - } + NSString *text = [NSString stringWithUTF8String:result.text().c_str()]; + + NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; + [zxiResults addObject: + [[ZXIResult alloc] init:text + format:ZXIFormatFromBarcodeFormat(result.format()) + bytes:bytes + position:[[ZXIPosition alloc]initWithPosition: result.position()] + ]]; } return zxiResults; } From 86211915ef454588017b907a2a8d8ca4610da5d6 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Fri, 8 Jul 2022 15:32:16 +0200 Subject: [PATCH 85/88] Remove charset from writer api --- wrappers/ios/Sources/Wrapper/UmbrellaHeader.h | 1 - .../Sources/Wrapper/Writer/ZXIBarcodeWriter.h | 7 - .../Wrapper/Writer/ZXIBarcodeWriter.mm | 10 -- .../ios/Sources/Wrapper/Writer/ZXICharset.h | 46 ------ .../Sources/Wrapper/Writer/ZXICharsetHelper.h | 14 -- .../Wrapper/Writer/ZXICharsetHelper.mm | 145 ------------------ 6 files changed, 223 deletions(-) delete mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h delete mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h delete mode 100644 wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm diff --git a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h index b890d2313f..951357f673 100644 --- a/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h +++ b/wrappers/ios/Sources/Wrapper/UmbrellaHeader.h @@ -11,7 +11,6 @@ #import "Reader/ZXIPoint.h" #import "Reader/ZXIDecodeHints.h" #import "Writer/ZXIBarcodeWriter.h" -#import "Writer/ZXICharset.h" #import "ZXIErrors.h" #import "ZXIFormat.h" diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h index be730365ef..3a703985fe 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h @@ -15,13 +15,6 @@ NS_ASSUME_NONNULL_BEGIN height:(int)height format:(ZXIFormat)format error:(NSError **)error; - --(nullable CGImageRef)write:(NSString *)contents - width:(int)width - height:(int)height - format:(ZXIFormat)format - charset:(ZXICharset)charset - error:(NSError **)error; @end NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index 02d04f3581..badce77ea3 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -40,22 +40,12 @@ @implementation ZXIBarcodeWriter --(nullable CGImageRef)write:(nonnull NSString *)contents - width:(int)width - height:(int)height - format:(ZXIFormat)format - error:(NSError **)error { - return [self write:contents width:width height:height format:format charset:Unknown error:error]; -} - -(CGImageRef)write:(NSString *)contents width:(int)width height:(int)height format:(ZXIFormat)format - charset:(ZXICharset)charset error:(NSError *__autoreleasing _Nullable *)error { MultiFormatWriter writer { BarcodeFormatFromZXIFormat(format) }; - writer.setEncoding(CharsetFromZXICharset(charset)); // Catch exception for invalid formats try { BitMatrix result = writer.encode(NSStringToStringW(contents), width, height); diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h deleted file mode 100644 index d3005ede67..0000000000 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharset.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2022 KURZ Digital Solutions GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#ifndef Header_h -#define Header_h - -#import - -typedef NS_ENUM(NSInteger, ZXICharset) { - Unknown, - ASCII, - ISO8859_1, - ISO8859_2, - ISO8859_3, - ISO8859_4, - ISO8859_5, - ISO8859_6, - ISO8859_7, - ISO8859_8, - ISO8859_9, - ISO8859_10, - ISO8859_11, - ISO8859_13, - ISO8859_14, - ISO8859_15, - ISO8859_16, - Cp437, - Cp1250, - Cp1251, - Cp1252, - Cp1256, - - Shift_JIS, - Big5, - GB2312, - GB18030, - EUC_JP, - EUC_KR, - UnicodeBig, - UTF8, - - BINARY -}; - -#endif /* Header_h */ diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h deleted file mode 100644 index 517b4a1d82..0000000000 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2022 KURZ Digital Solutions GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#import -#import "ZXing/CharacterSet.h" -#import "ZXICharset.h" - -NS_ASSUME_NONNULL_BEGIN - -ZXICharset ZXICharsetFromCharset(ZXing::CharacterSet charset); -ZXing::CharacterSet CharsetFromZXICharset(ZXICharset charset); - -NS_ASSUME_NONNULL_END diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm deleted file mode 100644 index e7dedc0b0b..0000000000 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXICharsetHelper.mm +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2022 KURZ Digital Solutions GmbH -// -// SPDX-License-Identifier: Apache-2.0 - -#import "ZXICharsetHelper.h" - -ZXICharset ZXICharsetFromCharset(ZXing::CharacterSet charset) { - switch(charset) { - case ZXing::CharacterSet::Unknown: - return Unknown; - case ZXing::CharacterSet::ASCII: - return ASCII; - case ZXing::CharacterSet::ISO8859_1: - return ISO8859_1; - case ZXing::CharacterSet::ISO8859_2: - return ISO8859_2; - case ZXing::CharacterSet::ISO8859_3: - return ISO8859_3; - case ZXing::CharacterSet::ISO8859_4: - return ISO8859_4; - case ZXing::CharacterSet::ISO8859_5: - return ISO8859_5; - case ZXing::CharacterSet::ISO8859_6: - return ISO8859_6; - case ZXing::CharacterSet::ISO8859_7: - return ISO8859_7; - case ZXing::CharacterSet::ISO8859_8: - return ISO8859_8; - case ZXing::CharacterSet::ISO8859_9: - return ISO8859_9; - case ZXing::CharacterSet::ISO8859_10: - return ISO8859_10; - case ZXing::CharacterSet::ISO8859_11: - return ISO8859_11; - case ZXing::CharacterSet::ISO8859_13: - return ISO8859_13; - case ZXing::CharacterSet::ISO8859_14: - return ISO8859_14; - case ZXing::CharacterSet::ISO8859_15: - return ISO8859_15; - case ZXing::CharacterSet::ISO8859_16: - return ISO8859_16; - case ZXing::CharacterSet::Cp437: - return Cp437; - case ZXing::CharacterSet::Cp1250: - return Cp1250; - case ZXing::CharacterSet::Cp1251: - return Cp1251; - case ZXing::CharacterSet::Cp1252: - return Cp1252; - case ZXing::CharacterSet::Cp1256: - return Cp1256; - case ZXing::CharacterSet::Shift_JIS: - return Shift_JIS; - case ZXing::CharacterSet::Big5: - return Big5; - case ZXing::CharacterSet::GB2312: - return GB2312; - case ZXing::CharacterSet::GB18030: - return GB18030; - case ZXing::CharacterSet::EUC_JP: - return EUC_JP; - case ZXing::CharacterSet::EUC_KR: - return EUC_KR; - case ZXing::CharacterSet::UnicodeBig: - return UnicodeBig; - case ZXing::CharacterSet::UTF8: - return UTF8; - case ZXing::CharacterSet::BINARY: - return BINARY; - case ZXing::CharacterSet::CharsetCount: - return Unknown; - } - NSLog(@"ZXIWrapper: Received invalid CharacterSet, returning Unknown"); - return Unknown; -} - -ZXing::CharacterSet CharsetFromZXICharset(ZXICharset charset) { - switch(charset) { - case Unknown: - return ZXing::CharacterSet::Unknown; - case ASCII: - return ZXing::CharacterSet::ASCII; - case ISO8859_1: - return ZXing::CharacterSet::ISO8859_1; - case ISO8859_2: - return ZXing::CharacterSet::ISO8859_2; - case ISO8859_3: - return ZXing::CharacterSet::ISO8859_3; - case ISO8859_4: - return ZXing::CharacterSet::ISO8859_4; - case ISO8859_5: - return ZXing::CharacterSet::ISO8859_5; - case ISO8859_6: - return ZXing::CharacterSet::ISO8859_6; - case ISO8859_7: - return ZXing::CharacterSet::ISO8859_7; - case ISO8859_8: - return ZXing::CharacterSet::ISO8859_8; - case ISO8859_9: - return ZXing::CharacterSet::ISO8859_9; - case ISO8859_10: - return ZXing::CharacterSet::ISO8859_10; - case ISO8859_11: - return ZXing::CharacterSet::ISO8859_11; - case ISO8859_13: - return ZXing::CharacterSet::ISO8859_13; - case ISO8859_14: - return ZXing::CharacterSet::ISO8859_14; - case ISO8859_15: - return ZXing::CharacterSet::ISO8859_15; - case ISO8859_16: - return ZXing::CharacterSet::ISO8859_16; - case Cp437: - return ZXing::CharacterSet::Cp437; - case Cp1250: - return ZXing::CharacterSet::Cp1250; - case Cp1251: - return ZXing::CharacterSet::Cp1251; - case Cp1252: - return ZXing::CharacterSet::Cp1252; - case Cp1256: - return ZXing::CharacterSet::Cp1256; - case Shift_JIS: - return ZXing::CharacterSet::Shift_JIS; - case Big5: - return ZXing::CharacterSet::Big5; - case GB2312: - return ZXing::CharacterSet::GB2312; - case GB18030: - return ZXing::CharacterSet::GB18030; - case EUC_JP: - return ZXing::CharacterSet::EUC_JP; - case EUC_KR: - return ZXing::CharacterSet::EUC_KR; - case UnicodeBig: - return ZXing::CharacterSet::UnicodeBig; - case UTF8: - return ZXing::CharacterSet::UTF8; - case BINARY: - return ZXing::CharacterSet::BINARY; - } - NSLog(@"ZXIWrapper: Received invalid ZXIFormat, returning Unknown"); - return ZXing::CharacterSet::Unknown; -} From 651e54d9be8772a6b23feb1ec1dae6b8236732dd Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 11 Jul 2022 16:29:21 +0200 Subject: [PATCH 86/88] Remove character encoding --- wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h | 1 - wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm | 1 - 2 files changed, 2 deletions(-) diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h index 3a703985fe..664ff3dd84 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.h @@ -4,7 +4,6 @@ #import #import "ZXIFormat.h" -#import "ZXICharset.h" NS_ASSUME_NONNULL_BEGIN diff --git a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm index badce77ea3..430fed9995 100644 --- a/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm +++ b/wrappers/ios/Sources/Wrapper/Writer/ZXIBarcodeWriter.mm @@ -7,7 +7,6 @@ #import "ZXing/MultiFormatWriter.h" #import "ZXing/BitMatrix.h" #import "ZXIFormatHelper.h" -#import "ZXICharsetHelper.h" #import "ZXIErrors.h" #import From c1c78983e8ec4c651c7fd03d1000b39f1eef78e0 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 11 Jul 2022 16:29:38 +0200 Subject: [PATCH 87/88] Use initWithBytes for text --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 7fc278d1f0..5c82ccd67c 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -111,7 +111,8 @@ + (DecodeHints)DecodeHintsFromZXIOptions:(ZXIDecodeHints*)hints { NSMutableArray* zxiResults = [NSMutableArray array]; for (auto result: results) { - NSString *text = [NSString stringWithUTF8String:result.text().c_str()]; + auto resultText = result.text(); + NSString *text = [[NSString alloc]initWithBytes:resultText.data() length:resultText.size() encoding:NSUTF8StringEncoding]; NSData *bytes = [[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()]; [zxiResults addObject: From f1fe8b258dc5ea84dda6a32f4a2105beee46c197 Mon Sep 17 00:00:00 2001 From: Christian Braun Date: Mon, 11 Jul 2022 16:51:33 +0200 Subject: [PATCH 88/88] Remove #define ZX_USE_UTF8 --- wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm index 5c82ccd67c..abee63aabc 100644 --- a/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm +++ b/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: Apache-2.0 -#define ZX_USE_UTF8 #import "ZXIBarcodeReader.h" #import "ZXing/ReadBarcode.h" #import "ZXing/ImageView.h" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy