Taking Photos Simply

这部分关于怎么通过现有的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>

如果你的app在没有camera也可以执行主要功能时,那么上面的 android:required设置为false。这样做的话,Google Play就会允许没有camera的设备来下载你的app。那么在app中你必须检查设备是否有camera这个设备,可以通过函数hasSystemFeature(PackageManager.FEATURE_CAMERA)来检测,如果检测到没有camera,那么就不能去执行需要camera的代码块。

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

注意在调用函数startActivityForResult()前,必须检查是否有符合条件的组件。如果没有符合条件的组件,那么就不能执行startActivity函数,否则app会崩溃。

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



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值