28 |
29 | /**
30 | * The camera switch button.
31 | * @since 2.0.0
32 | */
33 | @interface QRCameraSwitchButton : UIButton
34 |
35 | #pragma mark - Managing Properties
36 | /** @name Managing Properties */
37 |
38 | /**
39 | * @abstract The edge color of the drawing.
40 | * @discussion The default color is the white.
41 | * @since 2.0.0
42 | */
43 | @property (nonatomic, strong) UIColor *edgeColor;
44 |
45 | /**
46 | * @abstract The fill color of the drawing.
47 | * @discussion The default color is the darkgray.
48 | * @since 2.0.0
49 | */
50 | @property (nonatomic, strong) UIColor *fillColor;
51 |
52 | /**
53 | * @abstract The edge color of the drawing when the button is touched.
54 | * @discussion The default color is the white.
55 | * @since 2.0.0
56 | */
57 | @property (nonatomic, strong) UIColor *edgeHighlightedColor;
58 |
59 | /**
60 | * @abstract The fill color of the drawing when the button is touched.
61 | * @discussion The default color is the black.
62 | * @since 2.0.0
63 | */
64 | @property (nonatomic, strong) UIColor *fillHighlightedColor;
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Example/QRCodeReaderViewControllerExample/ViewController.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import "ViewController.h"
28 | #import "QRCodeReaderViewController.h"
29 | #import "QRCodeReader.h"
30 |
31 | @interface ViewController ()
32 |
33 | @end
34 |
35 | @implementation ViewController
36 |
37 | - (IBAction)scanAction:(id)sender
38 | {
39 | if ([QRCodeReader supportsMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]) {
40 | static QRCodeReaderViewController *reader = nil;
41 | static dispatch_once_t onceToken;
42 |
43 | dispatch_once(&onceToken, ^{
44 | reader = [QRCodeReaderViewController new];
45 | });
46 | reader.delegate = self;
47 |
48 | [reader setCompletionWithBlock:^(NSString *resultAsString) {
49 | NSLog(@"Completion with result: %@", resultAsString);
50 | }];
51 |
52 | [self presentViewController:reader animated:YES completion:NULL];
53 | }
54 | else {
55 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Reader not supported by the current device" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
56 |
57 | [alert show];
58 | }
59 | }
60 |
61 | #pragma mark - QRCodeReader Delegate Methods
62 |
63 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result
64 | {
65 | [self dismissViewControllerAnimated:YES completion:^{
66 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"QRCodeReader" message:result delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
67 | [alert show];
68 | }];
69 | }
70 |
71 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader
72 | {
73 | [self dismissViewControllerAnimated:YES completion:NULL];
74 | }
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/Example/QRCodeReaderViewControllerExample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import "AppDelegate.h"
28 |
29 | @interface AppDelegate ()
30 |
31 | @end
32 |
33 | @implementation AppDelegate
34 |
35 |
36 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
37 | // Override point for customization after application launch.
38 | return YES;
39 | }
40 |
41 | - (void)applicationWillResignActive:(UIApplication *)application {
42 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
43 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
44 | }
45 |
46 | - (void)applicationDidEnterBackground:(UIApplication *)application {
47 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
48 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
49 | }
50 |
51 | - (void)applicationWillEnterForeground:(UIApplication *)application {
52 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
53 | }
54 |
55 | - (void)applicationDidBecomeActive:(UIApplication *)application {
56 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
57 | }
58 |
59 | - (void)applicationWillTerminate:(UIApplication *)application {
60 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/Example/QRCodeReaderViewControllerExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Example/QRCodeReaderViewControllerExample/Launch Screen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 创造不息,交付不止
4 |
5 |
6 |
7 |
8 |
9 |
10 | ---
11 |
12 | [English Guide](https://github.com/zhengjinghua/MQRCodeReaderViewController#readme-english)
13 |
14 | ## 说明
15 |
16 | MQRCodeReaderViewController 基于 [QRCodeReaderViewController](https://github.com/yannickl/QRCodeReaderViewController) 封装的二维码扫描控件, 仿照微信的二维码扫描器风格美化了界面, 直接加入你的项目中就能使用, 无需再次定制 UI.
17 |
18 | > Made with :heart: by [The EST Group](http://est-group.org) - We design and build: the Future!
19 |
20 | 
21 |
22 | ## 安装
23 |
24 | ### CocoaPods 安装
25 |
26 | 将下面代码复制进你的 `Podfile` 文件中
27 |
28 | ``` bash
29 | pod 'QRCodeReaderViewController', :git => 'https://github.com/zhengjinghua/MQRCodeReaderViewController.git'
30 | ```
31 |
32 | ### 手工安装
33 |
34 | [下载](https://github.com/YannickL/QRCodeReaderViewController/archive/master.zip) 此项目, 然后将该项目里的 `QRCodeReaderViewController` 文件夹里的所有文件复制进你的项目中, 然后在需要调用此项目的地方引入
35 |
36 | ```objective-c
37 | #import "QRCodeReaderViewController.h"
38 | ```
39 |
40 | ## 使用
41 |
42 | 支持以下两种方法调用, 选其一, 代码见下面:
43 |
44 | * 使用 Delegate 方法调用;
45 | * 使用 Block 方法调用;
46 |
47 | ```objective-c
48 | - (IBAction)scanAction:(id)sender
49 | {
50 | NSArray *types = @[AVMetadataObjectTypeQRCode];
51 | _reader = [QRCodeReaderViewController readerWithMetadataObjectTypes:types];
52 |
53 | // Using delegate methods
54 | _reader.delegate = self;
55 |
56 | // Or by using blocks
57 | [_reader setCompletionWithBlock:^(NSString *resultAsString) {
58 | [self dismissViewControllerAnimated:YES completion:^{
59 | NSLog(@"%@", resultAsString);
60 | }];
61 | }];
62 |
63 | [self presentViewController:_reader animated:YES completion:NULL];
64 | }
65 |
66 | #pragma mark - QRCodeReader Delegate Methods
67 |
68 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result
69 | {
70 | [self dismissViewControllerAnimated:YES completion:^{
71 | NSLog(@"%@", result);
72 | }];
73 | }
74 |
75 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader
76 | {
77 | [self dismissViewControllerAnimated:YES completion:NULL];
78 | }
79 | ```
80 |
81 | ## 协议
82 |
83 | MQRCodeReaderViewController 被许可在 MIT 协议下使用. 查阅 LICENSE 文件来获得更多信息.
84 |
85 |
86 | README (ENGLISH)
87 | ==========
88 |
89 |
90 | ## Description
91 | This projecd baesd on [QRCodeReaderViewController](https://github.com/yannickl/QRCodeReaderViewController), a little UI ajustment from `QRCodeReaderView`, make the interface more like **WeChat**.
92 |
93 | > Made with :heart: by [The EST Group](http://est-group.org) - We design and build: the Future!
94 |
95 |
96 | ## Install
97 |
98 | ### CocoaPods
99 | If you're using [CocoaPods](http://cocoapods.org/) (You are not?! You should!!) just add
100 |
101 | ``` bash
102 | pod 'QRCodeReaderViewController', :git => 'https://github.com/zhengjinghua/MQRCodeReaderViewController.git'
103 | ```
104 | into your Podfile file.
105 |
106 | ### Manually
107 |
108 | [Download](https://github.com/zhengjinghua/MQRCodeReaderViewController/archive/master.zip) the project and copy the `QRCodeReaderViewController` folder into your project and then simply `#import "QRCodeReaderViewController.h"` in the file(s) you would like to use it in.
109 |
110 | ## Usage
111 |
112 | ```objective-c
113 | - (IBAction)scanAction:(id)sender
114 | {
115 | NSArray *types = @[AVMetadataObjectTypeQRCode];
116 | _reader = [QRCodeReaderViewController readerWithMetadataObjectTypes:types];
117 |
118 | // Using delegate methods
119 | _reader.delegate = self;
120 |
121 | // Or by using blocks
122 | [_reader setCompletionWithBlock:^(NSString *resultAsString) {
123 | [self dismissViewControllerAnimated:YES completion:^{
124 | NSLog(@"%@", resultAsString);
125 | }];
126 | }];
127 |
128 | [self presentViewController:_reader animated:YES completion:NULL];
129 | }
130 |
131 | #pragma mark - QRCodeReader Delegate Methods
132 |
133 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result
134 | {
135 | [self dismissViewControllerAnimated:YES completion:^{
136 | NSLog(@"%@", result);
137 | }];
138 | }
139 |
140 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader
141 | {
142 | [self dismissViewControllerAnimated:YES completion:NULL];
143 | }
144 | ```
145 |
146 | ## License
147 |
148 | StitchingImage is available under the MIT license. See the LICENSE file for more info.
149 |
150 | ---
151 |
--------------------------------------------------------------------------------
/MQRCodeReaderViewController.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint MQRCodeReaderViewController.podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | #
13 | # These will help people to find your library, and whilst it
14 | # can feel like a chore to fill in it's definitely to your advantage. The
15 | # summary should be tweet-length, and the description more in depth.
16 | #
17 |
18 | s.name = "MQRCodeReaderViewController"
19 | s.version = "0.0.1"
20 | s.summary = "A short description of MQRCodeReaderViewController."
21 |
22 | s.description = <<-DESC
23 | A longer description of MQRCodeReaderViewController in Markdown format.
24 |
25 | * Think: Why did you write this? What is the focus? What does it do?
26 | * CocoaPods will be using this to generate tags, and improve search results.
27 | * Try to keep it short, snappy and to the point.
28 | * Finally, don't worry about the indent, CocoaPods strips it!
29 | DESC
30 |
31 | s.homepage = "http://EXAMPLE/MQRCodeReaderViewController"
32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
33 |
34 |
35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
36 | #
37 | # Licensing your code is important. See http://choosealicense.com for more info.
38 | # CocoaPods will detect a license file if there is a named LICENSE*
39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
40 | #
41 |
42 | s.license = "MIT (example)"
43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
44 |
45 |
46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
47 | #
48 | # Specify the authors of the library, with email addresses. Email addresses
49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
50 | # accepts just a name if you'd rather not provide an email address.
51 | #
52 | # Specify a social_media_url where others can refer to, for example a twitter
53 | # profile URL.
54 | #
55 |
56 | s.author = { "zhengjinghua" => "jin114001251@gmail.com" }
57 | # Or just: s.author = "zhengjinghua"
58 | # s.authors = { "zhengjinghua" => "jin114001251@gmail.com" }
59 | # s.social_media_url = "http://twitter.com/zhengjinghua"
60 |
61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
62 | #
63 | # If this Pod runs only on iOS or OS X, then specify the platform and
64 | # the deployment target. You can optionally include the target after the platform.
65 | #
66 |
67 | # s.platform = :ios
68 | # s.platform = :ios, "5.0"
69 |
70 | # When using multiple platforms
71 | # s.ios.deployment_target = "5.0"
72 | # s.osx.deployment_target = "10.7"
73 | # s.watchos.deployment_target = "2.0"
74 |
75 |
76 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
77 | #
78 | # Specify the location from where the source should be retrieved.
79 | # Supports git, hg, bzr, svn and HTTP.
80 | #
81 |
82 | s.source = { :git => "http://EXAMPLE/MQRCodeReaderViewController.git", :tag => "0.0.1" }
83 |
84 |
85 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
86 | #
87 | # CocoaPods is smart about how it includes source code. For source files
88 | # giving a folder will include any swift, h, m, mm, c & cpp files.
89 | # For header files it will include any header in the folder.
90 | # Not including the public_header_files will make all headers public.
91 | #
92 |
93 | s.source_files = "Classes", "Classes/**/*.{h,m}"
94 | s.exclude_files = "Classes/Exclude"
95 |
96 | # s.public_header_files = "Classes/**/*.h"
97 |
98 |
99 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
100 | #
101 | # A list of resources included with the Pod. These are copied into the
102 | # target bundle with a build phase script. Anything else will be cleaned.
103 | # You can preserve files from being cleaned, please don't preserve
104 | # non-essential files like tests, examples and documentation.
105 | #
106 |
107 | # s.resource = "icon.png"
108 | # s.resources = "Resources/*.png"
109 |
110 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
111 |
112 |
113 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
114 | #
115 | # Link your library with frameworks, or libraries. Libraries do not include
116 | # the lib prefix of their name.
117 | #
118 |
119 | # s.framework = "SomeFramework"
120 | # s.frameworks = "SomeFramework", "AnotherFramework"
121 |
122 | # s.library = "iconv"
123 | # s.libraries = "iconv", "xml2"
124 |
125 |
126 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
127 | #
128 | # If your library depends on compiler flags you can set them in the xcconfig hash
129 | # where they will only apply to your library. If you depend on other Podspecs
130 | # you can include multiple dependencies to ensure it works.
131 |
132 | # s.requires_arc = true
133 |
134 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
135 | # s.dependency "JSONKit", "~> 1.4"
136 |
137 | end
138 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCodeReader.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReader
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import
28 | #import
29 | #import
30 |
31 | /**
32 | * Reader object base on the `AVCaptureDevice` to read / scan 1D and 2D codes.
33 | */
34 | @interface QRCodeReader : NSObject
35 |
36 | #pragma mark - Creating and Inializing QRCode Readers
37 | /** @name Creating and Inializing QRCode Readers */
38 |
39 | /**
40 | * @abstract Initializes a reader with a list of metadata object types.
41 | * @param metadataObjectTypes An array of strings identifying the types of
42 | * metadata objects to process.
43 | * @since 3.0.0
44 | */
45 | - (id)initWithMetadataObjectTypes:(NSArray *)metadataObjectTypes;
46 |
47 | /**
48 | * @abstract Creates a reader with a list of metadata object types.
49 | * @param metadataObjectTypes An array of strings identifying the types of
50 | * metadata objects to process.
51 | * @see initWithMetadataObjectTypes:
52 | * @since 3.0.0
53 | */
54 | + (instancetype)readerWithMetadataObjectTypes:(NSArray *)metadataObjectTypes;
55 |
56 | #pragma mark - Checking the Reader Availabilities
57 | /** @name Checking the Reader Availabilities */
58 |
59 | /**
60 | * @abstract Returns whether the reader is available with the current device.
61 | * @return a Boolean value indicating whether the reader is available.
62 | * @since 3.0.0
63 | */
64 | + (BOOL)isAvailable;
65 |
66 | /**
67 | * @abstract Checks and return whether the given metadata object types are
68 | * supported by the current device.
69 | * @return a Boolean value indicating whether the given metadata object types
70 | * are supported by the current device.
71 | * @since 3.2.0
72 | */
73 | + (BOOL)supportsMetadataObjectTypes:(NSArray *)metadataObjectTypes;
74 |
75 | #pragma mark - Checking the Metadata Items Types
76 | /** @name Checking the Metadata Items Types */
77 |
78 | /**
79 | * @abstract An array of strings identifying the types of metadata objects to
80 | * process.
81 | * @since 3.0.0
82 | */
83 | @property (strong, nonatomic, readonly) NSArray *metadataObjectTypes;
84 |
85 | #pragma mark - Viewing the Camera
86 | /** @name Viewing the Camera */
87 |
88 | /**
89 | * @abstract CALayer that you use to display video as it is being captured
90 | * by an input device.
91 | * @since 3.0.0
92 | */
93 | @property (strong, nonatomic, readonly) AVCaptureVideoPreviewLayer *previewLayer;
94 |
95 | #pragma mark - Controlling the Reader
96 | /** @name Controlling the Reader */
97 |
98 | /**
99 | * @abstract Starts scanning the codes.
100 | * @since 3.0.0
101 | */
102 | - (void)startScanning;
103 |
104 | /**
105 | * @abstract Stops scanning the codes.
106 | * @since 3.0.0
107 | */
108 | - (void)stopScanning;
109 |
110 | /**
111 | * @abstract Indicates whether the session is currently running.
112 | * @discussion The value of this property is a Bool indicating whether the
113 | * receiver is running.
114 | * Clients can key value observe the value of this property to be notified
115 | * when the session automatically starts or stops running.
116 | * @since 3.3.0
117 | */
118 | - (BOOL)running;
119 |
120 | /**
121 | * @abstract Switch between the back and the front camera.
122 | * @since 3.0.0
123 | */
124 | - (void)switchDeviceInput;
125 |
126 | /**
127 | * @abstract Returns true whether a front device is available.
128 | * @return true whether a front device is available.
129 | * @since 3.0.0
130 | */
131 | - (BOOL)hasFrontDevice;
132 |
133 | #pragma mark - Getting Inputs and Outputs
134 | /** @name Getting Inputs and Outputs */
135 |
136 | /**
137 | * @abstract Accessing to the `AVCaptureDeviceInput` object representing
138 | * the default device input (generally the back camera).
139 | * @since 3.5.0
140 | */
141 | @property (readonly) AVCaptureDeviceInput *defaultDeviceInput;
142 |
143 | /**
144 | * @abstract Accessing to the `AVCaptureDeviceInput` object representing
145 | * the front device input.
146 | * @since 3.5.0
147 | */
148 | @property (readonly) AVCaptureDeviceInput *frontDeviceInput;
149 |
150 | /**
151 | * @abstract Accessing to the `AVCaptureMetadataOutput` object.
152 | * @discussion It allows you to configure the scanner to restrict the area of
153 | * the scan to the overlay one for example.
154 | * @since 3.5.0
155 | */
156 | @property (readonly) AVCaptureMetadataOutput *metadataOutput;
157 |
158 | #pragma mark - Managing the Orientation
159 | /** @name Managing the Orientation */
160 |
161 | /**
162 | * @abstract Returns the video orientation correspongind to the given interface
163 | * orientation.
164 | * @param interfaceOrientation An interface orientation.
165 | * @return the video orientation correspongind to the given device orientation.
166 | * @since 3.1.0
167 | */
168 | + (AVCaptureVideoOrientation)videoOrientationFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
169 |
170 | #pragma mark - Managing the Block
171 | /** @name Managing the Block */
172 |
173 | /**
174 | * @abstract Sets the completion with a block that executes when a QRCode
175 | * or when the user did stopped the scan.
176 | * @param completionBlock The block to be executed. This block has no
177 | * return value and takes one argument: the `resultAsString`. If the user
178 | * stop the scan and that there is no response the `resultAsString` argument
179 | * is nil.
180 | * @since 3.0.0
181 | */
182 | - (void)setCompletionWithBlock:(void (^) (NSString *resultAsString))completionBlock;
183 |
184 | @end
185 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCodeReaderView/QRCodeReaderView.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 |
28 | #import "QRCodeReaderView.h"
29 | #import "QRCodeReaderMaskView.h"
30 | #import "QRCodeReaderAanimationLineView.h"
31 |
32 | #define DeviceWidth [UIScreen mainScreen].bounds.size.width
33 | #define DeviceHeight [UIScreen mainScreen].bounds.size.height
34 | #define DeviceFrame [UIScreen mainScreen].bounds
35 |
36 | static const float CancelButtonHeight = 40;
37 | static const float ReaderViewLengthRatio = 0.72;
38 |
39 | @interface QRCodeReaderView ()
40 | @property (nonatomic, strong) QRCodeReaderAanimationLineView *animationLine;
41 | @property (nonatomic, strong) NSTimer *lineTimer;
42 | @property (nonatomic) QRCodeReaderMaskView *maskView;
43 |
44 | @property (nonatomic) float animationLineMaxY;
45 | @property (nonatomic) float animationLineMinY;
46 | @property (nonatomic) float readerViewSideLength;
47 | @end
48 |
49 | @implementation QRCodeReaderView
50 |
51 | - (id)initWithFrame:(CGRect)frame
52 | {
53 | if ((self = [super initWithFrame:frame])) {
54 | [self initSettingValue];
55 | [self setOverlayPickerView];
56 | }
57 |
58 | return self;
59 | }
60 |
61 | - (void)initSettingValue {
62 | _readerViewSideLength = DeviceWidth * ReaderViewLengthRatio;
63 | _animationLineMinY = (DeviceHeight - 20 - _readerViewSideLength - CancelButtonHeight) / 2;
64 | _animationLineMaxY = _animationLineMinY + _readerViewSideLength;
65 | }
66 |
67 | - (QRCodeReaderAanimationLineView *)animationLine {
68 | if(_animationLine == nil) {
69 | _animationLine = [[QRCodeReaderAanimationLineView alloc] initWithFrame:CGRectMake((DeviceWidth - _readerViewSideLength) / 2, 0, _readerViewSideLength, 12 * self.readerViewSideLength / DeviceWidth) minY:self.animationLineMinY maxY:self.animationLineMaxY];
70 | }
71 | return _animationLine;
72 | }
73 |
74 | #pragma mark - Private Methods
75 | - (void)setOverlayPickerView
76 | {
77 | // Add line in the middle.
78 | [self addSubview:self.animationLine];
79 |
80 | // Add mask view
81 | UIView* maskTopView = [[QRCodeReaderMaskView alloc] initWithFrame:CGRectMake(0, 0, DeviceWidth, self.animationLineMinY)];
82 | [self addSubview:maskTopView];
83 |
84 | UIView *maskLeftView = [[QRCodeReaderMaskView alloc] initWithFrame:CGRectMake(0, self.animationLineMinY, (DeviceWidth - self.readerViewSideLength) / 2.0, self.readerViewSideLength)];
85 | [self addSubview:maskLeftView];
86 |
87 | UIView *maskRightView = [[QRCodeReaderMaskView alloc] initWithFrame:CGRectMake(DeviceWidth - CGRectGetMaxX(maskLeftView.frame), self.animationLineMinY, CGRectGetMaxX(maskLeftView.frame), self.readerViewSideLength)];
88 | [self addSubview:maskRightView];
89 |
90 | CGFloat space_h = DeviceHeight - self.animationLineMaxY;
91 |
92 | UIView *maskBottomView = [[QRCodeReaderMaskView alloc] initWithFrame:CGRectMake(0, self.animationLineMaxY, DeviceWidth, space_h)];
93 | [self addSubview:maskBottomView];
94 |
95 | CGFloat scanCropViewWidth = DeviceWidth - 2 * CGRectGetMaxX(maskLeftView.frame) + 1;
96 | UIView *scanCropView = [[UIView alloc] initWithFrame:CGRectMake((DeviceWidth - scanCropViewWidth)/2, self.animationLineMinY-1.0, scanCropViewWidth, self.readerViewSideLength + 2)];
97 | scanCropView.layer.borderColor = [UIColor whiteColor].CGColor;
98 | scanCropView.layer.borderWidth = 1.0;
99 | [self addSubview:scanCropView];
100 |
101 | // Add cornet Image
102 | UIImage *cornerImage = [UIImage imageNamed:@"QRCodeTopLeft"];
103 | UIImageView *topLeftImageView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(maskLeftView.frame) - 1.0, CGRectGetMaxY(maskTopView.frame) - 1.0, cornerImage.size.width, cornerImage.size.height)];
104 | topLeftImageView.image = cornerImage;
105 | [self addSubview:topLeftImageView];
106 |
107 | cornerImage = [UIImage imageNamed:@"QRCodeTopRight"];
108 | UIImageView *topRightImage = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMinX(maskRightView.frame) - cornerImage.size.width + 1.0, CGRectGetMaxY(maskTopView.frame) - 1.0, cornerImage.size.width, cornerImage.size.height)];
109 | topRightImage.image = cornerImage;
110 | [self addSubview:topRightImage];
111 |
112 | cornerImage = [UIImage imageNamed:@"QRCodeBottomLeft"];
113 | UIImageView *bottomLeftImage = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(maskLeftView.frame) - 1.0, CGRectGetMinY(maskBottomView.frame) - cornerImage.size.height + 2.0, cornerImage.size.width, cornerImage.size.height)];
114 | bottomLeftImage.image = cornerImage;
115 | [self addSubview:bottomLeftImage];
116 |
117 | cornerImage = [UIImage imageNamed:@"QRCodeBottomRight"];
118 | UIImageView *bottomRightImage = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetMinX(maskRightView.frame) - cornerImage.size.width + 1.0, CGRectGetMinY(maskBottomView.frame) - cornerImage.size.height + 2.0, cornerImage.size.width, cornerImage.size.height)];
119 | bottomRightImage.image = cornerImage;
120 | [self addSubview:bottomRightImage];
121 |
122 | //说明label
123 | UILabel *labIntroudction = [[UILabel alloc] init];
124 | labIntroudction.backgroundColor = [UIColor clearColor];
125 | labIntroudction.frame = CGRectMake(CGRectGetMaxX(maskLeftView.frame), CGRectGetMinY(maskBottomView.frame) + 25, self.readerViewSideLength, 20);
126 | labIntroudction.textAlignment = NSTextAlignmentCenter;
127 | labIntroudction.font = [UIFont boldSystemFontOfSize:13.0];
128 | labIntroudction.textColor = [UIColor whiteColor];
129 | labIntroudction.text = @"将二维码置于框内, 即可自动扫描";
130 | [self addSubview:labIntroudction];
131 |
132 |
133 | }
134 |
135 | - (void)startScanning
136 | {
137 | _lineTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 50 target:self selector:@selector(animationForLine) userInfo:nil repeats:YES];
138 | }
139 |
140 | - (void)stopScanning
141 | {
142 | if (_lineTimer)
143 | {
144 | [_lineTimer invalidate];
145 | _lineTimer = nil;
146 | }
147 |
148 | }
149 |
150 | - (void)animationForLine
151 | {
152 | [self.animationLine startAnimation];
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCodeReaderViewController.h:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import
28 | #import "QRCodeReaderDelegate.h"
29 | #import "QRCodeReader.h"
30 |
31 | /**
32 | * Convenient controller to display a view to scan/read 1D or 2D bar codes like
33 | * the QRCodes. It is based on the `AVFoundation` framework from Apple. It aims
34 | * to replace ZXing or ZBar for iOS 7 and over.
35 | */
36 | @interface QRCodeReaderViewController : UIViewController
37 |
38 | #pragma mark - Creating and Inializing QRCodeReader Controllers
39 | /** @name Creating and Inializing QRCode Reader Controllers */
40 |
41 | /**
42 | * @abstract Initializes a view controller to read QRCodes from a displayed
43 | * video preview and a cancel button to be go back.
44 | * @param cancelTitle The title of the cancel button.
45 | * @discussion This convenient method is used to instanciate a reader with
46 | * only one supported metadata object types: the QRCode.
47 | * @see initWithCancelButtonTitle:metadataObjectTypes:
48 | * @since 1.0.0
49 | */
50 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle;
51 |
52 | /**
53 | * @abstract Creates a view controller to read QRCodes from a displayed
54 | * video preview and a cancel button to be go back.
55 | * @param cancelTitle The title of the cancel button.
56 | * @see initWithCancelButtonTitle:
57 | * @since 1.0.0
58 | */
59 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle;
60 |
61 | /**
62 | * @abstract Initializes a reader view controller with a list of metadata
63 | * object types.
64 | * @param metadataObjectTypes An array of strings identifying the types of
65 | * metadata objects to process.
66 | * @see initWithCancelButtonTitle:metadataObjectTypes:
67 | * @since 3.0.0
68 | */
69 | - (nonnull id)initWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes;
70 |
71 | /**
72 | * @abstract Creates a reader view controller with a list of metadata object
73 | * types.
74 | * @param metadataObjectTypes An array of strings identifying the types of
75 | * metadata objects to process.
76 | * @see initWithMetadataObjectTypes:
77 | * @since 3.0.0
78 | */
79 | + (nonnull instancetype)readerWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes;
80 |
81 | /**
82 | * @abstract Initializes a view controller to read wanted metadata object
83 | * types from a displayed video preview and a cancel button to be go back.
84 | * @param cancelTitle The title of the cancel button.
85 | * @param metadataObjectTypes The type (“symbology”) of barcode to scan.
86 | * @see initWithCancelButtonTitle:codeReader:
87 | * @since 2.0.0
88 | */
89 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle metadataObjectTypes:(nonnull NSArray *)metadataObjectTypes;
90 |
91 | /**
92 | * @abstract Creates a view controller to read wanted metadata object types
93 | * from a displayed video preview and a cancel button to be go back.
94 | * @param cancelTitle The title of the cancel button.
95 | * @param metadataObjectTypes The type (“symbology”) of barcode to scan.
96 | * @see initWithCancelButtonTitle:metadataObjectTypes:
97 | * @since 2.0.0
98 | */
99 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle metadataObjectTypes:(nonnull NSArray *)metadataObjectTypes;
100 |
101 | /**
102 | * @abstract Initializes a view controller using a cancel button title and
103 | * a code reader.
104 | * @param cancelTitle The title of the cancel button.
105 | * @param codeReader The reader to decode the codes.
106 | * @see initWithCancelButtonTitle:codeReader:startScanningAtLoad:
107 | * @since 3.0.0
108 | */
109 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader;
110 |
111 | /**
112 | * @abstract Initializes a view controller using a cancel button title and
113 | * a code reader.
114 | * @param cancelTitle The title of the cancel button.
115 | * @param codeReader The reader to decode the codes.
116 | * @see initWithCancelButtonTitle:codeReader:
117 | * @since 3.0.0
118 | */
119 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader;
120 |
121 | /**
122 | * @abstract Initializes a view controller using a cancel button title and
123 | * a code reader.
124 | * @param cancelTitle The title of the cancel button.
125 | * @param codeReader The reader to decode the codes.
126 | * @param startScanningAtLoad Flag to know whether the view controller start scanning the codes when the view will appear.
127 | * @since 3.0.0
128 | */
129 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad;
130 |
131 | /**
132 | * @abstract Initializes a view controller using a cancel button title and
133 | * a code reader.
134 | * @param cancelTitle The title of the cancel button.
135 | * @param codeReader The reader to decode the codes.
136 | * @param startScanningAtLoad Flag to know whether the view controller start scanning the codes when the view will appear.
137 | * @see initWithCancelButtonTitle:codeReader:startScanningAtLoad:
138 | * @since 3.0.0
139 | */
140 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad;
141 |
142 | #pragma mark - Controlling the Reader
143 | /** @name Controlling the Reader */
144 |
145 | /**
146 | * @abstract Starts scanning the codes.
147 | * @since 3.0.0
148 | */
149 | - (void)startScanning;
150 |
151 | /**
152 | * @abstract Stops scanning the codes.
153 | * @since 3.0.0
154 | */
155 | - (void)stopScanning;
156 |
157 | #pragma mark - Managing the Delegate
158 | /** @name Managing the Delegate */
159 |
160 | /**
161 | * @abstract The object that acts as the delegate of the receiving QRCode
162 | * reader.
163 | * @since 1.0.0
164 | */
165 | @property (nonatomic, weak) id __nullable delegate;
166 |
167 | /**
168 | * @abstract Sets the completion with a block that executes when a QRCode
169 | * or when the user did stopped the scan.
170 | * @param completionBlock The block to be executed. This block has no
171 | * return value and takes one argument: the `resultAsString`. If the user
172 | * stop the scan and that there is no response the `resultAsString` argument
173 | * is nil.
174 | * @since 1.0.1
175 | */
176 | - (void)setCompletionWithBlock:(nullable void (^) (NSString * __nullable resultAsString))completionBlock;
177 |
178 | #pragma mark - Managing the Reader
179 | /** @name Managing the Reader */
180 |
181 | /**
182 | * @abstract The default code reader created with the controller.
183 | * @since 3.0.0
184 | */
185 | @property (strong, nonatomic, readonly) QRCodeReader * __nonnull codeReader;
186 |
187 | @end
188 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCodeReader.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReader
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import "QRCodeReader.h"
28 |
29 | @interface QRCodeReader ()
30 | @property (strong, nonatomic) AVCaptureDevice *defaultDevice;
31 | @property (strong, nonatomic) AVCaptureDeviceInput *defaultDeviceInput;
32 | @property (strong, nonatomic) AVCaptureDevice *frontDevice;
33 | @property (strong, nonatomic) AVCaptureDeviceInput *frontDeviceInput;
34 | @property (strong, nonatomic) AVCaptureMetadataOutput *metadataOutput;
35 | @property (strong, nonatomic) AVCaptureSession *session;
36 | @property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
37 |
38 | @property (copy, nonatomic) void (^completionBlock) (NSString *);
39 |
40 | @end
41 |
42 | @implementation QRCodeReader
43 |
44 | - (id)initWithMetadataObjectTypes:(NSArray *)metadataObjectTypes
45 | {
46 | if ((self = [super init])) {
47 | _metadataObjectTypes = metadataObjectTypes;
48 |
49 | [self setupAVComponents];
50 | [self configureDefaultComponents];
51 | }
52 | return self;
53 | }
54 |
55 | + (instancetype)readerWithMetadataObjectTypes:(NSArray *)metadataObjectTypes
56 | {
57 | return [[self alloc] initWithMetadataObjectTypes:metadataObjectTypes];
58 | }
59 |
60 | #pragma mark - Initializing the AV Components
61 |
62 | - (void)setupAVComponents
63 | {
64 | self.defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
65 |
66 | if (_defaultDevice) {
67 | self.defaultDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_defaultDevice error:nil];
68 | self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
69 | self.session = [[AVCaptureSession alloc] init];
70 | self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
71 |
72 | for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
73 | if (device.position == AVCaptureDevicePositionFront) {
74 | self.frontDevice = device;
75 | }
76 | }
77 |
78 | if (_frontDevice) {
79 | self.frontDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_frontDevice error:nil];
80 | }
81 | }
82 | }
83 |
84 | - (void)configureDefaultComponents
85 | {
86 | [_session addOutput:_metadataOutput];
87 |
88 | if (_defaultDeviceInput) {
89 | [_session addInput:_defaultDeviceInput];
90 | }
91 |
92 | [_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
93 | [_metadataOutput setMetadataObjectTypes:_metadataObjectTypes];
94 | [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
95 | }
96 |
97 | - (void)switchDeviceInput
98 | {
99 | if (_frontDeviceInput) {
100 | [_session beginConfiguration];
101 |
102 | AVCaptureDeviceInput *currentInput = [_session.inputs firstObject];
103 | [_session removeInput:currentInput];
104 |
105 | AVCaptureDeviceInput *newDeviceInput = (currentInput.device.position == AVCaptureDevicePositionFront) ? _defaultDeviceInput : _frontDeviceInput;
106 | [_session addInput:newDeviceInput];
107 |
108 | [_session commitConfiguration];
109 | }
110 | }
111 |
112 | - (BOOL)hasFrontDevice
113 | {
114 | return _frontDevice != nil;
115 | }
116 |
117 | #pragma mark - Controlling Reader
118 |
119 | - (void)startScanning
120 | {
121 | if (![self.session isRunning]) {
122 | [self.session startRunning];
123 | }
124 | }
125 |
126 | - (void)stopScanning
127 | {
128 | if ([self.session isRunning]) {
129 | [self.session stopRunning];
130 | }
131 | }
132 |
133 | - (BOOL)running {
134 | return self.session.running;
135 | }
136 |
137 | #pragma mark - Managing the Orientation
138 |
139 | + (AVCaptureVideoOrientation)videoOrientationFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
140 | {
141 | switch (interfaceOrientation) {
142 | case UIInterfaceOrientationLandscapeLeft:
143 | return AVCaptureVideoOrientationLandscapeLeft;
144 | case UIInterfaceOrientationLandscapeRight:
145 | return AVCaptureVideoOrientationLandscapeRight;
146 | case UIInterfaceOrientationPortrait:
147 | return AVCaptureVideoOrientationPortrait;
148 | default:
149 | return AVCaptureVideoOrientationPortraitUpsideDown;
150 | }
151 | }
152 |
153 | #pragma mark - Checking the Reader Availabilities
154 |
155 | + (BOOL)isAvailable
156 | {
157 | @autoreleasepool {
158 | AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
159 |
160 | if (!captureDevice) {
161 | return NO;
162 | }
163 |
164 | NSError *error;
165 | AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
166 |
167 | if (!deviceInput || error) {
168 | return NO;
169 | }
170 |
171 | return YES;
172 | }
173 | }
174 |
175 | + (BOOL)supportsMetadataObjectTypes:(NSArray *)metadataObjectTypes
176 | {
177 | if (![self isAvailable]) {
178 | return NO;
179 | }
180 |
181 | @autoreleasepool {
182 | // Setup components
183 | AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
184 | AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
185 | AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
186 | AVCaptureSession *session = [[AVCaptureSession alloc] init];
187 |
188 | [session addInput:deviceInput];
189 | [session addOutput:output];
190 |
191 | if (metadataObjectTypes == nil || metadataObjectTypes.count == 0) {
192 | // Check the QRCode metadata object type by default
193 | metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
194 | }
195 |
196 | for (NSString *metadataObjectType in metadataObjectTypes) {
197 | if (![output.availableMetadataObjectTypes containsObject:metadataObjectType]) {
198 | return NO;
199 | }
200 | }
201 |
202 | return YES;
203 | }
204 | }
205 |
206 | #pragma mark - Managing the Block
207 |
208 | - (void)setCompletionWithBlock:(void (^) (NSString *resultAsString))completionBlock
209 | {
210 | self.completionBlock = completionBlock;
211 | }
212 |
213 | #pragma mark - AVCaptureMetadataOutputObjects Delegate Methods
214 |
215 | - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
216 | {
217 | for (AVMetadataObject *current in metadataObjects) {
218 | if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]]
219 | && [_metadataObjectTypes containsObject:current.type]) {
220 | NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue];
221 |
222 | if (_completionBlock) {
223 | _completionBlock(scannedResult);
224 | }
225 |
226 | break;
227 | }
228 | }
229 | }
230 |
231 | @end
232 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCameraSwitchButton.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import "QRCameraSwitchButton.h"
28 |
29 | @implementation QRCameraSwitchButton
30 |
31 | - (id)initWithFrame:(CGRect)frame
32 | {
33 | if ((self = [super initWithFrame:frame])) {
34 | _edgeColor = [UIColor whiteColor];
35 | _fillColor = [UIColor darkGrayColor];
36 | _edgeHighlightedColor = [UIColor whiteColor];
37 | _fillHighlightedColor = [UIColor blackColor];
38 | }
39 | return self;
40 | }
41 |
42 | - (void)drawRect:(CGRect)rect
43 | {
44 | CGFloat width = rect.size.width;
45 | CGFloat height = rect.size.height;
46 | CGFloat center = width / 2;
47 | CGFloat middle = height / 2;
48 |
49 | CGFloat strokeLineWidth = 2;
50 |
51 | // Colors
52 |
53 | UIColor *paintColor = (self.state != UIControlStateHighlighted) ? _fillColor : _fillHighlightedColor;
54 | UIColor *strokeColor = (self.state != UIControlStateHighlighted) ? _edgeColor : _edgeHighlightedColor;
55 |
56 | // Camera box
57 |
58 | CGFloat cameraWidth = width * 0.4;
59 | CGFloat cameraHeight = cameraWidth * 0.6;
60 | CGFloat cameraX = center - cameraWidth / 2;
61 | CGFloat cameraY = middle - cameraHeight / 2;
62 | CGFloat cameraRadius = cameraWidth / 80;
63 |
64 | UIBezierPath *boxPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(cameraX, cameraY, cameraWidth, cameraHeight) cornerRadius:cameraRadius];
65 |
66 | // Camera lens
67 |
68 | CGFloat outerLensSize = cameraHeight * 0.8;
69 | CGFloat outerLensX = center - outerLensSize / 2;
70 | CGFloat outerLensY = middle - outerLensSize / 2;
71 |
72 | CGFloat innerLensSize = outerLensSize * 0.7;
73 | CGFloat innerLensX = center - innerLensSize / 2;
74 | CGFloat innerLensY = middle - innerLensSize / 2;
75 |
76 | UIBezierPath *outerLensPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(outerLensX, outerLensY, outerLensSize, outerLensSize)];
77 | UIBezierPath *innerLensPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(innerLensX, innerLensY, innerLensSize, innerLensSize)];
78 |
79 | // Draw flash box
80 |
81 | CGFloat flashBoxWidth = cameraWidth * 0.8;
82 | CGFloat flashBoxHeight = cameraHeight * 0.17;
83 | CGFloat flashBoxDeltaWidth = flashBoxWidth * 0.14;
84 | CGFloat flashLeftMostX = cameraX + (cameraWidth - flashBoxWidth) * 0.5;
85 | CGFloat flashBottomMostY = cameraY;
86 |
87 | UIBezierPath *flashPath = [UIBezierPath bezierPath];
88 | [flashPath moveToPoint:CGPointMake(flashLeftMostX, flashBottomMostY)];
89 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxWidth, flashBottomMostY)];
90 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxWidth - flashBoxDeltaWidth, flashBottomMostY - flashBoxHeight)];
91 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxDeltaWidth, flashBottomMostY - flashBoxHeight)];
92 | [flashPath closePath];
93 |
94 | flashPath.lineCapStyle = kCGLineCapRound;
95 | flashPath.lineJoinStyle = kCGLineJoinRound;
96 |
97 | // Arrows
98 |
99 | CGFloat arrowHeadHeigth = cameraHeight * 0.5;
100 | CGFloat arrowHeadWidth = ((width - cameraWidth) / 2) * 0.3;
101 | CGFloat arrowTailHeigth = arrowHeadHeigth * 0.6;
102 | CGFloat arrowTailWidth = ((width - cameraWidth) / 2) * 0.7;
103 |
104 | // Draw left arrow
105 |
106 | CGFloat arrowLeftX = center - cameraWidth * 0.2;
107 | CGFloat arrowLeftY = middle + cameraHeight * 0.45;
108 |
109 | UIBezierPath *leftArrowPath = [UIBezierPath bezierPath];
110 | [leftArrowPath moveToPoint:CGPointMake(arrowLeftX, arrowLeftY)];
111 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY - arrowHeadHeigth / 2)];
112 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY - arrowTailHeigth / 2)];
113 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth - arrowTailWidth, arrowLeftY - arrowTailHeigth / 2)];
114 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth - arrowTailWidth, arrowLeftY + arrowTailHeigth / 2)];
115 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY + arrowTailHeigth / 2)];
116 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY + arrowHeadHeigth / 2)];
117 | [leftArrowPath closePath];
118 |
119 | // Right arrow
120 |
121 | CGFloat arrowRightX = center + cameraWidth * 0.2;
122 | CGFloat arrowRightY = middle + cameraHeight * 0.60;
123 |
124 | UIBezierPath *rigthArrowPath = [UIBezierPath bezierPath];
125 | [rigthArrowPath moveToPoint:CGPointMake(arrowRightX, arrowRightY)];
126 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY - arrowHeadHeigth / 2)];
127 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY - arrowTailHeigth / 2)];
128 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth + arrowTailWidth, arrowRightY - arrowTailHeigth / 2)];
129 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth + arrowTailWidth, arrowRightY + arrowTailHeigth / 2)];
130 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY + arrowTailHeigth / 2)];
131 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY + arrowHeadHeigth / 2)];
132 | [rigthArrowPath closePath];
133 |
134 | // Drawing
135 |
136 | [paintColor setFill];
137 | [rigthArrowPath fill];
138 | [strokeColor setStroke];
139 | rigthArrowPath.lineWidth = strokeLineWidth;
140 | [rigthArrowPath stroke];
141 |
142 | [paintColor setFill];
143 | [boxPath fill];
144 | [strokeColor setStroke];
145 | boxPath.lineWidth = strokeLineWidth;
146 | [boxPath stroke];
147 |
148 | [strokeColor setFill];
149 | [outerLensPath fill];
150 |
151 | [paintColor setFill];
152 | [innerLensPath fill];
153 |
154 | [paintColor setFill];
155 | [flashPath fill];
156 | [strokeColor setStroke];
157 | flashPath.lineWidth = strokeLineWidth;
158 | [flashPath stroke];
159 |
160 | [paintColor setFill];
161 | [leftArrowPath fill];
162 | [strokeColor setStroke];
163 | leftArrowPath.lineWidth = strokeLineWidth;
164 | [leftArrowPath stroke];
165 | }
166 |
167 | // MARK: - UIResponder Methods
168 |
169 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
170 | {
171 | [super touchesBegan:touches withEvent:event];
172 |
173 | [self setNeedsDisplay];
174 | }
175 |
176 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
177 | {
178 | [super touchesMoved:touches withEvent:event];
179 |
180 | [self setNeedsDisplay];
181 | }
182 |
183 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
184 | {
185 | [super touchesEnded:touches withEvent:event];
186 |
187 | [self setNeedsDisplay];
188 | }
189 |
190 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
191 | {
192 | [super touchesCancelled:touches withEvent:event];
193 |
194 | [self setNeedsDisplay];
195 | }
196 |
197 | @end
198 |
--------------------------------------------------------------------------------
/QRCodeReaderViewController/QRCodeReaderViewController.m:
--------------------------------------------------------------------------------
1 | /*
2 | * QRCodeReaderViewController
3 | *
4 | * Copyright 2014-present Yannick Loriot.
5 | * http://yannickloriot.com
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | * THE SOFTWARE.
24 | *
25 | */
26 |
27 | #import "QRCodeReaderViewController.h"
28 | #import "QRCameraSwitchButton.h"
29 | #import "QRCodeReaderView.h"
30 |
31 | @interface QRCodeReaderViewController ()
32 | @property (strong, nonatomic) QRCameraSwitchButton *switchCameraButton;
33 | @property (strong, nonatomic) QRCodeReaderView *cameraView;
34 | @property (strong, nonatomic) UIButton *cancelButton;
35 | @property (strong, nonatomic) QRCodeReader *codeReader;
36 | @property (assign, nonatomic) BOOL startScanningAtLoad;
37 |
38 | @property (copy, nonatomic) void (^completionBlock) (NSString * __nullable);
39 |
40 | @end
41 |
42 | @implementation QRCodeReaderViewController
43 |
44 | - (void)dealloc
45 | {
46 | [self stopScanning];
47 |
48 | [[NSNotificationCenter defaultCenter] removeObserver:self];
49 | }
50 |
51 | - (id)init
52 | {
53 | return [self initWithCancelButtonTitle:nil];
54 | }
55 |
56 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle
57 | {
58 | return [self initWithCancelButtonTitle:cancelTitle metadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
59 | }
60 |
61 | - (id)initWithMetadataObjectTypes:(NSArray *)metadataObjectTypes
62 | {
63 | return [self initWithCancelButtonTitle:nil metadataObjectTypes:metadataObjectTypes];
64 | }
65 |
66 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle metadataObjectTypes:(NSArray *)metadataObjectTypes
67 | {
68 | QRCodeReader *reader = [QRCodeReader readerWithMetadataObjectTypes:metadataObjectTypes];
69 |
70 | return [self initWithCancelButtonTitle:cancelTitle codeReader:reader];
71 | }
72 |
73 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader
74 | {
75 | return [self initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:true];
76 | }
77 |
78 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad
79 | {
80 | if ((self = [super init])) {
81 | self.view.backgroundColor = [UIColor blackColor];
82 | self.codeReader = codeReader;
83 | self.startScanningAtLoad = startScanningAtLoad;
84 |
85 | if (cancelTitle == nil) {
86 | cancelTitle = NSLocalizedString(@"Cancel", @"Cancel");
87 | }
88 |
89 | [self setupUIComponentsWithCancelButtonTitle:cancelTitle];
90 | [self setupAutoLayoutConstraints];
91 |
92 | [_cameraView.layer insertSublayer:_codeReader.previewLayer atIndex:0];
93 |
94 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
95 |
96 | __weak typeof(self) weakSelf = self;
97 |
98 | [codeReader setCompletionWithBlock:^(NSString *resultAsString) {
99 | if (weakSelf.completionBlock != nil) {
100 | weakSelf.completionBlock(resultAsString);
101 | }
102 |
103 | if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(reader:didScanResult:)]) {
104 | [weakSelf.delegate reader:weakSelf didScanResult:resultAsString];
105 | }
106 | }];
107 | }
108 | return self;
109 | }
110 |
111 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle
112 | {
113 | return [[self alloc] initWithCancelButtonTitle:cancelTitle];
114 | }
115 |
116 | + (instancetype)readerWithMetadataObjectTypes:(NSArray *)metadataObjectTypes
117 | {
118 | return [[self alloc] initWithMetadataObjectTypes:metadataObjectTypes];
119 | }
120 |
121 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle metadataObjectTypes:(NSArray *)metadataObjectTypes
122 | {
123 | return [[self alloc] initWithCancelButtonTitle:cancelTitle metadataObjectTypes:metadataObjectTypes];
124 | }
125 |
126 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader
127 | {
128 | return [[self alloc] initWithCancelButtonTitle:cancelTitle codeReader:codeReader];
129 | }
130 |
131 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad
132 | {
133 | return [[self alloc] initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:startScanningAtLoad];
134 | }
135 |
136 | - (void)viewWillAppear:(BOOL)animated
137 | {
138 | [super viewWillAppear:animated];
139 |
140 | if (_startScanningAtLoad) {
141 | [self startScanning];
142 | }
143 | }
144 |
145 | - (void)viewWillDisappear:(BOOL)animated
146 | {
147 | [self stopScanning];
148 |
149 | [super viewWillDisappear:animated];
150 | }
151 |
152 | - (void)viewWillLayoutSubviews
153 | {
154 | [super viewWillLayoutSubviews];
155 |
156 | _codeReader.previewLayer.frame = self.view.bounds;
157 | }
158 |
159 | - (BOOL)shouldAutorotate
160 | {
161 | return YES;
162 | }
163 |
164 | #pragma mark - Controlling the Reader
165 |
166 | - (void)startScanning {
167 | [_codeReader startScanning];
168 |
169 | [_cameraView startScanning];
170 | }
171 |
172 | - (void)stopScanning {
173 | [_codeReader stopScanning];
174 |
175 | [_cameraView stopScanning];
176 | }
177 |
178 | #pragma mark - Managing the Orientation
179 |
180 | - (void)orientationChanged:(NSNotification *)notification
181 | {
182 | [_cameraView setNeedsDisplay];
183 |
184 | if (_codeReader.previewLayer.connection.isVideoOrientationSupported) {
185 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
186 |
187 | _codeReader.previewLayer.connection.videoOrientation = [QRCodeReader videoOrientationFromInterfaceOrientation:
188 | orientation];
189 | }
190 | }
191 |
192 | #pragma mark - Managing the Block
193 |
194 | - (void)setCompletionWithBlock:(void (^) (NSString *resultAsString))completionBlock
195 | {
196 | self.completionBlock = completionBlock;
197 | }
198 |
199 | #pragma mark - Initializing the AV Components
200 |
201 | - (void)setupUIComponentsWithCancelButtonTitle:(NSString *)cancelButtonTitle
202 | {
203 | self.cameraView = [[QRCodeReaderView alloc] init];
204 | _cameraView.translatesAutoresizingMaskIntoConstraints = NO;
205 | _cameraView.clipsToBounds = YES;
206 | [self.view addSubview:_cameraView];
207 |
208 | [_codeReader.previewLayer setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
209 |
210 | if ([_codeReader.previewLayer.connection isVideoOrientationSupported]) {
211 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
212 |
213 | _codeReader.previewLayer.connection.videoOrientation = [QRCodeReader videoOrientationFromInterfaceOrientation:orientation];
214 | }
215 |
216 | self.cancelButton = [[UIButton alloc] init];
217 | _cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
218 | [_cancelButton setTitle:cancelButtonTitle forState:UIControlStateNormal];
219 | [_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
220 | [_cancelButton addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside];
221 | [self.view addSubview:_cancelButton];
222 | }
223 |
224 | - (void)setupAutoLayoutConstraints
225 | {
226 | NSDictionary *views = NSDictionaryOfVariableBindings(_cameraView, _cancelButton);
227 |
228 | [self.view addConstraints:
229 | [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_cameraView][_cancelButton(40)]|" options:0 metrics:nil views:views]];
230 | [self.view addConstraints:
231 | [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_cameraView]|" options:0 metrics:nil views:views]];
232 | [self.view addConstraints:
233 | [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_cancelButton]-|" options:0 metrics:nil views:views]];
234 |
235 | if (_switchCameraButton) {
236 | NSDictionary *switchViews = NSDictionaryOfVariableBindings(_switchCameraButton);
237 |
238 | [self.view addConstraints:
239 | [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_switchCameraButton(50)]" options:0 metrics:nil views:switchViews]];
240 | [self.view addConstraints:
241 | [NSLayoutConstraint constraintsWithVisualFormat:@"H:[_switchCameraButton(70)]|" options:0 metrics:nil views:switchViews]];
242 | }
243 | }
244 |
245 | - (void)switchDeviceInput
246 | {
247 | [_codeReader switchDeviceInput];
248 | }
249 |
250 | #pragma mark - Catching Button Events
251 |
252 | - (void)cancelAction:(UIButton *)button
253 | {
254 | [_codeReader stopScanning];
255 |
256 | if (_completionBlock) {
257 | _completionBlock(nil);
258 | }
259 |
260 | if (_delegate && [_delegate respondsToSelector:@selector(readerDidCancel:)]) {
261 | [_delegate readerDidCancel:self];
262 | }
263 | }
264 |
265 | - (void)switchCameraAction:(UIButton *)button
266 | {
267 | [self switchDeviceInput];
268 | }
269 |
270 | @end
271 |
--------------------------------------------------------------------------------
/Example/QRCodeReaderViewControllerExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | C154819C1BBA87DA00124400 /* QRCodeBottomLeft@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481921BBA87DA00124400 /* QRCodeBottomLeft@2x.png */; settings = {ASSET_TAGS = (); }; };
11 | C154819D1BBA87DA00124400 /* QRCodeBottomLeft@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481931BBA87DA00124400 /* QRCodeBottomLeft@3x.png */; settings = {ASSET_TAGS = (); }; };
12 | C154819E1BBA87DA00124400 /* QRCodeBottomRight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481941BBA87DA00124400 /* QRCodeBottomRight@2x.png */; settings = {ASSET_TAGS = (); }; };
13 | C154819F1BBA87DA00124400 /* QRCodeBottomRight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481951BBA87DA00124400 /* QRCodeBottomRight@3x.png */; settings = {ASSET_TAGS = (); }; };
14 | C15481A01BBA87DA00124400 /* QRCodeLine@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481961BBA87DA00124400 /* QRCodeLine@2x.png */; settings = {ASSET_TAGS = (); }; };
15 | C15481A11BBA87DA00124400 /* QRCodeLine@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481971BBA87DA00124400 /* QRCodeLine@3x.png */; settings = {ASSET_TAGS = (); }; };
16 | C15481A21BBA87DA00124400 /* QRCodeTopLeft@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481981BBA87DA00124400 /* QRCodeTopLeft@2x.png */; settings = {ASSET_TAGS = (); }; };
17 | C15481A31BBA87DA00124400 /* QRCodeTopLeft@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15481991BBA87DA00124400 /* QRCodeTopLeft@3x.png */; settings = {ASSET_TAGS = (); }; };
18 | C15481A41BBA87DA00124400 /* QRCodeTopRight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C154819A1BBA87DA00124400 /* QRCodeTopRight@2x.png */; settings = {ASSET_TAGS = (); }; };
19 | C15481A51BBA87DA00124400 /* QRCodeTopRight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C154819B1BBA87DA00124400 /* QRCodeTopRight@3x.png */; settings = {ASSET_TAGS = (); }; };
20 | C18C20671BB3CCE3007FECF1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C18C20661BB3CCE3007FECF1 /* Launch Screen.storyboard */; settings = {ASSET_TAGS = (); }; };
21 | C18C206C1BB3DF21007FECF1 /* QRCodeReaderMaskView.m in Sources */ = {isa = PBXBuildFile; fileRef = C18C206B1BB3DF21007FECF1 /* QRCodeReaderMaskView.m */; settings = {ASSET_TAGS = (); }; };
22 | C18C206F1BB3DF43007FECF1 /* QRCodeReaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = C18C206E1BB3DF43007FECF1 /* QRCodeReaderView.m */; settings = {ASSET_TAGS = (); }; };
23 | C18C20721BB3E458007FECF1 /* QRCodeReaderAanimationLineView.m in Sources */ = {isa = PBXBuildFile; fileRef = C18C20711BB3E458007FECF1 /* QRCodeReaderAanimationLineView.m */; settings = {ASSET_TAGS = (); }; };
24 | CE29601E1987F124008FA93B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CE29601D1987F124008FA93B /* main.m */; };
25 | CE2960211987F124008FA93B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960201987F124008FA93B /* AppDelegate.m */; };
26 | CE2960241987F124008FA93B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960231987F124008FA93B /* ViewController.m */; };
27 | CE2960271987F124008FA93B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE2960251987F124008FA93B /* Main.storyboard */; };
28 | CE2960351987F125008FA93B /* QRCodeReaderViewControllerExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960341987F125008FA93B /* QRCodeReaderViewControllerExampleTests.m */; };
29 | CE2960421987F140008FA93B /* QRCodeReaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960411987F140008FA93B /* QRCodeReaderViewController.m */; };
30 | CE2960431987F140008FA93B /* QRCodeReaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960411987F140008FA93B /* QRCodeReaderViewController.m */; };
31 | CE99CEFD1A9BCA1100CB8AD8 /* QRCodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */; };
32 | CEAF7A691A16B05400991CF8 /* QRCameraSwitchButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXContainerItemProxy section */
36 | CE29602F1987F125008FA93B /* PBXContainerItemProxy */ = {
37 | isa = PBXContainerItemProxy;
38 | containerPortal = CE2960101987F124008FA93B /* Project object */;
39 | proxyType = 1;
40 | remoteGlobalIDString = CE2960171987F124008FA93B;
41 | remoteInfo = QRCodeReaderViewControllerExample;
42 | };
43 | /* End PBXContainerItemProxy section */
44 |
45 | /* Begin PBXFileReference section */
46 | C15481921BBA87DA00124400 /* QRCodeBottomLeft@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeBottomLeft@2x.png"; sourceTree = ""; };
47 | C15481931BBA87DA00124400 /* QRCodeBottomLeft@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeBottomLeft@3x.png"; sourceTree = ""; };
48 | C15481941BBA87DA00124400 /* QRCodeBottomRight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeBottomRight@2x.png"; sourceTree = ""; };
49 | C15481951BBA87DA00124400 /* QRCodeBottomRight@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeBottomRight@3x.png"; sourceTree = ""; };
50 | C15481961BBA87DA00124400 /* QRCodeLine@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeLine@2x.png"; sourceTree = ""; };
51 | C15481971BBA87DA00124400 /* QRCodeLine@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeLine@3x.png"; sourceTree = ""; };
52 | C15481981BBA87DA00124400 /* QRCodeTopLeft@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeTopLeft@2x.png"; sourceTree = ""; };
53 | C15481991BBA87DA00124400 /* QRCodeTopLeft@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeTopLeft@3x.png"; sourceTree = ""; };
54 | C154819A1BBA87DA00124400 /* QRCodeTopRight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeTopRight@2x.png"; sourceTree = ""; };
55 | C154819B1BBA87DA00124400 /* QRCodeTopRight@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QRCodeTopRight@3x.png"; sourceTree = ""; };
56 | C18C20661BB3CCE3007FECF1 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; };
57 | C18C206A1BB3DF21007FECF1 /* QRCodeReaderMaskView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderMaskView.h; sourceTree = ""; };
58 | C18C206B1BB3DF21007FECF1 /* QRCodeReaderMaskView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderMaskView.m; sourceTree = ""; };
59 | C18C206D1BB3DF43007FECF1 /* QRCodeReaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderView.h; sourceTree = ""; };
60 | C18C206E1BB3DF43007FECF1 /* QRCodeReaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderView.m; sourceTree = ""; };
61 | C18C20701BB3E458007FECF1 /* QRCodeReaderAanimationLineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderAanimationLineView.h; sourceTree = ""; };
62 | C18C20711BB3E458007FECF1 /* QRCodeReaderAanimationLineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderAanimationLineView.m; sourceTree = ""; };
63 | CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QRCodeReaderViewControllerExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
64 | CE29601C1987F124008FA93B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
65 | CE29601D1987F124008FA93B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
66 | CE29601F1987F124008FA93B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
67 | CE2960201987F124008FA93B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
68 | CE2960221987F124008FA93B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
69 | CE2960231987F124008FA93B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
70 | CE2960261987F124008FA93B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
71 | CE29602E1987F125008FA93B /* QRCodeReaderViewControllerExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QRCodeReaderViewControllerExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
72 | CE2960331987F125008FA93B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
73 | CE2960341987F125008FA93B /* QRCodeReaderViewControllerExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderViewControllerExampleTests.m; sourceTree = ""; };
74 | CE29603F1987F140008FA93B /* QRCodeReaderDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderDelegate.h; sourceTree = ""; };
75 | CE2960401987F140008FA93B /* QRCodeReaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderViewController.h; sourceTree = ""; };
76 | CE2960411987F140008FA93B /* QRCodeReaderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderViewController.m; sourceTree = ""; };
77 | CE99CEFB1A9BCA1100CB8AD8 /* QRCodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReader.h; sourceTree = ""; };
78 | CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReader.m; sourceTree = ""; };
79 | CEAF7A671A16B05400991CF8 /* QRCameraSwitchButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCameraSwitchButton.h; sourceTree = ""; };
80 | CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCameraSwitchButton.m; sourceTree = ""; };
81 | /* End PBXFileReference section */
82 |
83 | /* Begin PBXFrameworksBuildPhase section */
84 | CE2960151987F124008FA93B /* Frameworks */ = {
85 | isa = PBXFrameworksBuildPhase;
86 | buildActionMask = 2147483647;
87 | files = (
88 | );
89 | runOnlyForDeploymentPostprocessing = 0;
90 | };
91 | CE29602B1987F124008FA93B /* Frameworks */ = {
92 | isa = PBXFrameworksBuildPhase;
93 | buildActionMask = 2147483647;
94 | files = (
95 | );
96 | runOnlyForDeploymentPostprocessing = 0;
97 | };
98 | /* End PBXFrameworksBuildPhase section */
99 |
100 | /* Begin PBXGroup section */
101 | C15481911BBA87DA00124400 /* Resources */ = {
102 | isa = PBXGroup;
103 | children = (
104 | C15481921BBA87DA00124400 /* QRCodeBottomLeft@2x.png */,
105 | C15481931BBA87DA00124400 /* QRCodeBottomLeft@3x.png */,
106 | C15481941BBA87DA00124400 /* QRCodeBottomRight@2x.png */,
107 | C15481951BBA87DA00124400 /* QRCodeBottomRight@3x.png */,
108 | C15481961BBA87DA00124400 /* QRCodeLine@2x.png */,
109 | C15481971BBA87DA00124400 /* QRCodeLine@3x.png */,
110 | C15481981BBA87DA00124400 /* QRCodeTopLeft@2x.png */,
111 | C15481991BBA87DA00124400 /* QRCodeTopLeft@3x.png */,
112 | C154819A1BBA87DA00124400 /* QRCodeTopRight@2x.png */,
113 | C154819B1BBA87DA00124400 /* QRCodeTopRight@3x.png */,
114 | );
115 | path = Resources;
116 | sourceTree = "";
117 | };
118 | C18C20691BB3DF11007FECF1 /* QRCodeReaderView */ = {
119 | isa = PBXGroup;
120 | children = (
121 | C18C206D1BB3DF43007FECF1 /* QRCodeReaderView.h */,
122 | C18C206E1BB3DF43007FECF1 /* QRCodeReaderView.m */,
123 | C18C206A1BB3DF21007FECF1 /* QRCodeReaderMaskView.h */,
124 | C18C206B1BB3DF21007FECF1 /* QRCodeReaderMaskView.m */,
125 | C18C20701BB3E458007FECF1 /* QRCodeReaderAanimationLineView.h */,
126 | C18C20711BB3E458007FECF1 /* QRCodeReaderAanimationLineView.m */,
127 | );
128 | path = QRCodeReaderView;
129 | sourceTree = "";
130 | };
131 | CE29600F1987F124008FA93B = {
132 | isa = PBXGroup;
133 | children = (
134 | CE29603E1987F140008FA93B /* QRCodeReaderViewController */,
135 | CE29601A1987F124008FA93B /* QRCodeReaderViewControllerExample */,
136 | CE2960311987F125008FA93B /* QRCodeReaderViewControllerExampleTests */,
137 | CE2960191987F124008FA93B /* Products */,
138 | );
139 | sourceTree = "";
140 | };
141 | CE2960191987F124008FA93B /* Products */ = {
142 | isa = PBXGroup;
143 | children = (
144 | CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */,
145 | CE29602E1987F125008FA93B /* QRCodeReaderViewControllerExampleTests.xctest */,
146 | );
147 | name = Products;
148 | sourceTree = "";
149 | };
150 | CE29601A1987F124008FA93B /* QRCodeReaderViewControllerExample */ = {
151 | isa = PBXGroup;
152 | children = (
153 | CE29601F1987F124008FA93B /* AppDelegate.h */,
154 | CE2960201987F124008FA93B /* AppDelegate.m */,
155 | CE2960221987F124008FA93B /* ViewController.h */,
156 | CE2960231987F124008FA93B /* ViewController.m */,
157 | CE2960251987F124008FA93B /* Main.storyboard */,
158 | CE29601B1987F124008FA93B /* Supporting Files */,
159 | );
160 | path = QRCodeReaderViewControllerExample;
161 | sourceTree = "";
162 | };
163 | CE29601B1987F124008FA93B /* Supporting Files */ = {
164 | isa = PBXGroup;
165 | children = (
166 | CE29601C1987F124008FA93B /* Info.plist */,
167 | CE29601D1987F124008FA93B /* main.m */,
168 | C18C20661BB3CCE3007FECF1 /* Launch Screen.storyboard */,
169 | );
170 | name = "Supporting Files";
171 | sourceTree = "";
172 | };
173 | CE2960311987F125008FA93B /* QRCodeReaderViewControllerExampleTests */ = {
174 | isa = PBXGroup;
175 | children = (
176 | CE2960341987F125008FA93B /* QRCodeReaderViewControllerExampleTests.m */,
177 | CE2960321987F125008FA93B /* Supporting Files */,
178 | );
179 | path = QRCodeReaderViewControllerExampleTests;
180 | sourceTree = "";
181 | };
182 | CE2960321987F125008FA93B /* Supporting Files */ = {
183 | isa = PBXGroup;
184 | children = (
185 | CE2960331987F125008FA93B /* Info.plist */,
186 | );
187 | name = "Supporting Files";
188 | sourceTree = "";
189 | };
190 | CE29603E1987F140008FA93B /* QRCodeReaderViewController */ = {
191 | isa = PBXGroup;
192 | children = (
193 | C15481911BBA87DA00124400 /* Resources */,
194 | C18C20691BB3DF11007FECF1 /* QRCodeReaderView */,
195 | CE29603F1987F140008FA93B /* QRCodeReaderDelegate.h */,
196 | CE2960401987F140008FA93B /* QRCodeReaderViewController.h */,
197 | CE2960411987F140008FA93B /* QRCodeReaderViewController.m */,
198 | CE99CEFB1A9BCA1100CB8AD8 /* QRCodeReader.h */,
199 | CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */,
200 | CEAF7A671A16B05400991CF8 /* QRCameraSwitchButton.h */,
201 | CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */,
202 | );
203 | name = QRCodeReaderViewController;
204 | path = ../QRCodeReaderViewController;
205 | sourceTree = "";
206 | };
207 | /* End PBXGroup section */
208 |
209 | /* Begin PBXNativeTarget section */
210 | CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */ = {
211 | isa = PBXNativeTarget;
212 | buildConfigurationList = CE2960381987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExample" */;
213 | buildPhases = (
214 | CE2960141987F124008FA93B /* Sources */,
215 | CE2960151987F124008FA93B /* Frameworks */,
216 | CE2960161987F124008FA93B /* Resources */,
217 | );
218 | buildRules = (
219 | );
220 | dependencies = (
221 | );
222 | name = QRCodeReaderViewControllerExample;
223 | productName = QRCodeReaderViewControllerExample;
224 | productReference = CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */;
225 | productType = "com.apple.product-type.application";
226 | };
227 | CE29602D1987F124008FA93B /* QRCodeReaderViewControllerExampleTests */ = {
228 | isa = PBXNativeTarget;
229 | buildConfigurationList = CE29603B1987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExampleTests" */;
230 | buildPhases = (
231 | CE29602A1987F124008FA93B /* Sources */,
232 | CE29602B1987F124008FA93B /* Frameworks */,
233 | CE29602C1987F124008FA93B /* Resources */,
234 | );
235 | buildRules = (
236 | );
237 | dependencies = (
238 | CE2960301987F125008FA93B /* PBXTargetDependency */,
239 | );
240 | name = QRCodeReaderViewControllerExampleTests;
241 | productName = QRCodeReaderViewControllerExampleTests;
242 | productReference = CE29602E1987F125008FA93B /* QRCodeReaderViewControllerExampleTests.xctest */;
243 | productType = "com.apple.product-type.bundle.unit-test";
244 | };
245 | /* End PBXNativeTarget section */
246 |
247 | /* Begin PBXProject section */
248 | CE2960101987F124008FA93B /* Project object */ = {
249 | isa = PBXProject;
250 | attributes = {
251 | LastUpgradeCheck = 0600;
252 | ORGANIZATIONNAME = "Yannick Loriot";
253 | TargetAttributes = {
254 | CE2960171987F124008FA93B = {
255 | CreatedOnToolsVersion = 6.0;
256 | DevelopmentTeam = ZQA8RKS39U;
257 | };
258 | CE29602D1987F124008FA93B = {
259 | CreatedOnToolsVersion = 6.0;
260 | TestTargetID = CE2960171987F124008FA93B;
261 | };
262 | };
263 | };
264 | buildConfigurationList = CE2960131987F124008FA93B /* Build configuration list for PBXProject "QRCodeReaderViewControllerExample" */;
265 | compatibilityVersion = "Xcode 3.2";
266 | developmentRegion = English;
267 | hasScannedForEncodings = 0;
268 | knownRegions = (
269 | en,
270 | Base,
271 | );
272 | mainGroup = CE29600F1987F124008FA93B;
273 | productRefGroup = CE2960191987F124008FA93B /* Products */;
274 | projectDirPath = "";
275 | projectRoot = "";
276 | targets = (
277 | CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */,
278 | CE29602D1987F124008FA93B /* QRCodeReaderViewControllerExampleTests */,
279 | );
280 | };
281 | /* End PBXProject section */
282 |
283 | /* Begin PBXResourcesBuildPhase section */
284 | CE2960161987F124008FA93B /* Resources */ = {
285 | isa = PBXResourcesBuildPhase;
286 | buildActionMask = 2147483647;
287 | files = (
288 | C154819E1BBA87DA00124400 /* QRCodeBottomRight@2x.png in Resources */,
289 | C154819D1BBA87DA00124400 /* QRCodeBottomLeft@3x.png in Resources */,
290 | C18C20671BB3CCE3007FECF1 /* Launch Screen.storyboard in Resources */,
291 | C15481A21BBA87DA00124400 /* QRCodeTopLeft@2x.png in Resources */,
292 | C15481A11BBA87DA00124400 /* QRCodeLine@3x.png in Resources */,
293 | C154819F1BBA87DA00124400 /* QRCodeBottomRight@3x.png in Resources */,
294 | CE2960271987F124008FA93B /* Main.storyboard in Resources */,
295 | C15481A31BBA87DA00124400 /* QRCodeTopLeft@3x.png in Resources */,
296 | C15481A41BBA87DA00124400 /* QRCodeTopRight@2x.png in Resources */,
297 | C15481A51BBA87DA00124400 /* QRCodeTopRight@3x.png in Resources */,
298 | C15481A01BBA87DA00124400 /* QRCodeLine@2x.png in Resources */,
299 | C154819C1BBA87DA00124400 /* QRCodeBottomLeft@2x.png in Resources */,
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | };
303 | CE29602C1987F124008FA93B /* Resources */ = {
304 | isa = PBXResourcesBuildPhase;
305 | buildActionMask = 2147483647;
306 | files = (
307 | );
308 | runOnlyForDeploymentPostprocessing = 0;
309 | };
310 | /* End PBXResourcesBuildPhase section */
311 |
312 | /* Begin PBXSourcesBuildPhase section */
313 | CE2960141987F124008FA93B /* Sources */ = {
314 | isa = PBXSourcesBuildPhase;
315 | buildActionMask = 2147483647;
316 | files = (
317 | C18C206F1BB3DF43007FECF1 /* QRCodeReaderView.m in Sources */,
318 | CE2960241987F124008FA93B /* ViewController.m in Sources */,
319 | C18C206C1BB3DF21007FECF1 /* QRCodeReaderMaskView.m in Sources */,
320 | C18C20721BB3E458007FECF1 /* QRCodeReaderAanimationLineView.m in Sources */,
321 | CEAF7A691A16B05400991CF8 /* QRCameraSwitchButton.m in Sources */,
322 | CE99CEFD1A9BCA1100CB8AD8 /* QRCodeReader.m in Sources */,
323 | CE2960211987F124008FA93B /* AppDelegate.m in Sources */,
324 | CE29601E1987F124008FA93B /* main.m in Sources */,
325 | CE2960421987F140008FA93B /* QRCodeReaderViewController.m in Sources */,
326 | );
327 | runOnlyForDeploymentPostprocessing = 0;
328 | };
329 | CE29602A1987F124008FA93B /* Sources */ = {
330 | isa = PBXSourcesBuildPhase;
331 | buildActionMask = 2147483647;
332 | files = (
333 | CE2960351987F125008FA93B /* QRCodeReaderViewControllerExampleTests.m in Sources */,
334 | CE2960431987F140008FA93B /* QRCodeReaderViewController.m in Sources */,
335 | );
336 | runOnlyForDeploymentPostprocessing = 0;
337 | };
338 | /* End PBXSourcesBuildPhase section */
339 |
340 | /* Begin PBXTargetDependency section */
341 | CE2960301987F125008FA93B /* PBXTargetDependency */ = {
342 | isa = PBXTargetDependency;
343 | target = CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */;
344 | targetProxy = CE29602F1987F125008FA93B /* PBXContainerItemProxy */;
345 | };
346 | /* End PBXTargetDependency section */
347 |
348 | /* Begin PBXVariantGroup section */
349 | CE2960251987F124008FA93B /* Main.storyboard */ = {
350 | isa = PBXVariantGroup;
351 | children = (
352 | CE2960261987F124008FA93B /* Base */,
353 | );
354 | name = Main.storyboard;
355 | sourceTree = "";
356 | };
357 | /* End PBXVariantGroup section */
358 |
359 | /* Begin XCBuildConfiguration section */
360 | CE2960361987F125008FA93B /* Debug */ = {
361 | isa = XCBuildConfiguration;
362 | buildSettings = {
363 | ALWAYS_SEARCH_USER_PATHS = NO;
364 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
365 | CLANG_CXX_LIBRARY = "libc++";
366 | CLANG_ENABLE_MODULES = YES;
367 | CLANG_ENABLE_OBJC_ARC = YES;
368 | CLANG_WARN_BOOL_CONVERSION = YES;
369 | CLANG_WARN_CONSTANT_CONVERSION = YES;
370 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
371 | CLANG_WARN_EMPTY_BODY = YES;
372 | CLANG_WARN_ENUM_CONVERSION = YES;
373 | CLANG_WARN_INT_CONVERSION = YES;
374 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
375 | CLANG_WARN_UNREACHABLE_CODE = YES;
376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
377 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
378 | COPY_PHASE_STRIP = NO;
379 | ENABLE_STRICT_OBJC_MSGSEND = YES;
380 | GCC_C_LANGUAGE_STANDARD = gnu99;
381 | GCC_DYNAMIC_NO_PIC = NO;
382 | GCC_OPTIMIZATION_LEVEL = 0;
383 | GCC_PREPROCESSOR_DEFINITIONS = (
384 | "DEBUG=1",
385 | "$(inherited)",
386 | );
387 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
390 | GCC_WARN_UNDECLARED_SELECTOR = YES;
391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
392 | GCC_WARN_UNUSED_FUNCTION = YES;
393 | GCC_WARN_UNUSED_VARIABLE = YES;
394 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
395 | MTL_ENABLE_DEBUG_INFO = YES;
396 | ONLY_ACTIVE_ARCH = YES;
397 | SDKROOT = iphoneos;
398 | TARGETED_DEVICE_FAMILY = "1,2";
399 | };
400 | name = Debug;
401 | };
402 | CE2960371987F125008FA93B /* Release */ = {
403 | isa = XCBuildConfiguration;
404 | buildSettings = {
405 | ALWAYS_SEARCH_USER_PATHS = NO;
406 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
407 | CLANG_CXX_LIBRARY = "libc++";
408 | CLANG_ENABLE_MODULES = YES;
409 | CLANG_ENABLE_OBJC_ARC = YES;
410 | CLANG_WARN_BOOL_CONVERSION = YES;
411 | CLANG_WARN_CONSTANT_CONVERSION = YES;
412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
413 | CLANG_WARN_EMPTY_BODY = YES;
414 | CLANG_WARN_ENUM_CONVERSION = YES;
415 | CLANG_WARN_INT_CONVERSION = YES;
416 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
417 | CLANG_WARN_UNREACHABLE_CODE = YES;
418 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
419 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
420 | COPY_PHASE_STRIP = YES;
421 | ENABLE_NS_ASSERTIONS = NO;
422 | ENABLE_STRICT_OBJC_MSGSEND = YES;
423 | GCC_C_LANGUAGE_STANDARD = gnu99;
424 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
425 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
426 | GCC_WARN_UNDECLARED_SELECTOR = YES;
427 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
428 | GCC_WARN_UNUSED_FUNCTION = YES;
429 | GCC_WARN_UNUSED_VARIABLE = YES;
430 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
431 | MTL_ENABLE_DEBUG_INFO = NO;
432 | SDKROOT = iphoneos;
433 | TARGETED_DEVICE_FAMILY = "1,2";
434 | VALIDATE_PRODUCT = YES;
435 | };
436 | name = Release;
437 | };
438 | CE2960391987F125008FA93B /* Debug */ = {
439 | isa = XCBuildConfiguration;
440 | buildSettings = {
441 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
442 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
443 | CODE_SIGN_IDENTITY = "iPhone Developer";
444 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
445 | INFOPLIST_FILE = QRCodeReaderViewControllerExample/Info.plist;
446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
447 | PRODUCT_NAME = "$(TARGET_NAME)";
448 | PROVISIONING_PROFILE = "";
449 | };
450 | name = Debug;
451 | };
452 | CE29603A1987F125008FA93B /* Release */ = {
453 | isa = XCBuildConfiguration;
454 | buildSettings = {
455 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
456 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
457 | CODE_SIGN_IDENTITY = "iPhone Developer";
458 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
459 | INFOPLIST_FILE = QRCodeReaderViewControllerExample/Info.plist;
460 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
461 | PRODUCT_NAME = "$(TARGET_NAME)";
462 | PROVISIONING_PROFILE = "";
463 | };
464 | name = Release;
465 | };
466 | CE29603C1987F125008FA93B /* Debug */ = {
467 | isa = XCBuildConfiguration;
468 | buildSettings = {
469 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/QRCodeReaderViewControllerExample.app/QRCodeReaderViewControllerExample";
470 | FRAMEWORK_SEARCH_PATHS = (
471 | "$(SDKROOT)/Developer/Library/Frameworks",
472 | "$(inherited)",
473 | );
474 | GCC_PREPROCESSOR_DEFINITIONS = (
475 | "DEBUG=1",
476 | "$(inherited)",
477 | );
478 | INFOPLIST_FILE = QRCodeReaderViewControllerExampleTests/Info.plist;
479 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
480 | PRODUCT_NAME = "$(TARGET_NAME)";
481 | TEST_HOST = "$(BUNDLE_LOADER)";
482 | };
483 | name = Debug;
484 | };
485 | CE29603D1987F125008FA93B /* Release */ = {
486 | isa = XCBuildConfiguration;
487 | buildSettings = {
488 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/QRCodeReaderViewControllerExample.app/QRCodeReaderViewControllerExample";
489 | FRAMEWORK_SEARCH_PATHS = (
490 | "$(SDKROOT)/Developer/Library/Frameworks",
491 | "$(inherited)",
492 | );
493 | INFOPLIST_FILE = QRCodeReaderViewControllerExampleTests/Info.plist;
494 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
495 | PRODUCT_NAME = "$(TARGET_NAME)";
496 | TEST_HOST = "$(BUNDLE_LOADER)";
497 | };
498 | name = Release;
499 | };
500 | /* End XCBuildConfiguration section */
501 |
502 | /* Begin XCConfigurationList section */
503 | CE2960131987F124008FA93B /* Build configuration list for PBXProject "QRCodeReaderViewControllerExample" */ = {
504 | isa = XCConfigurationList;
505 | buildConfigurations = (
506 | CE2960361987F125008FA93B /* Debug */,
507 | CE2960371987F125008FA93B /* Release */,
508 | );
509 | defaultConfigurationIsVisible = 0;
510 | defaultConfigurationName = Release;
511 | };
512 | CE2960381987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExample" */ = {
513 | isa = XCConfigurationList;
514 | buildConfigurations = (
515 | CE2960391987F125008FA93B /* Debug */,
516 | CE29603A1987F125008FA93B /* Release */,
517 | );
518 | defaultConfigurationIsVisible = 0;
519 | defaultConfigurationName = Release;
520 | };
521 | CE29603B1987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExampleTests" */ = {
522 | isa = XCConfigurationList;
523 | buildConfigurations = (
524 | CE29603C1987F125008FA93B /* Debug */,
525 | CE29603D1987F125008FA93B /* Release */,
526 | );
527 | defaultConfigurationIsVisible = 0;
528 | defaultConfigurationName = Release;
529 | };
530 | /* End XCConfigurationList section */
531 | };
532 | rootObject = CE2960101987F124008FA93B /* Project object */;
533 | }
534 |
--------------------------------------------------------------------------------