Android ZXing 二維碼、條形碼掃描介紹

jopen 11年前發布 | 219K 次閱讀 Android Android開發 移動開發

最近公司的Android項目需要用到攝像頭做條碼或二維碼的掃描,Google一下,發現一個開源的 ZXing項目。它提供二維碼和條形碼的掃描。掃描條形碼就是直接讀取條形碼的內容,掃描二維碼是按照自己指定的二維碼格式進行編碼和解碼。

1.什么是二維碼和條形碼?

Android ZXing 二維碼、條形碼掃描介紹                         Android ZXing 二維碼、條形碼掃描介紹

二維條形碼最早發明于日本,它是用某種特定的幾何圖形按一定規律在平面(二維方向上)分布的黑白相間的圖形記錄數據符號 信息的,在代碼編制上巧妙地利用構成計算機內部邏輯基礎的“0”、“1”比特流的概念,使用若干個與二進制相對應的幾何形體來表示文字數值信息,通過圖象 輸入設備或光電掃描設備自動識讀以實現信息自動處理。它具有條碼技術的一些共性:每種碼制有其特定的字符集;每個字符占有一定的寬度;具有一定的校驗功能 等。同時還具有對不同行的信息自動識別功能、及處理圖形旋轉變化等特點。

條形碼(barcode)是將寬度不等的多個黑條和空白,按照一定的編碼規則排列,用以表達一組信息的圖形標識符。常見 的條形碼是由反射率相差很大的黑條(簡稱條)和白條(簡稱空)排成的平行線圖案。條形碼可以標出物品的生產國、制造廠家、商品名稱、生產日期、圖書分類 號、郵件起止地點、類別、日期等許多信息,因而在商品流通、圖書管理、郵政管理、銀行系統等許多領域都得到廣泛的應用。

2.ZXing基本介紹

ZXing是一個開源Java類庫用于解析多種格式的條形碼和二維碼.官網:http://code.google.com/p/zxing/

截止目前為止最新版本提供以下編碼格式的支持:

  • UPC-A and UPC-E
  • EAN-8 and EAN-13
  • Code 39
  • Code 93
  • Code 128
  • QR Code
  • ITF
  • Codabar
  • RSS-14 (all variants)
  • Data Matrix
  • PDF 417 ('alpha' quality)
  • Aztec ('alpha' quality)

同時官網提供了 Android、cpp、C#、iPhone、j2me、j2se、jruby、objc、rim、symbian等多種應用的類庫,具體詳情可以參考下載的源碼包中。

3.Android端編碼演示

這里使用的ZXing是經過簡化版的,去除了一些一般使用不必要的文件,項目工程和效果截圖如下:

Android ZXing 二維碼、條形碼掃描介紹 Android ZXing 二維碼、條形碼掃描介紹     Android ZXing 二維碼、條形碼掃描介紹

其中encoding包是在原基礎上加上去的,功能是根據傳入的字符串來生成二維碼圖片,返回一個Bitmap,其余的 包是ZXing項目自帶的。另外對掃描界面的布局也進行了修改,官方的掃描界面是橫向的,我改成了縱向的,并加入了頂部的Tab和取消按鈕 (camera.xml),另外還需要的一些文件是colors.xml、ids.xml,這些都是原本ZXing項目中自帶的,最后就是libs下面的 jar包。

接下來看如何使用,首先是把ZXing項目中的一些文件拷貝到我們自己的項目中,然后在Mainifest文件中進行配置權限:

 
 <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" />

還有就是掃描界面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>

接下來是我自己項目的布局文件:


 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android :color/white"
    android:orientation="vertical" >
    <Button
        android:id="@+id/btn_scan_barcode"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="Open camera" />

    <LinearLayout 
        android:orientation="horizontal"
        android:layout_marginTop="10dp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

        <TextView 
               android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android :color/black"
        android:textSize="18sp"
        android:text="Scan result:" />

        <TextView 
        android:id="@+id/tv_scan_result"
               android:layout_width="fill_parent"
               android:textSize="18sp"
               android:textColor="@android :color/black"
        android:layout_height="wrap_content" />
    </LinearLayout>

    <EditText 
        android:id="@+id/et_qr_string"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:hint="Input the text"/>

    <Button
        android:id="@+id/btn_add_qrcode"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Generate QRcode" />

    <ImageView 
        android:id="@+id/iv_qr_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"/>
</LinearLayout>

下面是主Activity的代碼,主要功能是打開掃描框、顯示掃描結果、根據輸入的字符串生成二維碼圖片:


 
public class BarCodeTestActivity extends Activity {
    /** Called when the activity is first created. */
        private TextView resultTextView;
        private EditText qrStrEditText;
        private ImageView qrImgImageView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        resultTextView = (TextView) this.findViewById(R.id.tv_scan_result);
        qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string);
        qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image);

        Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
        scanBarCodeButton.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                                //打開掃描界面掃描條形碼或二維碼
                                Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
                                startActivityForResult(openCameraIntent, 0);
                        }
                });

        Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode);
        generateQRCodeButton.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                                try {
                                        String contentString = qrStrEditText.getText().toString();
                                        if (!contentString.equals("")) {
                                                //根據字符串生成二維碼圖片并顯示在界面上,第二個參數為圖片的大小(350*350)
                                                Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
                                                qrImgImageView.setImageBitmap(qrCodeBitmap);
                                        }else {
                                                Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
                                        }

                                } catch (WriterException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        }
                });
    }
        @Override
        protected 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);
                }
        }
}

其中生成二維碼圖片的代碼在EncodingHandler.java中:

 
public final class EncodingHandler {
        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;
        }
}

最后是在哪里對掃描結果進行解碼,進入CaptureActivity.java找到下面這個方法便可以對自己對結果進行操作:


 /**
         * Handler scan result
         * @param result
         * @param barcode
         */
        public void handleDecode(Result result, Bitmap barcode) {
                inactivityTimer.onActivity();
                playBeepSoundAndVibrate();
                String resultString = result.getText();
                //FIXME
                if (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();
        }



4.Java端編碼演示

在Java端上實現條形碼(EAN-13)和二維碼(QRCode) 的編碼和解碼的示例,以供大家參考,用到了源碼中core和javase下面的相關源代碼,附件提供自己編譯之后的lib包:

zxing.jar
zxing-j2se.jar
有關各種手機系統的應用,有興趣的朋友可以下載官方源碼包,包下有具體詳細的應用介紹。
1)二維碼(QRCode)的編碼和解碼演示:
編碼示例:
 
     package michael.zxing;
    import java.io.File;
    import java.util.Hashtable;
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.client.j2se.MatrixToImageWriter;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    /**
    * [url=home.php?mod=space&uid=618199]@blog[/url] http://sjsky.iteye.com
    * @author Michael
    */
    public class ZxingEncoderHandler {
        /**
         * 編碼
         * @param contents
         * @param width
         * @param height
         * @param imgPath
         */
        public void encode(String contents, int width, int height, String imgPath) {
            Hashtable<Object, Object> hints = new Hashtable<Object, Object>();
            // 指定糾錯等級
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
            // 指定編碼格式
            hints.put(EncodeHintType.CHARACTER_SET, "GBK");
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                        BarcodeFormat.QR_CODE, width, height, hints);
                MatrixToImageWriter
                        .writeToFile(bitMatrix, "png", new File(imgPath));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/1.png";
            String contents = "Hello Word!";
            int width = 300, height = 300;
            ZxingEncoderHandler handler = new ZxingEncoderHandler();
            handler.encode(contents, width, height, imgPath);
        }
    } 
運行后生成的二維碼圖片如下:
Android ZXing 二維碼、條形碼掃描介紹
用手機的二維碼掃描軟件(本人用的:android 快拍二維碼 )來測試下,識別成功的截圖如下:
Android ZXing 二維碼、條形碼掃描介紹

解碼示例:
 
     package michael.zxing;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.util.Hashtable;
    import javax.imageio.ImageIO;
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.DecodeHintType;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.Result;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.HybridBinarizer;
    /**
    * @blog http://sjsky.iteye.com
    * @author Michael
    */
    public class ZxingDecoderHandler {
        /**
         * @param imgPath
         * [url=home.php?mod=space&uid=7300]@return[/url] String
         */
        public String decode(String imgPath) {
            BufferedImage image = null;
            Result result = null;
            try {
                image = ImageIO.read(new File(imgPath));
                if (image == null) {
                    System.out.println("the decode image may be not exit.");
                }
                LuminanceSource source = new BufferedImageLuminanceSource(image);
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
                Hashtable<Object, Object> hints = new Hashtable<Object, Object>();
                hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
                result = new MultiFormatReader().decode(bitmap, hints);
                return result.getText();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/1.png";
            ZxingDecoderHandler handler = new ZxingDecoderHandler();
            String decodeContent = handler.decode(imgPath);
            System.out.println("解碼內容如下:");
            System.out.println(decodeContent);
        }
    } 

Hello Word!
2)條形碼(EAN-13)的編碼和解碼演示:
編碼示例:

 
     package michael.zxing;
    import java.io.File;
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.client.j2se.MatrixToImageWriter;
    import com.google.zxing.common.BitMatrix;
    /**
    * @blog http://sjsky.iteye.com
    * @author Michael
    */
    public class ZxingEAN13EncoderHandler {
        /**
         * 編碼
         * @param contents
         * @param width
         * @param height
         * @param imgPath
         */
        public void encode(String contents, int width, int height, String imgPath) {
            int codeWidth = 3 + // start guard
                    (7 * 6) + // left bars
                    5 + // middle guard
                    (7 * 6) + // right bars
                    3; // end guard
            codeWidth = Math.max(codeWidth, width);
            try {
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                        BarcodeFormat.EAN_13, codeWidth, height, null);
                MatrixToImageWriter
                        .writeToFile(bitMatrix, "png", new File(imgPath));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/2.png";
            // 益達無糖口香糖的條形碼
            String contents = "6923450657713";
            int width = 105, height = 50;
            ZxingEAN13EncoderHandler handler = new ZxingEAN13EncoderHandler();
            handler.encode(contents, width, height, imgPath);
        }
    } 
運行后生成條形碼圖片如下:
Android ZXing 二維碼、條形碼掃描介紹
用手機的條形碼掃描軟件(本人用的:android 快拍二維碼 )來測試下,識別成功的截圖如下:
Android ZXing 二維碼、條形碼掃描介紹
解碼示例:
     package michael.zxing;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import javax.imageio.ImageIO;
    import com.google.zxing.BinaryBitmap;
    import com.google.zxing.LuminanceSource;
    import com.google.zxing.MultiFormatReader;
    import com.google.zxing.Result;
    import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
    import com.google.zxing.common.HybridBinarizer;
    /**
    * @blog http://sjsky.iteye.com
    * @author Michael
    */
    public class ZxingEAN13DecoderHandler {
        /**
         * @param imgPath
         * @return String
         */
        public String decode(String imgPath) {
            BufferedImage image = null;
            Result result = null;
            try {
                image = ImageIO.read(new File(imgPath));
                if (image == null) {
                    System.out.println("the decode image may be not exit.");
                }
                LuminanceSource source = new BufferedImageLuminanceSource(image);
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
                result = new MultiFormatReader().decode(bitmap, null);
                return result.getText();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        /**
         * @param args
         */
        public static void main(String[] args) {
            String imgPath = "d:/2.png";
            ZxingEAN13DecoderHandler handler = new ZxingEAN13DecoderHandler();
            String decodeContent = handler.decode(imgPath);
            System.out.println("解碼內容如下:");
            System.out.println(decodeContent);
        }
    } 


解碼內容如下:
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!