原理分析 :Android大图片裁剪解决方案

在上文提到的方法中,实际上我们对于4.4以上的手机是避开了大图问题的,也就是对于大图(或者高清手机拍摄的照片)采用上文的方法是有问题的,特别是小米,小米就是个坑!!!选取的照片剪切时必须将剪切框选择再小再小,所以更本就不能实现对大图的裁剪,因为我们设置了

intent.putExtra("return-data",true);

也就是说返回的是bitmap图,很占用内存,所以必须考虑采用本文的方法,对裁剪的图片存uri,即:

intent.putExtra("return-data",false);

                     intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);

但是对于上述uri方法,在某些奇葩的机器上又会出现奇葩的问题,4.4以上是拿不到uri数据的,小米的又可以,LG的某款机不行。所以,笨人的方法就是采用返回数据,也就是上文采用的方法,把大图直接给忽略掉了(不喜欢小米,就忽略小米咯)。。。话说这样是不行的,于是就有了此篇文章......对于上文的方法实际也可以直接屏蔽掉返回数据,全部设置为false,返回uri这样就是本文要讲到的方法。


Android中,Intent触发Camera程序,拍好照片后,将会返回数据,但是考虑到内存问题,Camera不会将全尺寸的图像返回给调用的Activity,一般情况下,有可能返回的是缩略图,比如120*160px

这是为什么呢?这不是一个Bug,而是经过精心设计的,却对开发者不透明。

以小米手机为例,摄像头800W像素,根据我目前设置拍出来的图片尺寸为3200*2400px。有人说,那就返回呗,大不了耗1-2M的内存,不错,这个尺寸的图片确实只有1.8M左右的大小。但是你想不到的是,这个尺寸对应的Bitmap会耗光你应用程序的所有内存。Android出于安全性考虑,只会给你一个寒碜的缩略图。


Android2.3中,默认的Bitmap32位,类型是ARGB_8888,也就意味着一个像素点占用4个字节的内存。我们来做一个简单的计算题:3200*2400*4bytes = 30M

如此惊人的数字!哪怕你愿意为一张生命周期超不过10s的位图愿意耗费这么巨大的内存,Android也不会答应的。

Mobiledevices typically have constrained system resources.

Androiddevices can have as little as 16MB of memory available to asingle application.



参考博客在于解决了Android对返回图片的大小限制,并且详细解释了裁剪图片的Intent附加数据的具体含义。

具体参数:



Intent("com.android.camera.action.CROP")对应的所有可选数据都一目了然。在了解上面个个选项的含义之后,最令人困惑的是MediaStore.EXTRA_OUTPUT以及return-data选项。我们将目光着眼于三个极为重要的选项:

dataMediaStore.EXTRA_OUTPUT以及return-data

dataMediaStore.EXTRA_OUTPUT都是可选的传入数据选项,你可以选择设置dataBitmap,或者将相应的数据与URI关联起来,你也可以选择是否返回数据(return-data:true)。即,有两种方式从这个Intent中取得返回的bitmap获取内部数据或者提供一个Uri以便程序可以将数据写入


为什么还有不用返回数据的选项?如果对URI足够了解的话,应该知道URIFile相似,你所有的操作如裁剪将数据都保存在了URI中,你已经持有了相应的URI,也就无需多此一举,再返回Bitmap了。

前面已经说到,可以设置dataBitmap,但是这种操作的限制在于,你的Bitmap不能太大。因此,我们前进的思路似乎明确了:截大图用URI,小图用Bitmap。思路如下:




上面说道的两种方法:

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

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

//Return the cropped image directly or save it to the specified URI.

BundlemyExtras = getIntent().getExtras();

if (myExtras!= null &&(myExtras.getParcelable("data")!= null||myExtras.getBoolean("return-data")))

{

Bundleextras = new Bundle();

extras.putParcelable("data",croppedImage);

setResult(RESULT_OK,(new Intent()).setAction("inline-data").putExtras(extras));

finish();

}


方法2:如果你将return-data设置为“false”,那么在onActivityResultIntent数据中你将不会接收到任何Bitmap,相反,你需要将

MediaStore.EXTRA_OUTPUT关联到一个Uri,此Uri是用来存放Bitmap的。

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

下面是CropImage.java关于操作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,"Cannotopen file: "+ mSaveUri, ex);

} finally{

Util.closeSilently(outputStream);

}

Bundle extras = newBundle();

setResult(RESULT_OK,newIntent(mSaveUri.toString()).putExtras(extras));

}






参考:http://blog.csdn.net/floodingfire/article/details/8144604

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值