使用Android MediaStore裁剪大图片初次探究

这篇文章相当经典而实用,想当初我做手机拍照截图的时候,大多都是在网上抄来抄去的内容,从来没有人考虑过实际项目中的需求。实际上,拍照传大图片,如果用普通方式会耗用极大的内存,Android一个App原则上的16M内存限制可以一下子被耗光。Android在拍照上有一个隐藏的设计,如果拍照图片过大,只返回一张缩略图。具体到不同手机,都是不一样的。

  首先,让我们探讨下Intent以及它的特点。在看了一些代码示例以后,我发现我可以很轻松的使用如下的Intent调用裁剪功能:

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

然而,这是在我缺少附加的文档,不知道这些选项的具体含义等等情况之下的选择。所以,我将我的研究整理成一个表格 ,并写了一个演示程序,力图演示控制此功能的所有可供选项。 
你可以在你的程序中使用使用我的代码,并且扩展它。我会将之附加在这篇文章上。 

Exta Options Table for image/* crop:

附加选项数据类型描述
cropString发送裁剪信号
aspectXintX方向上的比例
aspectYintY方向上的比例
outputXint裁剪区的宽
outputYint裁剪区的高
scaleboolean是否保留比例
return-databoolean是否将数据保留在Bitmap中返回
dataParcelable相应的Bitmap数据
circleCropString圆形裁剪区域?
MediaStore.EXTRA_OUTPUT ("output")URI将URI指向相应的file:///...,详见代码示例
 现在,最令人困惑的是MediaStore.EXTRA_OUTPUT以及return-data选项。

 你主要有两种方式从这个Intent中取得返回的bitmap:获取内部数据或者提供一个Uri以便程序可以将数据写入。 

 方法1:如果你将return-data设置为“true”,你将会获得一个与内部数据关联的Action,并且bitmap以此方式返回:(Bitmap)extras.getParcelable("data")。注意:如果你最终要获取的图片非常大,那么此方法会给你带来麻烦,所以你要控制outputX和outputY保持在较小的尺寸。鉴于此原因,在我的代码中没有使用此方法((Bitmap)extras.getParcelable("data"))。

下面是CropImage.java的源码片段: 

// 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();
}
  方法2:   如果你将return-data设置为“false”,那么在onActivityResult的Intent数据中你将不会接收到任何Bitmap,相反,你需要将MediaStore.EXTRA_OUTPUT关联到一个Uri,此Uri是用来存放Bitmap的。 

但是还有一些条件,首先你需要有一个短暂的与此Uri相关联的文件地址,当然这不是个大问题(除非是那些没有sdcard的设备)。

下面是CropImage.java关于操作Uri的源码片段: 

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

  我已经附上了一些代码示例,应该可以让你测试多种配置。请让我知道它对你是否有用。

/** 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()); <span style= "color:#48465A;font-family:monospace;font-size:11px;line-height:normal;background-color:#EFEFEF;" >                                  // lol, negative boolean noFaceDetection</span> intent.putExtra("noFaceDetection", !faceDetection);
                 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 ;
     }


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值