Android平台下利用zxing实现二维码开发

2024-05-05 02:58

本文主要是介绍Android平台下利用zxing实现二维码开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing进行二维码开发。

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

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

  我这里下载的是1.6版本的,我试验了几个版本,发现2.0以后的版本实际用起来没有1.6和1.7版本的好用,最后选择了1.6版本。

  zxing 1.6源码结构如下:

 

  其中android文件夹就是android平台下的官方例子。

  在导入之前先要对core文件下的源码进行编译,得到核心包core.jar。

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

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

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

  

  2)导入核心包core.jar。

  3)修改strings.xml文件。在导入core.jar之后工程还是会有错误:

  

  出现这种错误可能是由于字符错误导致的,只需要把所有的%s 和%f改成 %1 s s和f   即可。

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

  

   4)运行效果:

  

2.代码简化

  上面代码中,很多功能我们在自己的项目中都用不到,因此需要对其进行简化,至于如何简化这里就不赘述了,网上有很多教程。下面只给出简化后的结果:

  

  如果只进行二维码识别和二维码生成的话,只需要上面包中的文件。其中CaptureActivity.java是拍照取景的类,camera包下面的类主要与照相机相关的类,decoding和encoding是解码和编码相关的类,view是取景框相关的类。

3.将简化的zxing代码嵌入自己的工程。

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

  嵌入方法:

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

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

  3)建立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" ><SurfaceViewandroid:id="@+id/preview_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center" /><com.zxing.view.ViewfinderViewandroid:id="@+id/viewfinder_view"android:layout_width="wrap_content"android:layout_height="wrap_content" /><RelativeLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_gravity="center"android:orientation="vertical" ><TextViewandroid: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" /><Buttonandroid: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>
复制代码

  3)导入core.jar包

  4)修改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><!-- 隐藏键盘 --><!-- 全屏 --><activityandroid: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>
复制代码

  5)运行效果:

   

  在这里识别二维码之后是把结果返回到上一个activity显示,所以在MainActivity中调用方法是:

Intent openCameraIntent = new Intent(MainActivity.this,CaptureActivity.class);
startActivityForResult(openCameraIntent, 0);

  然后获取结果在onActivityResult中进行:

复制代码
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == RESULT_OK) {Bundle bundle = data.getExtras();String scanResult = bundle.getString("result");resultTextView.setText(scanResult);}}
复制代码

  如果要直接在CaptureActivity中弹出识别结果,可以更改CaptureActivity.java的handleDecode方法:

复制代码
public void handleDecode(Result result, Bitmap barcode) {inactivityTimer.onActivity();playBeepSoundAndVibrate();String resultString = result.getText();//FIXMEif (resultString.equals("")) {Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();}else {
//            System.out.println("Result:"+resultString);Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString("result", resultString);resultIntent.putExtras(bundle);this.setResult(RESULT_OK, resultIntent);}CaptureActivity.this.finish();}
复制代码

  上述代码是得到结果之后传给之前调用CaptureActivity的activity,所以如果要改的话只需要把else语句块下面的语句和最后一句finish注释掉,补上自己的代码就可以了。比如可以改成:

复制代码
public void handleDecode(Result result, Bitmap barcode) {inactivityTimer.onActivity();playBeepSoundAndVibrate();final String resultString = result.getText();//FIXMEif (resultString.equals("")) {Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();}else {
//            System.out.println("Result:"+resultString);/*Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString("result", resultString);resultIntent.putExtras(bundle);this.setResult(RESULT_OK, resultIntent);*/AlertDialog resutlDialog = new AlertDialog.Builder(CaptureActivity.this).create();resutlDialog.setTitle("扫描结果");resutlDialog.setMessage(resultString);resutlDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}});    resutlDialog.show();}//CaptureActivity.this.finish();}
复制代码

  我的工程源码下载:http://files.cnblogs.com/dolphin0520/QRCode.rar

3.关于zxing源码的若干问题。

  在实际使用过程中发现zxing源码存在一些问题,下面逐一来说一下:

  1)竖屏问题。

  zxing给出的官方例子是横屏的,但是对于手机实际上竖屏操作更加方便一点,如果要改成竖屏,需要修改以下几个文件:

  首先将AndrodMainfest.xml下CaptureActivity的配置改为竖屏:

android:screenOrientation="portrait"

  然后需要修改CameraConfigurationManager.java下的setDesiredCameraParameters方法,该方法直接使用

camera.setDisplayOrientation(90);

  来让屏幕旋转90度,这个办法在android 2.2版本以后是可行的,但是2.2之前的版本并没有提供这个接口,因此需要对sdk版本进行判断:

复制代码
if (Integer.parseInt(Build.VERSION.SDK) >=8) setDisplayOrientation(camera, 90);    else {     if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {      parameters.set("orientation", "portrait");      parameters.set("rotation", 90);     }     if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {      parameters.set("orientation", "landscape");      parameters.set("rotation", 90);     }  }   
复制代码

  在修改为竖屏之后发现取景框会发生拉伸,需要进行以下几点修改:

  在CameraManager.java中将:

rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;

  修改为:

rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;

  然后将DecodeHandler类中的方法decode改为:

复制代码
private void decode(byte[] data, int width, int height) {long start = System.currentTimeMillis();Result rawResult = null;//modify herebyte[] rotatedData = new byte[data.length];for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++)rotatedData[x * height + height - y - 1] = data[x + y * width];}int tmp = width; // Here we are swapping, that's the difference to #11width = height;height = tmp;PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));try {rawResult = multiFormatReader.decodeWithState(bitmap);} catch (ReaderException re) {// continue} finally {multiFormatReader.reset();}if (rawResult != null) {long end = System.currentTimeMillis();Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);Bundle bundle = new Bundle();bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());message.setData(bundle);//Log.d(TAG, "Sending decode succeeded message...");
      message.sendToTarget();} else {Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);message.sendToTarget();}}
复制代码

  再将CameraConfigurationManager类中的方法initFromCameraParameters修改为:

复制代码
void initFromCameraParameters(Camera camera) {Camera.Parameters parameters = camera.getParameters();previewFormat = parameters.getPreviewFormat();previewFormatString = parameters.get("preview-format");Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = manager.getDefaultDisplay();screenResolution = new Point(display.getWidth(), display.getHeight());Log.d(TAG, "Screen resolution: " + screenResolution);Point screenResolutionForCamera = new Point();screenResolutionForCamera.x = screenResolution.x;screenResolutionForCamera.y = screenResolution.y;// preview size is always something like 480*320, other 320*480if (screenResolution.x < screenResolution.y) {screenResolutionForCamera.x = screenResolution.y;screenResolutionForCamera.y = screenResolution.x;}cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);//cameraResolution = getCameraResolution(parameters, screenResolution);Log.d(TAG, "Camera resolution: " + screenResolution);}
复制代码

  最后将PlanarYUVLuminanceSource.java中的renderCroppedGreyscaleBitmap方法改为:

复制代码
public Bitmap renderCroppedGreyscaleBitmap() {int width = getWidth();int height = getHeight();int[] pixels = new int[width * height];byte[] yuv = yuvData;int inputOffset = top * dataHeight + left;for (int y = 0; y < height; y++) {int outputOffset = y * width;for (int x = 0; x < width; x++) {int grey = yuv[inputOffset + x] & 0xff;pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);}inputOffset += dataHeight;}Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmap.setPixels(pixels, 0, width, 0, 0, width, height);return bitmap;}
复制代码

  3)取景框的绘制

  取景框的绘制可以参照这篇博文:http://www.cnblogs.com/forrestsun/archive/2012/11/06/2757005.html

  4)闪光灯的开启和关闭

  如果需要开启和关闭闪光灯,在CameraManager.java中添加2个方法:

复制代码
  public void openLight()   //打开闪光灯
    {if(camera!=null){Parameters parameter=camera.getParameters();  parameter.setFlashMode(Parameters.FLASH_MODE_TORCH); camera.setParameters(parameter);}}public void closeLight()  //关闭闪光灯
    {if(camera!=null){Parameters parameter=camera.getParameters();  parameter.setFlashMode(Parameters.FLASH_MODE_OFF); camera.setParameters(parameter);}}
复制代码

  然后在CaptureActivity中的initCamera方法中打开闪光灯:

CameraManager.get().openDriver(surfaceHolder);
CameraManager.get().openLight();   //开闪光灯

  在需要的地方关闭闪光灯即可。

  5)连续扫描问题

  如果在识别二维码成功之后,需要连续多次扫描二维码,只需在扫描完成之后添加代码(在CaptureActivity的dandleDecode方法中添加):

if(handler!=null)     //实现连续扫描handler.restartPreviewAndDecode();

  比如:

复制代码
public void handleDecode(Result result, Bitmap barcode) {inactivityTimer.onActivity();playBeepSoundAndVibrate();final String resultString = result.getText();//FIXMEif (resultString.equals("")) {Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();}else {
//            System.out.println("Result:"+resultString);/*Intent resultIntent = new Intent();Bundle bundle = new Bundle();bundle.putString("result", resultString);resultIntent.putExtras(bundle);this.setResult(RESULT_OK, resultIntent);*/AlertDialog resutlDialog = new AlertDialog.Builder(CaptureActivity.this).create();resutlDialog.setTitle("扫描结果");resutlDialog.setMessage(resultString);resutlDialog.setButton(AlertDialog.BUTTON_POSITIVE, "打开链接", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();if(!isLegalUrl(resultString))   //如果url不合法
                    {Toast.makeText(getApplicationContext(), "该链接不是合法的URL", Toast.LENGTH_SHORT).show();if(handler!=null)     //实现连续扫描
                            handler.restartPreviewAndDecode();return;}Intent intent = new Intent();      //打开链接   intent.setAction("android.intent.action.VIEW");    Uri content_url = Uri.parse(resultString);   intent.setData(content_url);  startActivity(intent);}});resutlDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();if(handler!=null)     //实现连续扫描
                        handler.restartPreviewAndDecode();}});    resutlDialog.show();}//CaptureActivity.this.finish();}
复制代码

  6)识别完成之后的震动。

  如果需要取消二维码识别之后的震动,只需要在CaptureActivity类的onResume方法中将vibrate 设置为false即可。

  7)修改取景框距屏幕顶部位置

  如果需要修改取景框距屏幕顶部位置,只需要修改CameraManager.java的getFramingRect方法,在getFramingRect方法中,

int topOffset = (screenResolution.y - height) / 2

  这句是控制取景框到屏幕顶部的距离,若需要减小距屏幕顶部的距离,只需要将分母变大即可。

  8)取景框下方提示文字的绘制。

  在ViewfinderView.java的 Collection<ResultPoint> currentPossible = possibleResultPoints前面加入以下代码:

  

复制代码
TextPaint textPaint = new TextPaint();           
textPaint.setARGB(
0xFF, 0xFF, 0xFF,0xFF); //字体颜色 textPaint.setTextSize(TEXT_SIZE * density); textPaint.setAntiAlias(true); //设置抗锯齿,否则字迹会很模糊
StaticLayout layout = new StaticLayout(getResources().getString(R.string.scan_text),textPaint,frame.right-frame.left,Alignment.ALIGN_NORMAL,1.0F,0.0F,true); canvas.translate(frame.left, (float) (frame.bottom + (float)TEXT_PADDING_TOP *density)); //绘制起始位置 layout.draw(canvas);
复制代码

  这里解释一下,textPaint.setAntiAlias(true); 是设置为抗锯齿,否则字体会很模糊。StaticLayout的第一个参数就是要绘制的字符串,第二个是画笔,第三个参数是设置每一行的宽度,即超过该宽度就换行,第四个是对齐方式。

  canvas.translate(frame.left, (float) (frame.bottom + (float)TEXT_PADDING_TOP *density))的参数是绘制字符串的起始位置。

  9)乱码问题

  在扫描一部分二维码时会出现乱码的情况,是由于编码的问题,可以参照这篇文章:

  http://www.2cto.com/kf/201209/152900.html

  如果不想编译core包,我的工程源码中的core包是已经改好了的,可以识别GBK二维码,需要的朋友可以直接拿去用。

  关于zxing 二维码识别的问题暂时就讨论这么多,有兴趣的朋友可以读源码深入研究一下。

 

作者: 海子
    
出处: http://www.cnblogs.com/dolphin0520/
    
本博客中未标明转载的文章归作者 海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

这篇关于Android平台下利用zxing实现二维码开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/960671

相关文章

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log