最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android平臺生成二維碼并實現(xiàn)掃描 & 識別功能

 更新時間:2016年06月08日 17:12:45   作者:Joyfulmath  
這篇文章主要介紹了Android平臺生成二維碼并實現(xiàn)掃描 & 識別功能的相關資料,需要的朋友可以參考下

1.二維碼的前世今生

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

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

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

條碼起源與20世紀40年代,后來在1970年 UPC碼發(fā)明,并開始廣泛應用與食品包裝。

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

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

2.二維碼的java支持庫

為了讓java或者說android方便繼承條碼的功能,google就開發(fā)了一個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的結果,通過摸個算法,設置每個點白色,或者黑色。

最后創(chuàng)建一張二維碼的圖片。

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);
}
} 

過程也是很簡單,使用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;
}
} 

5.掃描二維碼

掃描二維碼,其實比上面只多了一步,就是把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預覽的數(shù)據(jù)放入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");
}
} 

可以看到,預覽的數(shù)據(jù)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));

相關文章

  • Android多渠道打包的方法步驟

    Android多渠道打包的方法步驟

    本篇文章主要介紹了Android多渠道打包的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Android GridView不改變背景色實現(xiàn)網(wǎng)格線效果

    Android GridView不改變背景色實現(xiàn)網(wǎng)格線效果

    這篇文章主要介紹了Android GridView不改變背景色實現(xiàn)網(wǎng)格線效果,需要的朋友可以參考下
    2016-03-03
  • Android布局耗時監(jiān)測的三種實現(xiàn)方式

    Android布局耗時監(jiān)測的三種實現(xiàn)方式

    在Android應用開發(fā)中,性能優(yōu)化是一個至關重要的方面,為了更好地監(jiān)測布局渲染的耗時,我們需要一種可靠的實現(xiàn)方案,本文將介紹三種針對Android布局耗時監(jiān)測的實現(xiàn)方案,幫助開發(fā)者及時發(fā)現(xiàn)并解決布局性能問題,需要的朋友可以參考下
    2024-03-03
  • Android源碼系列之深入理解ImageView的ScaleType屬性

    Android源碼系列之深入理解ImageView的ScaleType屬性

    Android源碼系列第一篇,這篇文章主要從源碼的角度深入理解ImageView的ScaleType屬性,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android應用開發(fā)中單元測試分析

    Android應用開發(fā)中單元測試分析

    這篇文章主要介紹了Android應用開發(fā)中單元測試的作用,以及何為單元測試,深入學習Android應用開發(fā)中單元測試,需要的朋友可以參考下
    2015-12-12
  • 使用Eclipse配置android開發(fā)環(huán)境教程

    使用Eclipse配置android開發(fā)環(huán)境教程

    這篇文章主要介紹了使用Eclipse配置android開發(fā)環(huán)境教程,本文講解了下載需要用到的工具、下載完需要的工具之后開始安裝、讓Ecplise自動安裝Android開發(fā)插件(ADT- plugin)、配置Andiord SDK路徑、測試開發(fā)一個Android項目等內容,需要的朋友可以參考下
    2015-04-04
  • Android修改源碼解決Alertdialog觸摸對話框邊緣消失的問題

    Android修改源碼解決Alertdialog觸摸對話框邊緣消失的問題

    在開發(fā)的時候遇到一個問題,就是一觸摸對話框邊緣外部,對話框會自動消失。這個問題很糾結啊,查找了一下發(fā)現(xiàn)從Android 4.0開始,AlertDialog有了變化,就是在觸摸對話框邊緣外部,對話框會自動消失,查了源碼,找到解決辦法如下
    2013-11-11
  • 基于Android實現(xiàn)自動滾動布局

    基于Android實現(xiàn)自動滾動布局

    在平時的開發(fā)中,有時會碰到這樣的場景,設計上布局的內容會比較緊湊,導致部分機型上某些布局中的內容顯示不完全,或者在數(shù)據(jù)內容多的情況下,單行無法顯示所有內容,這里給大家簡單介紹下布局自動滾動的一種實現(xiàn)方式,感興趣的朋友可以參考下
    2023-12-12
  • Android Studio綁定下拉框數(shù)據(jù)詳解

    Android Studio綁定下拉框數(shù)據(jù)詳解

    這篇文章主要為大家詳細介紹了Android Studio綁定下拉框數(shù)據(jù),Android Studio綁定網(wǎng)絡JSON數(shù)據(jù),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Android簡易音樂播放器實現(xiàn)代碼

    Android簡易音樂播放器實現(xiàn)代碼

    這篇文章主要為大家詳細介紹了Android簡易音樂播放器的實現(xiàn)代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02

最新評論

英山县| 沙湾县| 孝昌县| 宁陕县| 龙泉市| 盐城市| 顺平县| 柳河县| 报价| 囊谦县| 田林县| 石门县| 屯留县| 若尔盖县| 定襄县| 海南省| 岚皋县| 河间市| 镇雄县| 出国| 雷州市| 卓尼县| 绥滨县| 新田县| 鲁甸县| 黔西县| 平泉县| 南宫市| 河间市| 城市| 贵德县| 鄂温| 建昌县| 苗栗市| 威信县| 固始县| 蚌埠市| 邯郸市| 会宁县| 台北县| 禹城市|