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

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM