zoukankan      html  css  js  c++  java
  • Android从本地选择图片文件转为Bitmap,并用zxing解析Bitmap

    如何从本地选择图片文件

    使用Intent调用系统相册后,onActivityResult函数返回的是Uri格式的路径

    /**
     * 打开系统相册
     */
    private void openSysAlbum() {
        Intent innerIntent = new Intent();
        if (Build.VERSION.SDK_INT < 19) {
            innerIntent.setAction(Intent.ACTION_GET_CONTENT);
        } else {
            innerIntent.setAction(Intent.ACTION_OPEN_DOCUMENT);
        }
        innerIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
        startActivityForResult(wrapperIntent, SELECT_IMAGE_REQUEST_CODE);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case SELECT_IMAGE_REQUEST_CODE:
                if (resultCode == RESULT_OK) {
                    Uri uri = data.getData();
                    scanningImage(uri);
                }
                break;
        }
    }
    

    如何将Uri的路径转化为Bitmap

    获取Bitmap现在我查到两种解决方案:

    两种方案都可以,我感觉第二种方案更加靠谱一点,因为系统的数据库可能会更改,但是直接获取InputStream是不会变的。

    第一种方案代码

    /**
     * 
     * @param intent
     */
    public void ecognition(Intent intent) {
    	String photo_path = null;
    	// 获取选中图片的路径
    	String[] proj = { MediaStore.Images.Media.DATA };
    	Cursor cursor = getContentResolver().query(intent.getData(), proj, null, null, null);
    	if (cursor.moveToFirst()) {
    		photo_path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
    		if (photo_path == null) {
    			photo_path = Utils.getPath(getApplicationContext(), intent.getData());
    		}
    	}
    	cursor.close();
    	QRDecode.decodeQR(photo_path, this);
    }
    
    /**
     * 解析二维码图片
     *
     * @param picturePath
     * @param listener
     * @return
     */
    public static void decodeQR(String picturePath, OnScannerCompletionListener listener) {
    	try {
    		decodeQR(loadBitmap(picturePath), listener);
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	}
    }
    
    public static Bitmap loadBitmap(String picturePath) throws FileNotFoundException {
    	BitmapFactory.Options opt = new BitmapFactory.Options();
    	opt.inJustDecodeBounds = true;
    	Bitmap bitmap = BitmapFactory.decodeFile(picturePath, opt);
    	// 获取到这个图片的原始宽度和高度
    	int picWidth = opt.outWidth;
    	int picHeight = opt.outHeight;
    	// 获取画布中间方框的宽度和高度
    	int screenWidth = CameraManager.MAX_FRAME_WIDTH;
    	int screenHeight = CameraManager.MAX_FRAME_HEIGHT;
    	// isSampleSize是表示对图片的缩放程度,比如值为2图片的宽度和高度都变为以前的1/2
    	opt.inSampleSize = 1;
    	// 根据屏的大小和图片大小计算出缩放比例
    	if (picWidth > picHeight) {
    		if (picWidth > screenWidth)
    			opt.inSampleSize = picWidth / screenWidth;
    	} else {
    		if (picHeight > screenHeight)
    			opt.inSampleSize = picHeight / screenHeight;
    	}
    	// 生成有像素经过缩放了的bitmap
    	opt.inJustDecodeBounds = false;
    	bitmap = BitmapFactory.decodeFile(picturePath, opt);
    	if (bitmap == null) {
    		throw new FileNotFoundException("Couldn't open " + picturePath);
    	}
    	return bitmap;
    }
    

    第二种方案代码(推荐)

    代码来源博客:【Android】通过Uri获取Bitmap对象

    /**
     * 读取一个缩放后的图片,限定图片大小,避免OOM
     * http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html
     * @param uri       图片uri,支持“file://”、“content://”
     * @param maxWidth  最大允许宽度
     * @param maxHeight 最大允许高度
     * @return  返回一个缩放后的Bitmap,失败则返回null
     */
    public static Bitmap decodeUri(Context context, Uri uri, int maxWidth, int maxHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; //只读取图片尺寸
        resolveUri(context, uri, options);
    
        //计算实际缩放比例
        int scale = 1;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            if ((options.outWidth / scale > maxWidth &&
                    options.outWidth / scale > maxWidth * 1.4) ||
                    (options.outHeight / scale > maxHeight &&
                            options.outHeight / scale > maxHeight * 1.4)) {
                scale++;
            } else {
                break;
            }
        }
    
        options.inSampleSize = scale;
        options.inJustDecodeBounds = false;//读取图片内容
        options.inPreferredConfig = Bitmap.Config.RGB_565; //根据情况进行修改
        Bitmap bitmap = null;
        try {
            bitmap = resolveUriForBitmap(context, uri, options);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return bitmap;
    }
    
    // http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html
    private static void resolveUri(Context context, Uri uri, BitmapFactory.Options options) {
        if (uri == null) {
            return;
        }
    
        String scheme = uri.getScheme();
        if (ContentResolver.SCHEME_CONTENT.equals(scheme) ||
                ContentResolver.SCHEME_FILE.equals(scheme)) {
            InputStream stream = null;
            try {
                stream = context.getContentResolver().openInputStream(uri);
                BitmapFactory.decodeStream(stream, null, options);
            } catch (Exception e) {
                Log.w("resolveUri", "Unable to open content: " + uri, e);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        Log.w("resolveUri", "Unable to close content: " + uri, e);
                    }
                }
            }
        } else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
            Log.w("resolveUri", "Unable to close content: " + uri);
        } else {
            Log.w("resolveUri", "Unable to close content: " + uri);
        }
    }
    
    // http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html
    private static Bitmap resolveUriForBitmap(Context context, Uri uri, BitmapFactory.Options options) {
        if (uri == null) {
            return null;
        }
    
        Bitmap bitmap = null;
        String scheme = uri.getScheme();
        if (ContentResolver.SCHEME_CONTENT.equals(scheme) ||
                ContentResolver.SCHEME_FILE.equals(scheme)) {
            InputStream stream = null;
            try {
                stream = context.getContentResolver().openInputStream(uri);
                bitmap = BitmapFactory.decodeStream(stream, null, options);
            } catch (Exception e) {
                Log.w("resolveUriForBitmap", "Unable to open content: " + uri, e);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        Log.w("resolveUriForBitmap", "Unable to close content: " + uri, e);
                    }
                }
            }
        } else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
            Log.w("resolveUriForBitmap", "Unable to close content: " + uri);
        } else {
            Log.w("resolveUriForBitmap", "Unable to close content: " + uri);
        }
    
        return bitmap;
    }
    

    如何用zxing解析Bitmap

    /**
     * 解析二维码图片
     *
     * @param srcBitmap
     * @return
     */
    public static com.google.zxing.Result decodeQR(Bitmap srcBitmap) {
        com.google.zxing.Result result = null;
        if (srcBitmap != null) {
            int width = srcBitmap.getWidth();
            int height = srcBitmap.getHeight();
            int[] pixels = new int[width * height];
            srcBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
            // 新建一个RGBLuminanceSource对象
            RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
            // 将图片转换成二进制图片
            BinaryBitmap binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
            QRCodeReader reader = new QRCodeReader();// 初始化解析对象
            try {
                result = reader.decode(binaryBitmap, CodeHints.getDefaultDecodeHints());// 开始解析
            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (ChecksumException e) {
                e.printStackTrace();
            } catch (FormatException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
    

    其中CodeHints是一个自定义类,类代码:

    import java.util.ArrayList;
    import java.util.EnumMap;
    import java.util.List;
    import java.util.Map;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.DecodeHintType;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    
    import android.text.TextUtils;
    
    public class CodeHints {
    	private static Map<DecodeHintType, Object> DECODE_HINTS = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
    	private static Map<EncodeHintType, Object> ENCODE_HINTS = new EnumMap<>(EncodeHintType.class);
    
    	static {
    		List<BarcodeFormat> formats = new ArrayList<BarcodeFormat>();
    		formats.add(BarcodeFormat.QR_CODE);
    		DECODE_HINTS.put(DecodeHintType.POSSIBLE_FORMATS, formats);
    //		DECODE_HINTS.put(DecodeHintType.CHARACTER_SET, "UTF-8");
    
    		ENCODE_HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
    //		ENCODE_HINTS.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    	}
    
    	/**
    	 * 获取默认解析QR参数
    	 * 
    	 * @return
    	 */
    	public static Map<DecodeHintType, Object> getDefaultDecodeHints() {
    		return DECODE_HINTS;
    	}
    
    	/**
    	 * 获取自定义解析QR参数
    	 * 
    	 * @param characterSet
    	 *            编码方式
    	 * @return
    	 */
    	public static Map<DecodeHintType, Object> getCustomDecodeHints(String characterSet) {
    		Map<DecodeHintType, Object> decodeHints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class);
    		List<BarcodeFormat> formats = new ArrayList<BarcodeFormat>();
    		formats.add(BarcodeFormat.QR_CODE);
    		// 设置解码格式
    		decodeHints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
    		// 设置编码方式
    		if (TextUtils.isEmpty(characterSet)) {
    			characterSet = "UTF-8";
    		}
    		decodeHints.put(DecodeHintType.CHARACTER_SET, characterSet);
    		return decodeHints;
    	}
    
    	/**
    	 * 获取默认生成QR参数
    	 * 
    	 * @return
    	 */
    	public static Map<EncodeHintType, Object> getDefaultEncodeHints() {
    		return ENCODE_HINTS;
    	}
    
    	/**
    	 * 获取自定义生成QR参数
    	 * 
    	 * @param level
    	 *            容错率 L,M,Q,H
    	 * @param version
    	 *            版本号 1-40
    	 * @param characterSet
    	 *            编码方式
    	 * @return
    	 */
    	public static Map<EncodeHintType, Object> getCustomEncodeHints(ErrorCorrectionLevel level, Integer version,
    			String characterSet) {
    		Map<EncodeHintType, Object> encodeHints = new EnumMap<>(EncodeHintType.class);
    		// 设置容错率
    		if (level != null) {
    			encodeHints.put(EncodeHintType.ERROR_CORRECTION, level);
    		}
    		// 设置版本号
    		if (version >= 1 && version <= 40) {
    			encodeHints.put(EncodeHintType.QR_VERSION, version);
    		}
    		// 设置编码方式
    		if (!TextUtils.isEmpty(characterSet)) {
    //			characterSet = "UTF-8";
    			encodeHints.put(EncodeHintType.CHARACTER_SET, characterSet);
    		}
    		return encodeHints;
    	}
    
    }
    

    作者:itlgl
    出处:http://www.cnblogs.com/itlgl/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利

  • 相关阅读:
    Python中正则表达式的巧妙使用
    Django的ORM常用查询操作总结(Django编程-3)
    Django的datetime.timedelta类(Django编程-2)
    Python面向对象静态方法,类方法,属性方法
    Python常用的内置函数
    InnoDB和MyISAM的区别
    python中字典和json的区别
    分布式代码管理系统GIT
    安装php扩展 ffmpeg-php
    把文件每隔三行合并成一行(awk之RS、ORS与FS、OFS)
  • 原文地址:https://www.cnblogs.com/itlgl/p/10419278.html
Copyright © 2011-2022 走看看