Android使用TextureView拍照记录

1、创建一个textureView基础类

public class AutoTexturePreviewView extends FrameLayout {

    public TextureView textureView;

    private int videoWidth = 0;
    private int videoHeight = 0;


    public static int previewWidth = 0;
    private int previewHeight = 0;
    private static int scale = 2;

    public static float circleRadius;
    public static float circleX;
    public static float circleY;

    public AutoTexturePreviewView(Context context) {
        super(context);
        init();
    }

    public AutoTexturePreviewView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public AutoTexturePreviewView(Context context, AttributeSet attrs,
                                  int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }


    private Handler handler = new Handler(Looper.getMainLooper());

    private void init() {
        setWillNotDraw(false);
        textureView = new TextureView(getContext());
        addView(textureView);
    }


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        previewWidth = getWidth();
        previewHeight = getHeight();

        if (videoWidth == 0 || videoHeight == 0 || previewWidth == 0 || previewHeight == 0) {
            return;
        }

        if (previewWidth * videoHeight > previewHeight * videoWidth) {
            int scaledChildHeight = videoHeight * previewWidth / videoWidth;
            textureView.layout(0, (previewHeight - scaledChildHeight) / scale,
                    previewWidth, (previewHeight + scaledChildHeight) / scale);
        } else {
            int scaledChildWidth = videoWidth * previewHeight / videoHeight;
            textureView.layout((previewWidth - scaledChildWidth) / scale, 0,
                    (previewWidth + scaledChildWidth) / scale, previewHeight);

        }


    }

    public TextureView getTextureView() {
        return textureView;
    }



    public void setPreviewSize(int width, int height) {
        if (this.videoWidth == width && this.videoHeight == height) {
            return;
        }
        this.videoWidth = width;
        this.videoHeight = height;
        handler.post(new Runnable() {
            @Override
            public void run() {
                requestLayout();
            }
        });

    }

    //画一个圆框,用于放置人脸
    @Override
    protected void onDraw(Canvas canvas) {
          Path path = new Path();
          // 设置裁剪的圆心坐标,半径
          path.addCircle(getWidth() / 2, getHeight() / 2 - 70, getWidth() / 2, Path.Direction.CCW);
          // 裁剪画布,并设置其填充方式
//            canvas.clipPath(path, Region.Op.REPLACE);
          if (Build.VERSION.SDK_INT >= 28) {
              canvas.clipPath(path);
          } else {
              canvas.clipPath(path, Region.Op.REPLACE);
          }
          // 圆的半径
          circleRadius = getWidth() / 2;
          // 圆心的X坐标
          circleX = (getRight() - getLeft()) / 2;
          // 圆心的Y坐标
          circleY = (getBottom() - getTop()) / 2 - 70;
  
          super.onDraw(canvas);
    }
}

2、在xml中使用这个布局

3、camera设置

public class CameraPreviewManager implements TextureView.SurfaceTextureListener {

    AutoTexturePreviewView mTextureView;
  
    private SurfaceTexture mSurfaceTexture;

    private int previewWidth;
    private int previewHeight;

    private int videoWidth;
    private int videoHeight;

    private Camera mCamera;
 
    private CameraDataCallback mCameraDataCallback;
    private static volatile CameraPreviewManager instance = null;

    public static CameraPreviewManager getInstance() {
        synchronized (CameraPreviewManager.class) {
            if (instance == null) {
                instance = new CameraPreviewManager();
            }
        }
        return instance;
    }

    /**
     * 开启预览
     *
     * @param context
     * @param textureView
     */
    public void startPreview(Context context, AutoTexturePreviewView textureView, int width,int height, CameraDataCallback cameraDataCallback) {
        Log.e(TAG, "开启预览模式");
        Context mContext = context;
        this.mCameraDataCallback = cameraDataCallback;
        mTextureView = textureView;
        this.previewWidth = width;
        this.previewHeight = height;
        mSurfaceTexture = mTextureView.getTextureView().getSurfaceTexture();
        mTextureView.getTextureView().setSurfaceTextureListener(this);
    }

    /**
     * 拍照
     */
    public void take() {
        if (mCamera != null) {
            mCamera.takePicture(new Camera.ShutterCallback() {
                @Override
                public void onShutter() {

                }
            }, null, mPictureCallback);
        }
    }

    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            if (mCamera != null) {
                mCamera.stopPreview();
                new FileSaver(data).save();
            }
        }
    };

    private class FileSaver implements Runnable {
        private byte[] buffer;

        public FileSaver(byte[] buffer) {
            this.buffer = buffer;
        }

        public void save() {
            new Thread(this).start();
        }

        @Override
        public void run() {
            try {
                File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "zhangphil.png");
                file.createNewFile();

                FileOutputStream os = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(os);

                Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
                Bitmap bitmap1 = rotateMyBitmap(bitmap);

                bitmap1.compress(Bitmap.CompressFormat.PNG, 100, bos);

                bos.flush();
                bos.close();
                os.close();

                Log.d("照片已保存", file.getAbsolutePath());

                mCamera.startPreview();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //保存后查看图片发生了旋转,需要旋转后再保存
    private Bitmap rotateMyBitmap(Bitmap bmp) {
        Matrix matrix = new Matrix();
        matrix.postRotate(-90);
        Bitmap rotatedBitMap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
        return rotatedBitMap;
    }


    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture texture, int i, int i1) {
        Log.e(TAG, "--surfaceTexture--SurfaceTextureAvailable");
        mSurfaceTexture = texture;
        mSurfaceCreated = true;
        textureWidth = i;
        textureHeight = i1;
        openCamera();

    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int i, int i1) {
        Log.e(TAG, "--surfaceTexture--TextureSizeChanged");
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
        Log.e(TAG, "--surfaceTexture--destroyed");
        mSurfaceCreated = false;
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture texture) {
        // Log.e(TAG, "--surfaceTexture--Updated");
    }


    /**
     * 关闭预览
     */
    public void stopPreview() {
        if (mCamera != null) {
            try {
                mCamera.setPreviewTexture(null);
                mSurfaceCreated = false;
                mTextureView = null;
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;
            } catch (Exception e) {
                Log.e("qing", "camera destory error");
                e.printStackTrace();

            }
        }
    }


    /**
     * 开启摄像头
     */

    public void openCamera() {

        try {
            if (mCamera == null) {

                cameraId = cameraFacing;
                mCamera = Camera.open(cameraId);
                Log.e(TAG, "initCamera---open camera");
            }

            // 摄像头图像预览角度
            int cameraRotation = 90;
            switch (cameraFacing) {
                case CAMERA_FACING_FRONT: {
                    mCamera.setDisplayOrientation(cameraRotation);
                    break;
                }

                case CAMERA_FACING_BACK: {
                    mCamera.setDisplayOrientation(cameraRotation);
                    break;
                }

                case CAMERA_USB: {
                    mCamera.setDisplayOrientation(cameraRotation);
                    break;
                }

                default:
                    break;

            }

            int isRgbRevert = 0;
            if (isRgbRevert == 1) {
                mTextureView.setRotationY(180);
            } else {
                mTextureView.setRotationY(0);
            }
            // 旋转90度或者270,需要调整宽高
            mTextureView.setPreviewSize(previewHeight, previewWidth);
           
            Camera.Parameters params = mCamera.getParameters();
            List sizeList = params.getSupportedPreviewSizes(); // 获取所有支持的camera尺寸
            final Camera.Size optionSize = getOptimalPreviewSize(sizeList, previewWidth,
                    previewHeight); // 获取一个最为适配的camera.size
            if (optionSize.width == previewWidth && optionSize.height == previewHeight) {
                videoWidth = previewWidth;
                videoHeight = previewHeight;
            } else {
                videoWidth = optionSize.width;
                videoHeight = optionSize.height;
            }
            params.setPreviewSize(videoWidth, videoHeight);

            mCamera.setParameters(params);
            try {
                mCamera.setPreviewTexture(mSurfaceTexture);
                mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                    @Override
                    public void onPreviewFrame(byte[] bytes, Camera camera) {
                        if (mCameraDataCallback != null) {
                            mCameraDataCallback.onGetCameraData(bytes, camera,
                                    videoWidth, videoHeight);
                        }
                    }
                });
                mCamera.startPreview();

            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, e.getMessage());
            }
        } catch (RuntimeException e) {
            Log.e(TAG, e.getMessage());
        }
    }

    /**
     * 解决预览变形问题
     *
     * @param sizes
     * @param w
     * @param h
     * @return
     */
    private Camera.Size getOptimalPreviewSize(List sizes, int w, int h) {
        final double aspectTolerance = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) {
            return null;
        }
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > aspectTolerance) {
                continue;
            }
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }
}

4、使用定义的camera

class CameraFragment: BaseFragment(), FetchCallback {

    private var mAutoCameraPreviewView: AutoTexturePreviewView? = null

    private var imageData: ByteArray? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_camera, container, false).apply {
            
            mAutoCameraPreviewView = findViewById(R.id.auto_camera_preview_view)

        }
    }

    private fun startTestOpenDebugRegisterFunction() {

        CameraPreviewManager.getInstance().startPreview(context,
            mAutoCameraPreviewView,
            640,
            480,
            object : CameraDataCallback {
                override fun onGetCameraData(
                    data: ByteArray?,
                    camera: android.hardware.Camera?,
                    width: Int,
                    height: Int
                ) {
                    imageData = data
                }
            })
    }

    override fun onResume() {
        super.onResume()
        //只能在这个生命周期调用,不然会报错,找不到id
        startTestOpenDebugRegisterFunction()
    }

    //在不保存图片的相框下,直接展示需要进行Yuv转码显示,不然图片不能显示出来
    fun getImgBase64(buffer: ByteArray): String {

        val yuvimage = YuvImage(buffer, ImageFormat.NV21, 640, 480, null) //20、20分别是图的宽度与高度

        val baos = ByteArrayOutputStream()
        yuvimage.compressToJpeg(Rect(0, 0, 640, 480), 100, baos)//80--JPG图片的质量[0-100],100最高

        val jdata = baos.toByteArray()

        val bitmap = BitmapFactory.decodeByteArray(jdata, 0, jdata.size)
        val matrix = Matrix()
        matrix.postRotate(90f)
        val bitmap1: Bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
        val bos = ByteArrayOutputStream()
        bitmap1.compress(Bitmap.CompressFormat.PNG, 100, bos)
        val bb: ByteArray = bos.toByteArray()
        return Base64.encodeToString(bb, Base64.NO_WRAP)
    }
}

你可能感兴趣的:(android,android,studio,java)