1eafa96e0SStanisław Chmiela// Copyright 2016-present 650 Industries. All rights reserved. 2eafa96e0SStanisław Chmiela 3eafa96e0SStanisław Chmiela#import <EXBarCodeScanner/EXBarCodeScanner.h> 4eafa96e0SStanisław Chmiela#import <EXBarCodeScanner/EXBarCodeScannerUtils.h> 5314e850cSTomasz Sapeta#import <ExpoModulesCore/EXDefines.h> 61f9c336aSBartłomiej Bukowski#import <ZXingObjC/ZXingObjCCore.h> 71f9c336aSBartłomiej Bukowski#import <ZXingObjC/ZXingObjCPDF417.h> 81f9c336aSBartłomiej Bukowski#import <ZXingObjC/ZXingObjCOneD.h> 9eafa96e0SStanisław Chmiela 101f9c336aSBartłomiej Bukowski@interface EXBarCodeScanner() <AVCaptureMetadataOutputObjectsDelegate, AVCaptureVideoDataOutputSampleBufferDelegate> 11eafa96e0SStanisław Chmiela 12eafa96e0SStanisław Chmiela@property (nonatomic, strong) AVCaptureMetadataOutput *metadataOutput; 13eafa96e0SStanisław Chmiela@property (nonatomic, weak) AVCaptureSession *session; 14eafa96e0SStanisław Chmiela@property (nonatomic, weak) dispatch_queue_t sessionQueue; 15eafa96e0SStanisław Chmiela@property (nonatomic, copy, nullable) void (^onBarCodeScanned)(NSDictionary*); 16eafa96e0SStanisław Chmiela@property (nonatomic, assign, getter=isScanningBarCodes) BOOL barCodesScanning; 17eafa96e0SStanisław Chmiela@property (nonatomic, strong) NSDictionary<NSString *, id> *settings; 18bd4c8242SŁukasz Kosmaty@property (nonatomic, weak) AVCaptureVideoPreviewLayer *previewLayer; 19eafa96e0SStanisław Chmiela 205a06ec9aSUrata Daiki@property (nonatomic, strong) NSMutableDictionary<NSString *, id<ZXReader>> *zxingBarcodeReaders; 211f9c336aSBartłomiej Bukowski@property (nonatomic, assign) CGFloat zxingFPSProcessed; 221f9c336aSBartłomiej Bukowski@property (nonatomic, strong) AVCaptureVideoDataOutput* videoDataOutput; 231f9c336aSBartłomiej Bukowski@property (nonatomic, strong) dispatch_queue_t zxingCaptureQueue; 241f9c336aSBartłomiej Bukowski@property (nonatomic, assign) BOOL zxingEnabled; 251f9c336aSBartłomiej Bukowski 26eafa96e0SStanisław Chmiela@end 27eafa96e0SStanisław Chmiela 289cded925STomasz SapetaNSString *const EX_BARCODE_TYPES_KEY = @"barCodeTypes"; 29eafa96e0SStanisław Chmiela 30eafa96e0SStanisław Chmiela@implementation EXBarCodeScanner 31eafa96e0SStanisław Chmiela 32eafa96e0SStanisław Chmiela- (instancetype)init 33eafa96e0SStanisław Chmiela{ 34eafa96e0SStanisław Chmiela if (self = [super init]) { 35eafa96e0SStanisław Chmiela _settings = [[NSMutableDictionary alloc] initWithDictionary:[[self class] _getDefaultSettings]]; 361f9c336aSBartłomiej Bukowski 371f9c336aSBartłomiej Bukowski // zxing handles barcodes reading of following types: 385a06ec9aSUrata Daiki _zxingBarcodeReaders = [@{ 391f9c336aSBartłomiej Bukowski // PDF417 - built-in PDF417 reader doesn't handle u'\0' (null) character - https://github.com/expo/expo/issues/4817 401f9c336aSBartłomiej Bukowski AVMetadataObjectTypePDF417Code: [ZXPDF417Reader new], 411f9c336aSBartłomiej Bukowski // Code39 - built-in Code39 reader doesn't read non-ideal (slightly rotated) images like this - https://github.com/expo/expo/pull/5976#issuecomment-545001008 421f9c336aSBartłomiej Bukowski AVMetadataObjectTypeCode39Code: [ZXCode39Reader new], 435a06ec9aSUrata Daiki } mutableCopy]; 44*7e5da4d1SBartłomiej Bukowski#ifdef __IPHONE_15_4 455a06ec9aSUrata Daiki // Codabar - available in iOS 15.4+ 465a06ec9aSUrata Daiki if (@available(iOS 15.4, *)) { 475a06ec9aSUrata Daiki _zxingBarcodeReaders[AVMetadataObjectTypeCodabarCode] = [ZXCodaBarReader new]; 485a06ec9aSUrata Daiki } 49*7e5da4d1SBartłomiej Bukowski#endif 501f9c336aSBartłomiej Bukowski _zxingFPSProcessed = 6; 511f9c336aSBartłomiej Bukowski _zxingCaptureQueue = dispatch_queue_create("com.zxing.captureQueue", NULL); 521f9c336aSBartłomiej Bukowski _zxingEnabled = YES; 53eafa96e0SStanisław Chmiela } 54eafa96e0SStanisław Chmiela return self; 55eafa96e0SStanisław Chmiela} 56eafa96e0SStanisław Chmiela 57eafa96e0SStanisław Chmiela# pragma mark - JS properties setters 58eafa96e0SStanisław Chmiela 59eafa96e0SStanisław Chmiela- (void)setSettings:(NSDictionary<NSString *, id> *)settings 60eafa96e0SStanisław Chmiela{ 61eafa96e0SStanisław Chmiela for (NSString *key in settings) { 629cded925STomasz Sapeta if ([key isEqualToString:EX_BARCODE_TYPES_KEY]) { 63eafa96e0SStanisław Chmiela NSArray<NSString *> *value = settings[key]; 649cded925STomasz Sapeta NSSet *previousTypes = [NSSet setWithArray:_settings[EX_BARCODE_TYPES_KEY]]; 65eafa96e0SStanisław Chmiela NSSet *newTypes = [NSSet setWithArray:value]; 66eafa96e0SStanisław Chmiela if (![previousTypes isEqualToSet:newTypes]) { 67eafa96e0SStanisław Chmiela NSMutableDictionary<NSString *, id> *nextSettings = [[NSMutableDictionary alloc] initWithDictionary:_settings]; 689cded925STomasz Sapeta nextSettings[EX_BARCODE_TYPES_KEY] = value; 69eafa96e0SStanisław Chmiela _settings = nextSettings; 701f9c336aSBartłomiej Bukowski NSSet *zxingCoveredTypes = [NSSet setWithArray:[_zxingBarcodeReaders allKeys]]; 711f9c336aSBartłomiej Bukowski _zxingEnabled = [zxingCoveredTypes intersectsSet:newTypes]; 72314e850cSTomasz Sapeta EX_WEAKIFY(self); 73f870e5d8SStanisław Chmiela [self _runBlockIfQueueIsPresent:^{ 74314e850cSTomasz Sapeta EX_ENSURE_STRONGIFY(self); 75eafa96e0SStanisław Chmiela [self maybeStartBarCodeScanning]; 76f870e5d8SStanisław Chmiela }]; 77eafa96e0SStanisław Chmiela } 78eafa96e0SStanisław Chmiela } 79eafa96e0SStanisław Chmiela } 80eafa96e0SStanisław Chmiela} 81eafa96e0SStanisław Chmiela 82eafa96e0SStanisław Chmiela- (void)setIsEnabled:(BOOL)newBarCodeScanning 83eafa96e0SStanisław Chmiela{ 84eafa96e0SStanisław Chmiela if ([self isScanningBarCodes] == newBarCodeScanning) { 85eafa96e0SStanisław Chmiela return; 86eafa96e0SStanisław Chmiela } 87eafa96e0SStanisław Chmiela _barCodesScanning = newBarCodeScanning; 88314e850cSTomasz Sapeta EX_WEAKIFY(self); 89eafa96e0SStanisław Chmiela [self _runBlockIfQueueIsPresent:^{ 90314e850cSTomasz Sapeta EX_ENSURE_STRONGIFY(self); 91eafa96e0SStanisław Chmiela if ([self isScanningBarCodes]) { 92eafa96e0SStanisław Chmiela if (self.metadataOutput) { 93eafa96e0SStanisław Chmiela [self _setConnectionsEnabled:true]; 94eafa96e0SStanisław Chmiela } else { 95eafa96e0SStanisław Chmiela [self maybeStartBarCodeScanning]; 96eafa96e0SStanisław Chmiela } 97eafa96e0SStanisław Chmiela } else { 98eafa96e0SStanisław Chmiela [self _setConnectionsEnabled:false]; 99eafa96e0SStanisław Chmiela } 100eafa96e0SStanisław Chmiela }]; 101eafa96e0SStanisław Chmiela} 102eafa96e0SStanisław Chmiela 103eafa96e0SStanisław Chmiela# pragma mark - Public API 104eafa96e0SStanisław Chmiela 105eafa96e0SStanisław Chmiela- (void)maybeStartBarCodeScanning 106eafa96e0SStanisław Chmiela{ 107eafa96e0SStanisław Chmiela if (!_session || !_sessionQueue || ![self isScanningBarCodes]) { 108eafa96e0SStanisław Chmiela return; 109eafa96e0SStanisław Chmiela } 110eafa96e0SStanisław Chmiela 1111f9c336aSBartłomiej Bukowski if (!_metadataOutput || !_videoDataOutput) { 112eafa96e0SStanisław Chmiela [_session beginConfiguration]; 113eafa96e0SStanisław Chmiela 1141f9c336aSBartłomiej Bukowski if (!_metadataOutput) { 115eafa96e0SStanisław Chmiela AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init]; 116eafa96e0SStanisław Chmiela [metadataOutput setMetadataObjectsDelegate:self queue:_sessionQueue]; 117eafa96e0SStanisław Chmiela if ([_session canAddOutput:metadataOutput]) { 118eafa96e0SStanisław Chmiela [_session addOutput:metadataOutput]; 119eafa96e0SStanisław Chmiela _metadataOutput = metadataOutput; 120eafa96e0SStanisław Chmiela } 1211f9c336aSBartłomiej Bukowski } 1221f9c336aSBartłomiej Bukowski 1231f9c336aSBartłomiej Bukowski if (!_videoDataOutput) { 1241f9c336aSBartłomiej Bukowski AVCaptureVideoDataOutput *videoDataOutput = [AVCaptureVideoDataOutput new]; 1251f9c336aSBartłomiej Bukowski [videoDataOutput setVideoSettings:@{ 1261f9c336aSBartłomiej Bukowski (NSString *)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], 1271f9c336aSBartłomiej Bukowski }]; 1281f9c336aSBartłomiej Bukowski [videoDataOutput setAlwaysDiscardsLateVideoFrames:YES]; 1291f9c336aSBartłomiej Bukowski [videoDataOutput setSampleBufferDelegate:self queue:_zxingCaptureQueue]; 1301f9c336aSBartłomiej Bukowski if ([_session canAddOutput:videoDataOutput]) { 1311f9c336aSBartłomiej Bukowski [_session addOutput:videoDataOutput]; 1321f9c336aSBartłomiej Bukowski _videoDataOutput = videoDataOutput; 1331f9c336aSBartłomiej Bukowski } 1341f9c336aSBartłomiej Bukowski } 1351f9c336aSBartłomiej Bukowski 136eafa96e0SStanisław Chmiela [_session commitConfiguration]; 137eafa96e0SStanisław Chmiela 138eafa96e0SStanisław Chmiela if (!_metadataOutput) { 139eafa96e0SStanisław Chmiela return; 140eafa96e0SStanisław Chmiela } 141eafa96e0SStanisław Chmiela } 142eafa96e0SStanisław Chmiela 143eafa96e0SStanisław Chmiela NSArray<AVMetadataObjectType> *availableRequestedObjectTypes = @[]; 144eafa96e0SStanisław Chmiela NSArray<AVMetadataObjectType> *requestedObjectTypes = @[]; 145eafa96e0SStanisław Chmiela NSArray<AVMetadataObjectType> *availableObjectTypes = _metadataOutput.availableMetadataObjectTypes; 1469cded925STomasz Sapeta if (_settings && _settings[EX_BARCODE_TYPES_KEY]) { 1479cded925STomasz Sapeta requestedObjectTypes = [[NSArray alloc] initWithArray:_settings[EX_BARCODE_TYPES_KEY]]; 148eafa96e0SStanisław Chmiela } 149eafa96e0SStanisław Chmiela 150eafa96e0SStanisław Chmiela for(AVMetadataObjectType objectType in requestedObjectTypes) { 151eafa96e0SStanisław Chmiela if ([availableObjectTypes containsObject:objectType]) { 152eafa96e0SStanisław Chmiela availableRequestedObjectTypes = [availableRequestedObjectTypes arrayByAddingObject:objectType]; 153eafa96e0SStanisław Chmiela } 154eafa96e0SStanisław Chmiela } 155eafa96e0SStanisław Chmiela 156eafa96e0SStanisław Chmiela [_metadataOutput setMetadataObjectTypes:availableRequestedObjectTypes]; 157eafa96e0SStanisław Chmiela} 158eafa96e0SStanisław Chmiela 159eafa96e0SStanisław Chmiela- (void)stopBarCodeScanning 160eafa96e0SStanisław Chmiela{ 161eafa96e0SStanisław Chmiela if (!_session) { 162eafa96e0SStanisław Chmiela return; 163eafa96e0SStanisław Chmiela } 164eafa96e0SStanisław Chmiela 165eafa96e0SStanisław Chmiela [_session beginConfiguration]; 166eafa96e0SStanisław Chmiela 167eafa96e0SStanisław Chmiela if ([_session.outputs containsObject:_metadataOutput]) { 168eafa96e0SStanisław Chmiela [_session removeOutput:_metadataOutput]; 169eafa96e0SStanisław Chmiela _metadataOutput = nil; 170eafa96e0SStanisław Chmiela } 171eafa96e0SStanisław Chmiela 1721f9c336aSBartłomiej Bukowski if ([_session.outputs containsObject:_videoDataOutput]) { 1731f9c336aSBartłomiej Bukowski [_session removeOutput:_videoDataOutput]; 1741f9c336aSBartłomiej Bukowski _videoDataOutput = nil; 1751f9c336aSBartłomiej Bukowski } 1761f9c336aSBartłomiej Bukowski 177eafa96e0SStanisław Chmiela [_session commitConfiguration]; 178eafa96e0SStanisław Chmiela 179eafa96e0SStanisław Chmiela if ([self isScanningBarCodes] && _onBarCodeScanned) { 180eafa96e0SStanisław Chmiela _onBarCodeScanned(nil); 181eafa96e0SStanisław Chmiela } 182eafa96e0SStanisław Chmiela} 183eafa96e0SStanisław Chmiela 184eafa96e0SStanisław Chmiela# pragma mark - Private API 185eafa96e0SStanisław Chmiela 186eafa96e0SStanisław Chmiela- (void)_setConnectionsEnabled:(BOOL)enabled 187eafa96e0SStanisław Chmiela{ 188eafa96e0SStanisław Chmiela if (!_metadataOutput) { 189eafa96e0SStanisław Chmiela return; 190eafa96e0SStanisław Chmiela } 191eafa96e0SStanisław Chmiela for (AVCaptureConnection *connection in _metadataOutput.connections) { 192eafa96e0SStanisław Chmiela connection.enabled = enabled; 193eafa96e0SStanisław Chmiela } 194eafa96e0SStanisław Chmiela} 195eafa96e0SStanisław Chmiela 196eafa96e0SStanisław Chmiela- (void)_runBlockIfQueueIsPresent:(void (^)(void))block 197eafa96e0SStanisław Chmiela{ 198eafa96e0SStanisław Chmiela if (_sessionQueue) { 199eafa96e0SStanisław Chmiela dispatch_async(_sessionQueue, block); 200eafa96e0SStanisław Chmiela } 201eafa96e0SStanisław Chmiela} 202eafa96e0SStanisław Chmiela 203eafa96e0SStanisław Chmiela# pragma mark - AVCaptureMetadataOutputObjectsDelegate 204eafa96e0SStanisław Chmiela 205eafa96e0SStanisław Chmiela- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects 206eafa96e0SStanisław Chmiela fromConnection:(AVCaptureConnection *)connection 207eafa96e0SStanisław Chmiela{ 2089cded925STomasz Sapeta if (!_settings || !_settings[EX_BARCODE_TYPES_KEY] || !_metadataOutput) { 209eafa96e0SStanisław Chmiela return; 210eafa96e0SStanisław Chmiela } 211eafa96e0SStanisław Chmiela 212eafa96e0SStanisław Chmiela for (AVMetadataObject *metadata in metadataObjects) { 213eafa96e0SStanisław Chmiela if ([metadata isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) { 214bd4c8242SŁukasz Kosmaty AVMetadataMachineReadableCodeObject *codeMetadata; 215bd4c8242SŁukasz Kosmaty if (_previewLayer) { 216bd4c8242SŁukasz Kosmaty codeMetadata = (AVMetadataMachineReadableCodeObject *)[_previewLayer transformedMetadataObjectForMetadataObject:metadata]; 217bd4c8242SŁukasz Kosmaty } else { 218bd4c8242SŁukasz Kosmaty codeMetadata = (AVMetadataMachineReadableCodeObject *)metadata; 219bd4c8242SŁukasz Kosmaty } 220bd4c8242SŁukasz Kosmaty 2219cded925STomasz Sapeta for (id barcodeType in _settings[EX_BARCODE_TYPES_KEY]) { 2221f9c336aSBartłomiej Bukowski // some barcodes aren't handled properly by iOS SDK build-in reader -> zxing handles it in separate flow 2231f9c336aSBartłomiej Bukowski if ([_zxingBarcodeReaders objectForKey:barcodeType]) { 2241f9c336aSBartłomiej Bukowski continue; 2251f9c336aSBartłomiej Bukowski } 226e60eb2afSStanisław Chmiela if (codeMetadata.stringValue && [codeMetadata.type isEqualToString:barcodeType]) { 227eafa96e0SStanisław Chmiela if (_onBarCodeScanned) { 228bd4c8242SŁukasz Kosmaty _onBarCodeScanned([EXBarCodeScannerUtils avMetadataCodeObjectToDicitionary:codeMetadata]); 229eafa96e0SStanisław Chmiela } 230eafa96e0SStanisław Chmiela return; 231eafa96e0SStanisław Chmiela } 232eafa96e0SStanisław Chmiela } 233eafa96e0SStanisław Chmiela } 234eafa96e0SStanisław Chmiela } 235eafa96e0SStanisław Chmiela} 236eafa96e0SStanisław Chmiela 2371f9c336aSBartłomiej Bukowski# pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate for ZXing 2381f9c336aSBartłomiej Bukowski 2391f9c336aSBartłomiej Bukowski- (void)captureOutput:(AVCaptureVideoDataOutput *)output 2401f9c336aSBartłomiej BukowskididOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 2411f9c336aSBartłomiej Bukowski fromConnection:(AVCaptureConnection *)connection 2421f9c336aSBartłomiej Bukowski{ 2431f9c336aSBartłomiej Bukowski if (!_settings || !_settings[EX_BARCODE_TYPES_KEY] || !_metadataOutput) { 2441f9c336aSBartłomiej Bukowski return; 2451f9c336aSBartłomiej Bukowski } 2461f9c336aSBartłomiej Bukowski // do not use ZXing library if not scanning for predefined barcodes 2471f9c336aSBartłomiej Bukowski if (!_zxingEnabled) { 2481f9c336aSBartłomiej Bukowski return; 2491f9c336aSBartłomiej Bukowski } 2501f9c336aSBartłomiej Bukowski 2511f9c336aSBartłomiej Bukowski // below code is mostly taken from ZXing library itself 2521f9c336aSBartłomiej Bukowski float kMinMargin = 1.0 / _zxingFPSProcessed; 2531f9c336aSBartłomiej Bukowski 2541f9c336aSBartłomiej Bukowski // Gets the timestamp for each frame. 2551f9c336aSBartłomiej Bukowski CMTime presentTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer); 2561f9c336aSBartłomiej Bukowski 2571f9c336aSBartłomiej Bukowski @autoreleasepool { 2581f9c336aSBartłomiej Bukowski static double curFrameTimeStamp = 0; 2591f9c336aSBartłomiej Bukowski static double lastFrameTimeStamp = 0; 2601f9c336aSBartłomiej Bukowski 2611f9c336aSBartłomiej Bukowski curFrameTimeStamp = (double)presentTimeStamp.value / presentTimeStamp.timescale; 2621f9c336aSBartłomiej Bukowski 2631f9c336aSBartłomiej Bukowski if (curFrameTimeStamp - lastFrameTimeStamp > kMinMargin) { 2641f9c336aSBartłomiej Bukowski lastFrameTimeStamp = curFrameTimeStamp; 2651f9c336aSBartłomiej Bukowski 2661f9c336aSBartłomiej Bukowski CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer); 2671f9c336aSBartłomiej Bukowski CGImageRef videoFrameImage = [ZXCGImageLuminanceSource createImageFromBuffer:videoFrame]; 268bd4c8242SŁukasz Kosmaty [self scanBarcodesFromImage:videoFrameImage withCompletion:^(ZXResult *barCodeScannerResult, NSError *error) { 2691f9c336aSBartłomiej Bukowski if (self->_onBarCodeScanned) { 270bd4c8242SŁukasz Kosmaty self->_onBarCodeScanned([EXBarCodeScannerUtils zxResultToDicitionary:barCodeScannerResult]); 2711f9c336aSBartłomiej Bukowski } 2721f9c336aSBartłomiej Bukowski }]; 2731f9c336aSBartłomiej Bukowski } 2741f9c336aSBartłomiej Bukowski } 2751f9c336aSBartłomiej Bukowski} 2761f9c336aSBartłomiej Bukowski 2771f9c336aSBartłomiej Bukowski- (void)scanBarcodesFromImage:(CGImageRef)image 278bd4c8242SŁukasz Kosmaty withCompletion:(void(^)(ZXResult *barCodeResult, NSError *error))completion 2791f9c336aSBartłomiej Bukowski{ 2801f9c336aSBartłomiej Bukowski ZXCGImageLuminanceSource *source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:image]; 2811f9c336aSBartłomiej Bukowski CGImageRelease(image); 2821f9c336aSBartłomiej Bukowski 2831f9c336aSBartłomiej Bukowski ZXHybridBinarizer *binarizer = [[ZXHybridBinarizer alloc] initWithSource:source]; 2841f9c336aSBartłomiej Bukowski ZXBinaryBitmap *bitmap = [[ZXBinaryBitmap alloc] initWithBinarizer:binarizer]; 2851f9c336aSBartłomiej Bukowski 2861f9c336aSBartłomiej Bukowski NSError *error = nil; 2871f9c336aSBartłomiej Bukowski ZXResult *result; 2881f9c336aSBartłomiej Bukowski 2891f9c336aSBartłomiej Bukowski for (id<ZXReader> reader in [_zxingBarcodeReaders allValues]) { 2901f9c336aSBartłomiej Bukowski result = [reader decode:bitmap hints:nil error:&error]; 2911f9c336aSBartłomiej Bukowski if (result) { 2921f9c336aSBartłomiej Bukowski break; 2931f9c336aSBartłomiej Bukowski } 2941f9c336aSBartłomiej Bukowski } 2951f9c336aSBartłomiej Bukowski // rotate bitmap by 90° only, becasue zxing rotates bitmap by 180° internally, so that each possible orientation is covered 2961f9c336aSBartłomiej Bukowski if (!result && [bitmap rotateSupported]) { 2971f9c336aSBartłomiej Bukowski ZXBinaryBitmap *rotatedBitmap = [bitmap rotateCounterClockwise]; 2981f9c336aSBartłomiej Bukowski for (id<ZXReader> reader in [_zxingBarcodeReaders allValues]) { 2991f9c336aSBartłomiej Bukowski result = [reader decode:rotatedBitmap hints:nil error:&error]; 3001f9c336aSBartłomiej Bukowski if (result) { 3011f9c336aSBartłomiej Bukowski break; 3021f9c336aSBartłomiej Bukowski } 3031f9c336aSBartłomiej Bukowski } 3041f9c336aSBartłomiej Bukowski } 3051f9c336aSBartłomiej Bukowski 3061f9c336aSBartłomiej Bukowski if (result) { 307bd4c8242SŁukasz Kosmaty completion(result, error); 3081f9c336aSBartłomiej Bukowski } 3091f9c336aSBartłomiej Bukowski} 3101f9c336aSBartłomiej Bukowski 3111f9c336aSBartłomiej Bukowski+ (NSString *)zxingFormatToString:(ZXBarcodeFormat)format 3121f9c336aSBartłomiej Bukowski{ 3131f9c336aSBartłomiej Bukowski switch (format) { 3141f9c336aSBartłomiej Bukowski case kBarcodeFormatPDF417: 3151f9c336aSBartłomiej Bukowski return AVMetadataObjectTypePDF417Code; 3161f9c336aSBartłomiej Bukowski case kBarcodeFormatCode39: 3171f9c336aSBartłomiej Bukowski return AVMetadataObjectTypeCode39Code; 3185a06ec9aSUrata Daiki case kBarcodeFormatCodabar: 319*7e5da4d1SBartłomiej Bukowski#ifdef __IPHONE_15_4 3205a06ec9aSUrata Daiki if (@available(iOS 15.4, *)) { 3215a06ec9aSUrata Daiki return AVMetadataObjectTypeCodabarCode; 3225a06ec9aSUrata Daiki } 323*7e5da4d1SBartłomiej Bukowski#endif 324*7e5da4d1SBartłomiej Bukowski return @"unknown"; 3251f9c336aSBartłomiej Bukowski default: 3261f9c336aSBartłomiej Bukowski return @"unknown"; 3271f9c336aSBartłomiej Bukowski } 3281f9c336aSBartłomiej Bukowski} 3291f9c336aSBartłomiej Bukowski 330eafa96e0SStanisław Chmiela# pragma mark - default settings 331eafa96e0SStanisław Chmiela 332eafa96e0SStanisław Chmiela+ (NSDictionary *)_getDefaultSettings 333eafa96e0SStanisław Chmiela{ 334eafa96e0SStanisław Chmiela return @{ 3359cded925STomasz Sapeta EX_BARCODE_TYPES_KEY: [[EXBarCodeScannerUtils validBarCodeTypes] allValues], 336eafa96e0SStanisław Chmiela }; 337eafa96e0SStanisław Chmiela} 338eafa96e0SStanisław Chmiela 339eafa96e0SStanisław Chmiela@end 340