詳細解釋如何通過Android自帶的方式來實現圖片的裁剪——原理分析+解決方案


我們很多時候需要進行圖片的裁剪,其實這個功能在android系統中已經有一套解決方案了,雖然界面和效果並不是很優秀但功能毫無疑問是完美實現了。至於,不用自帶的方案怎么做自定義,這個就是后話了。本篇主要講解的是裁剪的原理和流程,外帶分析了大圖裁剪和小圖裁剪的不同之處,同時給出具體的實現方案。

一、原理+流程

andorid提供了一個action,com.android.camera.action.CROP

Intent intent = new Intent("com.android.camera.action.CROP");

通過這個action就可以實現圖片的裁剪,具體就是實現這個intent,然后在這個intent中putExtra()中put各種參數,最后通過來啟動一個startActivityForResult(intent, requestCode);,這是裁剪圖片的activity,進行裁剪。

裁剪完后返回一個bitmap,交給開發者進行處理。

也就是說,我們是通過系統寫好的Activity進行了主要的操作,自己只需要在activity類中的onActivityResult中根據requestCode來進行判斷和處理即可。

啟動系統相冊的Activity:

    /**
     * 從相冊獲取圖片 
     */
    private void choicePicFromAlbum() {
        // 來自相冊
        Intent albumIntent = new Intent(Intent.ACTION_PICK, null);
        /**
         * 下面這句話,與其它方式寫是一樣的效果,如果:
         * intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         * intent.setType(""image/*");設置數據類型
         * 要限制上傳到服務器的圖片類型時可以直接寫如:"image/jpeg 、 image/png等的類型"
         */
        albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(albumIntent, ALBUM_OK);
    }

 

啟動系統照相的Activity:

    /**
     * 拍照后獲取圖片
     */
    private void choicePicFromCamera() {
        // 來自相機
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 下面這句指定調用相機拍照后的照片存儲的路徑,這樣通過這個uri就可以得到這個照片了
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        startActivityForResult(cameraIntent, CAMERA_OK);// CAMERA_OK是用作判斷返回結果的標識
    }

 

啟動裁剪圖片的Activity:

    /**
     * 裁剪圖片方法實現
     * @param uri
     */
    public void clipPhoto(Uri uri) {

        Intent intent = new Intent("com.android.camera.action.CROP");
        //可以選擇圖片類型,如果是*表明所有類型的圖片
        intent.setDataAndType(uri, "image/*");
        // 下面這個crop = true是設置在開啟的Intent中設置顯示的VIEW可裁剪
        intent.putExtra("crop", "true");
        // aspectX aspectY 是寬高的比例,這里設置的是正方形(長寬比為1:1)
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪圖片寬高
        intent.putExtra("outputX", 1000);
        intent.putExtra("outputY", 1000);
        //裁剪時是否保留圖片的比例,這里的比例是1:1
        intent.putExtra("scale", true);
        //是否是圓形裁剪區域,設置了也不一定有效
        //intent.putExtra("circleCrop", true);
        //設置輸出的格式
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        //是否將數據保留在Bitmap中返回
        intent.putExtra("return-data", true);

        startActivityForResult(intent, CUT_OK);
    }

 

二、主要問題

如果我們截取的圖片是大圖,那么我們首先會想着提高輸出圖片的大小

// outputX outputY 是裁剪圖片寬高
intent.putExtra("outputX", 800);
intent.putExtra("outputY", 800);

但這樣就會出現問題,由於圖片過大,占用內存過多所以系統會自行將圖片進行壓縮,以避免出現OOM的問題。下面摘錄一篇博文的部分內容來解釋這個問題:

原文:http://blog.csdn.net/floodingfire/article/details/8144604

  在Android中,Intent觸發Camera程序,拍好照片后,將會返回數據,但是考慮到內存問題,Camera不會將全尺寸的圖像返回給調用的Activity,一般情況下,有可能返回的是縮略圖,比如120*160px。

  這是為什么呢?這不是一個Bug,而是經過精心設計的,卻對開發者不透明。以我的小米手機為例,攝像頭800W像素,根據我目前設置拍出來的圖片尺寸為3200*2400px。有人說,那就返回唄,大不了耗1-2M的內存,不錯,這個尺寸的圖片確實只有1.8M左右的大小。但是你想不到的是,這個尺寸對應的Bitmap會耗光你應用程序的所有內存。Android出於安全性考慮,只會給你一個寒磣的縮略圖。

    在Android2.3中,默認的Bitmap為32位,類型是ARGB_8888,也就意味着一個像素點占用4個字節的內存。我們來做一個簡單的計算題:3200*2400*4 bytes =   30M。

    如此驚人的數字!哪怕你願意為一張生命周期超不過10s的位圖願意耗費這么巨大的內存,Android也不會答應的。

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

    這是Android Doc的原文,雖然不同手機系統的廠商可能圍繞16M這個數字有微微的上調,但是這30M,一般的手機還真揮霍不起。也只有小米這種牛機,內存堪比個人PC,本着土財主般揮金如土的霸氣才能做到。

 

得出的結論是,如果你截取的是小圖那么就返回一個bitmap,但如果是大圖那么就返回一個uri。這樣就不會出現問題啦。

 

三、從相冊中截圖

參考自:http://blog.csdn.net/floodingfire/article/details/8144615

現在原作者托管的代碼已經用了lib包作為例子了,和博客中略有差異。

原作者博文中寫了兩種方式,我個人用的不是很習慣。通過自己的測試發現博主提供的方法在手機上也沒法適用,於是貼出自己的解決方案。目前在小米2-原生4.4系統上測試通過

 具體寫法參照:

http://www.cnblogs.com/tianzhijiexian/p/3989296.html

這個文章是參照博主的寫的,在miui上測試通過:http://www.cnblogs.com/tianzhijiexian/p/3859480.html,但之后就出問題了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM