这部分关于怎么通过现有的camera app来获得图片
假如你想制作一个全球气候图,你可以弄一个app,人们通过这个app来拍摄本地目前的天气,然后上传到你的服务器中,你再将这些图片整合成一张全球气候图。将图片聚合起来比较简单。剩下就是如何通过你的app拍照,为了尽量减少麻烦,你不希望直接调用camera接口,而是想通过第三方app中的camera组件来获得图片。幸运的是,在大多数的android设备上都预先装有一个camera应用,你可以通过这个camera应用来获取图片。在这部分,你将会学到如何获取图片。
Request Camera Permission (请求相机权限)
当你的app的一个主要功能是获取图片时,必须用你的app的设备有camera这个设备,所以你必须在你的manifest中的<uses-feature>中声明你的app需要用到camera.
<manifest ...>
<user-feature android:name="android.hardware.camera" android:required="true" />
...
</manifest>
Take a Photo with the Camera App(使用系统自带的相机获取图片)
当需要使用其他app的组件时,android通过intent这个中间媒介来查找合适的组件。这个过程包括:一个Intent对象,调用相应的函数来启动对应的activity和一些处理返回到当前activity后图片数据的代码。
下面代码是通过intent来获得图片的一个函数:
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
Get the Thumbnail (获得图片的缩略图)
如果拍照仅仅是你app的一小部分功能,主要的功能还是通过这图片干点其他事,那么你可能想要从camera 中拿到图片并对它进行处理。
Android系统将图片进行编码成Bitmap保存在返回的Intent中的extras中的”data"部分,通过函数onActivityResult()返回.下面的代码演示如何获得图片并在ImageView中显示。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras.data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(imageBitmap);
}
}
注意:从“data"获得的缩略图可能仅仅适合作为图标,对于处理全尺寸的图片更麻烦。
Save the Full-size Photo (保存全尺寸图片)
当你提供一个file来保存图片时,Android中的camera应用会将全尺寸的图片保存在对应的文件中,前提是你必须提供一个有效的文件名来保存全尺寸的图片。
一般用户通过设备中的camera拍照的图片都会保存在设备的公共外部存储中,以便所有的app都能访问。可以通过函数getExternalStoragePublicDirectory()中传人参数DIRECTORY_PICTURES来得到用于共享图片的目录。因为这个函数提供的目录所有的app都可以访问,所以读写这个目录需要相应的权限:READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE。当然可以学也就是可以读了,所以当你需要读取external storage的话,你只需申请READ_EXTERANL_STORAGE这个权限就行了。
<mainfest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</mainfest>
注意:当app被卸载后,相应保存在getExteranlFilesDir()提供的目录的文件也会被删除。
一旦你定了保存文件的目录后,你需要创建一个不会与其他文件冲突的文件名。当然为了以后使用,你可以将path保存在变量中。下面函数返回一个新照片的文件名,由于使用当前时间作为文件名一部分,保证了文件名不会冲突。
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
//Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName,
".jpg",
storageDir
);
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
return image;
}
使用上面函数来为照片创建一个文件,你可以通过下面的代码构造和调用Intent:
static final int REQUEST_TAKE_PHOTO = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//Ensure that there's a camera activity to handle the intent
if(takePictureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
}catch(IOException ex) {
//error occurred while creating the file
...
}
//Continue only if the file was successfully created
if(photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
Add the Photo to a Gallery(将照片添加到相册中)
当你通过intent创建一个照片,你应该知道这个照片在哪,因为一开始你已经指定了保存图片的目录。但其他人不知道这个目录,所以为了便于其他人能访问这个图片,最简单的方法是将图片添加到系统的Media Provider中。
注意:如果你将图片保存到有getExternalFileDir()提供的目录中,那么media scanner是无法访问这个文件的,因为这个文件在你的app中是私有的。
下面例子展示了如何调用系统的media scanner将你的图片添加到Media Provider的数据库中,这样其他相册应用就可以访问这个图片。
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(mdeiaScanIntent);
}
Decode a Scaled Image (对缩放图片进行解码)
在有限的内存在管理多个全尺寸的文件有点难。当你发现你的应用仅仅展示了一些图片就用完了所有的内存时,你可以通过将JPEG文件扩展成内存阵列以适合当初的视图大小来动态的减少动态堆。下面的例子演示如何实现该技术:
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.inSmapleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}