Android从本地选择图片文件转为Bitmap,并用zxing解析Bitmap

2018/11/09 note 共 8297 字,约 24 分钟

如何从本地选择图片文件

使用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;  
	}  
  
}  

文档信息

Search

    Table of Contents