Zbar扫码(摄像头+本地图片+6.0权限)

来源:互联网 发布:三国杀风火林山 知乎 编辑:程序博客网 时间:2024/05/01 18:58
Zbar调用摄像头扫码,没什么好说的,其他前辈写过无数文章,大概就是写布局--->调用摄像头(android 6.0以后需要判断权限)---->用Zbar的Decoder将摄像头拿到的数据进行解码。最近项目需要扫码功能支持相机扫码,也支持本地图片扫码,按照惯例,到网上各路搜索相关例子,看着代码都不多,但是就是移植到自己项目里就不行,本地图片扫码总是得到null,觉得很是奇怪,找了很多文章,有几篇大概提到Bitmap转YUV格式之后再去解码,于是参照说明,尝试发现部分可以解码,部分不能解码,很是不解,用微信的扫码测试却都可以得到正确的结果。于是又尝试各种方法,仍然不行,过程中发现我的程序界面得到结果(null)所用的时间较长,心想是不是图片太大,处理耗时太多,于是尝试压缩下,哇哈哈~~~突然间柳暗花明又一村,之前不能解码的图片现在也能解码了,啊哈哈哈,好开森~~于是继续压缩,结果发现玩大了额,之前能解码的现在又解码了了~~~压缩过头了,最终用了个自我感觉效果不错的压缩后大小。相关代码如下:

第一部分:发起查找图片的Intent

/** 这个地方需要注意,同样的Intent,Android 6.0之前返回的数据与6.0及之后返回的数据不一样,具体见onActivityResult部分 */Intent innerIntent = new Intent();        innerIntent.setAction(Intent.ACTION_GET_CONTENT);        innerIntent.setType("image/*");        Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");        startActivityForResult(wrapperIntent, 0x0202);

第二部分:onActivityResult数据处理

    private String photo_path;    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (requestCode == 0x0202) {            if (resultCode == Activity.RESULT_OK) {                DebugLog.d(data.getData().toString());                Uri intentData = data.getData();                /** 之前说的数据不同之处即在这里,6.0之前,得到的Uri字符以“content”开头,需要使用cursor获取路径,而6.0及之后,直接返回了以file开头的文件路径,可以直接使用 */                if (intentData.toString().startsWith("content")) {                    String[] proj = { MediaStore.Images.Media.DATA };                    // 获取选中图片的路径                    Cursor cursor = getContentResolver().query(data.getData(), proj, null, null, null);                    if (cursor.moveToFirst()) {                        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);                        photo_path = cursor.getString(column_index);                        if (photo_path == null) {                            photo_path = FileUtils.getPath(getApplicationContext(), data.getData());                        }                    }                    cursor.close();                } else if (intentData.toString().startsWith("file")) {                    photo_path = intentData.toString().substring("file://".length());                }                DebugLog.d("photo_path:" + photo_path);                new Thread(new Runnable() {                    @Override                    public void run() {                        // 创建Zbar解码器实例                        ZBarDecoder decoder = new ZBarDecoder();                        scanHandler.sendEmptyMessage(MSG_WHAT_START);                        // 得到Bitmap实例                        Bitmap bitmap = BitmapFileUtils.getDiskBitmap(photo_path);                        if (bitmap == null) {                            scanHandler.sendEmptyMessage(MSG_WHAT_NO_PERMISSION);                            return;                        }                        DebugLog.e("oldWidth:" + bitmap.getWidth() + "/oldHeight:" + bitmap.getHeight());                        // 压缩图片至宽、高最大400像素                        bitmap = BitmapFileUtils.reduce(bitmap, 400, 400, true);                        int wi = bitmap.getWidth();                        int he = bitmap.getHeight();                        DebugLog.e("width:" + wi + "/height:" + he);                        // 此处进行解码,先将bitmap转为YUV格式                        String qrcode = decoder.decodeRaw(Bmp2YUV.getYUV420sp(wi, he, bitmap), wi, he);                        DebugLog.e("--===scan result is : " + qrcode);                        if (qrcode == null || qrcode.isEmpty()) {                            scanHandler.sendEmptyMessage(MSG_WHAT_FAILED);                        } else {                            Message msg = Message.obtain(scanHandler);                            msg.what = MSG_WHAT_SUCCESS;                            msg.obj = qrcode;                            scanHandler.sendMessage(msg);                        }                        bitmap.recycle();                        bitmap = null;                    }                }).start();            }        }        super.onActivityResult(requestCode, resultCode, data);    }

第三部分:Bitmap转YUV格式

public class Bmp2YUV {    /**     * YUV420sp     *      * @param inputWidth     * @param inputHeight     * @param scaled     * @return     */    public static byte[] getYUV420sp(int inputWidth, int inputHeight, Bitmap scaled) {        int[] argb = new int[inputWidth * inputHeight];        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);// 这里我踩平了一个坑,数组长度要按如下格式写,其他同理//方法亦可。网络上其他前辈写的=new byte[inputWidth// * inputHeight*3/2]在某些情况下会出现数组越界异常        byte[] yuv = new byte[inputWidth                * inputHeight                + ((inputWidth % 2 == 0 ? inputWidth : (inputWidth + 1)) * (inputHeight % 2 == 0 ? inputHeight                        : (inputHeight + 1))) / 2];        encodeYUV420SP(yuv, argb, inputWidth, inputHeight);        scaled.recycle();        return yuv;    }    /**     * RGB转YUV420sp     *      * @param yuv420sp     *            inputWidth * inputHeight * 3 / 2     * @param argb     *            inputWidth * inputHeight     * @param width     * @param height     */    private static void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {        // 帧图片的像素大小        final int frameSize = width * height;        // ---YUV数据---        int Y, U, V;        // Y的index从0开始        int yIndex = 0;        // UV的index从frameSize开始        int uvIndex = frameSize;        // ---颜色数据---        int a, R, G, B;        //        int argbIndex = 0;        //        // ---循环所有像素点,RGB转YUV---        for (int j = 0; j < height; j++) {            for (int i = 0; i < width; i++) {                // a is not used obviously                a = (argb[argbIndex] & 0xff000000) >> 24;                R = (argb[argbIndex] & 0xff0000) >> 16;                G = (argb[argbIndex] & 0xff00) >> 8;                B = (argb[argbIndex] & 0xff);                //                argbIndex++;                // well known RGB to YUV algorithm                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;                //                Y = Math.max(0, Math.min(Y, 255));                U = Math.max(0, Math.min(U, 255));                V = Math.max(0, Math.min(V, 255));                // NV21 has a plane of Y and interleaved planes of VU each                // sampled by a factor of 2                // meaning for every 4 Y pixels there are 1 V and 1 U. Note the                // sampling is every other                // pixel AND every other scanline.                // ---Y---                yuv420sp[yIndex++] = (byte) Y;                // ---UV---                if ((j % 2 == 0) && (i % 2 == 0)) {                    //                    yuv420sp[uvIndex++] = (byte) V;                    //                    yuv420sp[uvIndex++] = (byte) U;                }            }        }    }}

Demo源码地址:http://download.csdn.net/detail/chicet/9729077

1 0
原创粉丝点击