天天看点

iOS中 扫描二维码/生成二维码详解

指示根视图:

self.window.rootviewcontroller = [[uinavigationcontroller alloc]initwithrootviewcontroller:[secondviewcontroller new]];  

生成二维码:

//  created by 韩俊强 on 15/11/27.  

//  copyright (c) 2015年 韩俊强. all rights reserved.  

//  

#import "secondviewcontroller.h"  

@interface secondviewcontroller ()  

@property (nonatomic, strong) uitextfield *tfcode;  

@property (nonatomic, strong) uibutton *btngenerate;  

@property (nonatomic, strong) uiimageview *imageview;  

@end  

@implementation secondviewcontroller  

- (void)viewdidload {  

    [super viewdidload];  

    cgsize windowsize = [uiscreen mainscreen].bounds.size;  

    self.tfcode = [[uitextfield alloc] initwithframe:cgrectmake(10, 64, windowsize.width-100, 40)];  

    [self.view addsubview:self.tfcode];  

    self.tfcode.borderstyle = uitextborderstyleroundedrect;  

    self.btngenerate = [[uibutton alloc] initwithframe:cgrectmake(windowsize.width-100, 64, 90, 40)];  

    [self.view addsubview:self.btngenerate];  

    [self.btngenerate addtarget:self action:@selector(actiongenerate) forcontrolevents:uicontroleventtouchupinside];  

    self.btngenerate.backgroundcolor = [uicolor lightgraycolor];  

    [self.btngenerate settitle:@"生成" forstate:uicontrolstatenormal];  

    [self.btngenerate settitlecolor:[uicolor blackcolor] forstate:uicontrolstatenormal];  

    self.imageview = [[uiimageview alloc] initwithframe:cgrectmake(0, 0, 300, 300)];  

    [self.view addsubview:self.imageview];  

    self.imageview.center = cgpointmake(windowsize.width/2, windowsize.height/2);  

    self.tfcode.text = @"http://www.baidu.com";  

}  

- (void)actiongenerate  

{  

    nsstring *text = self.tfcode.text;  

    nsdata *stringdata = [text datausingencoding: nsutf8stringencoding];  

    //生成  

    cifilter *qrfilter = [cifilter filterwithname:@"ciqrcodegenerator"];  

    [qrfilter setvalue:stringdata forkey:@"inputmessage"];  

    [qrfilter setvalue:@"m" forkey:@"inputcorrectionlevel"];  

    uicolor *oncolor = [uicolor blackcolor];  

    uicolor *offcolor = [uicolor whitecolor];  

    //上色  

    cifilter *colorfilter = [cifilter filterwithname:@"cifalsecolor" keysandvalues:@"inputimage",qrfilter.outputimage,@"inputcolor0",[cicolor colorwithcgcolor:oncolor.cgcolor],@"inputcolor1",[cicolor colorwithcgcolor:offcolor.cgcolor],nil];  

    ciimage *qrimage = colorfilter.outputimage;  

    //绘制  

    cgsize size = cgsizemake(300, 300);  

    cgimageref cgimage = [[cicontext contextwithoptions:nil] createcgimage:qrimage fromrect:qrimage.extent];  

    uigraphicsbeginimagecontext(size);  

    cgcontextref context = uigraphicsgetcurrentcontext();  

    cgcontextsetinterpolationquality(context, kcginterpolationnone);  

    cgcontextscalectm(context, 1.0, -1.0);  

    cgcontextdrawimage(context, cgcontextgetclipboundingbox(context), cgimage);  

    uiimage *codeimage = uigraphicsgetimagefromcurrentimagecontext();  

    uigraphicsendimagecontext();  

    cgimagerelease(cgimage);  

    self.imageview.image = codeimage;  

扫描二维码:

#import "rootviewcontroller.h"  

#import <avfoundation/avfoundation.h>  

@interface rootviewcontroller ()<avcapturemetadataoutputobjectsdelegate,uialertviewdelegate>  

@property (nonatomic, strong) uiview *scanrectview;  

// 硬件设备  

@property (strong, nonatomic) avcapturedevice            *device;  

//输入设备  

@property (strong, nonatomic) avcapturedeviceinput       *input;  

//输出设备  

@property (strong, nonatomic) avcapturemetadataoutput    *output;  

//桥梁.连接输入和输出设备,  

@property (strong, nonatomic) avcapturesession           *session;  

@property (strong, nonatomic) avcapturevideopreviewlayer *preview;  

@implementation rootviewcontroller  

    cgsize scansize = cgsizemake(windowsize.width*3/4, windowsize.width*3/4);  

    cgrect scanrect = cgrectmake((windowsize.width-scansize.width)/2, (windowsize.height-scansize.height)/2, scansize.width, scansize.height);  

    scanrect = cgrectmake(scanrect.origin.y/windowsize.height, scanrect.origin.x/windowsize.width, scanrect.size.height/windowsize.height,scanrect.size.width/windowsize.width);  

    self.device = [avcapturedevice defaultdevicewithmediatype:avmediatypevideo];  

    self.input = [avcapturedeviceinput deviceinputwithdevice:self.device error:nil];  

    self.output = [[avcapturemetadataoutput alloc]init];  

    [self.output setmetadataobjectsdelegate:self queue:dispatch_get_main_queue()];  

    self.session = [[avcapturesession alloc]init];  

    [self.session setsessionpreset:([uiscreen mainscreen].bounds.size.height<500)?avcapturesessionpreset640x480:avcapturesessionpresethigh];  

    [self.session addinput:self.input];  

    [self.session addoutput:self.output];  

    self.output.metadataobjecttypes=@[avmetadataobjecttypeqrcode];  

    self.output.rectofinterest = scanrect;  

    self.preview = [avcapturevideopreviewlayer layerwithsession:self.session];  

    self.preview.videogravity = avlayervideogravityresizeaspectfill;  

    self.preview.frame = [uiscreen mainscreen].bounds;  

    [self.view.layer insertsublayer:self.preview atindex:0];  

    self.scanrectview = [uiview new];  

    [self.view addsubview:self.scanrectview];  

    self.scanrectview.frame = cgrectmake(0, 0, scansize.width, scansize.height);  

    self.scanrectview.center = cgpointmake(cgrectgetmidx([uiscreen mainscreen].bounds), cgrectgetmidy([uiscreen mainscreen].bounds));  

    self.scanrectview.layer.bordercolor = [uicolor redcolor].cgcolor;  

    self.scanrectview.layer.borderwidth = 1;  

    //开始捕获  

    [self.session startrunning];  

- (void)captureoutput:(avcaptureoutput *)captureoutput didoutputmetadataobjects:(nsarray *)metadataobjects fromconnection:(avcaptureconnection *)connection  

    if ( (metadataobjects.count==0) )  

    {  

        return;  

    }  

    if (metadataobjects.count>0) {  

        [self.session stoprunning];  

        avmetadatamachinereadablecodeobject *metadataobject = metadataobjects.firstobject;  

        //输出扫描字符串  

        uialertview *alert = [[uialertview alloc] initwithtitle:metadataobject.stringvalue message:@"" delegate:self cancelbuttontitle:@"ok" otherbuttontitles: nil nil];  

        [alert show];  

- (void)alertview:(uialertview *)alertview willdismisswithbuttonindex:(nsinteger)buttonindex  

新浪微博

最终效果:(由于扫描二维码无法展示效果,所以自己动手真机测试吧!)

iOS中 扫描二维码/生成二维码详解

ios7之前,开发者进行扫码编程时,一般会借助第三方库。常用的是zbarsdk,ios7之后,系统的avmetadataobject类中,为我们提供了解析二维码的接口。经过测试,使用原生api扫描和处理的效率非常高,远远高于第三方库。

官方提供的接口非常简单,代码如下:

<a target="_blank" href="http://my.oschina.net/u/2340880/blog/405847#">?</a>

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

<code>@interface viewcontroller ()&lt;avcapturemetadataoutputobjectsdelegate&gt;</code><code>//用于处理采集信息的代理</code>

<code>{</code>

<code>    </code><code>avcapturesession * session;</code><code>//输入输出的中间桥梁</code>

<code>}</code>

<code>@end</code>

<code>@implementation viewcontroller</code>

<code>- (</code><code>void</code><code>)viewdidload {</code>

<code>    </code><code>[super viewdidload];</code>

<code>    </code><code>// do any additional setup after loading the view, typically from a nib.</code>

<code>    </code><code>//获取摄像设备</code>

<code>    </code><code>avcapturedevice * device = [avcapturedevice defaultdevicewithmediatype:avmediatypevideo];</code>

<code>    </code><code>//创建输入流</code>

<code>    </code><code>avcapturedeviceinput * input = [avcapturedeviceinput deviceinputwithdevice:device error:nil];</code>

<code>    </code><code>//创建输出流</code>

<code>    </code><code>avcapturemetadataoutput * output = [[avcapturemetadataoutput alloc]init];</code>

<code>    </code><code>//设置代理 在主线程里刷新</code>

<code>    </code><code>[output setmetadataobjectsdelegate:self queue:dispatch_get_main_queue()];</code>

<code>    </code> 

<code>    </code><code>//初始化链接对象</code>

<code>    </code><code>session = [[avcapturesession alloc]init];</code>

<code>    </code><code>//高质量采集率</code>

<code>    </code><code>[session setsessionpreset:avcapturesessionpresethigh];</code>

<code>    </code><code>[session addinput:input];</code>

<code>    </code><code>[session addoutput:output];</code>

<code>    </code><code>//设置扫码支持的编码格式(如下设置条形码和二维码兼容)</code>

<code>    </code><code>output.metadataobjecttypes=@[avmetadataobjecttypeqrcode,avmetadataobjecttypeean13code, avmetadataobjecttypeean8code, avmetadataobjecttypecode128code];</code>

<code>       </code> 

<code>    </code><code>avcapturevideopreviewlayer * layer = [avcapturevideopreviewlayer layerwithsession:session];</code>

<code>    </code><code>layer.videogravity=avlayervideogravityresizeaspectfill;</code>

<code>    </code><code>layer.frame=self.view.layer.bounds;</code>

<code>    </code><code>[self.view.layer insertsublayer:layer atindex:0];</code>

<code>    </code><code>//开始捕获</code>

<code>    </code><code>[session startrunning];</code>

之后我们的ui上已经可以看到摄像头捕获的内容,只要实现代理中的方法,就可以完成二维码条形码的扫描:

<code>-(</code><code>void</code><code>)captureoutput:(avcaptureoutput *)captureoutput didoutputmetadataobjects:(nsarray *)metadataobjects fromconnection:(avcaptureconnection *)connection{</code>

<code>    </code><code>if</code> <code>(metadataobjects.count&gt;0) {</code>

<code>        </code><code>//[session stoprunning];</code>

<code>        </code><code>avmetadatamachinereadablecodeobject * metadataobject = [metadataobjects objectatindex : 0 ];</code>

<code>        </code><code>//输出扫描字符串</code>

<code>        </code><code>nslog(@</code><code>"%@"</code><code>,metadataobject.stringvalue);</code>

<code>    </code><code>}</code>

通过上面的代码测试,我们可以发现系统的解析处理效率是相当的高,ios官方提供的api也确实非常强大,然而,我们可以做进一步的优化,将效率更加提高:

首先,avcapturemetadataoutput类中有一个这样的属性(在ios7.0之后可用):

@property(nonatomic) cgrect rectofinterest;

这个属性大致意思就是告诉系统它需要注意的区域,大部分app的扫码ui中都会有一个框,提醒你将条形码放入那个区域,这个属性的作用就在这里,它可以设置一个范围,只处理在这个范围内捕获到的图像的信息。如此一来,可想而知,我们代码的效率又会得到很大的提高,在使用这个属性的时候。需要几点注意:

1、这个cgrect参数和普通的rect范围不太一样,它的四个值的范围都是0-1,表示比例。

2、经过测试发现,这个参数里面的x对应的恰恰是距离左上角的垂直距离,y对应的是距离左上角的水平距离。

3、宽度和高度设置的情况也是类似。

3、举个例子如果我们想让扫描的处理区域是屏幕的下半部分,我们这样设置

<code>output.rectofinterest=cgrectmake(0.5,0,0.5, 1);</code>

具体apple为什么要设计成这样,或者是这个参数我的用法那里不对,还需要了解的朋友给个指导。