Device API【Camera】

2. Camera

为了能够访问照相机,你必须在你的Android Manifest内声明CAMERA权限。同时确保包括了<uses-feature>节点元素,来声明你所使用的camera功能。例如,如果你使用了照相机的自动对焦功能,你的Manifest应当包括以下内容:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

一般拍照和摄像的时候需要写到sd卡上,所以还有一向权限声明如下
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

真做摄像功能时,需要音频录制和视频录制功能,所以又需要下面两项权限声明
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

另外使用Camera API拍照或摄像,都需要用到预览,预览就要用到SurfaceView (容器),为此Activity的布局中必须有SurfaceView。使用SurfaceView的同时,我们还需要使用到SurfaceHolder,SurfaceHolder相当于一个监听器,可以监听Surface上的变化,通过其内部类CallBack来实现。

为了可以获取图片,我们需要使用Camera的takePicture方法,同时我们需要实现Camera.PictureCallBack类,实现onPictureTaken方法

开发者只需通过Intent就可以方便的打开系统自带的Camera APP,并通过 MediaStroe方便地获取照片和视频的文件路径。


使用系统相机Camera App
1)调用方式
系统相机的入口Action:MediaStore.ACTION_IMAGE_CAPTURE。只需以startActivityForResult(…)启动该Activity即可。
// 调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);

2)处理方式——在onActivityResult(…)中,处理返回信息。
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (1 == requestCode) { // 系统相机返回处理
if (resultCode == Activity.RESULT_OK) {
Bitmap cameraBitmap = (Bitmap) data.getExtras().get("data");
…… // 处理图像
}
takeBtn1.setClickable(true);
}
super.onActivityResult(requestCode, resultCode, data);
}

The camera app will start up and they will be able to take a photo. Whenever you attempt to launch an Intent outside of your own app, this is a precaution you may wish to take.

try {

    //use standard intent to capture an image
    Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    //we will handle the returned data in onActivityResult
    startActivityForResult(captureIntent, CAMERA_CAPTURE);
}
使用的是startActivityForResult,所以最好需要重载void onActivityResult(int requestCode, int resultCode, Intent data)函数,不过因为当传入文件路径的的情况下,data返回参数是null值,只要resultCode为RESULT_OK,则上述代码中/sdcard/test/img.jpg的图片文件就是最新的照片文件。
自定义相机
调用系统Camera App实现拍照和摄像功能的例子,虽然能够满足我们的需求,但是毕竟自由度降低了,而且拍照的界面就是系统的样子,现在很多拍照程序,比如火爆的Camera 360软件等,就需要根据SDK提供的Camera API来编写自己的程序。

1)照相预览

         继承SufaceView写自己的预览界面,继而放到你的照相Activity的布局里。可以写个照相监听接口,用于在Activity里处理这些照相操作。
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {

/** LOG标识 */
// private static final String TAG = "CameraPreview";

/** 分辨率 */
public static final int WIDTH = 1024;
public static final int HEIGHT = 768;

/** 监听接口 */
private OnCameraStatusListener listener;

private SurfaceHolder holder;
private Camera camera;

// 创建一个PictureCallback对象,并实现其中的onPictureTaken方法
private PictureCallback pictureCallback = new PictureCallback() {

// 该方法用于处理拍摄后的照片数据
@Override
public void onPictureTaken(byte[] data, Camera camera) {

// 停止照片拍摄
camera.stopPreview();
camera = null;

// 调用结束事件
if (null != listener) {
listener.onCameraStopped(data);
}
}
};

// Preview类的构造方法
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
// 获得SurfaceHolder对象
holder = getHolder();
// 指定用于捕捉拍照事件的SurfaceHolder.Callback对象
holder.addCallback(this);
// 设置SurfaceHolder对象的类型
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

// 在surface创建时激发
public void surfaceCreated(SurfaceHolder holder) {
// Log.e(TAG, "==surfaceCreated==");
// 获得Camera对象
camera = Camera.open();
try {
// 设置用于显示拍照摄像的SurfaceHolder对象
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
// 释放手机摄像头
camera.release();
camera = null;
}
}

// 在surface销毁时激发
public void surfaceDestroyed(SurfaceHolder holder) {
// Log.e(TAG, "==surfaceDestroyed==");
// 释放手机摄像头
camera.release();
}

// 在surface的大小发生改变时激发
public void surfaceChanged(final SurfaceHolder holder, int format, int w,
int h) {
// Log.e(TAG, "==surfaceChanged==");
try {
// 获取照相机参数
Camera.Parameters parameters = camera.getParameters();
// 设置照片格式
parameters.setPictureFormat(PixelFormat.JPEG);
// 设置预浏尺寸
parameters.setPreviewSize(WIDTH, HEIGHT);
// 设置照片分辨率
parameters.setPictureSize(WIDTH, HEIGHT);
// 设置照相机参数
camera.setParameters(parameters);
// 开始拍照
camera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}

// 停止拍照,并将拍摄的照片传入PictureCallback接口的onPictureTaken方法
public void takePicture() {
// Log.e(TAG, "==takePicture==");
if (camera != null) {
// 自动对焦
camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (null != listener) {
listener.onAutoFocus(success);
}
// 自动对焦成功后才拍摄
if (success) {
camera.takePicture(null, null, pictureCallback);
}
}
});
}
}

// 设置监听事件
public void setOnCameraStatusListener(OnCameraStatusListener listener) {
this.listener = listener;
}

/**
* 相机拍照监听接口
*/
public interface OnCameraStatusListener {

// 相机拍照结束事件
void onCameraStopped(byte[] data);

// 拍摄时自动对焦事件
void onAutoFocus(boolean success);
}

}

2)照相活动

         就是我们自己做的照相Activity了。完成后调用自己的相机,也就是跳转入这个Activity。而获得照片后,可以直接处理或者存入媒体库。
public class CameraActivity extends Activity implements 
        CameraPreview.OnCameraStatusListener { 

    public static final Uri IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 
    public static final String PATH = Environment.getExternalStorageDirectory() 
            .toString() + "/AndroidMedia/"; 

    private CameraPreview mCameraPreview; 
    private ImageView focusView; 
    private boolean isTaking = false; // 拍照中 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        // 设置横屏 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 
        // 设置全屏 
        requestWindowFeature(Window.FEATURE_NO_TITLE); 
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                WindowManager.LayoutParams.FLAG_FULLSCREEN); 
        // 设置布局视图 
        setContentView(R.layout.camera); 
        // 照相预览界面 
        mCameraPreview = (CameraPreview) findViewById(R.id.preview); 
        mCameraPreview.setOnCameraStatusListener(this); 
        // 焦点图片 
        focusView = (ImageView) findViewById(R.id.focusView); 
    } 

    /** 
     * 触屏事件 
     */ 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        if (event.getAction() == MotionEvent.ACTION_DOWN && !isTaking) { 
            isTaking = true; 
            mCameraPreview.takePicture(); 
        } 
        return super.onTouchEvent(event); 
    } 

    /** 
     * 存储图像并将信息添加入媒体数据库 
     */ 
    private Uri insertImage(ContentResolver cr, String name, long dateTaken, 
            String directory, String filename, Bitmap source, byte[] jpegData) { 

        OutputStream outputStream = null; 
        String filePath = directory + filename; 
        try { 
            File dir = new File(directory); 
            if (!dir.exists()) { 
                dir.mkdirs(); 
            } 
            File file = new File(directory, filename); 
            if (file.createNewFile()) { 
                outputStream = new FileOutputStream(file); 
                if (source != null) { 
                    source.compress(CompressFormat.JPEG, 75, outputStream); 
                } else { 
                    outputStream.write(jpegData); 
                } 
            } 
        } catch (FileNotFoundException e) { 
            e.printStackTrace(); 
            return null; 
        } catch (IOException e) { 
            e.printStackTrace(); 
            return null; 
        } finally { 
            if (outputStream != null) { 
                try { 
                    outputStream.close(); 
                } catch (Throwable t) { 
                } 
            } 
        } 
        ContentValues values = new ContentValues(7); 
        values.put(MediaStore.Images.Media.TITLE, name); 
        values.put(MediaStore.Images.Media.DISPLAY_NAME, filename); 
        values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken); 
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); 
        values.put(MediaStore.Images.Media.DATA, filePath); 
        return cr.insert(IMAGE_URI, values); 
    } 

    /** 
     * 相机拍照结束事件 
     */ 
    @Override 
    public void onCameraStopped(byte[] data) { 
        Log.e("onCameraStopped", "==onCameraStopped=="); 
        // 创建图像 
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 
        // 系统时间 
        long dateTaken = System.currentTimeMillis(); 
        // 图像名称 
        String filename = DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken) 
                .toString() + ".jpg"; 
        // 存储图像(PATH目录) 
        Uri uri = insertImage(getContentResolver(), filename, dateTaken, PATH, 
                filename, bitmap, data); 
        // 返回结果 
        Intent intent = getIntent(); 
        intent.putExtra("uriStr", uri.toString()); 
        intent.putExtra("dateTaken", dateTaken); 
        // intent.putExtra("filePath", PATH + filename); 
        // intent.putExtra("orientation", orientation); // 拍摄方向 
        setResult(20, intent); 
        // 关闭当前Activity 
        finish(); 
    } 

    /** 
     * 拍摄时自动对焦事件 
     */ 
    @Override 
    public void onAutoFocus(boolean success) { 
        // 改变对焦状态图像 
        if (success) { 
            focusView.setImageResource(R.drawable.focus2); 
        } else { 
            focusView.setImageResource(R.drawable.focus1); 
            Toast.makeText(this, "焦距不准,请重拍!", Toast.LENGTH_SHORT).show(); 
            isTaking = false; 
        } 
    } 

}

3)照相调用

         以startActivityForResult(…)方式跳转入照相Activity,在拍完照片后setResult(…)返回。建议存入媒体库,将照片的uri返回。直接data数据的话,多拍时,是承受不了的==。
// 调用自定义相机 
Intent intent = new Intent(this, CameraActivity.class); 
startActivityForResult(intent, 2); 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (2 == requestCode) { // 自定义相机返回处理 
        // 拍照成功后,响应码是20 
        if (resultCode == 20) { 
            Bundle bundle = data.getExtras(); 
            // 获得照片uri 
            Uri uri = Uri.parse(bundle.getString("uriStr")); 
            // 获得拍照时间 
            long dateTaken = bundle.getLong("dateTaken"); 
            try { 
                // 从媒体数据库获取该照片 
                Bitmap cameraBitmap = MediaStore.Images.Media.getBitmap( 
                        getContentResolver(), uri); 
                previewBitmap(cameraBitmap); // 预览图像 
                // 从媒体数据库删除该照片(按拍照时间) 
                getContentResolver().delete( 
                        CameraActivity.IMAGE_URI, 
                        MediaStore.Images.Media.DATE_TAKEN + "=" 
                                + String.valueOf(dateTaken), null); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
        } 
        takeBtn2.setClickable(true); 
    } 
    super.onActivityResult(requestCode, resultCode, data); 
}

4)照相处理

         在onActivityResult(…)中,处理返回信息。

如加蒙版效果

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

生活在西班牙

自己动手丰衣足食

BlueAsteroid

Just another WordPress.com site

Jing's Blog

Just another WordPress.com site

Start from here......

我的心情魔方

天才遠私廚

希望能做一個分享各種資訊的好地方

语义噪声

西瓜大丸子汤的博客

笑对人生,傲立寰宇

Just another WordPress.com site

Where On Earth Is Waldo?

A Project By Melanie Coles

the Serious Computer Vision Blog

A blog about computer vision and serious stuff

Cauthy's Blog

paper review...

Cornell Computer Vision Seminar Blog

Blog for CS 7670 - Special Topics in Computer Vision

datarazzi

Life through nerd-colored glasses

Luciana Haill

Brainwaves Augmenting Consciousness

槑烎

1,2,∞

Dr Paul Tennent

and the university of nottingham

turn off the lights, please

A bunch of random, thinned and stateless thoughts around the Web

%d bloggers like this: