在这篇文章之前,如果还不知道如何下载、运行官方demo,打包zxing jar包,请跳到
http://blog.csdn.net/quwei3930921/article/details/51206245
1.在AndroidManifest.xml中,把Activity的属性
android:screenOrientation="landscape"
改为
android:screenOrientation="portrait"
2.在CameraManager.java文件中,选择框调整
原代码:
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) / 2;
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated framing rect: " + framingRect);
}
return framingRect;
}
修改为
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, height, leftOffset, topOffset;
if (screenResolution.x < screenResolution.y) { // 竖屏
width = screenResolution.x * 9 / 10;
height = width * 9 / 16; // 采用16:9的比例
leftOffset = (screenResolution.x - width) / 2;
topOffset = (screenResolution.y - height) / 2;
} else {
height = screenResolution.y * 5 / 10;
width = height * 16 / 9;
leftOffset = (screenResolution.x - width) / 2;
topOffset = (screenResolution.y - height) / 2;
}
// 修改完成
framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
Log.d(TAG, "Calculated framing rect: " + framingRect);
}
return framingRect;
}
3.在CameraManager.java文件中,修改预览缩放
原代码:
public synchronized Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect framingRect = getFramingRect();
if (framingRect == null) {
return null;
}
Rect rect = new Rect(framingRect);
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
if (cameraResolution == null || screenResolution == null) {
// Called early, before init even finished
return null;
}
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;
framingRectInPreview = rect;
}
return framingRectInPreview;
}
修改为
public synchronized Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect framingRect = getFramingRect();
if (framingRect == null) {
return null;
}
Rect rect = new Rect(framingRect);
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
if (cameraResolution == null || screenResolution == null) {
// Called early, before init even finished
return null;
}
// 修改开始
if (screenResolution.x < screenResolution.y) {
// 下面为竖屏模式
rect.left = framingRect.left * cameraResolution.y / screenResolution.x;
rect.right = framingRect.right * cameraResolution.y / screenResolution.x;
rect.top = framingRect.top * cameraResolution.x / screenResolution.y;
rect.bottom = framingRect.bottom * cameraResolution.x / screenResolution.y;
} else {
// 下面为横屏模式
rect.left = framingRect.left * cameraResolution.x / screenResolution.x;
rect.right = framingRect.right * cameraResolution.x / screenResolution.x;
rect.top = framingRect.top * cameraResolution.y / screenResolution.y;
rect.bottom = framingRect.bottom * cameraResolution.y / screenResolution.y;
}
// 修改完成
framingRectInPreview = rect;
}
return framingRectInPreview;
}
4.在CameraManager.java文件中,修改解析函数
原代码:
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
Rect rect = getFramingRectInPreview();
if (rect == null) {
return null;
}
// Go ahead and assume it's YUV rather than die.
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height(), false);
}
修改后:
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
Rect rect = getFramingRectInPreview();
if (rect == null) {
return null;
}
// 修改开始
PlanarYUVLuminanceSource source;
Point point = configManager.getScreenResolution();
if (point.x < point.y) {
// 竖屏对应修改,条码解析默认是横向解析
byte[] rotatedData = new byte[data.length];
int newWidth = height;
int newHeight = width;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * newWidth + newWidth - 1 - y] = data[x + y * width];
}
source = new PlanarYUVLuminanceSource(rotatedData, newWidth, newHeight,
rect.left, rect.top, rect.width(), rect.height(), false);
} else {
source = new PlanarYUVLuminanceSource(data, width, height,
rect.left, rect.top, rect.width(), rect.height(), false);
}
// 修改完成
return source;
}
5.在CameraConfigurationUtils.java文件中,我们在findBestPreviewSizeValue方法找到以下代码
boolean isCandidatePortrait = realWidth < realHeight;
int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
double distortion = Math.abs(aspectRatio - screenAspectRatio);
if (distortion > MAX_ASPECT_DISTORTION) {
it.remove();
continue;
}
这段代码用于排除镜头分辨率纵横比例与屏幕分辨率纵横比例相差较大的镜头分辨率,还有一点就是上述代码aspectRatio的值始终是大值比小值,那么screenAspectRatio的值也应该是大值比小值。我们在该方法中找到screenAspectRatio的赋值语句:
double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
对于竖屏这里明显是不正确的,所以修改为
double screenAspectRatio;
if (screenResolution.x < screenResolution.y) { // 竖屏
screenAspectRatio = (double) screenResolution.y / (double) screenResolution.x;
} else {
screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
}
再这个函数中,还有个地方要注意,因为它直接影响到识别的速度和准确率:
if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
Point exactPoint = new Point(realWidth, realHeight);
Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
return exactPoint;
}
对于镜头分辨率高,而屏幕分辨率低的手机,这段代码直接导致zxing会采用较低的分辨率去生成用于解析的位图,所以直接去掉。然后你就会发现低分辨率的手机,对二维码、条码的识别率提高了n个级别。
6.在CameraConfigurationManager.java文件中,在setDesiredCameraParameters方法中找到:
parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);
在该代码上方添加对焦距的调整,让识别效果更加快速、准确:
CameraConfigurationUtils.setZoom(parameters, 1.5);
parameters.setPreviewSize(bestPreviewSize.x, bestPreviewSize.y);
总结,为了公司app较好的对条码的识别,zxing的demo也来回读了很多遍,最后得出以上调整。同时支持横竖屏,只需在manifest中设置即可。识别速度快、准,与微信基本没差距,领导、用户都很满意。如果还有什么问题,请留言。