zoukankan      html  css  js  c++  java
  • Camera 预览变形问题解决

      最近开发一款自定义相机采集照片的demo,花了一个上午开发了一个在测试机上功能正常的apk连同测试机一起交付(需求方反馈没有Android设备),然而晚上被喊去说是在华为畅玩某型号上预览会变形,拍到的图片边界都移位了,只要加个班处理一下机型适配的问题。根据开发经验,防止预览图像变形的终极奥义就是保持照相机硬件支持的某个size(每个特定的手机都有其支持的camera分辨率)、屏幕宽高比、界面上SurfaceView的宽高比尽量一致,同时保持拍照图与预览图分辨率一致,拍出来的照片就和预览看到的相同。

      下面给出实现代码:

      

        private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, w: Int, h: Int): Camera.Size? {
            val ASPECT_TOLERANCE = 0.1
            val targetRatio = h.toDouble() / w
    
            if (sizes == null) return null
    
            var optimalSize: Camera.Size? = null
            var minDiff = java.lang.Double.MAX_VALUE
    
            for (size in sizes) {
                val ratio = size.width.toDouble() / size.height
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue
                if (Math.abs(size.height - h) < minDiff) {
                    optimalSize = size
                    minDiff = Math.abs(size.height - h).toDouble()
                }
            }
    
            if (optimalSize == null) {
                minDiff = java.lang.Double.MAX_VALUE
                for (size in sizes) {
                    if (Math.abs(size.height - h) < minDiff) {
                        optimalSize = size
                        minDiff = Math.abs(size.height - h).toDouble()
                    }
                }
            }
            return optimalSize
        }

    其中第一个参数sizes是camera支持的预览size列表,第二个是View的宽,第三个是View的高,由于我这里的surfaceview是全屏的,所以传入的宽和高可以是屏幕的宽和高

    下面给出完整代码:

        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_camera)
            screenWidth = ScreenUtil.getWindowWidth(this)
            screenHeight = ScreenUtil.getWindowHeigh(this)
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK)
            surface.holder.addCallback(this)
        }
        
        override fun surfaceChanged(holder: SurfaceHolder?, format: Int,  Int, height: Int) {
            camera?.setPreviewDisplay(holder)
            camera?.startPreview()
        }
    
        override fun surfaceDestroyed(holder: SurfaceHolder?) {
        }
    
    
        override fun surfaceCreated(holder: SurfaceHolder?) {
            if (camera == null) {
                camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK)
            }
            val parameters = camera?.parameters
            var sizes = parameters!!.supportedPreviewSizes
            var preSize = getOptimalPreviewSize(sizes, screenWidth, screenHeight)
            parameters.setPreviewSize(preSize!!.width, preSize.height)
            //重新给定surfaceView宽高
            surface.resize(preSize.width, preSize.height)
            if (parameters.supportedFocusModes!!.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO
            }
            parameters.sceneMode = Camera.Parameters.SCENE_MODE_AUTO
            //保持picturesize与presize一致
            parameters.setPictureSize(preSize.width, preSize.height)
            parameters.previewFormat = ImageFormat.NV21
            camera?.parameters = parameters
            camera?.setPreviewDisplay(holder)
            camera?.startPreview()
        }
        
        
        private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, w: Int, h: Int): Camera.Size? {
            val ASPECT_TOLERANCE = 0.1
            val targetRatio = h.toDouble() / w
    
            if (sizes == null) return null
    
            var optimalSize: Camera.Size? = null
            var minDiff = java.lang.Double.MAX_VALUE
    
            for (size in sizes) {
                val ratio = size.width.toDouble() / size.height
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue
                if (Math.abs(size.height - h) < minDiff) {
                    optimalSize = size
                    minDiff = Math.abs(size.height - h).toDouble()
                }
            }
    
            if (optimalSize == null) {
                minDiff = java.lang.Double.MAX_VALUE
                for (size in sizes) {
                    if (Math.abs(size.height - h) < minDiff) {
                        optimalSize = size
                        minDiff = Math.abs(size.height - h).toDouble()
                    }
                }
            }
            return optimalSize
        }
    
        
        override fun onWindowFocusChanged(hasFocus: Boolean) {
            val decorView = this@CameraActivity.window.decorView
            decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
        }
    
        override fun onPause() {
            super.onPause()
            camera?.stopPreview()
        }
    
        override fun onDestroy() {
            super.onDestroy()
            camera?.setPreviewCallback(null)
            camera?.release()
        }
  • 相关阅读:
    wampserver2.2e-php5.3.13 版本 增加 php7 支持
    23种设计模式[3]:抽象工厂模式
    23种设计模式[2]:工厂方法模式
    23种设计模式[1]:单例模式
    [转]设计模式六大原则[6]:开闭原则
    [转]设计模式六大原则[5]:迪米特法则
    [转]设计模式六大原则[4]:接口隔离原则
    [转]设计模式六大原则[3]:依赖倒置原则
    [转]设计模式六大原则[2]:里氏替换原则
    [转]设计模式六大原则[1]:单一职责原则
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/9868664.html
Copyright © 2011-2022 走看看