胡凯

Android Training - 捕获照片(Lesson 1 - 简单的拍照动作)

| Comments

在多媒体流行之前,世界是沉闷(dismal)并且特色稀少(featureless)的。还记得Gopher? (Gopher是计算机上的一个工具软件,是Internet提供的一种由菜单式驱动的信息查询工具,采用客户机/服务器模式)。因为你的app将要成为你的用户的生活的一部分,请赋予你的app能够把用户生活装进去的功能。使用内置的Camera,你的程序可以使得用户扩展(augment)他们所看的事物,生成唯一的头像,查找角落的人偶(zombies),或者仅仅是分享他们的经验。

这一章节,会教你如何简单的使用已经存在的Camera程序。在后面的课程中,你会更加深入的( dive deeper )学习如何直接控制Camera的硬件。

试试下面的例子程序 PhotoIntentActivity.zip


假设你想通过你的客户端程序实现一个聚合全球天气的地图,上面会有各地的当前天气图片。那么集合图片只是你程序的一部分。你想要最简单的动作来获取图片,而不是重新发明(reinvent)一个camera。幸运的是,大多数Android设备都已经至少安装了一款相机程序。在这节课中,你会学习,如何拍照。

Request Camera Permission(请求使用相机权限)

在写程序之前,需要在你的程序的manifest文件中添加下面的权限:

1
2
3
4
 <manifest ... >
    <uses-feature android:name="android.hardware.camera" />
    ...
</manifest ... >

如果你的程序并不需要一定有Camera,可以添加android:required=”false” 的tag属性。这样的话,Google Play 也会允许没有camera的设备下载这个程序。当然你有必要在使用Camera之前通过hasSystemFeature(PackageManager.FEATURE_CAMERA)方法来检查设备上是否有Camera。如果没有,你应该关闭你的Camera相关的功能!(这个几乎没有人去做检查,因为目前所有的智能手机都会有相机)

Take a Photo with the Camera App(使用相机应用程序进行拍照]

Android中的方法是:启动一个Intent来完成你想要的动作。这个步骤包含三部分: Intent 本身,启动的外部 Activity, 与一些处理返回照片的代码。如:

1
2
3
4
private void dispatchTakePictureIntent(int actionCode) {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(takePictureIntent, actionCode);
}

当然在发出Intent之前,你需要检查是否有app会来handle这个intent,否则会引起启动失败:

1
2
3
4
5
6
7
public static boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list =
            packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}

View the Photo(查看照片)

Android的Camera程序会把拍好的照片编码为bitmap,使用extra value的方式添加到返回的 Intent 当中, 对应的key为data。

1
2
3
4
5
private void handleSmallCameraPhoto(Intent intent) {
    Bundle extras = intent.getExtras();
    mImageBitmap = (Bitmap) extras.get("data");
    mImageView.setImageBitmap(mImageBitmap);
}

Note: 这仅仅是处理一张很少的缩略图而已,如果是大的全图,需要做更多的事情来避免ANR。

Save the Photo(保存照片)

如果你提供一个file对象给Android的Camera程序,它会保存这张全图到给定的路径下。你必须提供存储的卷名,文件夹名与文件名。对于2.2以上的系统,如下操作即可:

1
2
3
4
5
6
storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ),
    getAlbumName()
);

Set the file name(设置文件名)

正如上面描述的那样,文件的路径会有设备的系统环境决定。你自己需要做的只是定义个不会引起文件名冲突的命名scheme。下面会演示一种解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp =
        new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
    File image = File.createTempFile(
        imageFileName,
        JPEG_FILE_SUFFIX,
        getAlbumDir()
    );
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

Append the file name onto the Intent(把文件名添加到网络上)

Once you have a place to save your image, pass that location to the camera application via the Intent.

1
2
File f = createImageFile();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));

Add the Photo to a Gallery(添加照片到相册)

对于大多数人来说,最简单查看你的照片的方式是通过系统的Media Provider。下面会演示如何触发系统的Media Scanner来添加你的照片到Media Provider的DB中,这样使得相册程序与其他程序能够读取到那些图片。

1
2
3
4
5
6
7
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

Decode a Scaled Image(解码缩放图片)

在有限的内存下,管理全尺寸的图片会很麻烦。下面会介绍如何缩放图片来适应程序的显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void setPic() {
    // Get the dimensions of the View
    int targetW = mImageView.getWidth();
    int targetH = mImageView.getHeight();

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    mImageView.setImageBitmap(bitmap);
}

学习自:http://developer.android.com/training/camera/photobasics.html,请多指教,谢谢!
转载请注明出自http://kesenhoo.github.com,谢谢配合!

Comments