Android自定义相机实现N连拍

昨天有朋友让我帮他实现一个进入系统相机实现3连拍,然后自动返回拍到的结果,一可以我觉得这个需求有点可笑,但是作为技术人员,我还是值得探索一下,所以我就自己写了个相机,改系统的有点费劲。给我一个Camera,我还你五杀。


##首先看一下用到了那些知识点

  • Camera 取景
  • SurfaceView 显示 Camera扑捉到的景
  • SurfaceHolder 将Camera与SurfaceView绑定
    注意:次Camera 非彼Camera ,导包android.hardware.Camera,于硬件有关;而不是android.graphics.Camera,这个是做3D图形变换的

##下面是布局文件



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_auto_take_pictures"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   tools:context="com.jrt.customcamera.AutoTakePicturesActivity">
    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</RelativeLayout>

注意:千万不要因为SurfaceView长得太丑而给它设置background,那样就掉坑里了,你根本就看不到Camera 扑捉到的景


##具体代码如下




package com.jrt.customcamera;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.os.Environment;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

/**
 * 描述:自动连续拍照
 * 开发者:开发者的乐趣JRT
 * 创建时间:2017-3-15 19:16
 * CSDN地址:http://blog.csdn.net/Jiang_Rong_Tao/article
 * E-mail:jrtxb520@163.com
 **/
public class AutoTakePicturesActivity extends AppCompatActivity implements SurfaceHolder.Callback{
    private static final String TAG = "AutoTakePicturesActivity";
    private SurfaceView mSurfaceView;
    private Camera mCamera;
    private SurfaceHolder mSurfaceViewHolder;
    private int mPictureCount=3;//默认自动拍一张
    private final int mPictureCountMax=30;//默认自动拍一张
    int pic_count=0;
    private ArrayList<String> mPicturePaths;
    private String mPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_auto_take_pictures);
        init();
    }
    private void init() {
        mPicturePaths=new ArrayList<String>();
        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
        //获取SurfaceHolder
        mSurfaceViewHolder = mSurfaceView.getHolder();
        mSurfaceViewHolder.addCallback(this);
        //触摸屏幕完成对焦
        mSurfaceView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mCamera.autoFocus(null);
                //平滑的缩放:取值在0~mCamera.getParameters().getMaxZoom()
//                 mCamera.startSmoothZoom(2);
            }
        });
    }
    private void startCapture(){
        if (mCamera != null) {
            Camera.Parameters parameters = mCamera.getParameters();
            //设置拍照的图片格式
            parameters.setPictureFormat(ImageFormat.JPEG);
            //设置图片的预览大小
            parameters.setPreviewSize(200, 300);
            //设置自动对焦
            parameters.setFocusMode(Camera.Parameters.ANTIBANDING_AUTO);
            Log.d(TAG, "startCapture: "+parameters.getFocusMode());
            mCamera.autoFocus(new Camera.AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    //动态对对焦成功后,获取拍摄的图片
                    if (success) {
                        camera.takePicture(null, null, mPictureCallback);
                    }
                }
            });
        }
    }
    /**
     * 拍摄成功后对图片的处理
     */
    private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        @SuppressLint("LongLogTag")
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

            if (Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) {
                FileOutputStream fileOutputStream = null;
                try {
                    File file = new File(Environment.getExternalStorageDirectory()
                            , getPhotoFileName());
                    mPath = file.getAbsolutePath();
                    Log.i(TAG, "onPictureTaken: " + mPath);
                    fileOutputStream = new FileOutputStream(file);
                    fileOutputStream.write(data);
                } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(AutoTakePicturesActivity.this, "图片保存失败", Toast.LENGTH_SHORT).show();
                } finally {
                    if (fileOutputStream != null) {
                        try {
                            if (mPictureCount>mPictureCountMax){
                                Toast.makeText(AutoTakePicturesActivity.this,"为了节约内存,连拍张数不要超过"+mPictureCountMax+"张", Toast.LENGTH_SHORT).show();
                            }else {
                                if (++pic_count<mPictureCount){
                                    //连拍三张
                                    mPicturePaths.add(mPath);
                                    setStartPreview(mCamera, mSurfaceViewHolder);
                                }else {

                                    mPicturePaths.add(mPath);//最后一张图片加入集合
                                    Intent intent = new Intent().putStringArrayListExtra(Contast.PICTURE_PATHS, mPicturePaths);
                                    setResult(RESULT_OK,intent);
                                    fileOutputStream.close();
                                    //保证最后一张图片加入集合并优化用户体验
                                    SystemClock.sleep(2000);
                                    finish();
                                }
                                Toast.makeText(AutoTakePicturesActivity.this, "图片保存成功"+pic_count+"张", Toast.LENGTH_SHORT).show();
                            }


                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            } else {
                Toast.makeText(AutoTakePicturesActivity.this, "SD不存在,图片保存失败", Toast.LENGTH_SHORT).show();
            }
        }
    };

    /**
     * 获取Camera对象
     *
     * @return
     */
    private Camera getCamera() {
        mCamera = Camera.open();
        return mCamera;
    }

    /**
     * 设置并且开启相机预览
     */
    private void setStartPreview(Camera camera, SurfaceHolder holder) {
        try {
            //将Camera与SurfaceView开始绑定
            camera.setPreviewDisplay(holder);
            //调整拍摄的方向(默认横屏)
            camera.setDisplayOrientation(90);//旋转90度
            //开启预览
            camera.startPreview();
            startCapture();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放Camera资源
     */
    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);//取消回调
            stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 停止取景
     */
    private void stopPreview() {
        mCamera.stopPreview();
    }

    /**
     * 将Camera和Activity的生命周期绑定
     */
    @Override
    protected void onResume() {
        super.onResume();
        if (mCamera == null) {
            mCamera = getCamera();
//            if (mSurfaceViewHolder != null) {
//                setStartPreview(mCamera, mSurfaceViewHolder);
//            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseCamera();
    }


    /**
     * SurfaceHolder 的回调处理
     *
     * @param surfaceHolder
     */
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "surfaceCreated: ");
//        setStartPreview(mCamera, mSurfaceViewHolder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        Log.i(TAG, "surfaceChanged: ");
        stopPreview();//先停止取景,再重新打开
        setStartPreview(mCamera, mSurfaceViewHolder);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        Log.i(TAG, "surfaceDestroyed: ");
        releaseCamera();
    }

    // 使用系统当前日期加以调整作为照片的名称
    private String getPhotoFileName() {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat(
                "'IMG'_yyyyMMdd_HHmmss");
        return dateFormat.format(date) + ".jpg";
    }
}

这里有几个点:

  • takePicture(null, null, mPictureCallback);强两个参数值得我们去研究它的用法
  • 这里我返回的是图片的路径,具体的图片展示的时候应该在onActivityResult方法中用BitmapFactory和Bitmap类进行处理
  • 我这只做了三张,如果想拍更多的可以手动去改mPictureCount的值,如果超过30张可以去该mPictureCountMax和mPictureCount。这里我没有提供set方法。
  • 其实还做了个手动拍照的,这个连拍就是在手动的基础上改过来的,你可以想着把它还原回去

##调用相机的界面处理


public class MainActivity extends AppCompatActivity {

    private TextView mShowPaths;
    private ImageView mIvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         mShowPaths = (TextView)findViewById(R.id.tv_show_paths);
        mIvShow = (ImageView)findViewById(R.id.iv_show);
    }

    public void startCamera1(View view){
        Intent intent = new Intent(this,CustomCameraActivity.class);
        startActivity(intent);
    }
    public void startCamera2(View view){
        Intent intent = new Intent(this,AutoTakePicturesActivity.class);
        startActivityForResult(intent,0);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode==0){
             if (resultCode==RESULT_OK){
                  if (data!=null){
                      ArrayList<CharSequence> picturePaths = data.getCharSequenceArrayListExtra(Contast.PICTURE_PATHS);
                      String paths="连拍图片的路径如下:\n";
                      for (int i = 0; i <picturePaths.size() ; i++) {
                          paths+=picturePaths.get(i)+"\n";
                      }
                      String  path = picturePaths.get(0).toString();
                      Bitmap bitmap = BitmapFactory.decodeFile(path);
                      Matrix matrix = new Matrix();
                      matrix.setRotate(90);//默认是横屏的,旋转90度
                      Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),matrix,true);
                      mIvShow.setImageBitmap(bitmap1);
                      mShowPaths.setText(paths);
                  }
             }
        }
    }
}

这里我对拍摄 的第一张照片进行了预览,默认是横屏的,用Matrix来个转矩阵实现我们想要的效果


由于模拟器不支持摄像头,所以只能用真机截个图:
连拍中
这里写图片描述

github:源码下载


2020年五月16日更新,具体代码移步github,下载最新的代码;应粉丝要求,我把这个项目从原有的项目中单独分离出来新建了一个仓库

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值