Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zxing-cpp/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zxing-cpp/wrappers/ios/Sources/Wrapper/Reader/ZXIBarcodeReader.mm Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,155 @@ +// Copyright 2022 KURZ Digital Solutions GmbH +// +// SPDX-License-Identifier: Apache-2.0 + +#import "ZXIBarcodeReader.h" +#import "ReadBarcode.h" +#import "ImageView.h" +#import "Barcode.h" +#import "GTIN.h" +#import "ZXIFormatHelper.h" +#import "ZXIPosition+Helper.h" +#import "ZXIErrors.h" + +using namespace ZXing; + +NSString *stringToNSString(const std::string &text) { + return [[NSString alloc]initWithBytes:text.data() length:text.size() encoding:NSUTF8StringEncoding]; +} + +ZXIGTIN *getGTIN(const Result &result) { + try { + auto country = GTIN::LookupCountryIdentifier(result.text(TextMode::Plain), result.format()); + auto addOn = GTIN::EanAddOn(result); + return country.empty() + ? nullptr + : [[ZXIGTIN alloc]initWithCountry:stringToNSString(country) + addOn:stringToNSString(addOn) + price:stringToNSString(GTIN::Price(addOn)) + issueNumber:stringToNSString(GTIN::IssueNr(addOn))]; + } catch (std::exception e) { + // Because invalid GTIN data can lead to exceptions, in which case + // we don't want to discard the whole result. + return nullptr; + } +} + +@interface ZXIReaderOptions() +@property(nonatomic) ZXing::ReaderOptions cppOpts; +@end + +@interface ZXIBarcodeReader() +@property (nonatomic, strong) CIContext* ciContext; +@end + +@implementation ZXIBarcodeReader + +- (instancetype)init { + return [self initWithOptions: [[ZXIReaderOptions alloc] init]]; +} + +- (instancetype)initWithOptions:(ZXIReaderOptions*)options{ + self = [super init]; + self.ciContext = [[CIContext alloc] initWithOptions:@{kCIContextWorkingColorSpace: [NSNull new]}]; + self.options = options; + return self; +} + +- (NSArray<ZXIResult *> *)readCVPixelBuffer:(nonnull CVPixelBufferRef)pixelBuffer + error:(NSError *__autoreleasing _Nullable *)error { + 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<const uint8_t *>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)); + ImageView imageView = ImageView( + static_cast<const uint8_t *>(bytes), + static_cast<int>(cols), + static_cast<int>(rows), + ImageFormat::Lum, + static_cast<int>(bytesPerRow), + 0); + NSArray* results = [self readImageView:imageView error:error]; + 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] error:error]; +} + +- (NSArray<ZXIResult *> *)readCIImage:(nonnull CIImage *)image + error:(NSError *__autoreleasing _Nullable *)error { + CGImageRef cgImage = [self.ciContext createCGImage:image fromRect:image.extent]; + auto results = [self readCGImage:cgImage error:error]; + CGImageRelease(cgImage); + return results; +} + +- (NSArray<ZXIResult *> *)readCGImage:(nonnull CGImageRef)image + error:(NSError *__autoreleasing _Nullable *)error { + CGFloat cols = CGImageGetWidth(image); + CGFloat rows = CGImageGetHeight(image); + NSMutableData *data = [NSMutableData dataWithLength: cols * rows]; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray); + 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 + CGColorSpaceRelease(colorSpace); + CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image); + CGContextRelease(contextRef); + + ImageView imageView = ImageView( + static_cast<const uint8_t *>(data.bytes), + static_cast<int>(cols), + static_cast<int>(rows), + ImageFormat::Lum); + return [self readImageView:imageView error:error]; +} + +- (NSArray<ZXIResult*> *)readImageView:(ImageView)imageView + error:(NSError *__autoreleasing _Nullable *)error { + try { + Barcodes results = ReadBarcodes(imageView, self.options.cppOpts); + NSMutableArray* zxiResults = [NSMutableArray array]; + for (auto result: results) { + [zxiResults addObject: + [[ZXIResult alloc] init:stringToNSString(result.text()) + format:ZXIFormatFromBarcodeFormat(result.format()) + bytes:[[NSData alloc] initWithBytes:result.bytes().data() length:result.bytes().size()] + position:[[ZXIPosition alloc]initWithPosition: result.position()] + orientation:result.orientation() + ecLevel:stringToNSString(result.ecLevel()) + symbologyIdentifier:stringToNSString(result.symbologyIdentifier()) + sequenceSize:result.sequenceSize() + sequenceIndex:result.sequenceIndex() + sequenceId:stringToNSString(result.sequenceId()) + readerInit:result.readerInit() + lineCount:result.lineCount() + gtin:getGTIN(result)] + ]; + } + return zxiResults; + } catch(std::exception &e) { + SetNSError(error, ZXIReaderError, e.what()); + return nil; + } catch (...) { + SetNSError(error, ZXIReaderError, "An unknown error occurred"); + return nil; + } +} + +@end
