如何從本地選擇圖片文件
使用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;
}
}