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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u012721519/article/details/51737058


二维码/条形码生成器

二维码/条形码扫描器



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


目前的很多应用上都有扫码功能,当时微信推出二维码扫码功能时,觉得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











展开阅读全文

没有更多推荐了,返回首页