上篇文章中我们已经完成了及其粗糙版本的扫码App,这篇文章我们将对这个粗糙的扫码App进行优化;
和市面大多数扫码一样,做成竖屏
扫码框的位置优化
自定义title
看心情优化
立起来!
CaptureActivity 配置设成portait,onResume 中注释掉设置横屏的代码
<activity android:name=".CaptureActivity"
android:screenOrientation="portrait"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
跑一下程序,完美!
这个时候,已经能扫二维码了,但是识别率很低,把手机横着扫,识别率就高,把扫码后识别的图片打印出来,发现只是表面上看起来竖屏了,但是相机识别的还是横屏的内容。
ZXing 横屏转竖屏
需要修改的地方就2处
第一个地方,CameraManager里的 getFramingRectInpreview()方法,增加cameraResolution的判断
if(cameraResolution.x>cameraResolution.y){ //x大于y 改成竖屏数据,y和x互换 计算截图
rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
}else{
rect.left = rect.left * cameraResolution.x / screenResolution.x;
rect.right = rect.right * cameraResolution.x / screenResolution.x;
rect.top = rect.top * cameraResolution.y / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
}
第二个地方,DecodeHandler 的decode(byte[] data, int width, int height) 方法对data[](这个data就是要解析的数据源)数据进行矩阵替换,宽高互换
private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
Result rawResult = null;
byte[] newData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
newData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width; // Here we are swapping, that's the difference to #11
width = height;
height = tmp;
data = newData;
PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
if (source != null) {
两步骚操作之后,我们再来看看效果
完美!
如果想修改扫码框的位置 可以在此处修改
public synchronized Rect getFramingRect() {
if (framingRect == null) {
if (camera == null) {
return null;
}
Point screenResolution = configManager.getScreenResolution();
if (screenResolution == null) {
// Called early, before init even finished
return null;
}
int width = findDesiredDimensionInRange(screenResolution.x, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
int height = findDesiredDimensionInRange(screenResolution.y, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
int leftOffset = (screenResolution.x - width) / 2;//修改比例改变扫码框位置
int topOffset = (screenResolution.y - height) / 3;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated framing rect: " + framingRect);
}
return framingRect;
}
Zxing 增加从相册选取图片二维码识别
添加一个按钮,点击事件吊起相册
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); //"android.intent.action.GET_CONTENT"
innerIntent.setType("image/*");
Intent wrapperIntent = Intent.createChooser(innerIntent, "选择二维码");
startActivityForResult(wrapperIntent, 100);
}
});
在onActivityResult里处理选择的代码
@Override
protected void onActivityResult(final int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case 100:
handleAlbumPic(data);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
这个地方碰到超多坑,利用Zxing给的方法和网上找的方法,各种识别图片NotfoundException,
而且新的Zxing包和之前的包接口还不一样了,用网上的很多方法都不行,就在我快要放弃的时候,看到一篇博客提供了如下代码,虽然识别率不是很高,但是也算是成功了。识别率这个问题,大家可以在加入zbar解析。
Uri sourceUri = data.getData();
try {
// 下面这句话可以通过URi获取到文件的bitmap
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),sourceUri);
// 在这里我用到的 getSmallerBitmap 非常重要,下面就要说到
bitmap = ImageUtil.getSmallerBitmap(bitmap);
// 获取bitmap的宽高,像素矩阵
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width*height];
bitmap.getPixels(pixels,0,width,0,0,width,height);
// 最新的库中,RGBLuminanceSource 的构造器参数不只是bitmap了
RGBLuminanceSource source = new RGBLuminanceSource(width,height,pixels);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
MultiFormatReader reader = new MultiFormatReader();
Result result = null;
// 尝试解析此bitmap,!!注意!! 这个部分一定写到外层的try之中,因为只有在bitmap获取到之后才能解析。写外部可能会有异步的问题。(开始解析时bitmap为空)
try {
result = reader.decode(binaryBitmap);
handleDecode(result,bitmap,1);
} catch (NotFoundException e) {
Log.i(TAG, "onActivityResult: notFind");
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
这里将bitmap进行了转化,将大图变小,太大zxing就notfound exception了
public static Bitmap getSmallerBitmap(Bitmap bitmap){
int size = bitmap.getWidth()*bitmap.getHeight() / 160000;
if (size <= 1) return bitmap; // 如果小于
else {
Matrix matrix = new Matrix();
matrix.postScale((float) (1 / Math.sqrt(size)), (float) (1 / Math.sqrt(size)));
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
return resizeBitmap;
}
}
博客原文 https://blog.csdn.net/qq_28057541/article/details/52119896
老版本Zxing 解决方案:https://blog.csdn.net/u013200308/article/details/68067564
GitHub 项目地址,ZxingDemo是修改后的
主要难点就是Zxing竖屏切换,Camera获取的数据源也要切换的问题。都看到这里了,点个赞呗。