专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > Go

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

发布时间:2011-06-29 17:58:31 文章来源:www.iduyao.cn 采编人员:星星草
Android基于Google Zxing实现二维码/条形码扫描、生成二维码/条形码


二维码/条形码生成器

二维码/条形码扫描器



一、二维码与条形码工作原理


目前的很多应用上都有扫码功能,当时微信推出二维码扫码功能时,觉得imagine,通过一张简单的图片就能扫描添加还有,还有分享名片功能(也是一张二维码图片,识别扫描)。

下面小编将通过文章主要介绍QRCode方面技术.

QRCode是被广泛应用的一种二维码,解码速度快。二维码相对于条形码来说,二维码的存储数据量更大,空间利用率高,有一定的容错性。

二维码原理介绍:

二维码是用某种特定的几何图形按一定的规律在平面上分布的黑白相间的图形记录数据符号信息的;

在代码编制上巧妙的利用构成计算机内部逻辑基础的0/1比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图像输入设备或光电扫描设备自动识读以实现信息自动处理;

二维码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息;

二维码相对于条形码的优势就是省空间;


QRCode基本结构


上图是一个QRCode的基本结构:

位置探测图形、位置探测图形分隔符、定位图形:用于二维码的定位,对每个QR来说,位置都是固定存在的,只是大小规格有所差异;

校正图形:确定规格,校正图形的数量和位置也就确定了;

格式信息:表示二维码的纠错级别,分为LMQH

版本信息:即二维码的规格,QR码符号共有40种规格的矩阵;

数据和纠错码字:实际保存的二维码信息,和纠错码字(用于修正二维码损坏带来的错误)。



条形码原理介绍:


 条形码扫描器结构


由于不同颜色的物体,其反射的可见光的波长不同,所以当条形码扫描器光源发出的光经光阑及凸透镜1后,照射到黑白相间的条形码上时,反射光经凸透镜2聚焦后,照射到光电转换器上,于是光电转换器接受到与白条和黑条相对应的强弱不同的反射光信号,并转换成相应的电信号输出到放大整形电路,整形电路把模拟信号转换成数字电信号,再经译码接口电路译成数字字符信息。

整形电路的脉冲数字信号经译码器译成数字、字符信息.它通过识别起始、终止字符来判别出条形码符号的码制及扫描方向;通过测量脉冲数字电信号01的数目来判别出条和空的数目.通过测量01信号持续的时间来判别条和空的宽度.这样便得到了被辩读的条形码符号的条和空的数目及相应的宽度和所用码制,根据码制所对应的编码规则,便可将条形符号换成相应的数字、字符信息,通过接口电路送给计算机系统进行数据处理与管理,便完成了条形码辨读的全过程。


 

二、Zxing使用原理介绍


Zxing是一个开源的,用于Java实现的多种格式的1D/2D条码图像处理库,它包含了联系到其他语言的接口。

Zxing可以实现使用手机的内置摄像头完成条形码和二维码的扫描与解码。

Zxing可以实现条形码和二维码的编码与解码。

Zxing目前支持的格式如下:UPC-AUPC-EEAN-8EAN-1339码、93码、代码128QR码。 


三、实现步骤


1.导入Zxing.jar包,直接将源码内的com.mining.app.zxing.camera,com.mining.app.zxing.decoding, com.mining.app.zxing.view, com.mining.app.zxing.encoding四个文件夹,zxing package直接复制到你的工程目录下。


源码下载地址:http://code.google.com/p/zxing/

GitHub下载地址:https://github.com/zxing/zxing

备用地址:http://download.csdn.net/detail/u012721519/9556800

如何引用jar包:http://blog.csdn.net/u012721519/article/details/51234611


2.raw文件(用于),values,权限以及资源文件,全部准备完全,详情可参见源码。

3. activity.xml主菜单布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffe1e0de"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="扫描二维码/条形码" />
    <EditText
        android:id="@+id/et_qr_string"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:text="生成二维码" />
        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:text="生成条形码" />
    </LinearLayout>


    <TextView
        android:id="@+id/result"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button1"
        android:lines="2"
        android:gravity="center_horizontal"
        android:textColor="@android:color/black"
        android:textSize="16sp" />

    <ImageView
        android:id="@+id/qrcode_bitmap"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/result"/>
</LinearLayout>

4.activity_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" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <SurfaceView
            android:id="@+id/preview_view"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_gravity="center" />

        <zxing.view.ViewfinderView
            android:id="@+id/viewfinder_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <include
            android:id="@+id/include1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            layout="@layout/activity_title" />
    </RelativeLayout>

</FrameLayout>

5.activity_title.xml  Title布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/mmtitle_bg_alpha" >

    <Button
        android:id="@+id/button_back"
        android:layout_width="75.0dip"
        android:text="返回"
        android:background="@drawable/mm_title_back_btn"
        android:textColor="@android:color/white"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="2dip" />

    <TextView
        android:id="@+id/textview_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button_back"
        android:layout_alignBottom="@+id/button_back"
        android:layout_centerHorizontal="true"
        android:gravity="center_vertical"
        android:text="二维码扫描"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</RelativeLayout>

上述文件用于<include />标签,便于修改以及占少量内存


6.MainActivity.java.主界面用于事件的处理

package example.com.zxingdemo;


import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.zxing.WriterException;

import zxing.encoding.EncodingHandler;

public class MainActivity extends Activity {
	private final static int SCANNIN_GREQUEST_CODE = 1;
	/**
	 * 显示扫描结果
	 */
	private TextView mTextView ;
	/**
	 * 显示扫描拍的图片
	 */
	private ImageView mImageView;

	/**
	 * 输入框产生二维码
	 * @param savedInstanceState
     */
	private EditText qrStrEditText;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mTextView = (TextView) findViewById(R.id.result);
		mImageView = (ImageView) findViewById(R.id.qrcode_bitmap);
		qrStrEditText = (EditText) findViewById(R.id.et_qr_string);

		//点击按钮跳转到二维码扫描界面,这里用的是startActivityForResult跳转
		//扫描完了之后调到该界面
		Button mButtonScan = (Button) findViewById(R.id.button1);
		Button mBtnTwoCode = (Button) findViewById(R.id.button2);
		Button mBtnOneCode = (Button) findViewById(R.id.button3);

		mButtonScan.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.setClass(MainActivity.this, MipcaActivityCapture.class);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivityForResult(intent, SCANNIN_GREQUEST_CODE);
			}
		});


		//产生二维码
		mBtnTwoCode.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String contentString = qrStrEditText.getText().toString();
				try {
					if (!contentString.equals("")) {
						Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
						mImageView.setImageBitmap(qrCodeBitmap);
						qrStrEditText.setText("");
						mTextView.setText(contentString);
					} else {
						Toast.makeText(getApplicationContext(), "Text can be not empty", Toast.LENGTH_SHORT).show();
					}
				} catch (WriterException e) {
					e.printStackTrace();
				}
			}
		});

		//产生条形码
		mBtnOneCode.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String contentString = qrStrEditText.getText().toString();
				int size = contentString.length();
				for (int i = 0; i < size; i++) {
					int c = contentString.charAt(i);
					if ((19968 <= c && c < 40623)) {
						Toast.makeText(getApplicationContext(), "text not be chinese", Toast.LENGTH_SHORT).show();
						return;
					}
				}
				Bitmap mBmpOneCode = null;
				try {
					if (contentString != null && !"".equals(contentString)) {
						mBmpOneCode = EncodingHandler.CreateOneDCode(contentString);
						qrStrEditText.setText("");
						mTextView.setText(contentString);
					}
				} catch (WriterException e) {
					e.printStackTrace();
				}
				if (mBmpOneCode != null) {
					mImageView.setImageBitmap(mBmpOneCode);
				}
			}
		});
	}


	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
			case SCANNIN_GREQUEST_CODE:
				if(resultCode == RESULT_OK){
					Bundle bundle = data.getExtras();
					//显示扫描到的内容
					mTextView.setText(bundle.getString("result"));
					//显示
					mImageView.setImageBitmap((Bitmap) data.getParcelableExtra("bitmap"));
				}
				break;
		}
	}
}

7.MipcaActivityCapture.java.主要是调用起Camera功能进行扫描

package example.com.zxingdemo;

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;

import java.io.IOException;
import java.util.Vector;

import zxing.camera.CameraManager;
import zxing.decoding.CaptureActivityHandler;
import zxing.decoding.InactivityTimer;
import zxing.view.ViewfinderView;

/**
 * Initial the camera
 * @author Ryan.Tang
 */
public class MipcaActivityCapture extends Activity implements Callback {

    private CaptureActivityHandler handler;
    private ViewfinderView viewfinderView;
    private boolean hasSurface;
    private Vector<BarcodeFormat> decodeFormats;
    private String characterSet;
    private InactivityTimer inactivityTimer;
    private MediaPlayer mediaPlayer;
    private boolean playBeep;
    private static final float BEEP_VOLUME = 0.10f;
    private boolean vibrate;

    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_capture);
        //ViewUtil.addTopView(getApplicationContext(), this, R.string.scan_card);
        CameraManager.init(getApplication());
        viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);

        Button mButtonBack = (Button) findViewById(R.id.button_back);
        mButtonBack.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                MipcaActivityCapture.this.finish();

            }
        });
        hasSurface = false;
        inactivityTimer = new InactivityTimer(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        if (hasSurface) {
            initCamera(surfaceHolder);
        } else {
            surfaceHolder.addCallback(this);
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
        decodeFormats = null;
        characterSet = null;

        playBeep = true;
        AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
        if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
            playBeep = false;
        }
        initBeepSound();
        vibrate = true;

    }

    @Override
    protected void onPause() {
        super.onPause();
        if (handler != null) {
            handler.quitSynchronously();
            handler = null;
        }
        CameraManager.get().closeDriver();
    }

    @Override
    protected void onDestroy() {
        inactivityTimer.shutdown();
        super.onDestroy();
    }

    /**
     * 处理扫描结果
     *
     * @param result
     * @param barcode
     */
    public void handleDecode(Result result, Bitmap barcode) {
        inactivityTimer.onActivity();
        playBeepSoundAndVibrate();
        String resultString = result.getText();
        if (resultString.equals("")) {
            Toast.makeText(MipcaActivityCapture.this, "Scan failed!", Toast.LENGTH_SHORT).show();
        } else {
            Intent resultIntent = new Intent();
            Bundle bundle = new Bundle();
            bundle.putString("result", resultString);
            bundle.putParcelable("bitmap", barcode);
            resultIntent.putExtras(bundle);
            this.setResult(RESULT_OK, resultIntent);
        }
        MipcaActivityCapture.this.finish();
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        try {
            CameraManager.get().openDriver(surfaceHolder);
        } catch (IOException ioe) {
            return;
        } catch (RuntimeException e) {
            return;
        }
        if (handler == null) {
            handler = new CaptureActivityHandler(this, decodeFormats,
                    characterSet);
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!hasSurface) {
            hasSurface = true;
            initCamera(holder);
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        hasSurface = false;

    }

    public ViewfinderView getViewfinderView() {
        return viewfinderView;
    }

    public Handler getHandler() {
        return handler;
    }

    public void drawViewfinder() {
        viewfinderView.drawViewfinder();

    }

    private void initBeepSound() {
        if (playBeep && mediaPlayer == null) {
            // The volume on STREAM_SYSTEM is not adjustable, and users found it
            // too loud,
            // so we now play on the music stream.
            setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setOnCompletionListener(beepListener);

            AssetFileDescriptor file = getResources().openRawResourceFd(
                    R.raw.beep);
            try {
                mediaPlayer.setDataSource(file.getFileDescriptor(),
                        file.getStartOffset(), file.getLength());
                file.close();
                mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
                mediaPlayer.prepare();
            } catch (IOException e) {
                mediaPlayer = null;
            }
        }
    }

    private static final long VIBRATE_DURATION = 200L;

    private void playBeepSoundAndVibrate() {
        if (playBeep && mediaPlayer != null) {
            mediaPlayer.start();
        }
        if (vibrate) {
            Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
            vibrator.vibrate(VIBRATE_DURATION);
        }
    }

    /**
     * When the beep has finished playing, rewind to queue up another one.
     */
    private final OnCompletionListener beepListener = new OnCompletionListener() {
        public void onCompletion(MediaPlayer mediaPlayer) {
            mediaPlayer.seekTo(0);
        }
    };

}


四、代码分析

1.生成二维码

         调用方法:

//产生二维码
		mBtnTwoCode.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String contentString = qrStrEditText.getText().toString();
				try {
					if (!contentString.equals("")) {
						Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
						mImageView.setImageBitmap(qrCodeBitmap);
						qrStrEditText.setText("");
						mTextView.setText(contentString);
					} else {
						Toast.makeText(getApplicationContext(), "Text can be not empty", Toast.LENGTH_SHORT).show();
					}
				} catch (WriterException e) {
					e.printStackTrace();
				}
			}
		});

         实现方法:

private static final int BLACK = 0xff000000;
	//生成二维码
	public static Bitmap createQRCode(String str,int widthAndHeight) throws WriterException {
		Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();  
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 
		BitMatrix matrix = new MultiFormatWriter().encode(str,
				BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		int[] pixels = new int[width * height];
		
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (matrix.get(x, y)) {
					pixels[y * width + x] = BLACK;
				}
			}
		}
		Bitmap bitmap = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}

2.生成条形码

调用方法:

//产生条形码
		mBtnOneCode.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				String contentString = qrStrEditText.getText().toString();
				int size = contentString.length();
				for (int i = 0; i < size; i++) {
					int c = contentString.charAt(i);
					if ((19968 <= c && c < 40623)) {
						Toast.makeText(getApplicationContext(), "text not be chinese", Toast.LENGTH_SHORT).show();
						return;
					}
				}
				Bitmap mBmpOneCode = null;
				try {
					if (contentString != null && !"".equals(contentString)) {
						mBmpOneCode = EncodingHandler.CreateOneDCode(contentString);
						qrStrEditText.setText("");
						mTextView.setText(contentString);
					}
				} catch (WriterException e) {
					e.printStackTrace();
				}
				if (mBmpOneCode != null) {
					mImageView.setImageBitmap(mBmpOneCode);
				}
			}
		});

         实现方法:

//生成条形码
	public static Bitmap CreateOneDCode(String content) throws WriterException {
		// 生成一维条码,编码时指定大小,不要生成了图片以后再进行缩放,这样会模糊导致识别失败
		BitMatrix matrix = new MultiFormatWriter().encode(content,
				BarcodeFormat.CODE_128, 500, 200);
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		int[] pixels = new int[width * height];
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (matrix.get(x, y)) {
					pixels[y * width + x] = BLACK;
				}
			}
		}

3.扫描二维码、条形码 

mButtonScan.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.setClass(MainActivity.this, MipcaActivityCapture.class);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivityForResult(intent, SCANNIN_GREQUEST_CODE);
			}
		});


五、实现效果图

     

     


六、下载地址

项目源码下载地址:http://download.csdn.net/detail/u012721519/9556821

开源源码、jar下载地址:http://download.csdn.net/detail/u012721519/9556800



Good luck!

Write by Jimmy.li











友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

  • ModernUI课程:定义一个Logo

    ModernUI教程:定义一个Logo ModernWindow的标题栏包含了一块区域用来显示自定义的窗体Logo: 这个窗体logo通过ModernWindow.LogoD...

  • Django忘记管理员账号和密码的解决方法

    Django忘记管理员账号和密码的解决办法 看着Django的教程学习搭建网站,结果忘记第一次创建的账号和密码了。结果搭建成功以后,一直...

  • GO语言小结(1)——基本知识

    GO语言总结(1)——基本知识 1、注释(与C++一样)   行注释://  块注释:/*   ...  */ 2、标识符   可以这么说,除了数字开头...

  • golang 惯用的文件读取方式

    golang 常用的文件读取方式 Golang 的文件读取方法很多,刚上手时不知道怎么选择,所以贴在此处便后速查。 一次性读取 小文件推荐一...

  • 查询深圳市通相关信息

    查询深圳通相关信息 用 HTTP.GET 从开放 API 中查询深圳通信息,然后将 JSON 数据存入结构体中,再格式化输出。 注意:获取的并不是实...

  • Go语言设计模式实践:结合(Composite)

    Go语言设计模式实践:组合(Composite) 关于本系列 这个系列首先是关于Go语言实践的。在项目中实际使用Go语言也有段时间了,一个体会就...

  • 列出索引和遍历目录

    列出目录和遍历目录 获取目录列表用 ioutil.ReadDir(),遍历目录用 filepath.Walk(),使用方法请参考文章示例。 示例代码: package ma...

  • io 包的惯用接口速记

    io 包的常用接口速记 我没有 C/C++ 基础,没有接口的概念,且从 Python 投奔而来,Python 的极简主义(一个结果往往只提供一个方法),让我在...

  • 代理服务扩充

    代理服务扩展 之前自己实现了一个代理服务,当时考虑的是只要支持SOCKS5就好了,因为我经常用CHROME,配合着SwitchySharp,体验还是很棒...

  • 文件的创造与打开

    文件的创建与打开 文件操作是个很重要的话题,使用也非常频繁,熟悉如何操作文件是必不可少的。Golang 对文件的支持是在 os package ...

热门推荐: