总所周知,二维码非常普及,android当中我们一般做二维码扫一扫功能大部分用的是zxing库,但是zxing的库demo中没有实现本地相册二维码功能,小编今天拿出来说一下哈哈。
首先我们先导入zxing库,可在build的dependencies里添加 implementation ‘com.google.zxing:core:3.3.1’
// 通过激活系统图库,选择一张图片
Intent innerIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
startActivityForResult(wrapperIntent, IMAGE_CODE);
//我们可以通过这行几行代码进入系统相册选择一张图片然后在onActivityResult里获取数据
但是这里有个小的细节要注意一下:
我们要确保有存储权限之后,这个获取二维码的功能才能正常使用,所有我们应该这样写:
private final int IMAGE_CODE = 0; //这里的IMAGE_CODE是自己任意定义的
/
//跳转相册
private void onJumpPictures(){
PackageManager pm = getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, getPackageName()));
//判断有没有android.permission.WRITE_EXTERNAL_STORAGE权限
if (permission) {
//如果有权限则激活系统相册
// 激活系统图库,选择一张图片
Intent innerIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码图片");
startActivityForResult(wrapperIntent, IMAGE_CODE);
return;
}else {
//请求存储权限
displayFrameworkBugMessageAndExit();
}
}
//打开权限申请框
private void displayFrameworkBugMessageAndExit() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.app_name));
builder.setMessage("存储权限未开启");
builder.setPositiveButton("我的"), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
showInstalledAppDetails(getApplicationContext(), getPackageName());
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
dialog.dismiss();
}
});
builder.show();
}
/**
* 调用系统InstalledAppDetails界面显示已安装应用程序的详细信息。
* 对于Android 2.3(Api Level9)以上,使用SDK提供的接口; 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)。
*
* @param context
* @param packageName 应用程序的包名
*/
public static void showInstalledAppDetails(Context context, String packageName) {
Intent intent = new Intent();
final int apiLevel = Build.VERSION.SDK_INT;
if (apiLevel >= 9) { // 2.3(ApiLevel 9)以上,使用SDK提供的接口
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts(SCHEME, packageName, null);
intent.setData(uri);
} else { // 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)
// 2.2和2.1中,InstalledAppDetails使用的APP_PKG_NAME不同。
final String appPkgName = (apiLevel == 8 ? APP_PKG_NAME_22
: APP_PKG_NAME_21);
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName(APP_DETAILS_PACKAGE_NAME,
APP_DETAILS_CLASS_NAME);
intent.putExtra(appPkgName, packageName);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
//用户从相册选择图片之后的回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) { //此处的 RESULT_OK 是系统自定义得一个常量
return;
} else {
//此处的用于判断接收的Activity是不是你想要的那个
//这说明是用户点击了图片返回到的app界面
if (requestCode == IMAGE_CODE) {
Result result = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
// 获取选中图片的路径
// 外界的程序访问ContentProvider所提供数据 可以通过ContentResolver接口
Cursor cursor = getContentResolver().query(data.getData(),
proj, null, null, null);
if (cursor.moveToFirst()) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
path = cursor.getString(column_index);
if (path == null) {
path = Utils.getPath(getApplicationContext(),
data.getData());
}
}
cursor.close();
result = scanningImage(path);
if (result == null) {
Log.i(TAG,"未识别到二维码");
} else {
Log.i(TAG,"识别到的二维码" + result.toString());
}
} catch (Exception e) {
Log.i(TAG,"报错信息");
}
}
}
}
}
// TODO: 解析部分图片
protected Result scanningImage(String path) {
Bitmap scanBitmap;
if (TextUtils.isEmpty(path)) {
return null;
}
// DecodeHintType 和EncodeHintType
Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); // 设置二维码内容的编码
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 先获取原大小
scanBitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false; // 获取新的大小
int sampleSize = (int) (options.outHeight / (float) 200);
if (sampleSize <= 0)
sampleSize = 1;
options.inSampleSize = sampleSize;
scanBitmap = BitmapFactory.decodeFile(path, options);
if (scanBitmap == null) {
return null;
}
// --------------测试的解析方法---PlanarYUVLuminanceSource-这几行代码对project没作功----------
LuminanceSource source1 = new PlanarYUVLuminanceSource(
rgb2YUV(scanBitmap), scanBitmap.getWidth(),
scanBitmap.getHeight(), 0, 0, scanBitmap.getWidth(),
scanBitmap.getHeight());
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
source1));
MultiFormatReader reader1 = new MultiFormatReader();
Result result1;
try {
result1 = reader1.decode(binaryBitmap);
String content = result1.getText();
Log.i("123content", content);
} catch (NotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// ----------------------------
RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
try {
return reader.decode(bitmap1, hints);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (ChecksumException e) {
e.printStackTrace();
} catch (FormatException e) {
e.printStackTrace();
}
return null;
}
/**
* 中文乱码
* <p>
* 暂时解决大部分的中文乱码 但是还有部分的乱码无法解决 .
*
* @return
*/
private String recode(String str) {
String formart = "";
try {
boolean ISO = Charset.forName("ISO-8859-1").newEncoder()
.canEncode(str);
if (ISO) {
formart = new String(str.getBytes("ISO-8859-1"), "GB2312");
Log.i("1234 ISO8859-1", formart);
} else {
formart = str;
Log.i("1234 stringExtra", str);
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return formart;
}
/**
* //TODO: TAOTAO 将bitmap由RGB转换为YUV //TOOD: 研究中
*
* @param bitmap 转换的图形
* @return YUV数据
*/
public byte[] rgb2YUV(Bitmap bitmap) {
// 该方法来自QQ空间
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
int len = width * height;
byte[] yuv = new byte[len * 3 / 2];
int y, u, v;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int rgb = pixels[i * width + j] & 0x00FFFFFF;
int r = rgb & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb >> 16) & 0xFF;
y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
y = y < 16 ? 16 : (y > 255 ? 255 : y);
u = u < 0 ? 0 : (u > 255 ? 255 : u);
v = v < 0 ? 0 : (v > 255 ? 255 : v);
yuv[i * width + j] = (byte) y;
// yuv[len + (i >> 1) * width + (j & ~1) + 0] = (byte) u;
// yuv[len + (i >> 1) * width + (j & ~1) + 1] = (byte) v;
}
}
return yuv;
}
Utils:
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @param selection
* (Optional) Filter used in the query.
* @param selectionArgs
* (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}