TextureView实现相机预览、拍照功能

TextureView实现相机预览、拍照功能

效果图
在这里插入图片描述

下载链接

https://download.csdn.net/download/qq_38355313/10717497

1、首先AndroidManifest添加相机使用权限

<!-- 相机相关 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
   
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

使用的activity添加硬件加速(默认开启,为啥要开启可自行百度)

android:hardwareAccelerated="true"

2、创建继承于TextureView的类MyTextureView(添贴代码)

package com.nxm.interpreter.views;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.os.Build;
import android.os.Environment;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;

/**
 * **************************************************************************************************
 * 修改日期                         修改人             任务名称                         功能或Bug描述
 * 2018/10/12 10:36                 MUZI102                                             TextureView类目
 * **************************************************************************************************
 */
public class MyTextureView extends TextureView implements View.OnLayoutChangeListener {
    public Camera mCamera;
    private Context context;
    private Camera.Parameters param;
    private boolean isCanTakePicture = false;
    Matrix matrix;
    Camera camera;
    int mWidth = 0;
    int mHeight = 0;
    int mDisplayWidth = 0;
    int mDisplayHeight = 0;
    int mPreviewWidth = 640;
    int mPreviewHeight = 480;
    int orientation = 0;

    public MyTextureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    private void init() {
        if (null == mCamera) {
            mCamera = Camera.open();
        }
        this.setSurfaceTextureListener(new SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
                param = mCamera.getParameters();
                param.setPictureFormat(PixelFormat.JPEG);
                param.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                if (!Build.MODEL.equals("KORIDY H30")) {
                    param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
                } else {
                    param.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                }
                mCamera.setParameters(param);
                //变形处理
                RectF previewRect = new RectF(0, 0, mWidth, mHeight);
                double aspect = (double) mPreviewWidth / mPreviewHeight;
                if (getResources().getConfiguration().orientation
                        == Configuration.ORIENTATION_PORTRAIT) {
                    aspect = 1 / aspect;
                }
                if (mWidth < (mHeight * aspect)) {
                    mDisplayWidth = mWidth;
                    mDisplayHeight = (int) (mHeight * aspect + .5);
                } else {
                    mDisplayWidth = (int) (mWidth / aspect + .5);
                    mDisplayHeight = mHeight;
                }
                RectF surfaceDimensions = new RectF(0, 0, mDisplayWidth, mDisplayHeight);
                Matrix matrix = new Matrix();
                matrix.setRectToRect(previewRect, surfaceDimensions, Matrix.ScaleToFit.FILL);
                MyTextureView.this.setTransform(matrix);
                //<-处理变形
                int displayRotation = 0;
                WindowManager windowManager = (WindowManager) context
                        .getSystemService(Context.WINDOW_SERVICE);
                int rotation = windowManager.getDefaultDisplay().getRotation();
                switch (rotation) {
                    case Surface.ROTATION_0:
                        displayRotation = 0;
                        break;
                    case Surface.ROTATION_90:
                        displayRotation = 90;
                        break;
                    case Surface.ROTATION_180:
                        displayRotation = 180;
                        break;
                    case Surface.ROTATION_270:
                        displayRotation = 270;
                        break;
                }
                Camera.CameraInfo info = new Camera.CameraInfo();
                Camera.getCameraInfo(0, info);
                int orientation;
                if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    orientation = (info.orientation - displayRotation + 360) % 360;
                } else {
                    orientation = (info.orientation + displayRotation) % 360;
                    orientation = (360 - orientation) % 360;
                }
                mCamera.setParameters(param);
                mCamera.setDisplayOrientation(orientation);
                try {
                    mCamera.setPreviewTexture(surfaceTexture);
                    mCamera.startPreview();
                    isCanTakePicture = true;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.release();
                    mCamera = null;
                    isCanTakePicture = true;
                }
                return true;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

            }
        });
    }

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

                }
            }, null, mPictureCallback);
        }
    }

    public void startPreview() {
        if (mCamera != null && !isCanTakePicture) {
            MyTextureView.this.setBackgroundDrawable(null);
            mCamera.startPreview();
            isCanTakePicture = true;
        }
    }

    public void stopPreview() {
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }


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

    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        mWidth = right - left;
        mHeight = bottom - top;
    }

    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),
                        System.currentTimeMillis() + ".png");
                file.createNewFile();
                FileOutputStream os = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(os);
                Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
                bos.flush();
                bos.close();
                os.close();
                MyTextureView.this.setBackgroundDrawable(new BitmapDrawable(bitmap));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

3、acticity中使用

1、xml的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.nxm.textureviewdemo.MyTextureView
        android:id="@+id/mytextureview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/paizhai"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拍照" />

    <Button
        android:id="@+id/yulan"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/paizhai"
        android:text="预览" />

</RelativeLayout>

2、使用

package com.nxm.textureviewdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private MyTextureView myTextureView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myTextureView = findViewById(R.id.mytextureview);
        findViewById(R.id.paizhai).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myTextureView.take();
            }
        });
        findViewById(R.id.yulan).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myTextureView.startPreview();
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        myTextureView.startPreview();
    }

    @Override
    protected void onStop() {
        myTextureView.stopPreview();
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        myTextureView.releaseTextureView();
        super.onDestroy();
    }
}