参考文章 https://www.jianshu.com/p/a4ba10da4231
一、ZXing 项目
1.https://github.com/zxing/zxing
2.新建module
使用Android Studio 新建一个工程 包名设置为com.google.zxing.client.android
(与zxing android工程包名一样,省去一些手工导包修改过程操作)
2.1 gradle 引入zxing核心架包core 和 android-core
dependencies {
implementation 'com.google.zxing:core:3.3.3'
implementation 'com.google.zxing:android-core:3.3.0'
}
2.2 简单横屏转竖屏修改
参考https://github.com/zxing/zxing/issues/576
参考https://github.com/zxing/zxing/issues/111
中
@GuoJinyu用户的修改: https://github.com/zxing/zxing/issues/111#issuecomment-263175368
@srowen
I think the most important point to support for Android portrait mode is rotating the YUV preview frame data array, because the preview frame you get is only relative to the camera’s orientation (always landscape at nearly all of Android phones) which has no relation to the screen’s orientation.
So this is my steps to support portrait mode in version 4.7.7:
1. Removing "android:screenOrientation="sensorLandscape"
in AndroidManifest.xml
2. Changing lines from 172 to 176
in CaptureActivity.java
to support both landscape and portrait
if (prefs.getBoolean(PreferencesActivity.KEY_DISABLE_AUTO_ORIENTATION, true)) {
setRequestedOrientation(getCurrentOrientation());
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
3. Changing lines from 327 to 329
in CameraConfigurationUtils.java
to get proper aspectRatio in accordence with screen orientation
boolean isScreenPortrait = screenResolution.x < screenResolution.y;
int maybeFlippedWidth = isScreenPortrait ? realHeight : realWidth;
int maybeFlippedHeight = isScreenPortrait ? realWidth : realHeight;
4. Changing lines from 266 to 269
in CameraManager.java
to get precise preview rectangle for camera.
if(screenResolution.x < screenResolution.y){
// portrait
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 {
// landscape
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;
}
5. Changing lines from 47 to 48
in PreviewCallback.java
to send proper width and height of preview frame
Point screenResolution = configManager.getScreenResolution();
Message message;
if (screenResolution.x < screenResolution.y){
// portrait
message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.y,
cameraResolution.x, data);
} else {
// landscape
message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
}
6. Adding lines between 76 and 77
in DecodeHandler.java
to rotate data when portrait
long start = System.currentTimeMillis();
if (width < height) {
// portrait
byte[] rotatedData = new byte[data.length];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++)
rotatedData[y * width + width - x - 1] = data[y + x * height];
}
data = rotatedData;
}
Result rawResult = null;
7. To support portrait mode perfectly, you should also do this follow my comment in this issue
Above-mentioned code modify has been tested on both 1D and 2D code and works good in my two Android phones with back camera.
BTW, I have published an Android scanner library by simplifying this Android project SimpleZXing
2.3 zxing3.3.3 版本修改
1. AndroidManifest.xml
中CaptureActivity
设置竖屏android:screenOrientation="portrait"
<activity android:name=".CaptureActivity"
android:screenOrientation="portrait"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/CaptureTheme"
android:windowSoftInputMode="stateAlwaysHidden">
2.CameraManager.java
中方法getFramingRectInPreview
()修改
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;
}
boolean isScreenPortrait = screenResolution.x < screenResolution.y;
boolean isCameraSizePortrait = cameraResolution.x < cameraResolution.y;
if (isScreenPortrait == isCameraSizePortrait) {
/*默认 横屏*/
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;
} else {
/*竖屏*/
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;
}
framingRectInPreview = rect;
}
return framingRectInPreview;
}
3.DecodeHandler.java
中decode(byte[] data, int width, int height)
修改
private void decode(byte[] data, int width, int height) {
long start = System.nanoTime();
Result rawResult = null;
if (isScreenPortrait()) {
//竖屏
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width;
width = height;
height = tmp;
data = rotatedData;
}
PlanarYUVLuminanceSource source = activity.getCameraManager().buildLuminanceSource(data, width, height);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
} catch (ReaderException re) {
// continue
} finally {
multiFormatReader.reset();
}
}
...省略
private boolean isScreenPortrait() {
WindowManager manager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point screenResolution = new Point();
display.getSize(screenResolution);
return screenResolution.x < screenResolution.y;
}
4. 个别参数修改,如,扫码区自动对焦、扫描区域上移
CameraManager.java
里面 扫描区域偏上getFramingRect()
、扫码区自动对焦openDriver(SurfaceHolder holder)