Android—实现自定义相机倒计时拍照

这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能

首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件:

两个TextView是用来显示提示信息和倒计时的秒数的

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#266194"
    android:orientation="vertical"
    tools:context=".TestActivity" >

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical" >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="请调整位置到此区域"
            android:textColor="#ff0000"
            android:textSize="32sp" />

        <TextView
            android:id="@+id/tv_time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="10dp"
            android:gravity="center_horizontal"
            android:textColor="#266194"
            android:textSize="32sp" />
    </LinearLayout>

</RelativeLayout>

接下来是mainActivity中的具体实现以及详细注释:

package com.dhsr.pujiejia.ui;

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

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import com.example.pujiejiaapp.R;

@SuppressLint({ "NewApi", "SdCardPath" })
public class CameraActivity extends Activity implements Runnable {
    // 预览图片范围
    private SurfaceView surfaceView;
    private TextView tv_time;
    // 倒计时拍摄
    private int cameratime = 4;
    private Camera camera;
    private boolean preview = false;
    // 文件名字
    private String filename;
    // 文件名字的带的时间戳
    private String timeString;
    // 格式化时间
    private SimpleDateFormat dateFormat;
    // 日期对象
    private Date date;
    // 控制线程
    boolean stopThread = false;
    private File file;
    String photo;

    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            int what = msg.what;
            switch (what) {
            case 222:
                tv_time.setText("" + cameratime);
                if ("0".equals(tv_time.getText().toString())) {
                    tv_time.setText("拍摄成功!");
                    takePhoto();
                }
                break;

            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        CameraActivity.this.setFinishOnTouchOutside(false);
        // 初始化数据
        findView();
        surfaceView.getHolder().addCallback(new SufaceListener());
        /* 下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前 */
        surfaceView.getHolder()
                .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceView.getHolder().setFixedSize(200, 200); // 设置分辨率
    }

    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        // 开启线程
        new Thread(this).start();
    }

    private final class SufaceListener implements SurfaceHolder.Callback {
        /**
         * surface改变
         */
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }

        /**
         * surface创建
         */
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
                    CameraInfo info = new CameraInfo();
                    Camera.getCameraInfo(i, info);
                    // 调用系统的前置摄像头
                    if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
                        camera = Camera.open(i);
                    }
                }
                Camera.Parameters parameters = camera.getParameters();
                /* 每秒从摄像头捕获5帧画面, */
                parameters.setPreviewFrameRate(5);
                /* 设置照片的输出格式:jpg */
                parameters.setPictureFormat(PixelFormat.JPEG);
                /* 照片质量 */
                parameters.set("jpeg-quality", 85);
                WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
                camera.setParameters(parameters);
                camera.setPreviewDisplay(surfaceView.getHolder());// 通过SurfaceView显示取景画面
                camera.startPreview();
                preview = true;
            } catch (Exception e) {

            }
        }

        /**
         * surface销毁
         */
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (camera != null) {
                if (preview)
                    camera.stopPreview();
                camera.release();
                camera = null;
            }
        }
    }

    /**
     * 拍摄照片
     */
    private void takePhoto() {
        // 执行拍照效果
        camera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                try {
                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                            data.length);
                    timeString = formatDate();
                    //保存到data/data目录自定义文件夹下
                     filename = "/data/data/com.example.pujiejiaapp/images/"
                     + timeString + ".jpg";
                    File file = new File(filename);
                    boolean createNewFile = file.createNewFile()
                    System.out.println("创建文件夹成功没有" + createNewFile);
                    System.out.println(file);
                    FileOutputStream outStream = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 60, outStream);
                    outStream.flush();
                    outStream.close();
                    // 重新浏览
                    camera.stopPreview();
                    camera.startPreview();
                    preview = true;
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                }
            }
        });
    }

    @Override
    public void run() {
        while (!stopThread) {
            try {
                //按秒数倒计时
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            cameratime--;
            mHandler.sendEmptyMessage(222);
            if (cameratime <= 0) {
                break;
            }
        }
    }

    // 初始化数据
    private void findView() {
        surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
        tv_time = (TextView) findViewById(R.id.tv_time);
    }

    // 格式化系统的时间
    public String formatDate() {
        date = new Date(System.currentTimeMillis());
        // 日期格式
        dateFormat = new SimpleDateFormat("‘IMG‘_yyyyMMddHHmmss");
        return dateFormat.format(date);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        // 线程已关闭
        super.onDestroy();
        stopThread = true;
    }

}

核心代码详解:

1.创建SurfaceView时,surfaceCreated()方法中

for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
                    CameraInfo info = new CameraInfo();
                    Camera.getCameraInfo(i, info);
                    // 调用系统的前置摄像头
                    if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
                        camera = Camera.open(i);
                    }
                }

此部分代码为打开相机时默认打开前置摄像头CameraInfo.CAMERA_FACING_BACK为默认打开后置摄像头,CameraInfo.CAMERA_FACING_FRONT前置摄像头

2.照片拍摄takePhoto()方法中:

Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                            data.length);
                    timeString = formatDate();
                     filename = "/data/data/com.example.pujiejiaapp/images/"
                     + timeString + ".jpg";
                    photo = timeString + ".jpg";
                    File file = new File(filename);
                    boolean createNewFile = file.createNewFile();
                    FileOutputStream outStream = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 60, outStream);

此部分代码为将拍摄到的图片保存为以bitmap格式保存在指定的目录下

3.开子线程用于倒计时拍摄

public void run() {
        while (!stopThread) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            cameratime--;
            mHandler.sendEmptyMessage(222);
            if (cameratime <= 0) {
                break;
            }
        }
    }

希望大家理解核心代码的详细注释,欢迎提供意见,希望能给大家带来帮助,谢谢!

时间: 2024-10-05 08:41:06

Android—实现自定义相机倒计时拍照的相关文章

【Android】自定义相机的实现(支持连续拍照、前后摄像头切换、连续对焦)

~转载请注明http://blog.csdn.net/u013015161/article/details/46921257 介绍 这几天,写了一个自定义照相机的demo,支持连续拍照和摄像头切换.由于自己以前没接触过相关的编程,也算是一个学习的过程,在这里做一下记录,同时也分享出来,并附上源码和工程. 效果如图: 左上角switch切换摄像头,右边snap按钮进行拍照. 一般流程 Android进行拍照,需要调用摄像头类android.hardware.Camera.而要进行预览,则需要用an

android开发——自定义相机开发总结

最近这段时间我一直在开发自定义相机,谷歌了些网上的demo,发现有很多各种各样的问题.最终还是从API的camera类开始学习,进行改进.下面对之前的实现进行一些总结. 官方camera API: http://developer.android.com/guide/topics/media/camera.html 中文翻译: http://www.cnblogs.com/over140/archive/2011/11/16/2251344.html 自定义相机大致实现流程: 预览Camera这

Android调用系统相机、自定义相机、处理大图片

Android调用系统相机和自定义相机实例 本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显示出来,该例子也会涉及到Android加载大图片时候的处理(避免OOM),还有简要提一下有些人SurfaceView出现黑屏的原因. Android应用拍照的两种方式,下面为两种形式的Demo展示出来的效果.    知识点: 一.调用系统自带的相机应用 二.自定义我们自己的拍照界面 三.关于计算机解析图片原理(如何正确加载图片到Android应用中) 所需

Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段落,又是新一月,上月主要是围绕MediaPlayer相关展开,从今天开始,开始分析多媒体框架中的Camera模块,看下今天的Agenda: Camera拍照 Camera录像 新API android.hardware.camera2 新旧API特点对比 Camera自定义相机 新API andro

Android自定义相机超详细讲解

Android自定义相机超详细讲解 转载请标明出处: http://blog.csdn.net/vinicolor/article/details/49642861: 由于网上关于Android自定义相机的文章写得不是太详细,Google官方的文档又说得不太容易理解,所以今天我来详细讲解一下Android自定义相机. 这篇文章主要写给一些刚刚接触Android的那些看官方API困难以及不太了解Android机制的同学们,所以熟练开发者可以绕道了. 最近在使用Camera类的时候发现居然被弃用了,

Android 手把手带你玩转自定义相机

概述 相机几乎是每个APP都要用到的功能,万一老板让你定制相机方不方?反正我是有点方.关于相机的两天奋斗总结免费送给你. 启动相机的两种方式 1.直接启动系统相机 Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent); 或者指定返回图片的名称mCurrentPhotoFile Intent intent = new Intent(MediaSto

iOS开发笔记17:自定义相机拍照

之前用AVFoundation自定义相机做了拍照与视频相关的东西,为什么要自定义呢?主要是提供更个性化的交互设计,符合app主题,对于视频来说,也便于提供更多丰富有趣的功能.前段时间整理了下拍照部分的功能,主要分为以下五个部分 1.初始化,建立会话,获取摄像头 使用AVCaptureSessionPresetPhoto模式,输出的图片分辨率与系统相机输出的分辨率保持一致 添加后置摄像头与图片输出(默认采用后置摄像头拍摄) 2.嵌入实时预览层 获取实时预览画面,添加手势,初始化时默认在画面中心点对

自定义相机(二) -- 拍照

实现功能: 相机拍照,把图像保持到系统相册. 运行环境: 1.  XCODE 5.1.1 2.  真机(IPHONE5  ,  IOS6.1.4) #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> //导入 - "视频流" @interface MCViewController : UIViewController @property (strong, nonatomic) AVCaptu

android调用系统相机拍照并保存在本地

import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Locale; import android.annotation.SuppressLint; import android.app.Activity; import an