(又做了一些优化,就是在原来的基础上添加上了zbar识别二维码的功能,就是先对图片进行处理,然后通过zxing识别,如果zxing识别失败,再通过zbar识别 20170329)
最近项目里让添加本地图片扫描二维码的功能,本来已经加了扫一扫的功能,产品非得让加上本地图片扫码功能,我看了下搜狐和优酷,他们都是只有扫一扫,没有本地图片扫码,我就想着,产品让加就加吧。
在网上搜了搜,很快就搜到了一个demo,也很快就加到我的项目中了,截取了一张二维码的图片,识别出来了,OK,功能加好了,真开心。后来测试一测,说二维码功能没有添加,我就和他们理论,让他们过来复现,结果真的是识别不出来二维码,到底是啥原因啊,我就开始思考,因为他们是用手机拍得一张二维码图片,二维码在整个图片中占的比例很小,我那天自己测的时候,是整张图片基本上被二维码占完了,所以能扫描成功,接着就是解决问题。
一开始上网搜,zxing二维码本地图片识别不出来,识别率低,搜了半天搜出来一个把图片放大,比如放大一倍,这样就可以识别出来了,下面我把把图片放大的代码贴出来,
Bitmap scanBitmap;
int sampleSize=(int)(options.outHeight/(float)200);
options.inJustDecodeBounds=false;
if(sampleSize<=0){
options.inSampleSize=1;
scanBitmap=BitmapFactory.decodeFile(path, options);
Matrix matrix=new Matrix();
matrix.postScale(1.5f,1.5f);
scanBitmap=Bitmap.createBitmap(scanBitmap,0,0,scanBitmap.getWidth(),scanBitmap.getHeight(),matrix,true);
}else{
options.inSampleSize=sampleSize;
scanBitmap=BitmapFactory.decodeFile(path,options);
}
然而并没什么用,不仅没什么用,由于把图片放大了,还可能会造成outofmemory,然后就接着搜索,有人说用zbar,说它的图片二维码的识别率比zxing得高,我实在不想改,不过也没办法,就用zbar试了下,然而并没有什么用,这个时候,有点小崩溃,下班后回到家,就一直想到底是为什么呢,ios的就能识别出来,他们用的是他们系统自带的api来做的,难道是他们ios的扫一扫的apI里的算法比zxing和zbar的效率性能要好,肯定的了,不然为什么同样的图片他们的就能识别出二维码呢(猜得),接着继续想办法,然后就是回忆一下,自己手上的其他项目里有没有这些类似的功能参考下,想了一遍,也没有,但是有从相册中获取图片然后截取图片的功能,然后就又有思路了,对了,图片上的二维码识别不出,是因为二维码在整张图片中的占的比例太小,我能不能对这整张图片进行一下裁剪,把没用的多余的图片部分裁剪掉,接着就开始干,下面是对相册图片裁剪的代码:
public class ImageCropActivity extends BaseActivity { private static final int DEFAULT_ASPECT_RATIO_VALUES = 10; private CropImageView cropImageView; private String pre_path; private boolean pre_flag; private int screen_width, screen_height; private TextView tv_ok, tv_canle; private int x; private int y; private TextView tv_crop; private RelativeLayout rl_layout; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_image_crop); tv_ok = (TextView) findViewById(R.id.tv_ok); tv_canle = (TextView) findViewById(R.id.tv_canle); tv_ok.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub gotoNextStep(); } }); tv_canle.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); rl_layout = (RelativeLayout) findViewById(R.id.rl_image); tv_crop = (TextView) findViewById(R.id.tv_crop); tv_crop.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int switchsize = switchsize(); switch (switchsize) { case 0: x = y = 1; break; case 1: x = 4; y = 3; break; case 2: x = 3; y = 4; break; case 3: x = 674; y = 250; break; default: break; } cropImageView.setAspectRatio(x, y); tv_crop.setText(x + ":" + y); } }); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); screen_width = dm.widthPixels; screen_height = dm.heightPixels; cropImageView = (CropImageView) findViewById(R.id.CropImageView); Intent preIntent = this.getIntent(); pre_path = preIntent.getStringExtra("path"); pre_flag = preIntent.getBooleanExtra("flag", true); Bitmap bitmap = null; if (pre_path != null) { bitmap = BitmapUtil.getBitmapFromSDCard(pre_path); } else { bitmap = BitmapUtil.temp; } if (bitmap != null) { bitmap = resizeSurfaceWithScreen(bitmap, screen_width, screen_height); int degree = readPictureDegree(pre_path); bitmap = rotaingImageView(degree, bitmap); cropImageView.setImageBitmap(bitmap); } if (pre_flag) { cropImageView.setAspectRatio(DEFAULT_ASPECT_RATIO_VALUES, DEFAULT_ASPECT_RATIO_VALUES); } else { cropImageView.setAspectRatio(1, 1); rl_layout.setVisibility(View.INVISIBLE); } } private int size_index = 0; public int switchsize() { size_index++; if (size_index >= 3) { size_index = 0; } return size_index; } private Bitmap resizeSurfaceWithScreen(Bitmap bitmap, int screen_width, int screen_height) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); if (width < screen_width && height < screen_height) { float scale_width = screen_width * 1.0f / width; float scale_height = screen_height * 1.0f / height; float scale = scale_width > scale_height ? scale_height : scale_width; width *= scale; height *= scale; } else { if (width > screen_width) { height = height * screen_width / width; width = screen_width; } if (height > screen_height) { width = width * screen_height / height; height = screen_height; } } bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false); bitmap = BitmapUtil.zoomBitmap(bitmap, width, height); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos); while (baos.toByteArray().length > 1024 * 1024) { baos.reset(); bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos); } ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); Bitmap bitmap_new = BitmapFactory.decodeStream(isBm, null, null); return bitmap_new; } public String saveBitmap(Bitmap bm) { Long tolong = System.currentTimeMillis() / 1000; File f = new File(FileDownloadUtil.getDefaultLocalDir("/cntvScan/temp/"), tolong.toString()); if (f.exists()) { f.delete(); } try { FileOutputStream out = new FileOutputStream(f); bm.compress(Bitmap.CompressFormat.JPEG, 80, out); ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (baos.toByteArray().length > 1024 * 1024) { baos.reset(); bm.compress(Bitmap.CompressFormat.JPEG, 50, out); } out.flush(); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return f.getAbsolutePath(); } public void gotoNextStep() { try { Bitmap croppedImage = cropImageView.getCroppedImage(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); croppedImage.compress(Bitmap.CompressFormat.JPEG, 80, baos); byte[] bitmapByte = baos.toByteArray(); int width = croppedImage.getWidth(); int heigth = croppedImage.getHeight(); Intent data = new Intent(); data.putExtra("bitmap", bitmapByte); data.putExtra("path", saveBitmap(croppedImage)); data.putExtra("width", width); data.putExtra("heigth", heigth); setResult(20, data); finish(); } catch (Exception e) { e.printStackTrace(); } } /** * * @param angle * @param bitmap * @return Bitmap */ public Bitmap rotaingImageView(int angle, Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.postRotate(angle); System.out.println("angle2=" + angle); Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } public int readPictureDegree(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace(); } return degree; } }还有一些其他的工具类,比较多,我就不贴出来了,终于即使图片上二维码的占的比例比较低的图片,也能识别出来二维码了,如果不做这些处理,是识别不出来的,需要demo的人可以联系我,我给发过去,接下来贴出来几张效果图,这图片放的位置不好看哈!
demo下载地址:https://github.com/guoliuya/scant,花了一上午时间抽出来的!