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

来源:互联网 发布:战舰少女r重炮改数据 编辑:程序博客网 时间:2024/05/17 03:55

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

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

Intent intent = newIntent(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 = newBundle();
    extras.putParcelable("data", croppedImage);
    setResult(RESULT_OK,(newIntent()).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 = newBundle();
    setResult(RESULT_OK,newIntent(mSaveUri.toString()).putExtras(extras));
}

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

/** Called when the activity is first created. */
@Override
publicvoid 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(newOnClickListener() {
 
        publicvoid onClick(View v) {
            try{
                // Launch picker to choose photo for selected contact
                Intent intent = newIntent(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();
            }
        }
    });
 
}
 
privateUri getTempUri() {
    returnUri.fromFile(getTempFile());
}
 
privateFile getTempFile() {
    if(isSDCARDMounted()) {
 
        File f = newFile(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();
        }
        returnf;
    }else{
        returnnull;
    }
}
 
privateboolean isSDCARDMounted() {
    String status = Environment.getExternalStorageState();
 
    if(status.equals(Environment.MEDIA_MOUNTED))
        returntrue;
    returnfalse;
}
 
@Override
protectedvoid onActivityResult(intrequestCode, intresultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
 
    switch(requestCode) {
    casePHOTO_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;
            }
 
            finalBundle 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
原创粉丝点击