Android自定义相机填坑随笔

Android自定义相机填坑随笔


笔者一个小小的Android开发,于某厂辛勤的拧螺丝。日常面对如洪水猛兽般的需求大潮,坚守自己一方微不足道的人权小岛!@#¥%……

牢骚差不多了,开始进入正式吐槽……尊敬的观众姥爷没听错,奏是继续吐槽。

随着笔者公司的战略重心迁移,我们开展了新的业务线。因业务需求中,我需要集成自定义相机,于是开始了旷日持久的自定义相机趟坑之旅。作为模块集成在第三方app中,沿用了第三方app配置,由于第三方适配机型版本较低,兼容性问题也是相当的多。回归到自定义相机的开发,简单叙述下开发相机过程踩过的大大小小的坑。

1.照片转置问题

在项目伊始,需求尚不明确,我们调用自定义相机获取照片。在某些机型上照片出现了旋转,由于测试设备匮乏(直至笔者今日都没解决),几经周折,找到了问题机型最多三星测试机,根据图片MetaData的旋转角将图片做相应的还原。

**
     * 读取图片的旋转的角度
     *
     * @param path 图片绝对路径
     * @return 图片的旋转角度
     */
    public static int getBitmapDegree(String path) {
        int degree = 0;
        try {
            // 从指定路径下读取图片,并获取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 获取图片的旋转信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

MetaData仅仅在相机返回图片字节流生成的文件信息中能获取,一经压缩转换成bitmap之后就会丢失。笔者取到的旋转角始终为0,让笔者的胃很是翻江倒海。最后经过排查找到图片确实经过了转换。于是乎只要照片重置生成旋转角0的照片不就问题即将迎刃而解了?青年你的九九八十一难怎可如此简简单单就给你来个痛快,只有更多细腻的阻绊使你的开发之路多姿多彩。

2.相机重力问题

看到在三星测试机上转置处理完成,笔者喜形于色忍不住笑出猪叫来。可笔者拿起测试机拍摄了一张横拍照片,纳尼扩类,这就给转成一张竖屏照片了哈?!歪斜的图片笔者不自然的随着皂片歪起了脖子,久病之下的颈椎又刺激了中枢神经。所以说是笔者too young too navi,没有看出bug小妖背后隐藏的诸路仙君。由于是竖屏有拍摄问题,而横屏拍摄本身就是将照片做了旋转处理,如果仅仅按照皂片metadata做重置还原,只会将横屏照片还原为竖屏照片。

根据重力判断一下拍摄时是否是横屏,再做还原应该就可以了。于是乎笔者根据按下快门时重力做了相应处理。可为了适配横竖屏的情况,笔者在加入了横屏布局。也不得不因此委屈求全通过宽高判断屏幕朝向。

 DisplayMetrics dm = new DisplayMetrics();
            CameraActivity.this.getWindowManager().getDefaultDisplay().getMetrics(dm);
            int width = dm.widthPixels;
            int height = dm.heightPixels;
            if (height > width){
                // 竖屏
                isVertiPhoto = true;
            }else{
                // 横屏
                isVertiPhoto = false;
            }

终于旷日持久的相机大战中,笔者获得阶段性胜利。胜利的成果是喜悦的,胜利的路程是曲折的,曲折绝不是一时的。没错,在机型适配上,自定义相机继续绊了笔者一脚。

3.API判断错误


    @SuppressWarnings("WrongConstant")
    public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (isInEditMode()) {
            mCallbacks = null;
            mDisplayOrientationDetector = null;
            return;
        }
        // Internal setup
        final PreviewImpl preview = createPreviewImpl(context);
        mCallbacks = new CallbackBridge();
        if (Build.VERSION.SDK_INT < 21) {
            mImpl = new Camera1(mCallbacks, preview);
        } else if (Build.VERSION.SDK_INT < 23) {
            mImpl = new Camera2(mCallbacks, preview, context);
        } else {
            mImpl = new Camera2Api23(mCallbacks, preview, context);
        }
        // Attributes
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr,
                R.style.Widget_CameraView);
        mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);
        setFacing(a.getInt(R.styleable.CameraView_facing, FACING_BACK));
        String aspectRatio = a.getString(R.styleable.CameraView_aspectRatio);
        if (aspectRatio != null) {
            setAspectRatio(AspectRatio.parse(aspectRatio));
        } else {
            setAspectRatio(Constants.DEFAULT_ASPECT_RATIO);
        }
        setAutoFocus(a.getBoolean(R.styleable.CameraView_autoFocus, true));
        setFlash(a.getInt(R.styleable.CameraView_flash, Constants.FLASH_AUTO));
        a.recycle();
        // Display orientation detector
        mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
            @Override
            public void onDisplayOrientationChanged(int displayOrientation) {
                mImpl.setDisplayOrientation(displayOrientation);
            }
        };
    }

不难看出google提供的Api小于21,会实例化Camera1作为相机视图。但是令人惊奇的是,收到的崩溃日志Android 7.0的机器于Camera1处报错,大为惊诧之后,想想bug不修推锅给谷歌不现实,于是乎开始了调试之旅。

几经调查之后Camera1中会因为调用后stop()方法后,调用cancelAutoFocus()会报出无法在release()后使用api的错误。

笔者只能加上防护代码抵消报错。不过更神奇的是亲测小米8 Android 9.0 的测试机居然也初始化了Camera1的实例,奈何如何走到Camera1实例中又成为这个世纪最大的未解之谜。面对手上楚楚可怜几个测试机,只得双手合十,在2020年的心愿单上加上公司尽早补上主流机型测试机资源,早日助笔者脱离兼容性苦海。


随笔至此已入尾声,望着20后都要出生的新新时代,笔者再次感到万分压力。今年的职级是否能顺利提升,薪资是否能追上cpi的脚步,七大姑八大姨是否能在过年忘记笔者,都成为笔者来年的稀疏头顶的最大敌人。

望来年大事可成,未来可期。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • vue中使用elementui的时候,进行自定义的表单校验的时候。出现,一进入页面,没有对输入框进行任何操作的时候...
    computerliteral阅读 314评论 0 0
  • 我国有两种工业品没有: 1,像是核动力航母,航天飞机,高端芯片,航发等…… 这一类是真搞不定的,也一直努力在搞,但...
    马唐阅读 464评论 0 0
  • 练习题1: 请帮小明同学设计一个程序,输入上次考试成绩(int)和本次考试成绩(int),然后输出成绩提高的百分...
    炫小狼阅读 5,177评论 1 3
  • 以前患得患失的表现,自从遇见你,就没有了。是因为你不好看吗。哈哈,我真的是个颜控,但你如果真的有才,我会自动不颜控...
    法桐阅读 128评论 0 1
  • “一日之计在于晨”“早起的鸟儿有虫吃” 早起的重要性由此可见,道理我们都懂。 但过完年后的闹钟怎么都闹不醒你? 生...
    吴少轩阅读 1,013评论 31 39