日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

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

發(fā)布時(shí)間:2024/4/17 Android 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android大图片裁剪终极解决方案 原理分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

約幾個(gè)月前,我正為公司的APP在Android手機(jī)上實(shí)現(xiàn)拍照截圖而煩惱不已。

上網(wǎng)搜索,確實(shí)有不少的例子,大多都是抄來(lái)抄去,而且水平多半處于demo的樣子,可以用來(lái)講解知識(shí)點(diǎn),但是一碰到實(shí)際項(xiàng)目,就漏洞百出。

當(dāng)時(shí)我用大眾化的解決方案,暫時(shí)性的做了一個(gè)拍照截圖的功能,似乎看起來(lái)很不錯(cuò)。問(wèn)題隨之而來(lái),我用的是小米手機(jī),在別的手機(jī)上都運(yùn)行正常,小米這里卻總是碰釘子。雖然我是個(gè)理性的米粉,但是也暗地里把小米的工程師問(wèn)候了個(gè)遍。真是慚愧!

翻文檔也找不出個(gè)答案來(lái),我一直對(duì)com.android.camera.action.CROP持有大大的疑問(wèn),它是從哪里來(lái),它能干什么,它接收處理什么類型的數(shù)據(jù)?Google對(duì)此卻諱莫如深,在官方文檔中只有Intent中有只言片語(yǔ)言及,卻不甚詳盡。

隨著項(xiàng)目的驅(qū)動(dòng),我不能抱著不了解原理就不往前走的心態(tài),唯一要做的,是解決問(wèn)題。最后在德問(wèn)上找到一條解決方案,說(shuō)是哪怕是大米也沒(méi)問(wèn)題。當(dāng)時(shí)樂(lè)呵呵將代碼改了改,確實(shí)在所有的手機(jī)上跑起來(lái)了,一時(shí)如釋重負(fù),對(duì)這個(gè)的疑問(wèn)也拋諸腦后了。

直到月前,BOSS要求將拍照上傳到服務(wù)器的圖片分辨率加倍。OK,加倍簡(jiǎn)單,增加outputX以及outputY不就得了?

intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);

這一增加,嚇了我一跳。BOSS的手機(jī)拍到的照片幾乎就是個(gè)縮略圖,但是被我問(wèn)候了全體工程師的小米在這個(gè)時(shí)候就體現(xiàn)出國(guó)產(chǎn)神機(jī)的范兒了,小米上的尺寸一切正常。這個(gè)為什么呢?我大致了解原因,卻不知道如何解決。

在Android中,Intent觸發(fā)Camera程序,拍好照片后,將會(huì)返回?cái)?shù)據(jù),但是考慮到內(nèi)存問(wèn)題,Camera不會(huì)將全尺寸的圖像返回給調(diào)用的Activity,一般情況下,有可能返回的是縮略圖,比如120*160px。

這是為什么呢?這不是一個(gè)Bug,而是經(jīng)過(guò)精心設(shè)計(jì)的,卻對(duì)開發(fā)者不透明。

以我的小米手機(jī)為例,攝像頭800W像素,根據(jù)我目前設(shè)置拍出來(lái)的圖片尺寸為3200*2400px。有人說(shuō),那就返回唄,大不了耗1-2M的內(nèi)存,不錯(cuò),這個(gè)尺寸的圖片確實(shí)只有1.8M左右的大小。但是你想不到的是,這個(gè)尺寸對(duì)應(yīng)的Bitmap會(huì)耗光你應(yīng)用程序的所有內(nèi)存。Android出于安全性考慮,只會(huì)給你一個(gè)寒磣的縮略圖。

在Android2.3中,默認(rèn)的Bitmap為32位,類型是ARGB_8888,也就意味著一個(gè)像素點(diǎn)占用4個(gè)字節(jié)的內(nèi)存。我們來(lái)做一個(gè)簡(jiǎn)單的計(jì)算題:3200*2400*4 bytes = 30M。

如此驚人的數(shù)字!哪怕你愿意為一張生命周期超不過(guò)10s的位圖愿意耗費(fèi)這么巨大的內(nèi)存,Android也不會(huì)答應(yīng)的。

Mobile devices typically have constrained system resources.
Android devices can have as little as 16MB of memory available to a single application.

?這是Android Doc的原文,雖然不同手機(jī)系統(tǒng)的廠商可能圍繞16M這個(gè)數(shù)字有微微的上調(diào),但是這30M,一般的手機(jī)還真揮霍不起。也只有小米這種牛機(jī),內(nèi)存堪比個(gè)人PC,本著土財(cái)主般揮金如土的霸氣才能做到。

OK,說(shuō)了這么多,無(wú)非是吐吐苦水,爆爆個(gè)人經(jīng)歷而已,實(shí)際的解決方案在哪里呢?

我也是Google到的,話說(shuō)一般百度不了的問(wèn)題,那就Google或者直接StackOverFlow,只不過(guò)得看英文罷了。

最后翻來(lái)覆去,我在國(guó)外的一個(gè)Android團(tuán)隊(duì)的博客中找到了相應(yīng)的方案,印證了我的猜想同時(shí)也給出了實(shí)際的代碼。

我將這篇文章翻譯成了中文,作為本博客的基礎(chǔ),建議詳細(xì)看看。

【譯】如何使用Android MediaStore裁剪大圖片?http://www.linuxidc.com/Linux/2012-11/73939.htm

這篇網(wǎng)址了不起的地方在于解決了Android對(duì)返回圖片的大小限制,并且詳細(xì)解釋了裁剪圖片的Intent附加數(shù)據(jù)的具體含義。OK,我只是站在巨人的肩膀上,改善方案,適應(yīng)更廣泛需求而已。

拿圖說(shuō)事兒:

Intent("com.android.camera.action.CROP")對(duì)應(yīng)的所有可選數(shù)據(jù)都一目了然。在了解上面?zhèn)€個(gè)選項(xiàng)的含義之后,我們將目光著眼于三個(gè)極為重要的選項(xiàng):

data、MediaStore.EXTRA_OUTPUT以及return-data。

data和MediaStore.EXTRA_OUTPUT都是可選的傳入數(shù)據(jù)選項(xiàng),你可以選擇設(shè)置data為Bitmap,或者將相應(yīng)的數(shù)據(jù)與URI關(guān)聯(lián)起來(lái),你也可以選擇是否返回?cái)?shù)據(jù)(return-data: true)。

為什么還有不用返回?cái)?shù)據(jù)的選項(xiàng)?如果對(duì)URI足夠了解的話,應(yīng)該知道URI與File相似,你所有的操作如裁剪將數(shù)據(jù)都保存在了URI中,你已經(jīng)持有了相應(yīng)的URI,也就無(wú)需多此一舉,再返回Bitmap了。

前面已經(jīng)說(shuō)到,可以設(shè)置data為Bitmap,但是這種操作的限制在于,你的Bitmap不能太大。因此,我們前進(jìn)的思路似乎明確了:截大圖用URI,小圖用Bitmap。

我將這個(gè)思路整理成一張圖片:

這篇主要讓大家了解需求的來(lái)源,以及如何去思考分析并解決問(wèn)題。下一篇將介紹具體的操作。

?

在這篇文章中,我將向大家展示如何從相冊(cè)截圖。

上一篇文章中,我就拍照截圖這一需求進(jìn)行了詳細(xì)的分析,試圖讓大家了解Android本身的限制,以及我們應(yīng)當(dāng)采取的實(shí)現(xiàn)方案。

根據(jù)我們的分析與總結(jié),圖片的來(lái)源有拍照和相冊(cè),而可采取的操作有

? 使用Bitmap并返回?cái)?shù)據(jù)

? 使用Uri不返回?cái)?shù)據(jù)

前面我們了解到,使用Bitmap有可能會(huì)導(dǎo)致圖片過(guò)大,而不能返回實(shí)際大小的圖片,我將采用大圖Uri,小圖Bitmap的數(shù)據(jù)存儲(chǔ)方式。

我們將要使用到URI來(lái)保存拍照后的圖片:

private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";//temp file
Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap

不難知道,我們從相冊(cè)選取圖片的Action為Intent.ACTION_GET_CONTENT。

根據(jù)我們上一篇文章的分析,我準(zhǔn)備好了兩個(gè)實(shí)例的Intent。

一、從相冊(cè)截大圖:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 2);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 600);
intent.putExtra("outputY", 300);
intent.putExtra("scale", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, CHOOSE_BIG_PICTURE);

二、從相冊(cè)截小圖

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 2);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 100);
intent.putExtra("scale", true);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, CHOOSE_SMALL_PICTURE);

三、對(duì)應(yīng)的onActivityResult可以這樣處理返回的數(shù)據(jù)

switch (requestCode) {
case CHOOSE_BIG_PICTURE:
?Log.d(TAG, "CHOOSE_BIG_PICTURE: data = " + data);//it seems to be null
?if(imageUri != null){
? Bitmap bitmap = decodeUriAsBitmap(imageUri);//decode bitmap
? imageView.setImageBitmap(bitmap);
?}
?break;
case CHOOSE_SMALL_PICTURE:
?if(data != null){
? Bitmap bitmap = data.getParcelableExtra("data");
? imageView.setImageBitmap(bitmap);
?}else{
? Log.e(TAG, "CHOOSE_SMALL_PICTURE: data = " + data);
?}
?break;
default:
?break;
}

?

private Bitmap decodeUriAsBitmap(Uri uri){
?Bitmap bitmap = null;
?try {
? bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
?} catch (FileNotFoundException e) {
? e.printStackTrace();
? return null;
?}
?return bitmap;
}

效果圖:

大圖

小圖

?

上一篇博客中,我們學(xué)習(xí)到了如何使用Android相冊(cè)截圖。在這篇博客中,我將向大家展示如何拍照截圖。

拍照截圖有點(diǎn)兒特殊,要知道,現(xiàn)在的Android智能手機(jī)的攝像頭都是幾百萬(wàn)的像素,拍出來(lái)的圖片都是非常大的。因此,我們不能像對(duì)待相冊(cè)截圖一樣使用Bitmap小圖,無(wú)論大圖小圖都統(tǒng)一使用Uri進(jìn)行操作。

一、首先準(zhǔn)備好需要使用到的Uri:

private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";//temp file
Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);//The Uri to store the big bitmap

二、使用MediaStore.ACTION_IMAGE_CAPTURE可以輕松調(diào)用Camera程序進(jìn)行拍照:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//action is capture
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_BIG_PICTURE);//or TAKE_SMALL_PICTURE

三、接下來(lái)就可以在 onActivityResult中拿到返回的數(shù)據(jù)(Uri),并將Uri傳遞給截圖的程序。

switch (requestCode) {
case TAKE_BIG_PICTURE:
?Log.d(TAG, "TAKE_BIG_PICTURE: data = " + data);//it seems to be null
?//TODO sent to crop
?cropImageUri(imageUri, 800, 400, CROP_BIG_PICTURE);
?
?break;
case TAKE_SMALL_PICTURE:
?Log.i(TAG, "TAKE_SMALL_PICTURE: data = " + data);
?//TODO sent to crop?
?cropImageUri(imageUri, 300, 150, CROP_SMALL_PICTURE);
?
?break;
default:
?break;
}

可以看到,無(wú)論是拍大圖片還是小圖片,都是使用的Uri,只是尺寸不同而已。我們將這個(gè)操作封裝在一個(gè)方法里面。

private void cropImageUri(Uri uri, int outputX, int outputY, int requestCode){
?Intent intent = new Intent("com.android.camera.action.CROP");
?intent.setDataAndType(uri, "image/*");
?intent.putExtra("crop", "true");
?intent.putExtra("aspectX", 2);
?intent.putExtra("aspectY", 1);
?intent.putExtra("outputX", outputX);
?intent.putExtra("outputY", outputY);
?intent.putExtra("scale", true);
?intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
?intent.putExtra("return-data", false);
?intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
?intent.putExtra("noFaceDetection", true); // no face detection
?startActivityForResult(intent, requestCode);
}

四、最后一步,我們已經(jīng)將數(shù)據(jù)傳入裁剪圖片程序,接下來(lái)要做的就是處理返回的數(shù)據(jù)了:

switch (requestCode) {
case CROP_BIG_PICTURE://from crop_big_picture
?Log.d(TAG, "CROP_BIG_PICTURE: data = " + data);//it seems to be null
?if(imageUri != null){
? Bitmap bitmap = decodeUriAsBitmap(imageUri);
? imageView.setImageBitmap(bitmap);
?}
?break;
case CROP_SMALL_PICTURE:
?if(imageUri != null){
? Bitmap bitmap = decodeUriAsBitmap(imageUri);
? imageView.setImageBitmap(bitmap);
?}else{
? Log.e(TAG, "CROP_SMALL_PICTURE: data = " + data);
?}
?break;
default:
?break;
}

效果圖:

源碼下載:

免費(fèi)下載地址在?http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2012年資料/11月/11日/Android大圖片裁剪終極解決方案

總結(jié)

以上是生活随笔為你收集整理的Android大图片裁剪终极解决方案 原理分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。