1:去除了其余功能后,对于核心功能我们只需要一个SurfaceView和一个画界面的View就可以了。代码如下:
/** * use Java code to build layout instead of xml file * @ch */ private void buildLayout() { requestWindowFeature(Window.FEATURE_NO_TITLE); FrameLayout layout = new FrameLayout(this); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); layout.setLayoutParams(params); surfaceView = new SurfaceView(this); surfaceView.setLayoutParams(params); layout.addView(surfaceView); viewfinderView = new ViewfinderView(this, null); layout.addView(viewfinderView); setContentView(layout); }
ViewfinderView是ZXing自带的View,如果要修改界面,直接修改它就可以了,我们第7点会提到。
2:由于我最终的目的是能打包成jar包,所以beep文件不能放在res里,而是放在assets里。
//待补充
3、API兼容(源码只兼容4.0以上,现兼容至2.1)这部分修改在源码中标记为//@ch api compatible。
CaptureActivity.java: //@ch api compatible if (VERSION.SDK_INT < 11) { //surfaceview will push buffer automatically surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); }//API 11之前需要手动设置,否则会无法显示。API11之后为默认设置。CameraConfigurationManager.java: //@ch api compatible if (VERSION.SDK_INT < 13) { theScreenResolution.x = display.getWidth(); theScreenResolution.y = display.getHeight(); } else { display.getSize(theScreenResolution); }//getSize是API 13之后的新API,之前需要用getWidth和getHeight。AutoFocusManager.java: //@ch api compatible if (VERSION.SDK_INT > 11) { newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { newTask.execute(); }//源码中这里设置了多线程的模式,THREAD_POOL_EXECUTOR表示这个task最多只有5个线程同时运行,超过5个的就要等待。在低于API 11的版本中,此为默认选项。其实这里只有单线程,所以随便执行吧。OpenCameraInterface.java: //@ch api compatible if (VERSION.SDK_INT < 9) { return openWithLowApi(); }...... /** * for lower than API 9 * @ch api compatible */ public static Camera openWithLowApi() { //If the device does not have a back-facing camera, this returns null Camera camera = Camera.open(); return camera; }//源码的打开摄像头是能区分前后摄像头的,然而API 9之前并没有前置摄像头这个概念,所以做了一下处理
就几个地方,不过也找了我个把小时了。
4、转换为竖屏(源码为横屏)ZXing默认是横屏,但是我们一般的APP都会做成竖屏,如果扫码的时候强制切换成横屏那样体验就不好了。在修改ZXing的竖屏的时候,我按照的是一般APP的竖屏设置方法,结果发现没有源码的效果好,需要把码放到很小才能完成。后面在调试过程中发现扫码解析的区域和屏幕画出来的区域不一样,才知道这部分的修改出了问题。然后我搜索找到一篇前辈的文章,参考了一下发现没有改完全。附上文件链接: http://blog.csdn.net/aaawqqq/article/details/24804939
其中第五点我没有修改,文章中的源码可能比较旧,并不适合替换。第5点不替换替换是没有问题的。
此外还有一点需要修改的是:
CameraManager.java: //@ch change 240 to 120 for 320x240 machine private static final int MIN_FRAME_WIDTH = 120; private static final int MIN_FRAME_HEIGHT = 120; //@ch change to vertical private static final int MAX_FRAME_HEIGHT = (int) 1080; private static final int MAX_FRAME_WIDTH = (int) 1080;//此处为扫描框最大边界和最小边界的界定。但因为我最后做成了正方形,所以这里数值是一样的。如果为矩形,需要把两个值交换一下。//设置最小值是为了保证解码的成功率,毕竟分辨率太小就没法识别了。最大值是为了保证解码速度。其实最大值应该通过插值来重新构图,不然框的大小不一致体验就不好了。不过这样的分辨率起码是2K屏以上了,所以最大值设定不会有什么影响
5、扫码速度优化(主要分三点,现只完成了一点)1.二值化算法优化。ZXing一共提供了两种二值化算法,一种是HybridBinarizer,另一种是GlobalHistogramBinarizer,默认使用的是HybridBinarizer。我搜集资料的时候发现,HybridBinarizer算法用了更高级的算法,运算要求更高,而总体来讲GlobalHistogramBinarizer识别率要更高。在我的实际测试中(我用的Nexus5,Android 5.0.1),GlobalHistogramBinarizer效果确实是要好不少。
这里的修改很简单,换一个类就可以了:
DecodeHandler.java:private void decode(byte[] data, int width, int height) { ...... //@ch you can use HybridBinarizer or GlobalHistogramBinarizer //but in most of situations HybridBinarizer is shit BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source)); ......}
2.对焦优化。ZXing中的对焦功能在AutoFocusManager.java中,功能非常简单,设置自动对焦并2秒对焦一次。但自动对焦可能会带来一个问题,如下图:
(图片源自网络)
把二维码当作图中的那朵花,自动对焦则容易使摄像头对焦到背景(图中女性)中去。我在测试中使用三星S4的自动对焦经常对不了二维码。这里我们可以使用区域对焦的方法(对焦的区域即是扫描框的区域):
//定点对焦的代码 private void pointFocus(int x, int y) { if (cameraParameters.getMaxNumMeteringAreas() > 0) { List<Camera.Area> areas = new ArrayList<Camera.Area>(); Rect area = new Rect(x - 100, y - 100, x + 100, y + 100); areas.add(new Camera.Area(area, 600));
cameraParameters.setMeteringAreas(areas); } mCamera.cancelAutoFocus(); cameraParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO); mCamera.setParameters(cameraParameters); mCamera.autoFocus(autoFocusCallBack); }
区域对焦需要API 14以上。关于对焦暂时没有更多的想法,但我觉得确实是有优化的余地的。
3.算法优化。算法主要分两部分,第一部分是二值化,第二部分是提取码值。第二部分又分为1.寻找定位符,2.寻找校正符,3.转换矩阵。在测试过程中,影响识别的最大问题就是找不到定位符,即二维码、、的三个黑白相间的矩形点。比较大的原因可能是二值化部分的问题。这一部分暂时也还没有深入。
6、设备兼容(针对低分辨率设备)