Android之Camera
来源:互联网 发布:淘宝反作弊部门情况 编辑:程序博客网 时间:2024/06/14 04:36
今天无意当中发现在《Android开发学习之基于ZBar实现微信扫一扫》中的一部分代码可以用来以硬件方式实现一个照相机的功能,在《Android开发学习之调用系统相机完成拍照的实现》中我们是以Intent方式调用系统内置的相机来完成拍照的,今天呢,就让我们来以Camera类为核心来开发自己的相机应用吧。在Android的官方文档中,以硬件方式定制相机应用的步骤如下:
1. 检查和访问Camera
创建代码来检查Camera和所申请访问的存在性;
2. 创建一个预览类
继承SurfaceView来创建一个Camera的预览类,并实现SurfaceHolder接口。这个类用来预览来自Camera的实施图像。
3. 构建一个预览布局
一旦有了Camera预览类,就可以把这个预览类和你想要的用户界面控制结合在一起来创建一个视图布局。
4. 针对采集建立监听
把监听器与响应用户动作(如按下按钮)的界面控制连接到一起来启动图像或视频的采集。
5. 采集和保存文件
针对真正采集的图片或视频,以及输出的保存来编写代码。
6. 释放Camera
使用Camera之后,你的应用程序必须释放Camera,以便其他应用程序能够使用。
Camera硬件是一个必须要认真管理的共享资源,因此你的应用程序在使用它时,不能跟其他应用程序发生冲突。下文将讨论如何检查Camera硬件、如何申请对Camera的访问,如何采集图片和视频,以及在应用使用完成后如何释放Camera。
警告:在应用程序使用完Camera时,要记住通过调用Camera.release()方法来释放Camera对象。如果你的应用程序没有正确的释放Camera,所有的后续的视图对Camera的访问,包括你自己的应用程序,都会失败,并可能到你的或其他的应用程序关闭。
下面我们就来按照上面的步骤来一步步的制作一个属于自己的相机应用吧!
第一步:检查和访问相机
/** 官方建议的安全地访问摄像头的方法 **/
public
static
Camera getCameraInstance(){
Camera c =
null
;
try
{
c = Camera.open();
}
catch
(Exception e){
Log.d(
"TAG"
,
"Error is "
+e.getMessage());
}
return
c;
}
/** 检查设备是否支持摄像头 **/
private
boolean
CheckCameraHardware(Context mContext)
{
if
(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
{
// 摄像头存在
return
true
;
}
else
{
// 摄像头不存在
return
false
;
}
}
第二步:创建一个预览类。这里我们使用的是官方API中提供的一个基本的预览类:
package
com.android.OpenCamera;
import
java.io.IOException;
import
android.annotation.SuppressLint;
import
android.content.Context;
import
android.hardware.Camera;
import
android.util.Log;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
/** 一个基本的相机预览界面类 **/
@SuppressLint
(
"ViewConstructor"
)
public
class
CameraPreview
extends
SurfaceView
implements
SurfaceHolder.Callback {
/** Camera **/
private
Camera mCamera;
/** SurfaceHolder **/
private
SurfaceHolder mHolder;
/** CamreaPreview构造函数 **/
@SuppressWarnings
(
"deprecation"
)
public
CameraPreview(Context mContext,Camera mCamera)
{
super
(mContext);
this
.mCamera=mCamera;
// 安装一个SurfaceHolder.Callback,
// 这样创建和销毁底层surface时能够获得通知。
mHolder = getHolder();
mHolder.addCallback(
this
);
// 已过期的设置,但版本低于3.0的Android还需要
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public
void
surfaceChanged(SurfaceHolder arg0,
int
arg1,
int
arg2,
int
arg3)
{
}
@Override
public
void
surfaceCreated(SurfaceHolder holder)
{
try
{
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
mCamera.setDisplayOrientation(
90
);
}
catch
(IOException e) {
Log.d(
"TAG"
,
"Error is "
+e.getMessage());
}
}
@Override
public
void
surfaceDestroyed(SurfaceHolder arg0)
{
// 如果预览无法更改或旋转,注意此处的事件
// 确保在缩放或重排时停止预览
if
(mHolder.getSurface() ==
null
){
// 预览surface不存在
return
;
}
// 更改时停止预览
try
{
mCamera.stopPreview();
}
catch
(Exception e){
// 忽略:试图停止不存在的预览
}
// 在此进行缩放、旋转和重新组织格式
// 以新的设置启动预
try
{
mCamera.setPreviewDisplay(mHolder);
mCamera.setDisplayOrientation(
90
);
mCamera.startPreview();
}
catch
(Exception e){
Log.d(
"TAG"
,
"Error is "
+ e.getMessage());
}
}
}
第三步:构建预览布局。这里我们使用FrameLayout来加载第二步创建的预览类,使用一个按钮进行拍照并完成储存,使用一个ImageView显示拍照的缩略图,当我们点击这个缩略图时时,系统将会调用相应的程序来打开这个图片。
<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:orientation=
"vertical"
tools:context=
".MainActivity"
>
<frameLayout
android:id=
"@+id/PreviewView"
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"0.8"
>
</frameLayout>
<relativelayout android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_weight=
"0.2"
android:background=
"@drawable/main_bg"
>
<button android:id=
"@+id/BtnCapture"
android:layout_width=
"60dp"
android:layout_height=
"60dp"
android:layout_centerhorizontal=
"true"
android:layout_centervertical=
"true"
android:background=
"@drawable/camera"
>
<imageview android:id=
"@+id/ThumbsView"
android:layout_width=
"60dp"
android:layout_height=
"60dp"
android:layout_alignparentright=
"true"
android:layout_centervertical=
"true"
android:layout_margin=
"15dp"
android:contentdescription=
"@string/Description"
>
</imageview></button></relativelayout></linearlayout>
第四步:针对采集监听。其中PictureCallback接口用于处理拍照的结果,这里我们做三件事情,第一,保存图片;第二,显示缩略图;第三、保存当前图片的Uri,以便于系统的访问。ShutterCallback接口用于处理按下快门的事件,这里我们使用MediaPlayer类来播放快门按下时的音效。
/** 拍照回调接口 **/
private
PictureCallback mPicureCallback=
new
PictureCallback()
{
@Override
public
void
onPictureTaken(
byte
[] mData, Camera camera)
{
File mPictureFile = StorageHelper.getOutputFile(StorageHelper.MEDIA_TYPE_IMAGE);
if
(mPictureFile ==
null
){
return
;
}
try
{
/** 存储照片 **/
FileOutputStream fos =
new
FileOutputStream(mPictureFile);
fos.write(mData);
fos.close();
/** 设置缩略图 **/
Bitmap mBitmap=BitmapFactory.decodeByteArray(mData,
0
, mData.length);
ThumbsView.setImageBitmap(mBitmap);
/** 获取缩略图Uri **/
mUri=StorageHelper.getOutputUri(mPictureFile);
/**停止预览**/
mCamera.stopPreview();
/**开始预览**/
mCamera.startPreview();
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
}
};
/** 快门回调接口 **/
private
ShutterCallback mShutterCallback=
new
ShutterCallback()
{
@Override
public
void
onShutter()
{
mPlayer=
new
MediaPlayer();
mPlayer=MediaPlayer.create(MainActivity.
this
,R.raw.shutter);
try
{
mPlayer.prepare();
}
catch
(IllegalStateException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
mPlayer.start();
}
};
第五步:采集与保存。采集与保存在第四步已经给出了,这里给出一个用于保存文件的辅助类StorageHelper类:
package
com.android.OpenCamera;
import
java.io.File;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
android.annotation.SuppressLint;
import
android.net.Uri;
import
android.os.Environment;
@SuppressLint
(
"SimpleDateFormat"
)
public
final
class
StorageHelper
{
public
static
final
int
MEDIA_TYPE_IMAGE=
0
;
public
static
final
int
MEDIA_TYPE_VIDEO=
1
;
public
static
Uri getOutputUri(File mFile)
{
return
Uri.fromFile(mFile);
}
public
static
File getOutputFile(
int
mType)
{
File mMediaFileDir=
new
File(Environment.getExternalStorageDirectory(),
"OpenCamera"
);
if
(!mMediaFileDir.exists())
{
if
(!mMediaFileDir.mkdir())
{
return
null
;
}
}
File mMediaFile=
null
;
/** 创建文件名 **/
String mFileName=
new
SimpleDateFormat(
"yyyyMMddHHmmss"
).format(
new
Date());
switch
(mType)
{
case
MEDIA_TYPE_IMAGE:
mMediaFile=
new
File(mMediaFileDir.getPath()+File.separator+
"IMG_"
+mFileName+
".jpg"
);
break
;
case
MEDIA_TYPE_VIDEO:
mMediaFile=
new
File(mMediaFileDir.getPath()+File.separator+
"VID_"
+mFileName+
".mp4"
);
break
;
default
:
mMediaFile=
null
;
}
return
mMediaFile;
}
}
第六步:相机的释放
if
(mCamera !=
null
){
mCamera.release();
mCamera =
null
;
}
通过以上步骤,我们就完成了一个简单的相机,最后给出主要的逻辑代码:
package
com.android.OpenCamera;
import
java.io.File;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.hardware.Camera;
import
android.hardware.Camera.AutoFocusCallback;
import
android.hardware.Camera.PictureCallback;
import
android.hardware.Camera.ShutterCallback;
import
android.media.MediaPlayer;
import
android.net.Uri;
import
android.os.Bundle;
import
android.app.Activity;
import
android.content.Context;
import
android.content.Intent;
import
android.content.pm.PackageManager;
import
android.util.Log;
import
android.view.Menu;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.view.Window;
import
android.view.WindowManager;
import
android.widget.Button;
import
android.widget.FrameLayout;
import
android.widget.ImageView;
import
android.widget.Toast;
public
class
MainActivity
extends
Activity {
/** 相机 **/
private
Camera mCamera;
/** 预览界面 **/
private
CameraPreview mPreview;
/** 缩略图 **/
ImageView ThumbsView;
/** 当前缩略图Uri **/
private
Uri mUri;
/** MediaPlayer **/
private
MediaPlayer mPlayer;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
/** 隐藏标题栏 **/
requestWindowFeature(Window.FEATURE_NO_TITLE);
/** 隐藏状态栏 **/
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
/** 禁用锁屏,因为再次唤醒屏幕程序就会终止,暂时不知道怎么解决 **/
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
/** 硬件检查 **/
if
(CheckCameraHardware(
this
)==
false
)
{
Toast.makeText(
this
,
"很抱歉,您的设备可能不支持摄像头功能!"
, Toast.LENGTH_SHORT).show();
return
;
}
/** 获取相机 **/
mCamera=getCameraInstance();
/** 获取预览界面 **/
mPreview =
new
CameraPreview(
this
, mCamera);
FrameLayout mFrameLayout = (FrameLayout)findViewById(R.id.PreviewView);
mFrameLayout.addView(mPreview);
mCamera.startPreview();
/** 拍照按钮 **/
Button BtnCapture = (Button) findViewById(R.id.BtnCapture);
BtnCapture.setOnClickListener(
new
OnClickListener()
{
@Override
public
void
onClick(View v)
{
/** 使用takePicture()方法完成拍照 **/
mCamera.autoFocus(
new
AutoFocusCallback()
{
/** 自动聚焦聚焦后完成拍照 **/
@Override
public
void
onAutoFocus(
boolean
isSuccess, Camera camera)
{
if
(isSuccess&&camera!=
null
)
{
mCamera.takePicture(mShutterCallback,
null
, mPicureCallback);
}
}
});
}
});
/** 相机缩略图 **/
ThumbsView = (ImageView)findViewById(R.id.ThumbsView);
ThumbsView.setOnClickListener(
new
OnClickListener()
{
@Override
public
void
onClick(View v)
{
/** 使用Uri访问当前缩略图 **/
Intent intent =
new
Intent(Intent.ACTION_VIEW);
intent.setDataAndType(mUri,
"image/*"
);
startActivity(intent);
}
});
}
/** 快门回调接口 **/
private
ShutterCallback mShutterCallback=
new
ShutterCallback()
{
@Override
public
void
onShutter()
{
mPlayer=
new
MediaPlayer();
mPlayer=MediaPlayer.create(MainActivity.
this
,R.raw.shutter);
try
{
mPlayer.prepare();
}
catch
(IllegalStateException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
mPlayer.start();
}
};
/** 拍照回调接口 **/
private
PictureCallback mPicureCallback=
new
PictureCallback()
{
@Override
public
void
onPictureTaken(
byte
[] mData, Camera camera)
{
File mPictureFile = StorageHelper.getOutputFile(StorageHelper.MEDIA_TYPE_IMAGE);
if
(mPictureFile ==
null
){
return
;
}
try
{
/** 存储照片 **/
FileOutputStream fos =
new
FileOutputStream(mPictureFile);
fos.write(mData);
fos.close();
/** 设置缩略图 **/
Bitmap mBitmap=BitmapFactory.decodeByteArray(mData,
0
, mData.length);
ThumbsView.setImageBitmap(mBitmap);
/** 获取缩略图Uri **/
mUri=StorageHelper.getOutputUri(mPictureFile);
/**停止预览**/
mCamera.stopPreview();
/**开始预览**/
mCamera.startPreview();
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
}
};
/** 官方建议的安全地访问摄像头的方法 **/
public
static
Camera getCameraInstance(){
Camera c =
null
;
try
{
c = Camera.open();
}
catch
(Exception e){
Log.d(
"TAG"
,
"Error is "
+e.getMessage());
}
return
c;
}
/** 检查设备是否支持摄像头 **/
private
boolean
CheckCameraHardware(Context mContext)
{
if
(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA))
{
// 摄像头存在
return
true
;
}
else
{
// 摄像头不存在
return
false
;
}
}
@Override
protected
void
onPause() {
super
.onPause();
if
(mCamera !=
null
){
mCamera.release();
mCamera =
null
;
}
}
@Override
protected
void
onResume()
{
super
.onResume();
if
(mCamera ==
null
)
{
mCamera = getCameraInstance();
mCamera.startPreview();
}
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return
true
;
}
}
这里一直有一个困惑我的问题,就是当手机锁屏以后再次唤醒屏幕,程序会立即终止。因为找不到原因,所以目前只能用代码控制设备禁止锁屏来避免这个问题的发生。这个问题和《Android开发学习之基于ZBar实现微信扫一扫》是一样的,留给大家去思考了。记得给程序加入以下权限:
<uses-permission android:name=
"android.permission.CAMERA"
>
<uses-feature android:name=
"android.hardware.camera"
>
<uses-permission android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
></uses-permission></uses-feature></uses-permission>
晚上看到Camera360开放了SDK的消息。主推拍照和滤镜API,其实开源的滤镜有很多啦,结合我们今天的例子,我们完全可以做出一个不错的相机应用来,作为长期受益于开源社区的回报,我决定在整合滤镜以后把全部的程序开源,希望大家支持我哦。唉,明天要考试了,我竟然还能如此充满激情的编程,其实这就是编程的魅力啦,在编程的世界里,我可以完全按照自己的意愿去做自己喜欢的,而这就够了,当老师和同学们都觉得我在抱怨专业课的时候,其实我只是想让自己的内心感到快乐而已。好了,晚安,各位!
(全文转载自http://www.2cto.com/kf/201401/272099.htmlAndroid开发学习之以Camera方式实现相机功能(一)——快速实现相机)
- 【Android Camera】 之 SmoothZoom
- 【Android Camera】之 Preview
- 【Android Camera】之 Preview
- 【Android Camera】之 Preview
- Android之 Camera 框架
- android动画之Camera
- android之camera从上到下
- 【Android Camera】之 Preview
- 【Android Camera】之 Preview
- Android之Camera拍照
- Android之Camera预览
- Android之SurfaceView、Camera
- Android之Camera
- Android之Camera预览
- android 之 Camera
- android 之 Camera
- Android之Camera
- Android之Camera介绍
- Android代码内存优化建议-Android资源篇
- this关键字及内存分配
- 蓝桥杯 - 出现次数最多的整数
- Gallery重写baseadapter时getView函数中的view重用
- Mavlink 协议硬解析主要代码
- Android之Camera
- hdu 2167(状态压缩dp)
- Android布局文件中的四种单位
- MPLAB X IDE和Proteus联调方法
- 安装mysql教程(出现Install/Remove of the Service Denied)
- Jmeter-录制手机的http请求
- C++利用智能指针shared_ptr实现对象池
- 父子控制器
- 如何用AndroidStudio关联github导入项目