Overview

I’m writing this article to publish my brief research on the MediaStore crop functionality. Basically, if you want to write an application that leverages the existing Media Gallery and allows a user to pick (with optional face recognition) a portion of his/her image for use inside your application. There is an intent to do this, some bugs associated with it, and an overall lack of documentation on how to do it. Also, this article is based on 2.1 and tested on a Nexus One. The implementation of the Nexus One appears to be written by these guys (according to their site), seeMedia Gallery for Nexus One.

Feedback

This article is based on my research, needed for an application I wrote. If you find improvements over my suggested implementation, please let me know. I’ll update this post accordingly.

Intent Details:

First, lets discuss this Intent, and its features. After seeing some example code, I found that I could call it easily using an Intent like this:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType(“image/*”);
intent.putExtra(“crop”, “true”);

However, this is when I lacked additional documentation, what are the options, etc… So, I have put together a table, and a demo program, in an attempt to demonstrated all available options from this control. You may use my example code in your application, and expand upon it. I’ll attach it to this post.

Exta Options Table for image/* crop:

SetExtra DataType Description
crop String Signals the crop feature
aspectX int Aspect Ratio
aspectY int Aspect Ratio
outputX int width of output created from this Intent
outputY int width of output created from this Intent
scale boolean should it scale
return-data boolean Return the bitmap with Action=inline-data by using the data
data Parcelable Bitmap to process, you may provide it a bitmap (not tested)
circleCrop String if this string is not null, it will provide some circular cr
MediaStore.EXTRA_OUTPUT ("output") URI Set this URi to a File:///, see example code

Now, the biggest confusion is going to be around this MediaStore.EXTRA_OUTPUT and return-data options.

You basically have 2 ways to get the bitmap back from this Intent, you can ask for it inline or provide a Uri that it can write to.

Option #1: If you set return-data to "true", you will get back an Action = inline-data, and the bitmap returned will be inside the (Bitmap)extras.getParcelable("data"). Note: If the image ends up being to large, you will get a nasty exception with this method, so you are restricted to keeping your outputX and outputY small. In my code example attached, I did NOT use that method because of this reason.

Here is the code from CropImage.java (Android source code) where they write it inline:


// Return the cropped image directly or save it to the specified URI.
Bundle myExtras = getIntent().getExtras();
if (myExtras != null && (myExtras.getParcelable("data") != null
|| myExtras.getBoolean("return-data")))
{
Bundle extras = new Bundle();
extras.putParcelable("data", croppedImage);
setResult(RESULT_OK,(new Intent()).setAction("inline-data").putExtras(extras));
finish();

Option #2: If you set return-data to "false", you will not receive a Bitmap back from the onActivityResult Intent in-line, instead you will need to set MediaStore.EXTRA_OUTPUT to a Uri (of File scheme only) where you want the Bitmap to be stored. This has some restrictions, first you need to have a temp filesystem location in order to give the file scheme URI, not a huge problem (except on some devices that don't have sdcards).

Here is the code from CropImage.java (Android source code) where they write it to your Uri:


if (mSaveUri != null) {
OutputStream outputStream = null;
try {
outputStream = mContentResolver.openOutputStream(mSaveUri);
if (outputStream != null) {
croppedImage.compress(mOutputFormat, 75, outputStream);
}
} catch (IOException ex) {
// TODO: report error to caller
Log.e(TAG, "Cannot open file: " + mSaveUri, ex);
} finally {
Util.closeSilently(outputStream);
}
Bundle extras = new Bundle();
setResult(RESULT_OK, new Intent(mSaveUri.toString())
.putExtras(extras));
}

Example Code

I have attached some example code that should allow you to test various configurations. Let me know if you find it useful (or not).D
Download here ->MediaStoreTest

From the code (the essential parts)


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thiz = this;
setContentView(R.layout.main);
mBtn = (Button) findViewById(R.id.btnLaunch);
photo = (ImageView) findViewById(R.id.imgPhoto);

mBtn.setOnClickListener(new OnClickListener(){

public void onClick(View v) {
try {
// Launch picker to choose photo for selected contact
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
intent.putExtra("scale", scale);
intent.putExtra("return-data", return_data);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempUri());
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection",!faceDetection); // lol, negative boolean noFaceDetection
if (circleCrop) {
intent.putExtra("circleCrop", true);
}

startActivityForResult(intent, PHOTO_PICKED);
} catch (ActivityNotFoundException e) {
Toast.makeText(thiz, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
}
}
});

}

private Uri getTempUri() {
return Uri.fromFile(getTempFile());
}

private File getTempFile() {
if (isSDCARDMounted()) {

File f = new File(Environment.getExternalStorageDirectory(),TEMP_PHOTO_FILE);
try {
f.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
Toast.makeText(thiz, R.string.fileIOIssue, Toast.LENGTH_LONG).show();
}
return f;
} else {
return null;
}
}

private boolean isSDCARDMounted(){
String status = Environment.getExternalStorageState();

if (status.equals(Environment.MEDIA_MOUNTED))
return true;
return false;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

switch (requestCode) {
case PHOTO_PICKED:
if (resultCode == RESULT_OK) {
if (data == null) {
Log.w(TAG, "Null data, but RESULT_OK, from image picker!");
Toast t = Toast.makeText(this, R.string.no_photo_picked,
Toast.LENGTH_SHORT);
t.show();
return;
}

final Bundle extras = data.getExtras();
if (extras != null) {
File tempFile = getTempFile();
// new logic to get the photo from a URI
if (data.getAction() != null) {
processPhotoUpdate(tempFile);
}
}
}
break;
}
}

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. android : 圆角按钮 shape属性
  2. 软引用、弱引用和虚引用处理
  3. android 监听去电实现ip拨号 广播接收者
  4. 【Android ndk-stack tool】用ndk-stack
  5. mono for android 获取手机照片或拍照并
  6. Android 9Patch图片
  7. Android系列教程(三)
  8. eclipse ADT在线安装 https://dl-ssl.goo
  9. Android之自定义checkbox样式
  10. Android(安卓)应用程序组件学习