欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 自定义相机及分析源码

程序员文章站 2023-12-06 00:02:16
android 自定义相机及分析源码 使用android 系统相机的方法: 要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下...

android 自定义相机及分析源码

使用android 系统相机的方法:

要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下

 <intent-filter>
        <action android:name="android.intent.action.image_capture" />

        <category android:name="android.intent.category.default" />
      </intent-filter>

action的作用就是声明action的类型,便于intent的使用,category的作用就是注册,没有它。相关操作将不起作用。
一种方式是简单粗暴的实现,如下

intent intent=new intent(mediastore.action_image_capture);
    startactivityforresult(intent, req_1);
//然后在 onactivityresult方法中实现数据的获取,此处是展示在了一个imageview上
if(resultcode==result_ok){
      if(requestcode==req_1){
        bundle bundle=data.getextras();
        bitmap bitmap=(bitmap) bundle.get("data");
        imageview.setimagebitmap(bitmap);
        }

小总结:这样的好处是简单快捷,但是在现在的android智能机中,好多相片都是很大的,这里获得的仅仅是一个缩略图罢了

另外一种方式是稍微温婉一点了,而且效果也更好一点,好处就在于它是先将照片信息存储到本地一个临时文件中,然后让imageview去相关路径下进行读取,这样就可以获得清晰度很高的图片了。如下

/*
   * 此方法的存在意义就是不在onactivityresult方法的data中获取我们拍照的缩略图,而是从我们的文件输出目录下直接查看原图
   * 这样的好处就是可以对大容量的照片进行便捷的准确的操作
   */
  public void onstartcarema2(view view){
    intent intent=new intent(mediastore.action_image_capture);
    //见你给你路径传递回需要的处理方法中
    uri uri=uri.fromfile(new file(myfilepath));
    //设置文件的输出路径
    intent.putextra(mediastore.extra_output, uri);
    startactivityforresult(intent, req_2);
  }
//然后在onactivityresult方法中进行相关的处理就可以了
else if(requestcode==req_2){
        fileinputstream fis=null;
        try {
          fis=new fileinputstream(myfilepath);
          bitmap bitmap=bitmapfactory.decodestream(fis);
          imageview.setimagebitmap(bitmap);
        } catch (filenotfoundexception e) {
          // todo auto-generated catch block
          e.printstacktrace();
        }finally{
          try {
            fis.close();
          } catch (ioexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
          }
        }
      }
    }
//记得最后一定要关闭相关的流操作。否则会引起相关的异常的。

开发自定义的相机

由于开发自定义的相机要进行相关的权限的生命,所以一定不要忘记在清单文件中做相关的处理,如下

<uses-permission android:name="android.permission.write_external_storage"/>
  <uses-permission android:name="android.permission.camera"/>

然后有以下几个步骤:

  • 创建camera,并完成初始化camera,开始预览,释放资源三个方法
  • 与activity的surfaceview进行绑定。
  • 在系统的onpause(),onresume()方法中进行相关状态设置
  • 对camera进行参数设置,作用就是对照片类型和状态进行相关的设置
  • 将拍得的照片进行展示,一般会新开一个activity,用imageview进行承载,我们还可以在此activity上添加textview,实现水印效果等其他的美化操作
  • 另外,如果想加入自动聚焦的功能,就可以在surfaceview上添加onclicklistener(),对屏幕进行侦听,调用mycamera.autofocus(null);方法即可

以上就是整个思路

接下来就是使用系统camera的代码展示

(可以直接copy相关代码块,添加到你的应用中去,实现camera这一功能。)

首先是mainactivity

布局

<linearlayout 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:paddingbottom="@dimen/activity_vertical_margin"
  android:paddingleft="@dimen/activity_horizontal_margin"
  android:paddingright="@dimen/activity_horizontal_margin"
  android:paddingtop="@dimen/activity_vertical_margin"
  android:orientation="vertical"
  tools:context=".mainactivity" >

  <button 
    android:id="@+id/startcarema"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="6dp"
    android:text="startcarema"
    android:onclick="onstartcarema"
    />
  <button 
    android:id="@+id/startcarema2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="6dp"
    android:text="startcarema2"
    android:onclick="onstartcarema2"
    />
  <button 
    android:id="@+id/customcarema"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="6dp"
    android:text="customcarema"
    android:onclick="oncustomcarema"
    />

  <imageview 
    android:id="@+id/imageview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    />

</linearlayout>

代码

package com.example.camerademo;

import java.io.file;
import java.io.fileinputstream;
import java.io.filenotfoundexception;
import java.io.ioexception;

import android.app.activity;
import android.content.intent;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.net.uri;
import android.os.bundle;
import android.os.environment;
import android.provider.mediastore;
import android.view.view;
import android.widget.button;
import android.widget.imageview;

public class mainactivity extends activity {
  //为下面的获取请求所用
  private static int req_1=1;
  private static int req_2=2;

  button btn_startcareme,btn_startcarema2,btn_customcarema;
  imageview imageview;

  //定义照片存储的路径
  private string myfilepath;
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    btn_startcareme=(button) findviewbyid(r.id.startcarema);
    btn_startcarema2=(button) findviewbyid(r.id.startcarema2);
    btn_customcarema=(button) findviewbyid(r.id.customcarema);
    imageview=(imageview) findviewbyid(r.id.imageview);

    //初始化不同手机的sd卡的路径
    myfilepath=environment.getexternalstoragedirectory().getpath();
    myfilepath=myfilepath+"/"+"temperature.png";
  }

  public void oncustomcarema(view view){
    intent intent=new intent(this,customcarema.class);
    startactivity(intent);
  }

  public void onstartcarema(view view){
    intent intent=new intent(mediastore.action_image_capture);
    startactivityforresult(intent, req_1);
  }

  /*
   * 此方法的存在意义就是不在onactivityresult方法的data中获取我们拍照的缩略图,而是从我们的文件输出目录下直接查看原图
   * 这样的好处就是可以对大容量的照片进行便捷的准确的操作
   */
  public void onstartcarema2(view view){
    intent intent=new intent(mediastore.action_image_capture);
    //见你给你路径传递回需要的处理方法中
    uri uri=uri.fromfile(new file(myfilepath));
    //设置文件的输出路径
    intent.putextra(mediastore.extra_output, uri);
    startactivityforresult(intent, req_2);
  }

  @override
  protected void onactivityresult(int requestcode, int resultcode, intent data) {
    // todo auto-generated method stub
    super.onactivityresult(requestcode, resultcode, data);
    if(resultcode==result_ok){
      if(requestcode==req_1){
        bundle bundle=data.getextras();
        bitmap bitmap=(bitmap) bundle.get("data");
        imageview.setimagebitmap(bitmap);
      }else if(requestcode==req_2){
        fileinputstream fis=null;
        try {
          fis=new fileinputstream(myfilepath);
          bitmap bitmap=bitmapfactory.decodestream(fis);
          imageview.setimagebitmap(bitmap);
        } catch (filenotfoundexception e) {
          // todo auto-generated catch block
          e.printstacktrace();
        }finally{
          try {
            fis.close();
          } catch (ioexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
          }
        }
      }
    }
  }


}

接下来是自定义相机的代码

主界面布局

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >

  <button 
    android:id="@+id/capture"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="6dp"
    android:text="capture"
    android:onclick="oncapture"
    />

  <surfaceview 
    android:id="@+id/preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    />



</linearlayout>

resultactivity的布局

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >
  <textview 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="capture result"
    android:textsize="28dp"
    android:textcolor="#bfaacd"
    android:gravity="center"
    />  
    <imageview 
      android:id="@+id/picture"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scaletype="center"
      />

</linearlayout>

代码

首先是customcamera类,

package com.example.camerademo;

import java.io.file;
import java.io.filenotfoundexception;
import java.io.fileoutputstream;
import java.io.ioexception;

import android.app.activity;
import android.content.intent;
import android.graphics.imageformat;
import android.hardware.camera;
import android.os.bundle;
import android.view.surfaceholder;
import android.view.surfaceview;
import android.view.view;
import android.view.view.onclicklistener;
import android.widget.button;

@suppresswarnings("unused")
public class customcarema extends activity implements surfaceholder.callback{

  private camera mycamera;

  private surfaceview preview;
  private surfaceholder myholder;  //myholder勇于展现surfaceview的图像

  private camera.picturecallback mypicturecallback=new camera.picturecallback() {

    @override
    public void onpicturetaken(byte[] data, camera arg1) {
      //将拍照得到的数据信息存储到本地
      file tempfile=new file("/sdcard/temp.png");
      try {
        fileoutputstream fos=new fileoutputstream(tempfile);
        fos.write(data);
        fos.close();
        //然后将这个照片的数据信息传送给要进行展示的activity即可
        intent intent=new intent(customcarema.this,resultactivity.class);
        intent.putextra("picturepath", tempfile.getabsolutepath());
        startactivity(intent);
        //拍照结束之后销毁当前的activity,进入到图片展示界面
        customcarema.this.finish();
      } catch (filenotfoundexception e) {
        // todo auto-generated catch block
        e.printstacktrace();
      } catch (ioexception e) {
        // todo auto-generated catch block
        e.printstacktrace();
      }


    }
  };

  @override
  protected void oncreate(bundle savedinstancestate) {
    // todo auto-generated method stub
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.customcarema);
    preview=(surfaceview) findviewbyid(r.id.preview);
    myholder=preview.getholder();
    myholder.addcallback(this);

    //实现点击屏幕自动聚焦的功能,此处并不需要拍照,故只是聚焦
    preview.setonclicklistener(new onclicklistener() {

      @override
      public void onclick(view arg0) {
        // todo auto-generated method stub
        mycamera.autofocus(null);
      }
    });
  }


  @override
  protected void onresume() {
    super.onresume();
    if(mycamera==null){
      mycamera=getcamera();
      if(myholder != null ){
        setstartpreview(mycamera, myholder);
      }
    }
  }

  @override
  protected void onpause() {
    // todo auto-generated method stub
    super.onpause();
    releasecamera();
  }

  /**
   * 释放相机的资源
   */
  private void releasecamera(){
    if(mycamera !=null ){
      mycamera.setpreviewcallback(null);
      mycamera.stoppreview();
      mycamera.release();
      mycamera=null;
    }
  }


  /**
   * 拍照的一些参数设置,点击此按钮之后会触发拍照的会掉,进而实现拍照的效果
   * @param view
   */
  public void oncapture(view view){
    camera.parameters parameters=mycamera.getparameters();
    //设置照片的类型
    parameters.setpictureformat(imageformat.jpeg);
    parameters.setpicturesize(800, 600);
    //设置为自动聚焦
    parameters.setfocusmode(camera.parameters.focus_mode_auto);
    //设置为自动聚焦是不够的,因为我们先得到的是最为清晰的图片,所以要在聚焦成功的时候才进行拍照
    mycamera.autofocus(new camera.autofocuscallback() {

      @override
      public void onautofocus(boolean success, camera camera) {
        // todo auto-generated method stub
        if(success){
          mycamera.takepicture(null, null, mypicturecallback);
        }
      }
    });
  }

  /**
   * 获取系统的一个camera对象
   */
  private camera getcamera(){
    camera camera=null;
    try{
      camera=camera.open();
    }catch(exception e){
      e.printstacktrace();
    }

    return camera;
  }

  /**
   * 开始预览相机的内容,其实就是讲surfaceholder与之绑定
   */
  private void setstartpreview(camera camera,surfaceholder holder){
    //直接调用系统方式绑定预览
    try {
      camera.setpreviewdisplay(holder);
      //由于系统默认使用横屏预览,,所以要进行设置
      camera.setdisplayorientation(90);
      camera.startpreview();
    } catch (ioexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

  }




  @override
  public void surfacechanged(surfaceholder holder, int arg1, int arg2, int arg3) {
    // todo auto-generated method stub
    mycamera.stoppreview();
    setstartpreview(mycamera, myholder);
  }


  @override
  public void surfacecreated(surfaceholder holder) {
    // todo auto-generated method stub
    setstartpreview(mycamera, myholder);
  }


  @override
  public void surfacedestroyed(surfaceholder arg0) {
    // todo auto-generated method stub
    releasecamera();
  }

}

然后是结果界面代码:

package com.example.camerademo;

import java.io.fileinputstream;
import java.io.filenotfoundexception;

import android.app.activity;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.matrix;
import android.os.bundle;
import android.widget.imageview;

public class resultactivity extends activity {

  @override
  protected void oncreate(bundle savedinstancestate) {
    // todo auto-generated method stub
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.resultactivity);
    string path=getintent().getstringextra("picturepath");
    imageview imageview=(imageview) findviewbyid(r.id.picture);
    //由于这样稚嫩获得横屏,所以我们要使用流的形式来转换
//   bitmap bitmap=bitmapfactory.decodefile(path);
//   imageview.setimagebitmap(bitmap);
    fileinputstream fis;
    try {
      fis = new fileinputstream(path);
      bitmap bitmap=bitmapfactory.decodestream(fis);
      matrix matrix=new matrix();
      matrix.setrotate(90);
      bitmap=bitmap.createbitmap(bitmap, 0,0, bitmap.getwidth()
          ,bitmap.getheight(),matrix,true);
      imageview.setimagebitmap(bitmap);
    } catch (filenotfoundexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }


  }
}

以上代码中已经做了下关的代码注释

总结:

安卓6.0以上版本记得加动态权限,不然会报空指针哦,还有点击拍照事件那里  别忘了加进去,不然拍照没反应

以上就是android 自定义相机的实例详解,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!