android开发 如何实现扫描本地二维码图片

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android开发 如何实现扫描本地二维码图片相关的知识,希望对你有一定的参考价值。

开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发。

    如何将zxing的Android源码导入工程。

      在导入zxing的android源码之前,先去官方下载zxing的源码http://code.google.com/p/zxing/downloads/list。

      这里以1.6版本为例,zxing 1.6源码结构如下:


      其中android文件夹就是android平台下的官方例子,在导入之前先要对core文件下的源码进行编译,得到核心包core.jar。

      编译方法请参照:http://blog.163.com/yimigao@126/blog/static/671560502011611111116747/

      然后就可以导入android平台下的例子了,导入方法如下:

        打开Eclipse,新建android项目:(注意不要直接把android文件夹拷到workspace下导入,那样会无法导入)


        导入核心包core.jar。

        修改strings.xml文件。在导入core.jar之后工程还是会有下面的错误,出现这种错误可能是由于字符错误导致的,只需要把所有的%s 和%f改成 %1s和f   即可

        修改完之后重新清理项目,此时已经没有错误了

      将zxing代码嵌入自己的工程

        在自己的工程中嵌入简化的zxing代码即可实现二维码生成和识别功能

        嵌入方法:

          将上述简化的代码拖到自己工程目录下;

          将values文件夹和raw文件夹复制自己工程目录下;

        建立CaptureActivity.java的布局文件capture.xml:

        <?xml version="1.0" encoding="utf-8"?>
        <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
            <SurfaceView
                android:id="@+id/preview_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center" />
            <com.zxing.view.ViewfinderView
                android:id="@+id/viewfinder_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_gravity="center"
                android:orientation="vertical" >
                <TextView
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:layout_centerInParent="true"
                    android:gravity="center"
                    android:paddingBottom="10dp"
                    android:paddingTop="10dp"
                    android:text="Scan Barcode"
                    android:textColor="@android:color/white"
                    android:textSize="18sp"
                    android:textStyle="bold" />
                <Button
                    android:id="@+id/btn_cancel_scan"
                    android:layout_width="230dp"
                    android:layout_height="40dp"
                    android:layout_alignParentBottom="true"
                    android:layout_centerInParent="true"
                    android:layout_marginBottom="75dp"
                    android:text="Cancel"
                    android:textSize="15sp"
                    android:textStyle="bold" />
                
            </RelativeLayout>
        </FrameLayout>


        导入core.jar包

      修改AndrodMainfest.xml

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.qrcode"
            android:versionCode="1"
            android:versionName="1.0">
          <uses-sdk android:minSdkVersion="7" />
          
          <uses-permission android:name="android.permission.VIBRATE" />  <!-- 震动权限 -->
          <uses-permission android:name="android.permission.CAMERA" />
          <uses-feature android:name="android.hardware.camera" />        <!-- 使用照相机权限 -->
          <uses-feature android:name="android.hardware.camera.autofocus" />   <!-- 自动聚焦权限 -->
          <application android:icon="@drawable/icon" android:label="@string/app_name">
              <activity android:name=".MainActivity"
                        android:label="@string/app_name">
                  <intent-filter>
                      <action android:name="android.intent.action.MAIN" />
                      <category android:name="android.intent.category.LAUNCHER" />
                  </intent-filter>
              </activity>
              
              <!-- 隐藏键盘 --><!-- 全屏 -->
              <activity
                  android:configChanges="orientation|keyboardHidden"    
                  android:name="com.zxing.activity.CaptureActivity"
                  android:screenOrientation="portrait"
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"    
                  android:windowSoftInputMode="stateAlwaysHidden" >
              </activity>
          </application>
      </manifest>

      这种情况大致就可以实现二维码扫描了,想细化的话,还可以多看看安卓二维码扫描开发相关的教程

参考技术A 得到图片,使用 zxing 库处理本回答被提问者和网友采纳

二维码扫描

   本文中我们介绍一下如何在iOS平台实现二维码扫描,我们可以借助一些优秀的第三方库,比如ZBar SDK和ZXing。在iOS7.0之后,我们也可以使用iOS系统原生扫描,通过AVFoundation框架来实现二维码扫描,不过AVFoundation框架不能识别相册中的二维码图片。

1. 通过AVFoundation框架识别二维码

1.1 AVFoundation框架扫描二维码的基本方法

我们先来介绍一下如何使用AVFoundation框架实现二维码扫描。在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架。之前我们使用AVFoundation框架实现过拍照功能,基本的原理差不多类似;需要AVCaptureSession对象管理输入流和输出流;需要一个AVCaptureVideoPreviewLayer对象来显示信息。基本流程如下:
这里写图片描述

图中涉及到的几个相关类的说明如下:

  • AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
  • AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
  • AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
  • AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
  • AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。

下面我们看一下具体的实现步骤:
示例代码:

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()<AVCaptureMetadataOutputObjectsDelegate>

@property (weak, nonatomic) IBOutlet UISwitch *lightSwitch;// 闪光开关
@property (nonatomic) AVCaptureSession *captureSession;//捕获的管理会话
@property (nonatomic) AVCaptureVideoPreviewLayer *previewLayer;// 预览图层

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

// 开始二维码扫描
- (IBAction)startScan:(UIButton *)sender {

    // 1. 初始化捕获会话,并添加输入对象
    self.captureSession = [[AVCaptureSession alloc] init];

    // 2. 初始化捕获设备对象AVCaptureDevice
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // 3. 初始化捕获设备的输入对象AVCaptureDeviceInput
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    if (input == nil) {
        NSLog(@"输入对象初始化失败");
        return;
    }

    // 将输入对象添加到会话
    [self.captureSession addInput:input];

    // 4. 初始化输出对象AVCaptureMetadataOutput
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];

    // 将输出对象添加到会话
    [self.captureSession addOutput:output];
    // 设置输出对象源数据类型:AVMetadataObjectTypeQRCode条码类型
    [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    // 设置输出对象代理,并实现代理方法
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

    // 设置扫码区域为预览区域 默认全屏扫描
    CGFloat w = self.view.frame.size.width;
    CGFloat h = self.view.frame.size.height;
    // rectOfInterest属性:区域大小是相对于设备的大小的,默认值是(0, 0, 1, 1)。但是区域的坐标系统X和Y是互换的,同时,宽高的比例也互换了。
    [output setRectOfInterest:CGRectMake((h/2 -100)/h, (w/2 -100)/w, 200/h, 200/w)];
    NSLog(@"%@",NSStringFromCGRect(output.rectOfInterest));

    // 5. 初始化预览图层
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;// 拉伸属性
    self.previewLayer.frame = self.view.bounds;
    [self.view.layer addSublayer:self.previewLayer];

    // 6.开始会话
    [self.captureSession startRunning];

    // 关闭闪光灯
    self.lightSwitch.on = NO;
    [self.view bringSubviewToFront:self.lightSwitch];
}

#pragma mark -
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
// 此方法是在识别到QRCode,并且完成转换。如果QRCode的内容越大,转换需要的时间就越长
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {

    if (metadataObjects != nil && [metadataObjects count] > 0) {

        // 扫码成功 停止扫描,
        [self.captureSession stopRunning];

        // 获取扫码结果:
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSString *result;
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            result = metadataObj.stringValue;
            NSLog(@"%@",result);
        } else {
            NSLog(@"不是二维码");
        }
    }
}

#pragma mark -
#pragma mark - 开启闪光灯
- (IBAction)lightOpenOrClose:(UISwitch *)sender {

    BOOL isOpen = sender.on;
    // 获取设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    if ([device hasTorch]) {
        [device lockForConfiguration:nil];
        if (isOpen) {
            [device setTorchMode:AVCaptureTorchModeOn];
        } else {
            [device setTorchMode:AVCaptureTorchModeOff];
        }
        [device unlockForConfiguration];
    }
}

@end

1.2 AVFoundation框架扫描二维码的功能封装
上面是系统自带的二维码扫描的基本功能实现,下面我们来实现一下在实际开发中二维码扫描的实际效果,不过就是添加了一条扫描的线条。
示例代码:
Scan2CodeViewController.h

#import <UIKit/UIKit.h>

@protocol ScanImageViewDelegate<NSObject>

- (void)reportScanResult:(NSString *)result;

@end

@interface Scan2CodeViewController : UIViewController

@property (nonatomic,weak)id <ScanImageViewDelegate>delegate;//代理方法传递数据

@end
示例代码:
Scan2CodeViewController.m
#import "Scan2CodeViewController.h"
#import <AVFoundation/AVFoundation.h>

#define SCANVIEW_EdgeTop 70.0
#define SCANVIEW_EdgeLeft 50.0
#define TINTCOLOR_ALPHA 0.2 //浅色透明度
#define DARKCOLOR_ALPHA 0.3 //深色透明度
#define VIEW_WIDTH [UIScreen mainScreen].bounds.size.width
#define VIEW_HEIGHT [UIScreen mainScreen].bounds.size.height

static const char *kScanQRCodeQueueName = "ScanQRCodeQueue";
@interface Scan2CodeViewController () <AVCaptureMetadataOutputObjectsDelegate>{
    //设置扫描画面
    UIView *_scanView;
    NSTimer *_timer;

    UIView *_QrCodeline;
    UIView *_QrCodeline1;
    UIImageView *_scanCropView;//扫描窗口
    UIButton *_lightButton;//灯光按钮
    AVCaptureSession *_captureSession;
    AVCaptureVideoPreviewLayer *_videoPreviewLayer;
}

@end

@implementation Scan2CodeViewController

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self stopTimer];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化扫描界面
    [self setScanView];

    // 开始扫描
    [self startReading];

    //启动定时器
    [self createTimer];
}

- (BOOL)startReading
{
    // 获取 AVCaptureDevice 实例
    NSError * error;
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    // 初始化输入流
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (!input) {
        NSLog(@"%@", [error localizedDescription]);
        return NO;
    }
    // 创建会话
    _captureSession = [[AVCaptureSession alloc] init];
    //提高图片质量为1080P,提高识别效果
    _captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;
    // 添加输入流
    [_captureSession addInput:input];
    // 初始化输出流
    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];

    //设置扫描范围
    captureMetadataOutput.rectOfInterest =CGRectMake((_scanCropView.frame.origin.y-10)/VIEW_HEIGHT, (_scanCropView.frame.origin.x-10)/VIEW_WIDTH, (_scanCropView.frame.size.width+10)/VIEW_HEIGHT, (_scanCropView.frame.size.height+10)/VIEW_WIDTH);

    // 添加输出流
    [_captureSession addOutput:captureMetadataOutput];

    // 创建dispatch queue.
    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL);
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
    // 设置元数据类型 AVMetadataObjectTypeQRCode
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];

    // 创建输出对象
    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

    [_videoPreviewLayer setFrame:_scanView.layer.bounds];
    [_scanView.layer insertSublayer:_videoPreviewLayer atIndex:0];
    // 开始会话
    [_captureSession startRunning];

    return YES;
}

- (void)stopReading
{
    // 停止会话
    [_captureSession stopRunning];
    _captureSession = nil;
}

#pragma mark -
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
      fromConnection:(AVCaptureConnection *)connection
{
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSString *result;
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            result = metadataObj.stringValue;
        } else {
            NSLog(@"不是二维码");
        }
        //调用代理对象的协议方法来实现数据传递
        [self dismissViewControllerAnimated:YES completion:nil];
        dispatch_async(dispatch_get_main_queue(), ^{
            if ([self.delegate respondsToSelector:@selector(reportScanResult:)]) {
                [self.delegate reportScanResult:result];
            }
        });
        [self stopReading];
    }
    return;
}
- (void)createTimer
{
    _timer=[NSTimer scheduledTimerWithTimeInterval:2.2 target:self selector:@selector(moveUpAndDownLine) userInfo:nil repeats:YES];
}
- (void)stopTimer
{
    if ([_timer isValid] == YES) {
        [_timer invalidate];
        _timer = nil;
    }

}

// 二维码的扫描区域
- (void)setScanView
{
    _scanView=[[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,VIEW_HEIGHT )];
    _scanView.backgroundColor=[UIColor clearColor];
    [self.view addSubview:_scanView];

    //最上部view
    UIView *upView = [[UIView alloc] initWithFrame:CGRectMake(0,0, VIEW_WIDTH,SCANVIEW_EdgeTop)];
    upView.alpha =TINTCOLOR_ALPHA;
    upView.backgroundColor = [UIColor blackColor];
    [_scanView addSubview:upView];

    //左侧的view
    UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, SCANVIEW_EdgeTop, SCANVIEW_EdgeLeft,VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)];
    leftView.alpha =TINTCOLOR_ALPHA;
    leftView.backgroundColor = [UIColor blackColor];
    [_scanView addSubview:leftView];

    // 中间扫描区
    _scanCropView=[[UIImageView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)];
    //scanCropView.image=[UIImage imageNamed:@""];
    _scanCropView.layer.borderColor=[UIColor greenColor].CGColor;
    _scanCropView.layer.borderWidth=2.0;
    _scanCropView.backgroundColor=[UIColor clearColor];
    [_scanView addSubview:_scanCropView];

    //右侧的view
    UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(VIEW_WIDTH - SCANVIEW_EdgeLeft,SCANVIEW_EdgeTop, SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft)];
    rightView.alpha =TINTCOLOR_ALPHA;
    rightView.backgroundColor = [UIColor blackColor];
    [_scanView addSubview:rightView];

    //底部view
    UIView *downView = [[UIView alloc] initWithFrame:CGRectMake(0, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop, VIEW_WIDTH, VIEW_HEIGHT - (VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop))];
    //downView.alpha = TINTCOLOR_ALPHA;
    downView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:TINTCOLOR_ALPHA];
    [_scanView addSubview:downView];

    //用于说明的label
    UILabel *labIntroudction= [[UILabel alloc] init];
    labIntroudction.backgroundColor = [UIColor clearColor];
    labIntroudction.frame=CGRectMake(0,5, VIEW_WIDTH,20);
    labIntroudction.numberOfLines=1;
    labIntroudction.font=[UIFont systemFontOfSize:15.0];
    labIntroudction.textAlignment=NSTextAlignmentCenter;
    labIntroudction.textColor=[UIColor whiteColor];
    labIntroudction.text=@"将二维码对准方框,即可自动扫描";
    [downView addSubview:labIntroudction];

    //取消button
    UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
    cancelButton.backgroundColor =[[UIColor blackColor] colorWithAlphaComponent:DARKCOLOR_ALPHA];
    cancelButton.frame =CGRectMake(0, 90, VIEW_WIDTH, 40);
    cancelButton.titleLabel.font =[UIFont systemFontOfSize:15.0];
    cancelButton.titleLabel.textAlignment = NSTextAlignmentCenter;
    [cancelButton setTitle:@"取消" forState:UIControlStateNormal];
    [cancelButton addTarget:self action:@selector(cancelAction) forControlEvents:UIControlEventTouchUpInside];
    [downView addSubview:cancelButton];

    //用于开关灯操作的button
    _lightButton = [UIButton buttonWithType:UIButtonTypeCustom];
    _lightButton.frame =CGRectMake(0, 40, VIEW_WIDTH, 40);
    [_lightButton setTitle:@"开启闪光灯" forState:UIControlStateNormal];
    [_lightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    _lightButton.backgroundColor =[[UIColor blackColor] colorWithAlphaComponent:DARKCOLOR_ALPHA];
    _lightButton.titleLabel.textAlignment=NSTextAlignmentCenter;
    _lightButton.titleLabel.font=[UIFont systemFontOfSize:15.0];
    [_lightButton addTarget:self action:@selector(openLight) forControlEvents:UIControlEventTouchUpInside];
    [downView addSubview:_lightButton];

    //画中间的基准线
    _QrCodeline = [[UIView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH- 2 * SCANVIEW_EdgeLeft, 2)];
    _QrCodeline.backgroundColor = [UIColor greenColor];
    [_scanView addSubview:_QrCodeline];

    //画中间的基准线
    _QrCodeline1 = [[UIView alloc] initWithFrame:CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH- 2 * SCANVIEW_EdgeLeft, 2)];
    _QrCodeline1.backgroundColor = [UIColor greenColor];
    [_scanView addSubview:_QrCodeline1];

    // 先让第二根线运动一次,避免定时器执行的时差,让用户感到启动App后,横线就开始移动
    [UIView animateWithDuration:2.2 animations:^{

        _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1);
    }];


}

// 当地一根线到达底部时,第二根线开始下落运动,此时第一根线已经在顶部,当第一根线接着下落时,第二根线到达顶部.依次循环
- (void)moveUpAndDownLine
{
    CGFloat Y = _QrCodeline.frame.origin.y;
    if (Y == SCANVIEW_EdgeTop) {
        [UIView animateWithDuration:2.2 animations:^{

            _QrCodeline.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1);
        }];
        _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1);
    }
    else if (Y == VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2) {
        _QrCodeline.frame = CGRectMake(SCANVIEW_EdgeLeft, SCANVIEW_EdgeTop, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1);
        [UIView animateWithDuration:2.2 animations:^{

            _QrCodeline1.frame = CGRectMake(SCANVIEW_EdgeLeft, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft + SCANVIEW_EdgeTop - 2, VIEW_WIDTH - 2 * SCANVIEW_EdgeLeft, 1);
        }];
    }

}

//照明灯光
-(void)openLight{
    if ([_lightButton.titleLabel.text isEqualToString:@"开启闪光灯"]) {
        [self systemLightSwitch:YES];
    } else {
        [self systemLightSwitch:NO];
    }
}

- (void)systemLightSwitch:(BOOL)open
{
    if (open) {
        [_lightButton setTitle:@"关闭闪光灯" forState:UIControlStateNormal];
    } else {
        [_lightButton setTitle:@"开启闪光灯" forState:UIControlStateNormal];
    }
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    if ([device hasTorch]) {
        [device lockForConfiguration:nil];
        if (open) {
            [device setTorchMode:AVCaptureTorchModeOn];
        } else {
            [device setTorchMode:AVCaptureTorchModeOff];
        }
        [device unlockForConfiguration];
    }
}

// 取消button
- (void)cancelAction{
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

2. 使用ZBarSDK识别二维码

   在iOS7.0以前,大部分应用识别二维码都是通过第三方库来实现的。事实上,在主流APP中二维码/条形码的作用主要分三种表现形式来集成:
  • 调用手机摄像头并打开系统照相机全屏去拍摄。
  • 自定义照相机视图的frame,自己控制并添加相关扫码指南。
  • 识别相册图片中的二维码图片。

    首先我们先来看一下如何集成ZBarSDK:
    第一步:将 ZBarSDK导入到工程,并集成相关的框架,

  • AVFoundation.framework
  • CoreMedia.framework
  • CoreVideo.framework
  • QuartzCore.framework
  • libiconv.dylib
    如下图:
    这里写图片描述
    第二步:关闭代码优化
    导入相关框架后,系统编译仍然不通过,提示的错误如下:
    这里写图片描述
    这是由于系统代码优化产生的错误,将Xcode的bitcode选项设置为No就可以通过编译了。
    这里写图片描述

    第三步:导入头文件,初始化ZBar相机控制器,并实现相关代理;

  • 调用系统相机全屏拍摄,使用ZBarReaderViewController,并声明协议。
  • 自定义扫描窗口,使用ZBarReaderView,并声明协议。
  • 识别相册的二维码图片,使用ZBarReaderController,并声明

2.1 调用系统相机:

示例代码:

#import "ViewController.h"
#import "ZBarSDK.h"

@interface ViewController ()<ZBarReaderDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction)systemCamara:(id)sender {

    // 初始化扫码视图控制器
    ZBarReaderViewController *reader = [ZBarReaderViewController new];

    // 设置代理
    reader.readerDelegate = self;
    // 设置识别类型
    ZBarImageScanner *scanner = reader.scanner;
    [scanner setSymbology:ZBAR_I25
                   config:ZBAR_CFG_ENABLE
                       to:0];
    reader.showsZBarControls = YES;

    // 推出扫码视图控制器
    [self presentViewController:reader animated:YES completion:nil];

}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {

    id results = [info objectForKey:ZBarReaderControllerResults];
    ZBarSymbol * symbol;
    for(symbol in results) {

        NSString *result = symbol.data;
        NSLog(@"%@",result);
    }

    // 退出拍照界面
    [picker dismissViewControllerAnimated:YES completion:nil];

}

@end

注释:
直接调用系统相机来实现二维码扫描虽然简单,但是存在极大的问题,那就是这样只能做全屏扫描,不能自定义二维码扫描的选取框。

2.2 自定义扫描窗口

项目中实现的二维码扫描功能我们发现都是可以设置扫描范围内的,下面我们来看一下如何自定义扫描的窗口。

示例代码:

#import "ViewController.h"
#import "ZBarSDK.h"

@interface ViewController ()<ZBarReaderViewDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark -
#pragma mark - 自定义扫描窗口
- (IBAction)scan2Code:(id)sender {

    // 初始化扫描窗口
    ZBarReaderView *readerView = [[ZBarReaderView alloc] init];

    // 自定义大小
    readerView.frame = CGRectMake(self.view.frame.size.width/2-100, self.view.frame.size.height/2-100, 200, 200);

    // 设置代理
    readerView.readerDelegate = self;

    // 添加到父视图
    [self.view addSubview:readerView];

    // 二维码识别设置
    ZBarImageScanner *scanner = readerView.scanner;
    [scanner setSymbology:ZBAR_I25
                   config:ZBAR_CFG_ENABLE
                       to:0];

    // 开始扫描
    [readerView start];

}

#pragma mark - ZBarReaderViewDelegate
- (void)readerView:(ZBarReaderView *)readerView didReadSymbols:(ZBarSymbolSet *)symbols fromImage:(UIImage *)image {

    // 获取扫描的标识
    ZBarSymbol *symbol = nil;
    for (symbol in symbols) {

        NSString *result = symbol.data;

        NSLog(@"%@",result);
    }
    // 停止扫描
    [readerView stop];
}

@end

2.3 识别相册中的二维码图片:

使用ZBarSDK可以直接选中相册中的二维码图片进行识别,这是系统自带的识别功能所不具备的。下面是识别相册中的二维码图片的实现方法。

示例代码:

#import "ViewController.h"
#import "ZBarSDK.h"

@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

// 识别相册图片中的二维码
- (IBAction)pick2Code:(id)sender {

    // 进入相册选中相册中的二维码图片
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;// 图片来源为相册
    imagePicker.delegate = self;

    // 进入相册
    [self presentViewController:imagePicker animated:YES completion:nil];

}

#pragma mark -
#pragma mark - UIImagePickerControllerDelegate
// 选中图片后调用该方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {

    // 获取选中的图片
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    CGImageRef cgImage = image.CGImage;

    ZBarReaderController *reader = [[ZBarReaderController alloc] init];
    reader.delegate = self;
    ZBarSymbol *symbol = nil;
    for (symbol in [reader scanImage:cgImage]) {

        NSString *resulot = symbol.data;
        NSLog(@"%@",resulot);
    }

    // 识别结束后返回主界面
    [picker dismissViewControllerAnimated:YES completion:nil];
}

@end

以上是关于android开发 如何实现扫描本地二维码图片的主要内容,如果未能解决你的问题,请参考以下文章

H5混合开发二维码扫描以及调用本地摄像头

android 生成的二维码图片如何保存到sdcard? 这个我也不知道呢,能否告知

Android实现二维码扫描登录网页

Android基于Google Zxing实现二维码/条形码扫描生成二维码/条形码

Android 基于google Zxing实现二维码条形码扫描,仿微信二维码扫描效果

androidapp二维码扫码下载,途牛网站的效果,怎么实现?