1// Copyright 2016-present 650 Industries. All rights reserved.
2
3#import <UIKit/UIKit.h>
4#import <AVFoundation/AVFoundation.h>
5#import <EXBarCodeScanner/EXBarCodeScannerUtils.h>
6
7@implementation EXBarCodeScannerUtils
8
9+ (NSDictionary *)validBarCodeTypes
10{
11    NSMutableDictionary *validTypes = [@{
12      @"upc_e" : AVMetadataObjectTypeUPCECode,
13      @"code39" : AVMetadataObjectTypeCode39Code,
14      @"code39mod43" : AVMetadataObjectTypeCode39Mod43Code,
15      @"ean13" : AVMetadataObjectTypeEAN13Code,
16      @"ean8" : AVMetadataObjectTypeEAN8Code,
17      @"code93" : AVMetadataObjectTypeCode93Code,
18      @"code128" : AVMetadataObjectTypeCode128Code,
19      @"pdf417" : AVMetadataObjectTypePDF417Code,
20      @"qr" : AVMetadataObjectTypeQRCode,
21      @"aztec" : AVMetadataObjectTypeAztecCode,
22      @"interleaved2of5" : AVMetadataObjectTypeInterleaved2of5Code,
23      @"itf14" : AVMetadataObjectTypeITF14Code,
24      @"datamatrix" : AVMetadataObjectTypeDataMatrixCode,
25    } mutableCopy];
26#ifdef __IPHONE_15_4
27    if (@available(iOS 15.4, *)) {
28      validTypes[@"codabar"] = AVMetadataObjectTypeCodabarCode;
29    }
30#endif
31    return validTypes;
32}
33
34+ (AVCaptureVideoOrientation)videoOrientationForInterfaceOrientation:(UIInterfaceOrientation)orientation
35{
36  switch (orientation) {
37    case UIInterfaceOrientationPortrait:
38      return AVCaptureVideoOrientationPortrait;
39    case UIInterfaceOrientationPortraitUpsideDown:
40      return AVCaptureVideoOrientationPortraitUpsideDown;
41    case UIInterfaceOrientationLandscapeRight:
42      return AVCaptureVideoOrientationLandscapeRight;
43    case UIInterfaceOrientationLandscapeLeft:
44      return AVCaptureVideoOrientationLandscapeLeft;
45    default:
46      return 0;
47  }
48}
49
50+ (AVCaptureDevice *)deviceWithMediaType:(AVMediaType)mediaType
51                      preferringPosition:(AVCaptureDevicePosition)position
52{
53  return [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:mediaType position:position];
54}
55
56+ (NSDictionary *)ciQRCodeFeatureToDicitionary:(CIQRCodeFeature *)barCodeScannerResult barCodeType:(NSString *)type
57{
58  NSMutableDictionary *result = [NSMutableDictionary new];
59  result[@"type"] = type;
60  result[@"data"] = barCodeScannerResult.messageString;
61
62  if (!CGRectIsEmpty(barCodeScannerResult.bounds)) {
63    NSMutableArray<NSDictionary *> *cornerPointsResult = [NSMutableArray new];
64    for (NSValue *nsPoint in @[
65      [NSValue valueWithCGPoint:barCodeScannerResult.topLeft],
66      [NSValue valueWithCGPoint:barCodeScannerResult.topRight],
67      [NSValue valueWithCGPoint:barCodeScannerResult.bottomRight],
68      [NSValue valueWithCGPoint:barCodeScannerResult.bottomLeft]
69    ]) {
70      CGPoint point = [nsPoint CGPointValue];
71      [cornerPointsResult addObject:@{
72        @"x": @(point.x),
73        @"y": @(point.y)
74      }];
75    }
76
77    result[@"cornerPoints"] = cornerPointsResult;
78    result[@"bounds"] = @{
79      @"origin": @{
80        @"x": @(barCodeScannerResult.bounds.origin.x),
81        @"y": @(barCodeScannerResult.bounds.origin.y),
82      },
83      @"size": @{
84        @"width": @(barCodeScannerResult.bounds.size.width),
85        @"height": @(barCodeScannerResult.bounds.size.height),
86      }
87    };
88  } else {
89    [EXBarCodeScannerUtils addEmptyCornerPoints:result];
90  }
91
92  return result;
93}
94
95+ (NSDictionary *)avMetadataCodeObjectToDicitionary:(AVMetadataMachineReadableCodeObject *)barCodeScannerResult
96{
97  NSMutableDictionary *result = [NSMutableDictionary new];
98  result[@"type"] = barCodeScannerResult.type;
99  result[@"data"] = barCodeScannerResult.stringValue;
100
101  if (barCodeScannerResult.corners.count) {
102    NSMutableArray<NSDictionary *> *cornerPointsResult = [NSMutableArray new];
103    for (NSDictionary *point in barCodeScannerResult.corners) {
104      [cornerPointsResult addObject:@{
105        @"x": point[@"X"],
106        @"y": point[@"Y"]
107      }];
108    }
109    result[@"cornerPoints"] = cornerPointsResult;
110    result[@"bounds"] = @{
111      @"origin": @{
112        @"x": @(barCodeScannerResult.bounds.origin.x),
113        @"y": @(barCodeScannerResult.bounds.origin.y),
114      },
115      @"size": @{
116        @"width": @(barCodeScannerResult.bounds.size.width),
117        @"height": @(barCodeScannerResult.bounds.size.height),
118      }
119    };
120  } else {
121    [EXBarCodeScannerUtils addEmptyCornerPoints:result];
122  }
123  return result;
124}
125
126+ (NSDictionary *)zxResultToDicitionary:(ZXResult *)barCodeScannerResult
127{
128  NSMutableDictionary *result = [NSMutableDictionary new];
129  result[@"type"] = [EXBarCodeScannerUtils zxingFormatToString:barCodeScannerResult.barcodeFormat];
130
131  // text contains characteres u'\0' (null character) that malforme resulting string, so we get rid of them
132  NSMutableString* data = [NSMutableString new];
133  for (int i = 0; i < [barCodeScannerResult.text length]; i++) {
134    if ([barCodeScannerResult.text characterAtIndex:i] != u'\0') {
135      [data appendFormat:@"%c", [barCodeScannerResult.text characterAtIndex:i]];
136    }
137  }
138  result[@"data"] = data;
139
140  return result;
141}
142
143+ (NSString *)zxingFormatToString:(ZXBarcodeFormat)format
144{
145  switch (format) {
146    case kBarcodeFormatPDF417:
147      return AVMetadataObjectTypePDF417Code;
148    case kBarcodeFormatCode39:
149      return AVMetadataObjectTypeCode39Code;
150    case kBarcodeFormatCodabar:
151#ifdef __IPHONE_15_4
152      if (@available(iOS 15.4, *)) {
153        return AVMetadataObjectTypeCodabarCode;
154      }
155#endif
156      return @"unknown";
157    default:
158      return @"unknown";
159  }
160}
161
162+ (void)addEmptyCornerPoints:(NSMutableDictionary *)result
163{
164  result[@"cornerPoints"] = @[];
165  result[@"bounds"] = @{
166    @"origin": @{
167      @"x": @(0),
168      @"y": @(0),
169    },
170    @"size": @{
171      @"width": @(0),
172      @"height": @(0),
173    }
174  };
175}
176
177@end
178