Android自定义照相机的实例

Android自定义照相机实现

近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能。

创建一个项目:FingerTakePicture

首先来搞一下界面:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/FrameLayout1"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >
  <!-- 显示预览图形 -->
  <SurfaceView
    android:id="@+id/surfaceView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
  <!-- 相对布局,放置两个按钮 -->
    <RelativeLayout
      android:id="@+id/buttonLayout"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:visibility="gone"
    >
    <!-- 拍照按钮 -->
    <Button
      android:id="@+id/takepicture"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentRight="true"
      android:layout_alignParentBottom="true"
      android:background="@drawable/btn_tabkepicture_selector"
      android:onClick="btnOnclick"
      />
    <ImageView
      android:id="@+id/scalePic"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentLeft="true"
      android:layout_alignParentBottom="true"
      android:layout_marginLeft="5dp"
      android:background="@drawable/img_showpic_selector"
      android:onClick="imageClick"
      />
  </RelativeLayout>
</FrameLayout>

界面效果(无法把预览给截屏下来滴):

权限设置少不了:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.wwj.finger"
  android:versionCode="1"
  android:versionName="1.0" > 

  <uses-sdk
    android:minSdkVersion="4"
    android:targetSdkVersion="15" /> 

  <uses-permission android:name="android.permission.CAMERA" />
  <!-- 在SDCard中创建与删除文件权限 -->
  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  <!-- 往SDCard写入数据权限 -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
      android:name=".MainActivity"
      android:label="@string/title_activity_main"
      >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" /> 

        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity
      android:name=".ShowPicActivity"
      android:label="@string/app_name"
      android:theme="@style/AppTheme"
      android:configChanges="orientation|keyboardHidden"
      ></activity>
  </application> 

</manifest>

主Activity:

package com.wwj.finger; 

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

import android.app.Activity;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast; 

/**
 * Android手指拍照
 *
 * @author wwj
 * @date 2013/4/29
 */
public class MainActivity extends Activity {
  private View layout;
  private Camera camera;
  private Camera.Parameters parameters = null; 

  Bundle bundle = null; // 声明一个Bundle对象,用来存储数据 

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 显示界面
    setContentView(R.layout.activity_main); 

    layout = this.findViewById(R.id.buttonLayout); 

    SurfaceView surfaceView = (SurfaceView) this
        .findViewById(R.id.surfaceView);
    surfaceView.getHolder()
        .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    surfaceView.getHolder().setFixedSize(176, 144); //设置Surface分辨率
    surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
    surfaceView.getHolder().addCallback(new SurfaceCallback());//为SurfaceView的句柄添加一个回调函数
  } 

  /**
   * 按钮被点击触发的事件
   *
   * @param v
   */
  public void btnOnclick(View v) {
    if (camera != null) {
      switch (v.getId()) {
      case R.id.takepicture:
        // 拍照
        camera.takePicture(null, null, new MyPictureCallback());
        break;
      }
    }
  } 

  /**
   * 图片被点击触发的时间
   *
   * @param v
   */
  public void imageClick(View v) {
    if (v.getId() == R.id.scalePic) {
      if (bundle == null) {
        Toast.makeText(getApplicationContext(), R.string.takephoto,
            Toast.LENGTH_SHORT).show();
      } else {
        Intent intent = new Intent(this, ShowPicActivity.class);
        intent.putExtras(bundle);
        startActivity(intent);
      }
    }
  } 

  private final class MyPictureCallback implements PictureCallback { 

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
      try {
        bundle = new Bundle();
        bundle.putByteArray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换
        saveToSDCard(data); // 保存图片到sd卡中
        Toast.makeText(getApplicationContext(), R.string.success,
            Toast.LENGTH_SHORT).show();
        camera.startPreview(); // 拍完照后,重新开始预览 

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

  /**
   * 将拍下来的照片存放在SD卡中
   * @param data
   * @throws IOException
   */
  public static void saveToSDCard(byte[] data) throws IOException {
    Date date = new Date();
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间
    String filename = format.format(date) + ".jpg";
    File fileFolder = new File(Environment.getExternalStorageDirectory()
        + "/finger/");
    if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录
      fileFolder.mkdir();
    }
    File jpgFile = new File(fileFolder, filename);
    FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流
    outputStream.write(data); // 写入sd卡中
    outputStream.close(); // 关闭输出流
  } 

  private final class SurfaceCallback implements Callback { 

    // 拍照状态变化时调用该方法
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
      parameters = camera.getParameters(); // 获取各项参数
      parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式
      parameters.setPreviewSize(width, height); // 设置预览大小
      parameters.setPreviewFrameRate(5); //设置每秒显示4帧
      parameters.setPictureSize(width, height); // 设置保存的图片尺寸
      parameters.setJpegQuality(80); // 设置照片质量
    } 

    // 开始拍照时调用该方法
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
      try {
        camera = Camera.open(); // 打开摄像头
        camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象
        camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));
        camera.startPreview(); // 开始预览
      } catch (Exception e) {
        e.printStackTrace();
      } 

    } 

    // 停止拍照时调用该方法
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
      if (camera != null) {
        camera.release(); // 释放照相机
        camera = null;
      }
    }
  } 

  /**
   * 点击手机屏幕是,显示两个按钮
   */
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      layout.setVisibility(ViewGroup.VISIBLE); // 设置视图可见
      break;
    }
    return true;
  } 

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {
    case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮
      if (camera != null && event.getRepeatCount() == 0) {
        // 拍照
        //注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后
        //,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络
        camera.takePicture(null, null, new MyPictureCallback());
      }
    }
    return super.onKeyDown(keyCode, event);
  } 

  // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度
  public static int getPreviewDegree(Activity activity) {
    // 获得手机的方向
    int rotation = activity.getWindowManager().getDefaultDisplay()
        .getRotation();
    int degree = 0;
    // 根据手机的方向计算相机预览画面应该选择的角度
    switch (rotation) {
    case Surface.ROTATION_0:
      degree = 90;
      break;
    case Surface.ROTATION_90:
      degree = 0;
      break;
    case Surface.ROTATION_180:
      degree = 270;
      break;
    case Surface.ROTATION_270:
      degree = 180;
      break;
    }
    return degree;
  }
}

用来显示图片的Activity:

package com.wwj.finger; 

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.widget.ImageView; 

public class ShowPicActivity extends Activity {
  private ImageView ivPic = null; // 显示图片控件 

  /**
   * Activity在创建的时候回调的函数 主要用来初始化一些变量
   */
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.showpic);
    ivPic = (ImageView) findViewById(R.id.ivPic);
    setImageBitmap(getImageFormBundle()); 

  } 

  /**
   * 将MainActivity传过来的图片显示在界面当中
   *
   * @param bytes
   */
  public void setImageBitmap(byte[] bytes) {
    Bitmap cameraBitmap = byte2Bitmap();
    // 根据拍摄的方向旋转图像(纵向拍摄时要需要将图像选择90度)
    Matrix matrix = new Matrix();
    matrix.setRotate(MainActivity.getPreviewDegree(this));
    cameraBitmap = Bitmap
        .createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(),
            cameraBitmap.getHeight(), matrix, true);
    ivPic.setImageBitmap(cameraBitmap);
  } 

  /**
   * 从Bundle对象中获取数据
   *
   * @return
   */
  public byte[] getImageFormBundle() {
    Intent intent = getIntent();
    Bundle data = intent.getExtras();
    byte[] bytes = data.getByteArray("bytes");
    return bytes;
  } 

  /**
   * 将字节数组的图形数据转换为Bitmap
   *
   * @return
   */
  private Bitmap byte2Bitmap() {
    byte[] data = getImageFormBundle();
    // 将byte数组转换成Bitmap对象
    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    return bitmap;
  }
}

这是小巫那个创新项目的一小部分,已经完美实现简单的照相机功能了,保存图片不会像有些网友提供的代码给定一个特定的文件名,不能保存多张图片,还特定把一些方法封装了一下,有需要的朋友好好看看吧。

(0)

相关推荐

  • Android自定义照相机详解

    几乎每个APP都会用的相机功能,下面小编把内容整理分享到我们平台,供大家参考,感兴趣的朋友一起学习吧! 启动相机的两种方式 1.直接启动系统相机 <code class="hljs avrasm"> Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent);</code> 或者指定返回图片的名称mCurrentPho

  • Android自定义照相机Camera出现黑屏的解决方法

    本文实例讲述了Android自定义照相机Camera出现黑屏的解决方法.分享给大家供大家参考,具体如下: 对于一些手机,像HTC,当自定义Camera时,调用Camera.Parameters的 parameters.setPreviewSize(width, height)方法时,如果width和height为奇数情况下,则会出现黑屏现象,解决办法可参考SDK提供的ApiDemos中关于Camera的 例子: List<Size> sizes = parameters.getSupporte

  • Android自定义照相机倒计时拍照

    自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: 两个TextView是用来显示提示信息和倒计时的秒数的 相关教程:Android开发从相机或相册获取图片裁剪 Android启动相机拍照并返回图片 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&qu

  • Android自定义照相机的实例

    Android自定义照相机实现 近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能. 创建一个项目:FingerTakePicture 首先来搞一下界面: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu

  • Android 自定义ContentProvider简单实例

    Android 自定义ContentProvider简单实例 Android允许我们定义自己的的ContentProvider对象来共享数据,练练手,简单来实现一下. 要使用ContentProvider来操作数据,必须要有保存数据的场所.可以使用文件或SQLite数据库的方式来保存数据,通常使用SQLite数据库. 1,创建一个数据库帮助类,归根结底都是它在操作数据库.代码如下: package com.njue; import android.content.Context; import

  • Android 自定义标题栏的实例详解

     Android 自定义标题栏的实例详解 开发 Android APP 经常会用到自定义标题栏,而有多级页面的情况下还需要给自定义标题栏传递数据. 本文要点: 自定义标题填充不完整 自定义标题栏返回按钮的点击事件 一.代码 这里先介绍一下流程: 1. 创建一个标题栏布局文件 mytitlebar.xml 2. 在style.xml中创建 mytitlestyle 主题 3. 创建类 CustomTitleBar 4. 在需要自定义标题栏的Activity的OnCreate方法中实例化 Custo

  • Android自定义滚动选择器实例代码

    Android自定义滚动选择器 实现图片的效果 代码如下 package com.linzihui.widget; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graph

  • Android自定义扇形倒计时实例代码

    一.概述 严格来说,我是Android小白,写的目的只是想作为知识储备而已-.但是想到别人或许会不小心搜到我的这篇,如果我只是简单的描述,别人有可能看不懂,说不定还被吐槽,那岂不是很冤吗? 所以,我还是把问题及过程描述清楚,这也是对自己的一个交代,同时,这也是我的第一篇,我应该做好它; 先说一下需求: 最近工作中需要做一个倒计时,是那种一个圆,慢慢的被吃掉的动画倒计时,由于自己知识不是很足,只知道要用Canvas来画,在网上搜了一圈,发现要么是静态的画了一个扇形,要么是不能控制控件的位置大小-.

  • Android自定义Dialog原理实例解析

    Android开发过程中,常常会遇到一些需求场景--在界面上弹出一个弹框,对用户进行提醒并让用户进行某些选择性的操作, 如退出登录时的弹窗,让用户选择"退出"还是"取消"等操作. Android系统提供了Dialog类,以及Dialog的子类,常见如AlertDialog来实现此类功能. 一般情况下,利用Android提供的Dialog及其子类能够满足多数此类需求,然而,其不足之处体现在: 1. 基于Android提供的Dialog及其子类样式单一,风格上与App本

  • Android 自定义相机及分析源码

    Android 自定义相机及分析源码 使用Android 系统相机的方法: 要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下 <intent-filter> <action android:name="android.intent.action.IMAGE_CAPTURE" /> <category android:name="android.intent.category.DEFAULT" />

随机推荐