Android:使用Camera硬件拍照并保存相片

使用Camera拍照并保存相片,是调用硬件摄像头进行拍照,相当于自己写一个照相机程序。
有四个步骤:

  • 1.打开照相机:Cameraa.open()
  • 2.创建SufaceView对象
  • 3.添加回调事件监听器(SurfaceHolder.addCallback)
  • 4.预览(Camera.startPreview)
  • 5.拍照(Camera.takePicture)

1.添加权限

添加使用照相机的权限和写SD卡的权限



2.Activity:CustomPhoto.java

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.UUID;
    public class CustomPhoto extends AppCompatActivity {
    
        private Camera camera;
        private Preview preview;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.activity_custom_photo);
            //隐藏窗口标题
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            //设置全屏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            //创建Preview对象
            preview = new Preview(this);
            setContentView(preview);
    
        }
        //检查是否支持照相机
        private boolean checkCameraHardware(Context context) {
            if (context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_CAMERA)){
                return true;
            }else {
                return false;
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            //0.添加权限
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    == PackageManager.PERMISSION_GRANTED) {
                System.out.println("ok");
            }else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.CAMERA},1);
            }
            if (ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED){
                System.out.println("OK");
            }else {
                ActivityCompat.requestPermissions(this,
                        new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
            }
            //1.打开照相机
            camera = Camera.open();
            preview.setCamera(camera);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (camera != null) {
                //将camera释放掉,不然其他应用不能使用照相机
                camera.release();
                //把字段置空,当垃圾回收机制检测到这个字段为空,就会回收这块资源
                camera = null;
                preview.setCamera(null);
            }
        }
    
        //回调监听,预览的视图
        class Preview extends ViewGroup implements SurfaceHolder.Callback,View.OnClickListener{
    
            SurfaceView surfaceView;
            SurfaceHolder surfaceHolder;
            Camera.Size previewSize;
            List supportPreviewSizes;
            Camera mCamera;
            Context context;
    
            public Preview(Context context) {
                super(context);
                this.context = context;
                //2.创建SurfaceView对象
                surfaceView = new SurfaceView(context);
                surfaceView.setOnClickListener(this);
                //2.1把SurfaceView添加到视图中
                addView(surfaceView);
                //3.添加回调监听
                surfaceHolder = surfaceView.getHolder();
                surfaceHolder.addCallback(this);
            }
    
            public void setCamera(Camera camera) {
                mCamera = camera;
                if (mCamera != null) {
                    supportPreviewSizes = mCamera.getParameters().getSupportedPictureSizes();
                    //布局变化时重新调整布局
                    requestLayout();
                }
            }
    		//5.1往SD卡存文件
            private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {
                    mCamera.startPreview();
                    String name = "/sdcard/DCIM/"+ UUID.randomUUID()+".jpg";
                    File pictureFile = new File(name);
                    try {
                        FileOutputStream fos = new FileOutputStream(pictureFile);
                        fos.write(data);
                        fos.close();
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    if (mCamera != null) {
                        //将Camera和SurfaceView关联起来,通知Camera把所有的信息显示到SurfaceView上
                        mCamera.setPreviewDisplay(holder);
                    }
                }catch (Exception e) {
    
                }
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                //4.预览图片
                Camera.Parameters parameters = mCamera.getParameters();
                //4.1设置预览尺寸
                parameters.setPictureSize(previewSize.width,previewSize.height);
                mCamera.setParameters(parameters);
                //4.5开始预览
                mCamera.startPreview();
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (mCamera != null) {
                    //Camera停止预览
                    mCamera.stopPreview();
                }
            }
    
            @Override
            protected void onLayout(boolean changed, int l, int t, int r, int b) {
                //4.2调整实际预览的尺寸
                //试图发生改变并且子视图大于0
                if (changed && getChildCount()>0) {
                    //获取子视图
                    final View child = getChildAt(0);
    
                    int width = r - l;
                    int height = b -t;
    
                    int previewWidth = width;
                    int previewHeight = height;
    
                    if (previewSize != null) {
                        //预览的窗口大小=实际图像的大小,就不会失帧
                        previewWidth = previewSize.width;
                        previewHeight = previewSize.height;
                    }
                    //通过判断长宽比,让手机屏幕的宽高比大于采集图像的宽高比,使图像居中
                    if (width * previewHeight > height * previewWidth) {
                        final int scaledChildWidth = previewWidth * height / previewHeight;
                        child.layout((width-scaledChildWidth)/2,0,(width+scaledChildWidth)/2,height);
                    }else {
                        //当图像比屏幕宽时
                        final int scaleChildHeight = previewHeight * width /previewWidth;
                        child.layout(0,(height-scaleChildHeight)/2,width,(height+scaleChildHeight)/2);
                    }
                }
            }
    
            //4.3选一个最优尺寸
            private Camera.Size getOptimalPreviewSize(List sizes,int w,int h) {
                double ASPECT_TOLERANCE = 0.1;
                double targetRadio = (double)w/h;
                if (sizes == null) {
                    return null;
                }
                Camera.Size optimalSize = null;
                double minDiff = Double.MAX_VALUE;
                int targetHeight = h;
                for (Camera.Size size : sizes) {
                    double ratio = (double)size.width / size.height;
                    //选择实际图像的宽高比和预览窗口的宽高比小于0.1的尺寸
                    if (Math.abs(ratio - targetRadio) > ASPECT_TOLERANCE) {
                        continue;
                    }
                    //选择采集图像高度和实际窗口尽可能一致,尽能保证图像不被放大或缩小
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
                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.4测量窗口
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                int width = resolveSize(getSuggestedMinimumWidth(),widthMeasureSpec);
                int height = resolveSize(getSuggestedMinimumHeight(),heightMeasureSpec);
    
                setMeasuredDimension(width,height);
                if (supportPreviewSizes != null) {
                    previewSize = getOptimalPreviewSize(supportPreviewSizes,width,height);
                }
            }
    
            @Override
            public void onClick(View v) {
            	//5.拍照
                mCamera.takePicture(null,null,mPictureCallback);
                Toast.makeText(context,"拍照完成",Toast.LENGTH_LONG).show();
            }
        } 
    }

效果如下:

进入拍照界面,点击屏幕拍照
Android:使用Camera硬件拍照并保存相片_第1张图片
在手机的sdcard/DCIM文件夹下找到了该照片
Android:使用Camera硬件拍照并保存相片_第2张图片

你可能感兴趣的:(Android,Android,Camera)