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现在我查到两种解决方案:
- 一种是根据Uri查询图库的数据库,找到文件的真实路径,然后再解析为Bitmap;
- 第二种(http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html)是直接根据Uri直接获取到InputStream,再解析为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;
	}
}
Android从本地选择图片文件转为Bitmap,并用zxing解析Bitmap的更多相关文章
- 用java开发图形界面项目,如何实现从本地选择图片文件并以二进制流的形式保存到MySQL数据库,并重新现实到面板
- type="file"实现兼容IE8本地选择图片预览
		一.HTML代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Uploa ... 
- JS将图片文件转为64位字符串再post到接口上传图片
		HTML: <div class="ai-item upload-id-img"> <p>上传身份证照片</p> <div class=& ... 
- vue使用readAsDataURL实现选择图片文件后预览
		vue实现选择图片文件后预览 利用h5的api可以实现选择文件并实现预览 readAsDataURL 方法会读取指定的 Blob 或 File 对象.读取操作完成的时候,readyState 会变成已 ... 
- Android 调用图库选择图片实现和参数详解
		//选择图片,调用图库 bt4.setOnClickListener(new OnClickListener() { @Override public void o ... 
- [Android] 针对生成的图片文件在系统Gallery不显示的处理
		之前遇到过一个问题,就是发现我在程序中生成一个新的 Bitmap 之后,当我打开系统的 Gallery 查看时,并没有看到新生成的图像.然而打开文件浏览器,找到保存 Bitmap 所在的文件夹下,还能 ... 
- Android获取本地相册图片、拍照获取图片
		需求:从本地相册找图片,或通过调用系统相机拍照得到图片. 容易出错的地方: 1,当我们指定了照片的uri路径,我们就不能通过data.getData();来获取uri,而应该直接拿到uri(用全局变量 ... 
- Android中获取选择图片与获取拍照返回结果差异
		导语: 如今的安卓应用在选择图片的处理上大多合并使用拍照和从相册中选择这两种方式 今天在写一个这样的功能时遇到一个尴尬的问题,同样是拍照获取图片功能,在不同手机上运行的效果不一样,下面是在某型手机上测 ... 
- Android lint 删除无用图片文件和配置文件
		Android lint 删除无用.冗余的 配置文件和 图片资源 转载请注明 http://blog.csdn.net/aaawqqq?viewmode=contents Android项 ... 
随机推荐
- Codeforces - 102222C - Caesar Cipher
			https://codeforc.es/gym/102222/my 好像在哪里见过这个东西?字符的左右移还是小心,注意在mod26范围内. #include<bits/stdc++.h> ... 
- PAT1089【归并排序】
			这题略...恶心.. 他说归并排序依次是相邻有序两块合并,而一向打惯了递归??? #include <bits/stdc++.h> using namespace std; typedef ... 
- js async/await
			一.async 带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装. async f ... 
- 786A(博弈&bfs)
			题目链接: http://codeforces.com/problemset/problem/786/A 题意: 一个环形路径编号为1-n,1号点为黑洞,玩家轮流让怪物前进若干步(从自己的操作集合里随 ... 
- centos7网卡名称修改以及配置
			1.vi /etc/sysconfig/network-scripts/ifcfg-enoxxxxxx 为ifcfg-eth0并 将里面的NAME项修改为eth0 2.禁用该可预测命名规则.在启动时传 ... 
- Jmeter的BeanShell中报错:调用bsh方法时出错Error invoking bsh method: eval
			报错内容:ERROR - jmeter.util.BeanShellInterpreter: Error invoking bsh method: eval In file: inline evalu ... 
- sparkSQL元数据缓存不同步 beeline连接的表结构与hive不一致
			之前遇到过的坑,通过beeline连接spark thirft server,当在Hive进行表结构修改,如replace/add/change columns后,表结构没有变化,还是旧的表结构,导致 ... 
- 使用open live writer客户端写博客(亲测有效)
			博客都开了这么久了,才开始将资料上传,但是每次都要登录网页确实很麻烦,所以就用open live writer,使用起来真的是挺方便的,所以将我在安装配置时,发现的问题汇总起来以便日后再次碰到忘记怎么 ... 
- 配置了SSH后还是每次都要求输入密码
			保存凭证可以解决问题 git config --global credential.helper store 
- Windows下搭建QT环境
			必须软件 qt-windows-opensource-5.1.1-msvc2010-x86-offline qt-vs-addin-1.2.2-opensource支持vs2008.2010.2012 ... 
