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