Browse Source

初步集成原生

詹子聪 5 years ago
parent
commit
12037d3508

+ 1 - 1
app/build.gradle

@@ -76,7 +76,7 @@ dependencies {
     implementation 'com.zhihu.android:matisse:0.5.3-beta3'
 
     //startActivityForResult
-    //implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
+    implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
 
     // 图片压缩
     implementation 'id.zelory:compressor:2.1.0'

+ 27 - 28
app/src/main/java/com/miekir/ocr/OCRApplication.java

@@ -2,8 +2,7 @@ package com.miekir.ocr;
 
 import android.app.Application;
 
-import com.yc.toollib.crash.CrashHandler;
-import com.yc.toollib.crash.CrashListener;
+import rx_activity_result2.RxActivityResult;
 
 
 /**
@@ -23,31 +22,31 @@ public class OCRApplication extends Application {
         super.onCreate();
         sInstance = this;
 
-        //RxActivityResult.register(this);
-
-        CrashHandler.getInstance().init(this, new CrashListener() {
-            /**
-             * 重启app
-             */
-            @Override
-            public void againStartApp() {
-                //CrashToolUtils.reStartApp1(App.this,1000);
-                //CrashToolUtils.reStartApp2(App.this,1000, MainActivity.class);
-                //CrashToolUtils.reStartApp3(AppManager.getAppManager().currentActivity());
-            }
-
-            /**
-             * 自定义上传crash,支持开发者上传自己捕获的crash数据
-             * @param ex                        ex
-             */
-            @Override
-            public void recordException(Throwable ex) {
-                //崩溃文件存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashLogs
-                //崩溃文件存储路径:/storage/emulated/0/Android/data/com.miekir.ocr/cache/crashLogs
-                //崩溃页面截图存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashPics
-                //自定义上传crash,支持开发者上传自己捕获的crash数据
-                //StatService.recordException(getApplication(), ex);
-            }
-        });
+        RxActivityResult.register(this);
+
+//        CrashHandler.getInstance().init(this, new CrashListener() {
+//            /**
+//             * 重启app
+//             */
+//            @Override
+//            public void againStartApp() {
+//                //CrashToolUtils.reStartApp1(App.this,1000);
+//                //CrashToolUtils.reStartApp2(App.this,1000, MainActivity.class);
+//                //CrashToolUtils.reStartApp3(AppManager.getAppManager().currentActivity());
+//            }
+//
+//            /**
+//             * 自定义上传crash,支持开发者上传自己捕获的crash数据
+//             * @param ex                        ex
+//             */
+//            @Override
+//            public void recordException(Throwable ex) {
+//                //崩溃文件存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashLogs
+//                //崩溃文件存储路径:/storage/emulated/0/Android/data/com.miekir.ocr/cache/crashLogs
+//                //崩溃页面截图存储路径:/storage/emulated/0/Android/data/你的包名/cache/crashPics
+//                //自定义上传crash,支持开发者上传自己捕获的crash数据
+//                //StatService.recordException(getApplication(), ex);
+//            }
+//        });
     }
 }

+ 210 - 0
app/src/main/java/com/miekir/ocr/ui/camera/oppo/OppoCameraActivity.java

@@ -0,0 +1,210 @@
+package com.miekir.ocr.ui.camera.oppo;
+
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+
+import com.miekir.ocr.R;
+import com.miekir.ocr.base.BaseCameraActivity;
+import com.otaliastudios.cameraview.CameraListener;
+import com.otaliastudios.cameraview.CameraLogger;
+import com.otaliastudios.cameraview.CameraOptions;
+import com.otaliastudios.cameraview.CameraUtils;
+import com.otaliastudios.cameraview.CameraView;
+import com.otaliastudios.cameraview.PictureResult;
+import com.otaliastudios.cameraview.controls.Flash;
+import com.otaliastudios.cameraview.controls.Preview;
+import com.otaliastudios.cameraview.filter.Filters;
+import com.otaliastudios.cameraview.filter.MultiFilter;
+import com.otaliastudios.cameraview.filters.ContrastFilter;
+import com.otaliastudios.cameraview.filters.SharpnessFilter;
+import com.otaliastudios.cameraview.frame.Frame;
+import com.otaliastudios.cameraview.frame.FrameProcessor;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/10/29 15:14
+ * Description:
+ */
+public class OppoCameraActivity extends BaseCameraActivity {
+    protected CameraView camera;
+    private ImageView iv_flash;
+    private boolean mIsFlashOpen = false;
+    protected int mLeft;
+    protected int mTop;
+    protected int mRight;
+    protected int mBottom;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_oppo;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        camera = findViewById(R.id.camera);
+        setupCamera();
+
+        View fl_camera_size = findViewById(R.id.fl_camera_size);
+        fl_camera_size.post(new Runnable() {
+            @Override
+            public void run() {
+                // 设置拍照的分辨率
+                //AspectRatio ratio = AspectRatio.of(new Size(camera.getWidth(), camera.getHeight()));
+                /*AspectRatio ratio = AspectRatio.parse(camera.getWidth() + ":" + camera.getHeight());
+                SizeSelector matchRatio = SizeSelectors.aspectRatio(ratio, 50);
+                SizeSelector matchSize = new SizeSelector() {
+                    @NonNull
+                    @Override
+                    public List<Size> select(@NonNull List<Size> source) {
+                        List<Size> sizeList = new ArrayList<>();
+                        sizeList.add(new Size(camera.getWidth(), camera.getHeight()));
+                        return sizeList;
+                    }
+                };
+                SizeSelector matchAll = SizeSelectors.or(
+                        SizeSelectors.and(matchRatio, matchSize), // Try to respect both constraints.
+                        matchRatio, // If couldn't respect size, at least match aspect ratio
+                        matchSize, // If couldn't match aspect ratio, at least respect the size
+                        SizeSelectors.biggest() // If couldn't match any, take the biggest.
+                );
+                camera.setPictureSize(matchAll);*/
+
+
+                // 这两个方法只能设置小于屏幕分辨率的
+                //camera.setSnapshotMaxWidth(camera.getWidth() * 2 + 100);
+                //camera.setSnapshotMaxHeight(camera.getHeight() * 2 + 100);
+                // 高质量输出
+                //camera.setPictureSnapshotMetering(true);
+
+
+
+                setWidthHeight(camera.getWidth(), camera.getHeight());
+            }
+        });
+
+        camera.addFrameProcessor(new FrameProcessor() {
+            @Override
+            public void process(@NonNull Frame frame) {
+
+            }
+        });
+
+        iv_flash = findViewById(R.id.iv_flash);
+        iv_flash.setOnClickListener(v -> {
+            mIsFlashOpen = !mIsFlashOpen;
+            //mIsCapturing = false;
+            if (mIsFlashOpen) {
+                iv_flash.setImageResource(R.mipmap.flash_open);
+                camera.setFlash(Flash.OFF);
+            } else {
+                iv_flash.setImageResource(R.mipmap.flash_close);
+                camera.setFlash(Flash.OFF);
+            }
+        });
+    }
+
+    private void setupCamera() {
+        CameraLogger.setLogLevel(CameraLogger.LEVEL_ERROR);
+        camera.setLifecycleOwner(this);
+        camera.addCameraListener(new Listener());
+        camera.setPlaySounds(false);
+        camera.setSoundEffectsEnabled(false);
+        // 预览尺寸不要超过1920x1080,否则相机带宽吃紧,这也是Camera2 API的要求.
+        //camera.setPreviewStreamSize(SizeSelectors.biggest());将会卡顿
+        camera.close();
+        camera.open();
+        // 减少曝光
+        camera.post(new Runnable() {
+            @Override
+            public void run() {
+                CameraOptions options = camera.getCameraOptions();
+                if (options != null) {
+                    camera.setExposureCorrection(options.getExposureCorrectionMinValue()/5);
+                }
+            }
+        });
+
+        //camera.setWhiteBalance(WhiteBalance.CLOUDY);
+
+        //cameraView.setPictureSize { arrayListOf(Size(768, 1024)) }
+        //camera.setFilter(Filters.SHARPNESS.newInstance());
+        SharpnessFilter sharpnessFilter = (SharpnessFilter)Filters.SHARPNESS.newInstance();
+        //0~1.0
+        sharpnessFilter.setSharpness(0.06f);
+        ContrastFilter contrastFilter = (ContrastFilter)Filters.CONTRAST.newInstance();
+        //1.0~2.0
+        contrastFilter.setContrast(1.06f);
+
+        MultiFilter multiFilter = new MultiFilter(
+                sharpnessFilter,
+                contrastFilter
+        );
+        //camera.setFilter(multiFilter);
+        //camera.setHdr(Hdr.ON);
+    }
+
+    private boolean mIsCapturing = false;
+    protected boolean mIsUploading = false;
+    public void takePhoto() {
+        if (mIsUploading || mIsCapturing || camera.isTakingPicture()) {
+            return;
+        }
+        if (camera.getPreview() != Preview.GL_SURFACE) {
+            //Picture snapshots are only allowed with the GL_SURFACE preview.
+            return;
+        }
+
+        mIsUploading = true;
+
+        // 开始拍照,takePictureSnapshot不会触发闪光灯
+        if (mIsFlashOpen) {
+            mIsCapturing = true;
+            camera.setFlash(Flash.TORCH);
+            camera.startAutoFocus(new RectF(mLeft, mTop, mRight, mBottom));
+        } else {
+            camera.takePictureSnapshot();
+            //camera.takePicture();
+        }
+    }
+
+    class Listener extends CameraListener {
+        @Override
+        public void onAutoFocusEnd(boolean successful, @NonNull PointF point) {
+            super.onAutoFocusEnd(successful, point);
+            if (mIsCapturing) {
+                mIsCapturing = false;
+                camera.takePictureSnapshot();
+            }
+        }
+
+        @Override
+        public void onPictureTaken(@NonNull PictureResult result) {
+            super.onPictureTaken(result);
+
+            String extension;
+            switch (result.getFormat()) {
+                case JPEG:
+                    extension = ".jpg";
+                    break;
+                case DNG:
+                    extension = ".dng";
+                    break;
+                default:
+                    return;
+            }
+
+            camera.setFlash(Flash.OFF);
+            mIsCapturing = false;
+            Bitmap bitmap = CameraUtils.decodeBitmap(result.getData());
+            takePhotoResult(bitmap);
+        }
+    }
+}

+ 344 - 0
app/src/main/java/com/miekir/ocr/ui/camera/oppo/OppoOperationActivity.java

@@ -0,0 +1,344 @@
+package com.miekir.ocr.ui.camera.oppo;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.miekir.common.utils.SizeTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.ocr.R;
+import com.miekir.ocr.bean.OcrResult;
+import com.miekir.ocr.tool.AnimateManager;
+import com.miekir.ocr.tool.SystemTool;
+import com.miekir.ocr.ui.IOperationView;
+import com.miekir.ocr.ui.OperationPresenter;
+import com.miekir.ocr.widget.CropView;
+import com.miekir.ocr.widget.GlideV4ImageEngine;
+import com.miekir.ocr.widget.IndicatorText;
+import com.zhihu.matisse.Matisse;
+import com.zhihu.matisse.MimeType;
+
+import java.io.File;
+import java.util.List;
+
+import static android.os.Environment.DIRECTORY_PICTURES;
+
+/**
+ * Copyright (C), 2019-2020, Genlot
+ *
+ * @author 詹子聪
+ * @date 2020/7/27 9:01
+ * Description: 菜单操作
+ */
+public class OppoOperationActivity extends OppoCameraActivity implements CropView.OnRectChangeListener, View.OnClickListener, IOperationView {
+    private static final int REQUEST_CODE_CHOOSE = 6;
+
+    @InjectPresenter
+    OperationPresenter mOperationPresenter;
+
+    private int mCurrentType = CropView.SCAN_TYPE_ALL;
+    private String mCurrentScene = CropView.SCAN_SCENES[mCurrentType];
+    private int[] MENU_ID_LIST = {R.id.it_postal, R.id.it_address, R.id.it_name, R.id.it_all};
+
+    private TextView tv_orientation;
+    private String mLandscapeString;
+    private String mPortraitString;
+
+    private CropView pcv_scan;
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        super.initViews(savedInstanceState);
+
+        int[] clickIds = new int[]{R.id.it_postal, R.id.fl_take, R.id.it_address, R.id.it_name, R.id.it_all, R.id.fl_album};
+        ViewTool.setOnClickListener(this, clickIds, this);
+
+        // 裁剪View
+        pcv_scan = findViewById(R.id.pcv_scan);
+        pcv_scan.setLocationListener(this);
+        // debug,lambda可以回调,类实现接口可以回调,内部类可以回调,但是匿名内部类不行(实际上已经执行),估计是AS4的bug
+        pcv_scan.setOnFingerUpListener(event -> {
+            if (camera != null) {
+                camera.startAutoFocus(event.getX(), event.getY());
+            }
+        });
+
+        mLandscapeString = getResources().getString(R.string.landscape);
+        mPortraitString = getResources().getString(R.string.portrait);
+        tv_orientation = findViewById(R.id.tv_orientation);
+        tv_orientation.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fl_take:
+                takePhoto();
+                break;
+            case R.id.fl_album:
+                Matisse.from(this)
+                        .choose(MimeType.ofImage())
+                        .countable(true)
+                        .maxSelectable(1)
+                        //.addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
+                        //.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
+                        .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
+                        .thumbnailScale(0.85f)
+                        //.imageEngine(new GlideEngine())
+                        .imageEngine(new GlideV4ImageEngine())
+                        //.showPreview(false) // Default is `true`
+                        .forResult(REQUEST_CODE_CHOOSE);
+                break;
+
+            case R.id.it_postal:
+            case R.id.it_address:
+            case R.id.it_name:
+            case R.id.it_all:
+                setScanArea(v.getId());
+                if (v.getId() == R.id.it_all) {
+                    tv_orientation.setText(mLandscapeString);
+                    tv_orientation.setVisibility(View.VISIBLE);
+                } else {
+                    tv_orientation.setVisibility(View.INVISIBLE);
+                }
+                break;
+
+            case R.id.tv_orientation:
+                String textOld = tv_orientation.getText().toString();
+                if (TextUtils.equals(mLandscapeString, textOld)) {
+                    tv_orientation.setText(mPortraitString);
+                } else {
+                    tv_orientation.setText(mLandscapeString);
+                }
+
+                if (tv_orientation.getVisibility() == View.VISIBLE) {
+                    // 切换横竖屏
+                    AnimateManager.getInstance().stopAnimation();
+                    pcv_scan.switchOrientation();
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 设置裁剪区域
+     * @param viewId
+     */
+    private void setScanArea(int viewId) {
+        for (int index = 0, len = MENU_ID_LIST.length; index < len; index++) {
+            IndicatorText indicatorText = findViewById(MENU_ID_LIST[index]);
+            if (MENU_ID_LIST[index] == viewId) {
+                indicatorText.onIndicatorClicked();
+                mCurrentType = CropView.SCAN_TYPES[index];
+                mCurrentScene = CropView.SCAN_SCENES[index];
+            } else {
+                indicatorText.onIndicatorRelease();
+            }
+        }
+        pcv_scan.setScanArea(mCurrentType);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        pcv_scan.setLocationListener(null);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_CHOOSE && data != null) {
+            List<Uri> selectedList = Matisse.obtainResult(data);
+            if (selectedList != null && selectedList.size() > 0) {
+                if (tv_orientation.getVisibility() == View.VISIBLE) {
+                    mOperationPresenter.startOcrFromUri(this, selectedList.get(0), mCurrentScene, pcv_scan.isLandscape());
+                } else {
+                    mOperationPresenter.startOcrFromUri(this, selectedList.get(0), mCurrentScene, false);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void locationRect(int startX, int startY, int endX, int endY) {
+        // 截取的区域坐标信息
+        mLeft = startX;
+        mTop = startY;
+        mRight = endX;
+        mBottom = endY;
+        if (mLeft <= 0) {
+            mLeft = 0;
+            mRight += startX;
+        }
+
+        if (mLeft + mRight > SizeTool.SCREEN_WIDTH) {
+            mRight = SizeTool.SCREEN_WIDTH - mLeft;
+        }
+
+        if (mTop <= 0) {
+            mTop = 0;
+            mBottom += startY;
+        }
+
+        if (mTop + mBottom > SizeTool.SCREEN_HEIGHT) {
+            mBottom = SizeTool.SCREEN_HEIGHT - mTop;
+        }
+    }
+
+    @Override
+    public void onOcrResult(OcrResult result) {
+        // 识别结果
+        showResultDialog(result);
+    }
+
+    private AlertDialog dialog;
+    /**
+     * 弹出识别对话框
+     * @param result
+     */
+    private void showResultDialog(OcrResult result) {
+        if (dialog != null && dialog.isShowing()) {
+            return;
+        }
+        mIsUploading = false;
+        dialog = new AlertDialog.Builder(this).setView(R.layout.dialog_result).create();
+        dialog.show();
+        dialog.setCancelable(false);
+        dialog.setCanceledOnTouchOutside(false);
+
+        dialog.findViewById(R.id.tv_copy).setOnClickListener(v -> {
+            dialog.cancel();
+            if (result == null) {
+                return;
+            }
+
+            SystemTool.copyText(OppoOperationActivity.this, "");
+            // 复制全部识别信息
+            if (mCurrentType == CropView.SCAN_TYPE_ALL) {
+                StringBuilder builder = new StringBuilder();
+                if (result.postcode != null) {
+                    builder.append(result.postcode.getText()).append(",");
+                }
+                if (result.address != null) {
+                    builder.append(result.address.getText()).append(",");
+                }
+                if (result.name != null) {
+                    builder.append(result.name.getText()).append(",");
+                }
+                if (builder.length() > 0) {
+                    builder.deleteCharAt(builder.length()-1);
+                    SystemTool.copyText(OppoOperationActivity.this, builder.toString());
+                } else {
+                    SystemTool.copyText(OppoOperationActivity.this, " ");
+                }
+            } else if (mCurrentType == CropView.SCAN_TYPE_POSTAL) {
+                if (result.postcode != null) {
+                    SystemTool.copyText(OppoOperationActivity.this, result.postcode.getText());
+                } else {
+                    SystemTool.copyText(OppoOperationActivity.this, " ");
+                }
+            } else if (mCurrentType == CropView.SCAN_TYPE_ADDRESS) {
+                if (result.address != null) {
+                    SystemTool.copyText(OppoOperationActivity.this, result.address.getText());
+                } else {
+                    SystemTool.copyText(OppoOperationActivity.this, " ");
+                }
+            } else if (mCurrentType == CropView.SCAN_TYPE_NAME) {
+                if (result.name != null) {
+                    SystemTool.copyText(OppoOperationActivity.this, result.name.getText());
+                } else {
+                    SystemTool.copyText(OppoOperationActivity.this, " ");
+                }
+            }
+
+            ToastTool.showShort(getString(R.string.copy_success));
+        });
+        dialog.findViewById(R.id.tv_cancel).setOnClickListener(v -> {
+            dialog.cancel();
+        });
+
+        LinearLayout ll_postal = dialog.findViewById(R.id.ll_postal);
+        LinearLayout ll_address = dialog.findViewById(R.id.ll_address);
+        LinearLayout ll_name = dialog.findViewById(R.id.ll_name);
+        if (mCurrentType == CropView.SCAN_TYPE_ALL) {
+            ll_postal.setVisibility(View.VISIBLE);
+            ll_address.setVisibility(View.VISIBLE);
+            ll_name.setVisibility(View.VISIBLE);
+        } else if (mCurrentType == CropView.SCAN_TYPE_POSTAL) {
+            ll_postal.setVisibility(View.VISIBLE);
+            ll_address.setVisibility(View.GONE);
+            ll_name.setVisibility(View.GONE);
+        } else if (mCurrentType == CropView.SCAN_TYPE_ADDRESS) {
+            ll_address.setVisibility(View.VISIBLE);
+            ll_postal.setVisibility(View.GONE);
+            ll_name.setVisibility(View.GONE);
+
+        } else if (mCurrentType == CropView.SCAN_TYPE_NAME) {
+            ll_name.setVisibility(View.VISIBLE);
+            ll_postal.setVisibility(View.GONE);
+            ll_address.setVisibility(View.GONE);
+        }
+
+        TextView tv_postal = dialog.findViewById(R.id.tv_postal);
+        TextView tv_address = dialog.findViewById(R.id.tv_address);
+        TextView tv_name = dialog.findViewById(R.id.tv_name);
+        tv_postal.setText("");
+        tv_address.setText("");
+        tv_name.setText("");
+
+
+        if (result == null) {
+            return;
+        }
+
+        if (result.postcode != null) {
+            tv_postal.setText(result.postcode.getText());
+        }
+
+        if (result.address != null) {
+            tv_address.setText(result.address.getText());
+        }
+
+        if (result.name != null) {
+            tv_name.setText(result.name.getText());
+        }
+    }
+
+    @Override
+    protected void takePhotoResult(Bitmap bitmap) {
+        super.takePhotoResult(bitmap);
+        if (bitmap == null) {
+            return;
+        }
+        // 得到裁剪后的图片数据
+        int[] rectData = new int[]{mLeft, mTop, mRight, mBottom};
+        File file = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES) + "/" + System.currentTimeMillis() + ".jpg");
+        if (!file.getParentFile().exists()) {
+            file.getParentFile().mkdirs();
+        }
+        if (tv_orientation.getVisibility() == View.VISIBLE) {
+            mOperationPresenter.startOcrFromBitmap(this, bitmap, rectData, file, mCurrentScene, pcv_scan.isLandscape());
+        } else {
+            mOperationPresenter.startOcrFromBitmap(this, bitmap, rectData, file, mCurrentScene, false);
+        }
+    }
+
+    @Override
+    protected void setWidthHeight(int width, int height) {
+        mOperationPresenter.setWidthHeight(width, height);
+    }
+}

+ 103 - 47
app/src/main/java/com/miekir/ocr/ui/camera/otalia/OtaCameraActivity.java

@@ -1,9 +1,14 @@
 package com.miekir.ocr.ui.camera.otalia;
 
+import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.PointF;
 import android.graphics.RectF;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.provider.MediaStore;
 import android.view.View;
 import android.widget.ImageView;
 
@@ -26,6 +31,12 @@ import com.otaliastudios.cameraview.filters.SharpnessFilter;
 import com.otaliastudios.cameraview.frame.Frame;
 import com.otaliastudios.cameraview.frame.FrameProcessor;
 
+import java.io.File;
+
+import rx_activity_result2.RxActivityResult;
+
+import static android.os.Environment.DIRECTORY_PICTURES;
+
 /**
  * Copyright (C), 2019-2020, Miekir
  *
@@ -52,43 +63,10 @@ public class OtaCameraActivity extends BaseCameraActivity {
         camera = findViewById(R.id.camera);
         setupCamera();
 
-        View fl_camera_size = findViewById(R.id.fl_camera_size);
-        fl_camera_size.post(new Runnable() {
-            @Override
-            public void run() {
-                // 设置拍照的分辨率
-                //AspectRatio ratio = AspectRatio.of(new Size(camera.getWidth(), camera.getHeight()));
-                /*AspectRatio ratio = AspectRatio.parse(camera.getWidth() + ":" + camera.getHeight());
-                SizeSelector matchRatio = SizeSelectors.aspectRatio(ratio, 50);
-                SizeSelector matchSize = new SizeSelector() {
-                    @NonNull
-                    @Override
-                    public List<Size> select(@NonNull List<Size> source) {
-                        List<Size> sizeList = new ArrayList<>();
-                        sizeList.add(new Size(camera.getWidth(), camera.getHeight()));
-                        return sizeList;
-                    }
-                };
-                SizeSelector matchAll = SizeSelectors.or(
-                        SizeSelectors.and(matchRatio, matchSize), // Try to respect both constraints.
-                        matchRatio, // If couldn't respect size, at least match aspect ratio
-                        matchSize, // If couldn't match aspect ratio, at least respect the size
-                        SizeSelectors.biggest() // If couldn't match any, take the biggest.
-                );
-                camera.setPictureSize(matchAll);*/
-
-
-                // 这两个方法只能设置小于屏幕分辨率的
-                //camera.setSnapshotMaxWidth(camera.getWidth() * 2 + 100);
-                //camera.setSnapshotMaxHeight(camera.getHeight() * 2 + 100);
-                // 高质量输出
-                //camera.setPictureSnapshotMetering(true);
+        findViewById(R.id.iv_raw_camera).setOnClickListener(v -> openRawCamera());
 
-
-
-                setWidthHeight(camera.getWidth(), camera.getHeight());
-            }
-        });
+        View fl_camera_size = findViewById(R.id.fl_camera_size);
+        fl_camera_size.post(() -> setWidthHeight(camera.getWidth(), camera.getHeight()));
 
         camera.addFrameProcessor(new FrameProcessor() {
             @Override
@@ -122,20 +100,14 @@ public class OtaCameraActivity extends BaseCameraActivity {
         camera.close();
         camera.open();
         // 减少曝光
-        camera.post(new Runnable() {
-            @Override
-            public void run() {
-                CameraOptions options = camera.getCameraOptions();
-                if (options != null) {
-                    camera.setExposureCorrection(options.getExposureCorrectionMinValue()/5);
-                }
+        camera.post(() -> {
+            CameraOptions options = camera.getCameraOptions();
+            if (options != null) {
+                camera.setExposureCorrection(options.getExposureCorrectionMinValue()/5);
             }
         });
 
-        //camera.setWhiteBalance(WhiteBalance.CLOUDY);
 
-        //cameraView.setPictureSize { arrayListOf(Size(768, 1024)) }
-        //camera.setFilter(Filters.SHARPNESS.newInstance());
         SharpnessFilter sharpnessFilter = (SharpnessFilter)Filters.SHARPNESS.newInstance();
         //0~1.0
         sharpnessFilter.setSharpness(0.06f);
@@ -158,7 +130,6 @@ public class OtaCameraActivity extends BaseCameraActivity {
             return;
         }
         if (camera.getPreview() != Preview.GL_SURFACE) {
-            //Picture snapshots are only allowed with the GL_SURFACE preview.
             return;
         }
 
@@ -207,4 +178,89 @@ public class OtaCameraActivity extends BaseCameraActivity {
             takePhotoResult(bitmap);
         }
     }
+
+
+    /**
+     * 打开原生相机
+     */
+    private void openRawCamera() {
+        File file = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES) + "/" + System.currentTimeMillis() + ".jpg");
+        if (!file.getParentFile().exists()) {
+            file.getParentFile().mkdirs();
+        }
+        // 保存拍照的路径
+        Uri mImageCaptureUri;
+        // 跳转系统相机的intent
+        Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+        // 根据不同的Android版本uri不一样
+        /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            //android7.0以上
+            ContentValues contentValues = new ContentValues(1);
+            String absolutePath = file.getAbsolutePath();
+            contentValues.put(MediaStore.Images.Media.DATA, absolutePath);
+            mImageCaptureUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
+        } else {
+            mImageCaptureUri = Uri.fromFile(file);
+        }*/
+        mImageCaptureUri = Uri.fromFile(file);
+        takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
+
+        camera.close();
+        RxActivityResult.on(this)
+                .startIntent(takeIntent)
+                //.filter(result -> result.resultCode() == RESULT_OK)
+                //.map(result -> result.data().getData())
+                .doOnNext(data -> {
+                    if (data.resultCode() == RESULT_OK) {
+                        cropPhoto(file);
+                    } else {
+                        new Handler().postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                camera.open();
+                            }
+                        }, 1000);
+                    }
+                })
+                .subscribe();
+    }
+
+    private void cropPhoto(File file) {
+        File cropFile = new File(file.getParentFile().getAbsolutePath(), "crop_" + file.getName());
+        Uri cropUri = Uri.fromFile(cropFile);
+        Intent intent = new Intent("com.android.camera.action.CROP");
+        intent.setDataAndType(Uri.fromFile(file), "image/*");
+        intent.putExtra("crop", "true");//可裁剪
+        intent.putExtra("aspectX", 1); //裁剪的宽比例
+        intent.putExtra("aspectY", 1);  //裁剪的高比例
+        intent.putExtra("outputX", mRight-mLeft); //裁剪的宽度
+        intent.putExtra("outputY", mBottom-mTop);  //裁剪的高度
+        intent.putExtra("scale", true); //支持缩放
+        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);  //将裁剪的结果输出到指定的Uri
+        intent.putExtra("return-data", true); //若为true则表示返回数据
+        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//裁剪成的图片的格式
+
+        camera.close();
+        RxActivityResult.on(this)
+                .startIntent(intent)
+                //.filter(result -> result.resultCode() == RESULT_OK)
+                //.map(result -> result.data().getData())
+                .doOnNext(data -> {
+                    if (data.resultCode() == RESULT_OK) {
+                        onOppoResult(cropUri);
+                    } else {
+                        new Handler().postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                camera.open();
+                            }
+                        }, 1000);
+                    }
+                })
+                .subscribe();
+    }
+
+    protected void onOppoResult(Uri uri) {
+        camera.open();
+    }
 }

+ 10 - 0
app/src/main/java/com/miekir/ocr/ui/camera/otalia/OtaOperationActivity.java

@@ -341,4 +341,14 @@ public class OtaOperationActivity extends OtaCameraActivity implements CropView.
     protected void setWidthHeight(int width, int height) {
         mOperationPresenter.setWidthHeight(width, height);
     }
+
+    @Override
+    protected void onOppoResult(Uri uri) {
+        super.onOppoResult(uri);
+        if (tv_orientation.getVisibility() == View.VISIBLE) {
+            mOperationPresenter.startOcrFromUri(this, uri, mCurrentScene, pcv_scan.isLandscape());
+        } else {
+            mOperationPresenter.startOcrFromUri(this, uri, mCurrentScene, false);
+        }
+    }
 }

+ 192 - 0
app/src/main/res/layout/activity_oppo.xml

@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:keepScreenOn="true"
+    tools:ignore="MissingDefaultResource">
+    <!--屏幕常亮-->
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/colorPrimary"
+        android:gravity="center_vertical"
+        android:minHeight="64dp"
+        android:orientation="horizontal"
+        android:paddingStart="@dimen/margin_default"
+        android:paddingTop="@dimen/margin_ss"
+        android:paddingEnd="@dimen/margin_default"
+        android:paddingBottom="@dimen/margin_ss">
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@mipmap/logo" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:text="@string/app_name"
+            android:textColor="@color/white"
+            android:textSize="18sp"/>
+    </LinearLayout>
+
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/fl_camera_size">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="370">
+                <!--灰色遮罩-->
+
+            </FrameLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="0.8dp"
+                android:background="@color/white"/>
+
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="180"
+                android:orientation="vertical">
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:visibility="invisible">
+
+                    <Space
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+
+                    <com.miekir.ocr.widget.IndicatorText
+                        android:id="@+id/it_postal"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:text="@string/postal_code" />
+
+                    <Space
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+
+                    <com.miekir.ocr.widget.IndicatorText
+                        android:id="@+id/it_address"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:text="@string/address"/>
+
+                    <Space
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+
+                    <com.miekir.ocr.widget.IndicatorText
+                        android:id="@+id/it_name"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:text="@string/name"/>
+
+                    <Space
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+
+                    <com.miekir.ocr.widget.IndicatorText
+                        android:id="@+id/it_all"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:text="@string/full"
+                        app:focused="true"/>
+
+                    <Space
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1" />
+                </LinearLayout>
+
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingBottom="@dimen/margin_default">
+
+                    <RelativeLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1">
+
+                        <FrameLayout
+                            android:id="@+id/fl_album"
+                            android:foreground="@drawable/ripple_effect"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_centerInParent="true"
+                            android:padding="@dimen/margin_default"
+                            android:visibility="invisible">
+                            <ImageView
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:src="@mipmap/button_album"/>
+                        </FrameLayout>
+
+                    </RelativeLayout>
+
+                    <FrameLayout
+                        android:id="@+id/fl_take"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:foreground="@drawable/ripple_effect">
+
+                        <ImageView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:src="@mipmap/button_take" />
+
+                        <ImageView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:src="@mipmap/button_take_out" />
+                    </FrameLayout>
+
+                    <TextView
+                        android:id="@+id/tv_orientation"
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:layout_marginStart="@dimen/margin_default"
+                        android:layout_marginEnd="@dimen/margin_default"
+                        android:layout_weight="1"
+                        android:gravity="center"
+                        android:text="@string/landscape"
+                        android:textColor="@color/colorPrimary"
+                        android:textSize="@dimen/size_text_title_p"
+                        android:visibility="invisible"/>
+                </LinearLayout>
+            </LinearLayout>
+        </LinearLayout>
+    </FrameLayout>
+</LinearLayout>

+ 1 - 0
app/src/main/res/layout/activity_otalia_camera.xml

@@ -23,6 +23,7 @@
         android:paddingBottom="@dimen/margin_ss">
 
         <ImageView
+            android:id="@+id/iv_raw_camera"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:src="@mipmap/logo" />