Android從SD卡加載大圖裁剪爲指定大小

工作時候可能會遇到向服務器上傳頭像,或者從SD卡加載圖片到GrideView控件上,又或者是SD卡上的大圖顯示在listview上,而這時候如果圖片是高清大圖的話,加載不了幾張圖片,安卓就會報錯,出現OOM異常,這篇文章主要介紹如何把大圖變成小圖,變成指定分辨率的圖,且儘量保持不失真。
先來看一段很簡單的代碼:

public class MainActivity extends ActionBarActivity {
    private ImageView iv_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //ImageView的控件
        iv_main=(ImageView) findViewById(R.id.iv_main);
        //test.jpg在SD卡的路徑
        String path=Environment.getExternalStorageDirectory()+"/test.jpg";
        Bitmap bitmap=BitmapFactory.decodeFile(path);
        Log.e("test", bitmap.getByteCount()+"");

        iv_main.setImageBitmap(bitmap);

    }


}

這是模擬器讀出來的圖片:
這裏寫圖片描述
我們的test.jpg在windows下查看屬性是2.73MB的jpg圖片,把test.jpg導入到SD卡,轉換爲bitmap對象,然而Log日誌打印出來的bitmap所佔的字節數居然是38340864字節,換算之後是36.5MB,顯然把bitmap讀到內存裏,這張圖佔用了更多的字節!!!
那麼我們用如下代碼來處理:

public class MainActivity extends ActionBarActivity {
    private ImageView iv_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //ImageView的控件
        iv_main=(ImageView) findViewById(R.id.iv_main);
        //test.jpg在SD卡的路徑
        String path=Environment.getExternalStorageDirectory()+"/test.jpg";
        Bitmap bitmap=getSmallBitmap(path);
        Log.e("test", bitmap.getByteCount()+"");
        iv_main.setImageBitmap(bitmap);

    }

public Bitmap getSmallBitmap(String path){
    //new 出來一個bitmap的參數
    BitmapFactory.Options options=new BitmapFactory.Options();
    //設置爲true,不會生成bitmao對象,只是讀取尺寸和類型信息
    options.inJustDecodeBounds=true;
    BitmapFactory.decodeFile(path, options);
    //得到這個比例   並賦予option裏面的inSampleSize
    options.inSampleSize = calculateInSampleSize(options, 320, 480);
    //設置爲false,即將要生成bitmap對象啦
    options.inJustDecodeBounds = false;
    //有了這個option,我們可以生成bitmap對象了
    Bitmap bitmap=BitmapFactory.decodeFile(path, options);

    return bitmap;

}
public int calculateInSampleSize(BitmapFactory.Options options,int reqHeight,int reqWidth){
    //得到原始圖片寬高 
    int height=options.outHeight;
    int width=options.outWidth;
    //默認設置爲1,即不縮放
    int inSampleSize=1;
     //如果圖片原始的高大於我們期望的高,或者圖片的原始寬大於我們期望的寬,換句話意思就是,我們想讓它變小一點
    if (height > reqHeight || width > reqWidth) {
             //原始的高除以期望的高,得到一個比例
             final int heightRatio = Math.round((float) height/ (float) reqHeight);
             //原始的寬除以期望的寬,得到一個比例
             final int widthRatio = Math.round((float) width / (float) reqWidth);
             //取上面兩個比例中小的一個,返回這個比例
             inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
        return inSampleSize;

}
}

把高設置爲320,寬爲480,這是模擬器的截圖:
這裏寫圖片描述

可以看到,模擬器中imageview兩次顯示的圖片都基本一樣,Log打印出來的字節數是2398368,相當於2MB,這比之前的佔用36MB小了很多,我們再把這個bitmap對象壓縮一下,然後寫到sd卡上,命名爲test1.jpg,把這張圖導出到桌面,查看屬性,
修改getSmallBitmap方法如下:

public Bitmap getSmallBitmap(String path){
    //new 出來一個bitmap的參數
    BitmapFactory.Options options=new BitmapFactory.Options();
    //設置爲true,不會生成bitmao對象,只是讀取尺寸和類型信息
    options.inJustDecodeBounds=true;
    BitmapFactory.decodeFile(path, options);
    //得到這個比例   並賦予option裏面的inSampleSize
    options.inSampleSize = calculateInSampleSize(options, 320, 480);
    //設置爲false,即將要生成bitmap對象啦
    options.inJustDecodeBounds = false;
    //有了這個option,我們可以生成bitmap對象了
    Bitmap bitmap=BitmapFactory.decodeFile(path, options);

    try {
        FileOutputStream fos=new FileOutputStream(new File(Environment.getExternalStorageDirectory()+"/test1.jpg"));
        //把bitmap壓縮 一下,放在bos這個對象裏,這個40如果是100,代表無損壓縮,現在損失了60%,進行壓縮
        bitmap.compress(Bitmap.CompressFormat.JPEG, 40, fos);
        fos.close();
    }catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }



    return bitmap;

}

這是壓縮後test.jpg的屬性,大小爲37KB,看起來並沒有失真
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章