Android平台二維碼之產生,掃描 & 識別,android平台

來源:互聯網
上載者:User

Android平台二維碼之產生,掃描 & 識別,android平台
1.二維碼的前世今生

“二維條碼/二維碼(2-dimensional bar code)是用某種特定的幾何圖形按一定規律在平面(二維方向上)分布的黑白相間的圖形記錄資料符號資訊的;在代碼編製上巧妙地利用構成電腦內部邏輯基礎的“0”、“1”位元流的概念,使用若干個與二進位相對應的幾何形體來表示文字數值資訊,通過圖象輸入裝置或光電掃描裝置自動識讀以實現資訊自動處理:它具有條碼技術的一些共性:每種碼制有其特定的字元集;每個字元佔有一定的寬度;具有一定的校正功能等。同時還具有對不同行的資訊自動識別功能、及處理圖形旋轉變化點。 [1] ”

上面是百度百科的解釋。既然有二維碼,那麼肯定有一維碼。

一維碼。最為常見的就是食品 & 書本後面的條碼。

條碼起源與20世紀40年代,後來在1970年 UPC碼發明,並開始廣泛應用與食品封裝。

具體的介紹可以看百度百科 一維碼。

其實二維碼與一維碼本質上是類似的,就跟一維數組和二維數組一樣。

 2.二維碼的java支援庫

為了讓java或者說android方便繼承條碼的功能,google就開發了一個zxing的庫:

https://github.com/zxing/zxing

 

3.產生二維碼
public class EncodeThread {    public static void encode(final String url, final int width, final int height, final EncodeResult result) {        if (result == null) {            return;        }        if (TextUtils.isEmpty(url)) {            result.onEncodeResult(null);            return;        }        new Thread() {            @Override            public void run() {                try {                    MultiFormatWriter writer = new MultiFormatWriter();                    Hashtable<EncodeHintType, String> hints = new Hashtable<>();                    hints.put(EncodeHintType.CHARACTER_SET, "utf-8");                    BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, width, height, hints);                    Bitmap bitmap = parseBitMatrix(bitMatrix);                    result.onEncodeResult(bitmap);                    return;                } catch (WriterException e) {                    e.printStackTrace();                }                result.onEncodeResult(null);            }        }.start();    }    /**     * 產生二維碼內容<br>     *     * @param matrix     * @return     */    public static Bitmap parseBitMatrix(BitMatrix matrix) {        final int QR_WIDTH = matrix.getWidth();        final int QR_HEIGHT = matrix.getHeight();        int[] pixels = new int[QR_WIDTH * QR_HEIGHT];        //this we using qrcode algorithm        for (int y = 0; y < QR_HEIGHT; y++) {            for (int x = 0; x < QR_WIDTH; x++) {                if (matrix.get(x, y)) {                    pixels[y * QR_WIDTH + x] = 0xff000000;                } else {                    pixels[y * QR_WIDTH + x] = 0xffffffff;                }            }        }        Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888);        bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT);        return bitmap;    }    public interface EncodeResult {        void onEncodeResult(Bitmap bitmap);    }}

zxing 支援很多條碼格式:我們這裡使用QR_CODE碼。也就是我們常見的裡面的二維碼。

我們先來分析下這段代碼:

 MultiFormatWriter writer = new MultiFormatWriter();

這個是一個工具類,把所有支援的幾個write寫在裡面了。

public BitMatrix encode(String contents,                          BarcodeFormat format,                          int width, int height,                          Map<EncodeHintType,?> hints) throws WriterException {    Writer writer;    switch (format) {      case EAN_8:        writer = new EAN8Writer();        break;      case UPC_E:        writer = new UPCEWriter();        break;      case EAN_13:        writer = new EAN13Writer();        break;      case UPC_A:        writer = new UPCAWriter();        break;      case QR_CODE:        writer = new QRCodeWriter();        break;      case CODE_39:        writer = new Code39Writer();        break;      case CODE_93:        writer = new Code93Writer();        break;      case CODE_128:        writer = new Code128Writer();        break;      case ITF:        writer = new ITFWriter();        break;      case PDF_417:        writer = new PDF417Writer();        break;      case CODABAR:        writer = new CodaBarWriter();        break;      case DATA_MATRIX:        writer = new DataMatrixWriter();        break;      case AZTEC:        writer = new AztecWriter();        break;      default:        throw new IllegalArgumentException("No encoder available for format " + format);    }    return writer.encode(contents, format, width, height, hints);  }

這是官方最新支援的格式,具體看引入的jar裡面支援的格式。

對與bitmatrix的結果,通過摸個演算法,設定每個點白色,或者黑色。

最後建立一張二維碼的圖片。

4.識別二維碼

如何從一張圖片上面,識別二維碼呢:

public class ReDecodeThread { public static void encode(final Bitmap bitmap, final ReDecodeThreadResult listener) { if (listener == null) { return; } if (bitmap == null) { listener.onReDecodeResult(null); return; } new Thread() { @Override public void run() { try { MultiFormatReader multiFormatReader = new MultiFormatReader(); BitmapLuminanceSource source = new BitmapLuminanceSource(bitmap); BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source)); Result result1 = multiFormatReader.decode(bitmap1); listener.onReDecodeResult(result1.getText()); return; } catch (NotFoundException e) { e.printStackTrace(); } listener.onReDecodeResult(null); } }.start(); } public interface ReDecodeThreadResult { void onReDecodeResult(String url); }}View Code

過程也是很簡單,使用MultiFormatReader來分析圖片,這裡不需要缺人圖片的條碼格式。

如果分析下源碼,就是依次使用每種格式的reader來分析,直到找到合適的為止。

當然回了能夠把Bitmap轉化成Bitmatrix,然後在分析。

public final class BitmapLuminanceSource extends LuminanceSource{ private final byte[] luminances; public BitmapLuminanceSource(String path) throws FileNotFoundException { this(loadBitmap(path)); } public BitmapLuminanceSource(Bitmap bitmap) { super(bitmap.getWidth(), bitmap.getHeight()); int width = bitmap.getWidth(); int height = bitmap.getHeight(); int[] pixels = new int[width * height]; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); // In order to measure pure decoding speed, we convert the entire image // to a greyscale array // up front, which is the same as the Y channel of the // YUVLuminanceSource in the real app. luminances = new byte[width * height]; for (int y = 0; y < height; y++) { int offset = y * width; for (int x = 0; x < width; x++) { int pixel = pixels[offset + x]; int r = (pixel >> 16) & 0xff; int g = (pixel >> 8) & 0xff; int b = pixel & 0xff; if (r == g && g == b) { // Image is already greyscale, so pick any channel. luminances[offset + x] = (byte) r; } else { // Calculate luminance cheaply, favoring green. luminances[offset + x] = (byte) ((r + g + g + b) >> 2); } } } } @Override public byte[] getRow(int y, byte[] row) { if (y < 0 || y >= getHeight()) { throw new IllegalArgumentException("Requested row is outside the image: " + y); } int width = getWidth(); if (row == null || row.length < width) { row = new byte[width]; } System.arraycopy(luminances, y * width, row, 0, width); return row; } // Since this class does not support cropping, the underlying byte array // already contains // exactly what the caller is asking for, so give it to them without a copy. @Override public byte[] getMatrix() { return luminances; } private static Bitmap loadBitmap(String path) throws FileNotFoundException { Bitmap bitmap = BitmapFactory.decodeFile(path); if (bitmap == null) { throw new FileNotFoundException("Couldn't open " + path); } return bitmap; }}BitmapLuminanceSource5.掃描二維碼

掃描二維碼,其實比上面只多了一步,就是把camera擷取的東西直接轉換,然後進行識別。

  public void requestPreviewFrame(Handler handler, int message) {    if (camera != null && previewing) {      previewCallback.setHandler(handler, message);      if (useOneShotPreviewCallback) {        camera.setOneShotPreviewCallback(previewCallback);      } else {        camera.setPreviewCallback(previewCallback);      }    }  }

首先把camera預覽的資料放入previewCallback中。

final class PreviewCallback implements Camera.PreviewCallback
public void onPreviewFrame(byte[] data, Camera camera) {    Point cameraResolution = configManager.getCameraResolution();    if (!useOneShotPreviewCallback) {      camera.setPreviewCallback(null);    }    if (previewHandler != null) {      Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,          cameraResolution.y, data);      message.sendToTarget();      previewHandler = null;    } else {      Log.d(TAG, "Got preview callback, but no handler for it");    }  }

可以看到,預覽的資料data,回傳遞過來,然後handler的方式傳遞出去。

接收data的地方:

  @Override  public void handleMessage(Message message) {    switch (message.what) {      case R.id.decode:        //Log.d(TAG, "Got decode message");        decode((byte[]) message.obj, message.arg1, message.arg2);        break;      case R.id.quit:        Looper.myLooper().quit();        break;    }  }

然後是decode data

private void decode(byte[] data, int width, int height) {    long start = System.currentTimeMillis();    Result rawResult = null;        //modify here    byte[] 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 #11    width = 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();    }  }

當把camera上的圖片轉換成BinaryBitmap以後,剩下的事情,就更直接從圖片識別是一樣的。

PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

參考:

http://www.cnblogs.com/weixing/archive/2013/08/28/3287120.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.