创建多媒体APP 之 捕获图像:简单的拍照

这一节讲述如何利用已有的拍照应用获取一张照片。

假设你实现了大量的天气服务来绘制一张全球气象图,这个图里面的天气图片都是来自你的客户端APP拍照获取,收集图片只是很小的一部分工作,对于你的APP来说。所以在拍照获取图片方面,要尽可能的最简单化,做最少的工作,不需要完全去重新实现一个相机,绝大部分android设备都会至少有一个拍照应用。这一节里面就学习,如何利用已经存在的拍照应用获取照片。

请求拍照权限

如果你的APP要利用拍照获取图片,那么就要在GooglePlay里面限制,仅仅针对那些有相机的设备才能看到。要声明你的APP需要相机,只需要在manifest里面声明即可,利用<uses-feature>来声明:

<manifest ... >
    <uses-feature android:name="android.hardware.camera" />
    ...
</manifest ... >


如果你的APP使用了它,但是并不是说必须用camera来获取一张图片,那么在这个标签里面加入android:required="false"。这样做的的话GooglePlay允许那些没有摄像头的设备也来下载这个APP。然后你需要在运行的时候,通过hasSystemFeature(PackageManager.FEATURE_CAMERA)去检测设备的相机是可用。如果相机不可用,那么你就要隐藏你的APP的拍照特性。

利用相机APP获取照片

android利用intent来授权另外一个app来做你希望它做的事情。这个过程包括三块:intent自身的创建,调用方法来通过intent启动一个外部拍照Activity,处理拍照返回的图像数据。

下面的的方法就是利用intent来拍一张照片:

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


利用这个代码,你的APP可以让另外一个相机应用来执行你要求的拍照动作。当然,如果没有APP能够响应这个intent,你的APP会没有任何效果,拍照会失败。下面的代码可以检测是否有app能够处理这个intent.

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;
}


如果返回值true,说明至少有一个应用可以处理这个intent.

查看照片

如果你的APP不是仅仅想拍照照片那么简单,也许你会想从相机应用得到拍照获取的照片,然后对它进行一些处理。

android相机应用把照片数据放到一个intent里面,然后传递给了onActivityResult()函数,作为一个extra数据,是一个简单Bitmap,使用”data” 这个extra属性获取。下面的代码就是获取到照片,然后显示到一个ImageView.

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


注意:从data获取到的这个缩略图,很适合做为一个图标,不适合做wie其他,想要获得一个高分辨率的全图,需要更多的工作。

保存照片

android的相机应用在你可以它一个存储路径的时候,会获取到一张全幅的图像。你必须要提供一个路径,包括:存储盘,文件夹,文件名。

下面的方法是简单的一种获取存储照片路径的方法,但是仅仅针对android2.2(API 8)和之上的设备版本。

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);  


对于早期的API,你要自己提供路径名称:

storageDir = new File (
    Environment.getExternalStorageDirectory()
        + PICTURES_DIR
        + getAlbumName()
);


注意: PICTURES_DIR这个是的是Pictures/,是外部或者内部存储器上标准的用来分享照片的位置。

设置文件名称

如前面提到的,图像文件的位置是有设备环境决定的。你要做的就是要选择一种没有冲突的照片命名方案。你也许想把文件路径名字保存起来,供后面使用。下面是一种解决办法:

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;
}


添加文件名到另外一个Intent

当有了一个文件保存的位置,那么就把这个位置通话intent传递给拍照应用。

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


把照片添加到图库

当通过intent请求拍照到一张图片的时候,你应该是知道你的图片被保存到哪里,因为已经指定了路径。对于其他的应用来说,最简单的方法获取到你的照片是通过Media Provider来获取。

下面的代码就演示了如何让你的照片和系统的多媒体扫描相关联,来把你的照片添加到Media Provider的数据库。让其对android 图库类的应用可见或者是其他类似的应用。

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);
}


编码一个缩放的图像

管理多种全尺寸的照片,对于有限的内存来说是很费力的。如果你发现你的程序在显示一部分图片之后,内存溢出了,你可以减少那个已经被缩放到符合到比例的jepg展开时所用的内存堆。下面的代码展示了这个技术:

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);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值