forked from Jeykit/MUKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MUQRCodeManager.m
290 lines (248 loc) · 11 KB
/
MUQRCodeManager.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
//
// MUQRCodeManager.m
// MUKit
//
// Created by Jekity on 2018/5/24.
//
#import "MUQRCodeManager.h"
#import <ImageIO/ImageIO.h>
@interface MUQRCodeManager()<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate>
@property (nonatomic,strong)AVCaptureSession *session;
@property (nonatomic,strong)AVCaptureDevice *device;
@property (nonatomic,strong)AVCaptureDeviceInput *input;
@property (nonatomic,strong)AVCaptureMetadataOutput *output;
@property (nonatomic,strong)AVCaptureVideoPreviewLayer *preview;
@property(nonatomic, strong)UIImageView *imageView;//扫描框
@property(nonatomic, strong)UIImageView *scanImageView;//扫描线
@property(nonatomic, strong)UILabel *tipsLabel;//提示文字
@property(nonatomic, strong)NSTimer *timerScan;
@property(nonatomic, assign)BOOL isBottom;
@property(nonatomic, assign)CGFloat num;
@property (strong, nonatomic) AVAudioPlayer *beepPlayer;
@property(nonatomic, strong)AVCaptureVideoDataOutput *outputVideo;
@property (nonatomic,weak) UIView *retainViews;
@end
@implementation MUQRCodeManager
-(instancetype)initWithView:(UIView *)view backgroundImage:(UIImage *)backgroundImage scanlineImage:(UIImage *)scanlineImage{
if (self = [super init]) {
NSAssert(view != nil, @"view must not nil"); //第一个参数是条件,如果第一个参数不满足条件,就会记录和打印第二个参数
NSAssert(backgroundImage != nil, @"backgroundImage must not nil"); //第一个参数是条件,如果第一个参数不满足条件,就会记录和打印第二个参数
NSAssert(scanlineImage != nil, @"backgroundImage must not nil"); //第一个参数是条件,如果第一个参数不满足条件,就会记录和打印第二个参数
_retainViews = view;
[self configuredUI:backgroundImage scanImage:scanlineImage];
//初始化照相机
[self setupCamera];
}
return self;
}
//设置UI
-(void)configuredUI:(UIImage *)backgroundImage scanImage:(UIImage *)scanImage{
[self.retainViews addSubview:self.imageView];
[self.retainViews addSubview:self.scanImageView];
[self.retainViews addSubview:self.tipsLabel];
self.imageView.image = backgroundImage;
self.scanImageView.image = scanImage;
[self conguredImageView:backgroundImage];
NSString * wavPath = [[NSBundle mainBundle] pathForResource:@"beep" ofType:@"wav"];
NSData* data = [[NSData alloc] initWithContentsOfFile:wavPath];
_beepPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
}
-(void)conguredImageView:(UIImage *)image{
if (image) {
CGRect rect = [self rectByImage:image];
self.imageView.frame = rect;
self.imageView.image = image;
CGFloat imageWithFlex = CGRectGetHeight(self.retainViews.frame) * .38;
CGPoint center = self.imageView.center;
center.y = imageWithFlex;
self.imageView.center = center;
}
}
-(void)setTipsString:(NSString *)tipsString{
_tipsString = tipsString;
if (tipsString) {
_tipsLabel.text = tipsString;
[_tipsLabel sizeToFit];
CGPoint center = CGPointZero;
CGFloat height = CGRectGetHeight(_imageView.frame);
center.x = _imageView.center.x;
center.y = _imageView.center.y + height/2. + 24.;
_tipsLabel.center = center;
}
}
//开始扫描
- (void)startScanning;
{
if (_session) {
[_session startRunning];
}
if(_timerScan){
[_timerScan invalidate];
_timerScan = nil;
}
if (self.imageView.image) {//有背景图才开始扫描
_timerScan = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(scanAnimate) userInfo:nil repeats:YES];
}
}
- (void)stopScanning;
{
if ([self.session isRunning]) {
[self.session stopRunning];
}
if(_timerScan)
{
[_timerScan invalidate];
_timerScan = nil;
}
}
- (void)scanAnimate
{
if (!self.isBottom) {
self.num += 1;
_scanImageView.frame = CGRectMake(CGRectGetMinX(_imageView.frame)+5.f, CGRectGetMinY(_imageView.frame)+5.f+2*self.num, CGRectGetWidth(_imageView.frame) - 10.f, 2.);
if (self.num == (NSInteger)((CGRectGetHeight(_imageView.frame) - 10.f)/2.)) {
self.isBottom = YES;
}
}else{
self.num -= 1;
_scanImageView.frame = CGRectMake(CGRectGetMinX(_imageView.frame)+5.f, CGRectGetMinY(_imageView.frame)+5.f+2*self.num, CGRectGetWidth(_imageView.frame) - 10.f, 2.);
if (self.num == 0) {
self.isBottom = NO;
}
}
}
#pragma mark -lazy loading
//背景图片
-(UIImageView *)imageView{
if (!_imageView) {
_imageView = [[UIImageView alloc]initWithFrame:CGRectZero];
}
return _imageView;
}
//扫描线
-(UIImageView *)scanImageView{
if (!_scanImageView) {
_scanImageView = [[UIImageView alloc]initWithFrame:CGRectZero];
}
return _scanImageView;
}
-(UILabel *)tipsLabel{
if (!_tipsLabel) {
_tipsLabel = [UILabel new];
_tipsLabel.textAlignment = NSTextAlignmentCenter;
_tipsLabel.font = [UIFont systemFontOfSize:12.];
_tipsLabel.textColor = [UIColor lightGrayColor];
}
return _tipsLabel;
}
-(CGRect)rectByImage:(UIImage *)image{
CGFloat imageWithFlex = CGRectGetWidth(self.retainViews.frame) * .62;
CGFloat imageWidth = CGImageGetWidth(image.CGImage)/2.;
CGFloat imageHeight = CGImageGetHeight(image.CGImage)/2.;
if (imageWidth > imageWithFlex) {
imageWidth = imageHeight = imageWithFlex;
}
CGFloat imageX = (CGRectGetWidth(self.retainViews.bounds) - imageWidth)/2.;
CGFloat imageY = (CGRectGetHeight(self.retainViews.bounds) - imageHeight)/2.;
return CGRectMake(imageX, imageY, imageWidth, imageHeight);
}
//单独设置照相机
- (void)setupCamera{
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];// Device
NSError *error;
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];// Input
_output= [[AVCaptureMetadataOutput alloc]init];// Output
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
_outputVideo = [[AVCaptureVideoDataOutput alloc]init];
[_outputVideo setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
_session= [[AVCaptureSession alloc]init];// Session
[_session setSessionPreset:AVCaptureSessionPresetHigh];
if([_session canAddInput:_input]){
[_session addInput:_input];
}
if([_session canAddOutput:_output]){
[_session addOutput:_output];
}
if ([self.session canAddOutput:_outputVideo]) {
[self.session addOutput:_outputVideo];
}
//条码类型AVMetadataObjectTypeQRCode
_output.metadataObjectTypes=@[
AVMetadataObjectTypeQRCode,
AVMetadataObjectTypeUPCECode,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeAztecCode,
AVMetadataObjectTypeCode39Code,
AVMetadataObjectTypeCode93Code,
AVMetadataObjectTypePDF417Code,
AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypeCode39Mod43Code,
];
__weak typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
//更新界面
weakSelf.preview=[AVCaptureVideoPreviewLayer layerWithSession:weakSelf.session];
weakSelf.preview.videoGravity=AVLayerVideoGravityResizeAspectFill;
weakSelf.preview.frame = CGRectMake(0, 0, CGRectGetWidth(weakSelf.retainViews.frame), CGRectGetHeight(weakSelf.retainViews.frame));
[weakSelf.retainViews.layer insertSublayer:weakSelf.preview atIndex:0];
// [_preview setAffineTransform:CGAffineTransformMakeScale(1.5,1.5)];
CGRect rect = weakSelf.imageView.frame;
[weakSelf.output setRectOfInterest:CGRectMake(rect.origin.y/weakSelf.preview.frame.size.height,rect.origin.x/weakSelf.preview.frame.size.width,rect.size.height/ weakSelf.preview.frame.size.height ,rect.size.width/ weakSelf.preview.frame.size.width )];
[weakSelf.preview setAffineTransform:CGAffineTransformMakeScale(1.5,1.5)];
weakSelf.retainViews.clipsToBounds = YES;
weakSelf.retainViews.layer.masksToBounds = YES;
});
}
-(void)clickedColose:(UIControl *)control{
if ([self.session isRunning]) {
[self.session stopRunning];
}
if(_timerScan)
{
[_timerScan invalidate];
_timerScan = nil;
}
}
#pragma mark - AVCaptureMetadataOutputObjects Delegate Methods
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
[_beepPlayer play];
if (self.QRCodeScanedResult) {
AVMetadataMachineReadableCodeObject *data = metadataObjects.firstObject;
self.QRCodeScanedResult(metadataObjects,data.stringValue);
}
[self stopScanning];
}
#pragma mark- AVCaptureVideoDataOutputSampleBufferDelegate的方法
/*- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
CFRelease(metadataDict);
NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
// NSLog(@"%f",brightnessValue);
// 根据brightnessValue的值来打开和关闭闪光灯
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
BOOL result = [device hasTorch];// 判断设备是否有闪光灯
if ((brightnessValue < 0) && result) {// 打开闪光灯
[device lockForConfiguration:nil];
[device setTorchMode: AVCaptureTorchModeOn];//开
[device unlockForConfiguration];
}else if((brightnessValue > 0) && result) {// 关闭闪光灯
[device lockForConfiguration:nil];
[device setTorchMode: AVCaptureTorchModeOff];//关
[device unlockForConfiguration];
}
}
#pragma mark - 检测相机是否可用
-(BOOL)authority{
NSString *mediaType = AVMediaTypeVideo;//读取媒体类型
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];//读取设备授权状态
if (authStatus == AVAuthorizationStatusAuthorized) {
return YES;
}
return NO;
}
*/
@end