当前位置: 移动技术网 > 移动技术>移动开发>Android > Android 解析二维码图片的两种方法介绍

Android 解析二维码图片的两种方法介绍

2018年09月29日  | 移动技术网移动技术  | 我要评论

做了一个二维码扫描图片,主要是扫描不出来,看到一篇博客,其中的第二种方法可以扫描到,在此做笔记,以备后用,前面的进入相册,返回,到获取图片路径方法都一样;

1.项目需求:知道项目需求,才知道先从哪里入手,见图一。(点击相册,打开图库)

这里写图片描述

2.代码:

1.打开图库代码:

mbtnopenpicture.setonclicklistener(new view.onclicklistener() {
@override
public void onclick(view v) {
 //打开相册
 opengallery();
}
  });



/**打开相册*/
private void opengallery() {
  intent picture = new intent(intent.action_pick,android.provider.mediastore.images.media.external_content_uri);
  startactivityforresult(picture, picture);
 }

2.获取图片路径和解析。

(1). 获取图片路径:getpath(uri);由于android版本不同,返回的uri会有所不同,需要做特殊处理。


@suppresslint("newapi")
 private string getpath(uri uri) {
  int sdkversion = build.version.sdk_int;
  if (sdkversion >= 19) {
//log.e("hxy", "uri auth: " + uri.getauthority());
if (isexternalstoragedocument(uri)) {
 string docid = documentscontract.getdocumentid(uri);
 string[] split = docid.split(":");
 string type = split[0];
 if ("primary".equalsignorecase(type)) {
  return environment.getexternalstoragedirectory() + "/" + split[1];
 }
} 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(this, contenturi, null, null);
} 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(this, contenturi, selection, selectionargs);
} else if (ismedia(uri)) {
 string[] proj = {mediastore.images.media.data};
 cursor actualimagecursor = this.managedquery(uri, proj, null, null, null);
 int actual_image_column_index = actualimagecursor.getcolumnindexorthrow(mediastore.images.media.data);
 actualimagecursor.movetofirst();
 return actualimagecursor.getstring(actual_image_column_index);
}
  } else if ("content".equalsignorecase(uri.getscheme())) {
if (isgooglephotosuri(uri))
 return uri.getlastpathsegment();
return getdatacolumn(this, uri, null, null);
  }
  // file
  else if ("file".equalsignorecase(uri.getscheme())) {
return uri.getpath();
  }
  return null;
 }

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

 private static boolean isexternalstoragedocument(uri uri) {
  return "com.android.externalstorage.documents".equals(uri.getauthority());
 }

 public static boolean isdownloadsdocument(uri uri) {
  return "com.android.providers.downloads.documents".equals(uri.getauthority());
 }

 public static boolean ismediadocument(uri uri) {
  return "com.android.providers.media.documents".equals(uri.getauthority());
 }

 public static boolean ismedia(uri uri) {
  return "media".equals(uri.getauthority());
 }

 public static boolean isgooglephotosuri(uri uri) {
  return "com.google.android.apps.photos.content".equals(uri.getauthority());
 }

(2).开辟线程,解析图片,封装到result中:我看了网上的demo,大致上有2种方法。如下是第一种,稍后会把第二种方法也贴出来。


/**
  * 解析二维码图片
  * @param path
  * @return
  */
 protected result scanningimage(string path) {
  if (textutils.isempty(path)) {
return null;

  }
  hashtable hints = new hashtable();
  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);
  int[] data = new int[scanbitmap.getwidth() * scanbitmap.getheight()];
  scanbitmap.getpixels(data, 0, scanbitmap.getwidth(), 0, 0, scanbitmap.getwidth(), scanbitmap.getheight());
  rgbluminancesource rgbluminancesource = new rgbluminancesource(scanbitmap.getwidth(),scanbitmap.getheight(),data);
  binarybitmap binarybitmap = new binarybitmap(new hybridbinarizer(rgbluminancesource));
  qrcodereader reader = new qrcodereader();
  result result = null;
  try {
result = reader.decode(binarybitmap, hints);
  } catch (notfoundexception e) {
log.e("hxy","notfoundexception");
  }catch (checksumexception e){
log.e("hxy","checksumexception");
  }catch(formatexception e){
log.e("hxy","formatexception");
  }

  return result;


 }

注意:上面方法中有个关键的类,rgbluminancesource。 我把这个类的构造方法贴出来,因为我做的时候,发现网上demo 这个类中构造传递的都是bitmap, 而我这个类却不是。分析传递的参数之后,我做了个转化:见如下,然后会发现报:notfoundexception. 这个异常是在qrcodereader类:private static bitmatrix extractpurebits(bitmatrix image) throws notfoundexception 。(到这里我已经不是很懂了,然后又去网上搜索了下,最后自己探索出加scanbitmap.getpixels(data, 0, scanbitmap.getwidth(), 0, 0, scanbitmap.getwidth(), scanbitmap.getheight());),运行正常,能解析出来。


int[] data = new int[scanbitmap.getwidth() * scanbitmap.getheight()];
//一定要加以下这个代码:
//scanbitmap.getpixels(data, 0, scanbitmap.getwidth(), 0, 0, scanbitmap.getwidth(), //scanbitmap.getheight());
rgbluminancesource rgbluminancesource = new rgbluminancesource(scanbitmap.getwidth(),scanbitmap.getheight(),data);

public rgbluminancesource(int width, int height, int[] pixels) {
  super(width, height);
  this.datawidth = width;
  this.dataheight = height;
  this.left = 0;
  this.top = 0;
  this.luminances = new byte[width * height];

  for(int y = 0; y < height; ++y) {
int offset = y * width;

for(int x = 0; x < width; ++x) {
 int pixel = pixels[offset + x];
 int r = pixel >> 16 & 255;
 int g = pixel >> 8 & 255;
 int b = pixel & 255;
 if(r == g && g == b) {
  this.luminances[offset + x] = (byte)r;
 } else {
  this.luminances[offset + x] = (byte)((r + 2 * g + b) / 4);
 }
}
  }

 }

 

现在来看第二种解析方法:


protected result scanningimage(string path) {
  if (textutils.isempty(path)) {
return null;

  }

  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);
  byte[] data = getyuv420sp(scanbitmap.getwidth(), scanbitmap.getheight(), scanbitmap);

  hashtable hints = new hashtable();
  hints.put(decodehinttype.character_set, "utf-8"); // 设置二维码内容的编码
  hints.put(decodehinttype.try_harder,boolean.true);
  hints.put(decodehinttype.possible_formats, barcodeformat.qr_code);
  planaryuvluminancesource source = new planaryuvluminancesource(data,
 scanbitmap.getwidth(),
 scanbitmap.getheight(),
 0, 0,
 scanbitmap.getwidth(),
 scanbitmap.getheight(),
 false);

  binarybitmap bitmap1 = new binarybitmap(new hybridbinarizer(source));
  qrcodereader reader2= new qrcodereader();
  result result = null;
  try {
result = reader2.decode(bitmap1, hints);
log.e("hxy",result.gettext());
  } catch (notfoundexception e) {
log.e("hxy","notfoundexception");
  }catch (checksumexception e){
log.e("hxy","checksumexception");
  }catch(formatexception e){
log.e("hxy","formatexception");
  }

  return result;


 }



public  byte[] getyuv420sp(int inputwidth, int inputheight,
 bitmap scaled) {
  int[] argb = new int[inputwidth * inputheight];

  scaled.getpixels(argb, 0, inputwidth, 0, 0, inputwidth, inputheight);

  byte[] yuv = new byte[inputwidth * inputheight * 3 / 2];

  encodeyuv420sp(yuv, argb, inputwidth, inputheight);

  scaled.recycle();

  return yuv;
 }


 private void encodeyuv420sp(byte[] yuv420sp, int[] argb, int width,
int height) {
  // 帧图片的像素大小
  final int framesize = width * height;
  // ---yuv数据---
  int y, u, v;
  // y的index从0开始
  int yindex = 0;
  // uv的index从framesize开始
  int uvindex = framesize;

  // ---颜色数据---
//int a, r, g, b;
  int r, g, b;
  //
  int argbindex = 0;
  //

  // ---循环所有像素点,rgb转yuv---
  for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {

 // a is not used obviously
//  a = (argb[argbindex] & 0xff000000) >> 24;
 r = (argb[argbindex] & 0xff0000) >> 16;
 g = (argb[argbindex] & 0xff00) >> 8;
 b = (argb[argbindex] & 0xff);
 //
 argbindex++;

 // well known rgb to yuv algorithm
 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 = math.max(0, math.min(y, 255));
 u = math.max(0, math.min(u, 255));
 v = math.max(0, math.min(v, 255));

 // nv21 has a plane of y and interleaved planes of vu each
 // sampled by a factor of 2
 // meaning for every 4 y pixels there are 1 v and 1 u. note the
 // sampling is every other
 // pixel and every other scanline.
 // ---y---
 yuv420sp[yindex++] = (byte) y;

 // ---uv---
//  if ((j % 2 == 0) && (i % 2 == 0)) {
//
//
// 
//yuv420sp[uvindex++] = (byte) v;
//
//yuv420sp[uvindex++] = (byte) u;
//  }
}
  }
 }

最后2行代码在实际运行的时候,如果是拿一个二维码图片,能正常解析,但是如果不是二维码图片,数组越界。然后我将其注释掉之后,一切正常了。在这里的转化,我没有看懂,只是提供一种解析方案,期待对这方面了解之人能我和探讨。

3.将解析结果回调给调用activity.:


@override
 protected void onactivityresult(int requestcode, int resultcode, intent data) {
  if(resultcode==result_ok&&data != null&&requestcode == picture){
uri selectedimage = data.getdata();
final string pathresult = getpath(selectedimage);
log.e("hxy","pathresult:"+pathresult);

new thread(new runnable() {
 @override
 public void run() {
  result result = scanningimage(pathresult);
  if(result==null){
looper.prepare();
toast.maketext(captureactivity.this, "未识别到二维码",toast.length_long)
  .show();
looper.loop();
  }else{

handledecode(result,new bundle());
// string recode = recode(result.tostring());
// log.e("hxy","recode:"+recode);
// intent data = new intent();
// data.putextra("result", recode);
// setresult(300, data);
//finish();
  }

 }
}).start();
  }
 }

在这里调用handledecode。是由于captureactivity中,将结果就是通过handledecode回调的


/**
  * a valid barcode has been found, so give an indication of success and show
  * the results.
  * 
  * @param rawresult
  *the contents of the barcode.
  * 
  * @param bundle
  *the extras
  */
 public void handledecode(result rawresult, bundle bundle) {
  inactivitytimer.onactivity();
  beepmanager.playbeepsoundandvibrate();

  bundle.putint("width", mcroprect.width());
  bundle.putint("height", mcroprect.height());
  bundle.putstring("result", rawresult.gettext());

//startactivity(new intent(captureactivity.this, resultactivity.class).putextras(bundle));
  setresult(result_ok, new intent().putextras(bundle));
//toast.maketext(this, rawresult.gettext(), toast.length_long);


  finish();
 }

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网