圖片在記憶體中的大小

來源:互聯網
上載者:User

標籤:

Android.graphics.Bitmap類裡有一個內部類Bitmap.Config類,在Bitmap類裡createBitmap(intwidth, int height, Bitmap.Config config)方法裡會用到,開啟個這個類一看


枚舉變數
public static final Bitmap.Config ALPHA_8
public static final Bitmap.Config ARGB_4444
public static final Bitmap.Config ARGB_8888
public static final Bitmap.Config RGB_565

說白了就ALPHA_8就是Alpha由8位組成
ARGB_4444就是由4個4位組成即16位,
ARGB_8888就是由4個8位組成即32位,
RGB_565就是R為5位,G為6位,B為5位共16位

由此可見:
ALPHA_8 代表8位Alpha位元影像
ARGB_4444 代表16位ARGB位元影像
ARGB_8888 代表32位ARGB位元影像
RGB_565 代表8位RGB位元影像

位元影像位元越高代表其可以儲存的顏色資訊越多,當然映像也就越逼真。

 

圖片的解析度是3776 * 2520,每一點又是由ARGB色組成,每個色素佔4個Byte,所以這張圖片載入到記憶體中需要消耗的記憶體為:
3776 * 2520 * 4byte = 38062080byte,會造成記憶體溢出,那麼如何載入大圖片呢?

如何載入大解析度圖片

有時候我們確實會需要載入一些大解析度的圖片,但是對於行動裝置而言,哪怕載入能成功那麼大的記憶體也是一種浪費(螢幕解析度限制),所以就需要想辦法把圖片按照一定比率壓縮,使解析度降低,以至於又不需要耗費很大的堆記憶體空間,又可以最大的利用裝置螢幕的解析度來顯示圖片。這裡就用到一個BitmapFactory.Options對象,下面來介紹它。
BitmapFactory.Options為BitmapFactory的一個內部類,它主要用於設定與儲存BitmapFactory載入圖片的一些資訊。下面是Options中需要用到的屬性:
inJustDecodeBounds:如果設定為true,將不把圖片的像素數組載入到記憶體中,僅載入一些額外的資料到Options中。
outHeight:圖片的高度。
outWidth:圖片的寬度。
inSampleSize:如果設定,圖片將依據此採樣率進行載入,不能設定為小於1的數。例如設定為4,解析度寬和高將為原來的1/4,這個時候整體所佔記憶體將是原來的1/16。

 

範例程式碼:



 1 import android.os.Bundle; 2 import android.os.Environment; 3 import android.app.Activity; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.BitmapFactory.Options; 7 import android.view.Menu; 8 import android.view.View; 9 import android.view.WindowManager;10 import android.widget.Button;11 import android.widget.ImageView; 12 public class MainActivity extends Activity {13     private Button btn_loadimage;14     private ImageView iv_bigimage; 15      @Override16     protected void onCreate(Bundle savedInstanceState) {17         super.onCreate(savedInstanceState);18         setContentView(R.layout.activity_main); 19          btn_loadimage = (Button) findViewById(R.id.btn_loadimage);20         iv_bigimage = (ImageView) findViewById(R.id.iv_bigimage); 21          btn_loadimage.setOnClickListener(new View.OnClickListener() { 22              @Override23             public void onClick(View v) {24                 // Bitmap bitmap=BitmapFactory.decodeFile("/sdcard/a.jpg");25                 // iv_bigimage.setImageBitmap(bitmap); 26                  BitmapFactory.Options opts = new Options();27                 // 不讀取像素數組到記憶體中,僅讀取圖片的資訊28                 opts.inJustDecodeBounds = true;29                 BitmapFactory.decodeFile("/sdcard/a.jpg", opts);30                 // 從Options中擷取圖片的解析度31                 int imageHeight = opts.outHeight;32                 int imageWidth = opts.outWidth; 33                  // 擷取Android螢幕的服務34                 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);35                 // 擷取螢幕的解析度,getHeight()、getWidth已經被廢棄掉了36                 // 應該使用getSize(),但是這裡為了向下相容所以依然使用它們37                 int windowHeight = wm.getDefaultDisplay().getHeight();38                 int windowWidth = wm.getDefaultDisplay().getWidth(); 39                  // 計算採樣率40                 int scaleX = imageWidth / windowWidth;41                 int scaleY = imageHeight / windowHeight;42                 int scale = 1;43                 // 採樣率依照最大的方向為準44                 if (scaleX > scaleY && scaleY >= 1) {45                     scale = scaleX;46                 }47                 if (scaleX < scaleY && scaleX >= 1) {48                     scale = scaleY;49                 } 50                  // false表示讀取圖片像素數組到記憶體中,依照設定的採樣率51                 opts.inJustDecodeBounds = false;52                 // 採樣率53                 opts.inSampleSize = scale;54                 Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/a.jpg", opts);55                 iv_bigimage.setImageBitmap(bitmap); 56              }57         });58     }59 }60   
 
 1 import android.os.Bundle; 2 import android.os.Environment; 3 import android.app.Activity; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.BitmapFactory.Options; 7 import android.view.Menu; 8 import android.view.View; 9 import android.view.WindowManager;10 import android.widget.Button;11 import android.widget.ImageView; 12 public class MainActivity extends Activity {13     private Button btn_loadimage;14     private ImageView iv_bigimage; 15      @Override16     protected void onCreate(Bundle savedInstanceState) {17         super.onCreate(savedInstanceState);18         setContentView(R.layout.activity_main); 19          btn_loadimage = (Button) findViewById(R.id.btn_loadimage);20         iv_bigimage = (ImageView) findViewById(R.id.iv_bigimage); 21          btn_loadimage.setOnClickListener(new View.OnClickListener() { 22              @Override23             public void onClick(View v) {24                 // Bitmap bitmap=BitmapFactory.decodeFile("/sdcard/a.jpg");25                 // iv_bigimage.setImageBitmap(bitmap); 26                  BitmapFactory.Options opts = new Options();27                 // 不讀取像素數組到記憶體中,僅讀取圖片的資訊28                 opts.inJustDecodeBounds = true;29                 BitmapFactory.decodeFile("/sdcard/a.jpg", opts);30                 // 從Options中擷取圖片的解析度31                 int imageHeight = opts.outHeight;32                 int imageWidth = opts.outWidth; 33                  // 擷取Android螢幕的服務34                 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);35                 // 擷取螢幕的解析度,getHeight()、getWidth已經被廢棄掉了36                 // 應該使用getSize(),但是這裡為了向下相容所以依然使用它們37                 int windowHeight = wm.getDefaultDisplay().getHeight();38                 int windowWidth = wm.getDefaultDisplay().getWidth(); 39                  // 計算採樣率40                 int scaleX = imageWidth / windowWidth;41                 int scaleY = imageHeight / windowHeight;42                 int scale = 1;43                 // 採樣率依照最大的方向為準44                 if (scaleX > scaleY && scaleY >= 1) {45                     scale = scaleX;46                 }47                 if (scaleX < scaleY && scaleX >= 1) {48                     scale = scaleY;49                 } 50                  // false表示讀取圖片像素數組到記憶體中,依照設定的採樣率51                 opts.inJustDecodeBounds = false;52                 // 採樣率53                 opts.inSampleSize = scale;54                 Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/a.jpg", opts);55                 iv_bigimage.setImageBitmap(bitmap); 56              }57         });58     }59 }60   

 

載入縮圖

1. 使用inJustDecodeBounds,讀bitmap的長和寬。
2. 根據bitmap的長款和目標縮圖的長和寬,計算出inSampleSize的大小。
3. 使用inSampleSize,載入一個大一點的縮圖A
4. 使用createScaseBitmap,將縮圖A,產生我們需要的縮圖B。
5. 回收縮圖A。

 需要注意的事情

 createScaseBitmap如果原圖和目標縮圖大小一致,那麼不會產生一個新的bitmap直接返回bitmap,因此,回收的時候,要判斷縮圖A是否就是縮圖B,如果說是的話,不要回收。


 1 /** 2  * http://developer.android.com/training/displaying-bitmaps/load-bitmap.html 3  */ 4 public class BitmapUtils { 5     private static int calculateInSampleSize(BitmapFactory.Options options, 6             int reqWidth, int reqHeight) { 7         final int height = options.outHeight; 8         final int width = options.outWidth; 9         int inSampleSize = 1;10         if (height > reqHeight || width > reqWidth) {11             final int halfHeight = height / 2;12             final int halfWidth = width / 2;13             while ((halfHeight / inSampleSize) > reqHeight14                     && (halfWidth / inSampleSize) > reqWidth) {15                 inSampleSize *= 2;16             }17         }18         return inSampleSize;19     }20  21     // 如果是放大圖片,filter決定是否平滑,如果是縮小圖片,filter無影響22     private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,23             int dstHeight) {24         Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);25         if (src != dst) { // 如果沒有縮放,那麼不回收26             src.recycle(); // 釋放Bitmap的native像素數組27         }28         return dst;29     }30  31     // 從Resources中載入圖片32     public static Bitmap decodeSampledBitmapFromResource(Resources res,33             int resId, int reqWidth, int reqHeight) {34         final BitmapFactory.Options options = new BitmapFactory.Options();35         options.inJustDecodeBounds = true;36         BitmapFactory.decodeResource(res, resId, options); // 讀取圖片長款37         options.inSampleSize = calculateInSampleSize(options, reqWidth,38                 reqHeight); // 計算inSampleSize39         options.inJustDecodeBounds = false;40         Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 載入一個稍大的縮圖41         return createScaleBitmap(src, reqWidth, reqHeight); // 進一步得到目標大小的縮圖42     }43  44     // 從sd卡上載入圖片45     public static Bitmap decodeSampledBitmapFromFd(String pathName,46             int reqWidth, int reqHeight) {47         final BitmapFactory.Options options = new BitmapFactory.Options();48         options.inJustDecodeBounds = true;49         BitmapFactory.decodeFile(pathName, options);50         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);51         options.inJustDecodeBounds = false;52         Bitmap src = BitmapFactory.decodeFile(pathName, options);53         return createScaleBitmap(src, reqWidth, reqHeight);54     }55 }
 
 1 /** 2  * http://developer.android.com/training/displaying-bitmaps/load-bitmap.html 3  */ 4 public class BitmapUtils { 5     private static int calculateInSampleSize(BitmapFactory.Options options, 6             int reqWidth, int reqHeight) { 7         final int height = options.outHeight; 8         final int width = options.outWidth; 9         int inSampleSize = 1;10         if (height > reqHeight || width > reqWidth) {11             final int halfHeight = height / 2;12             final int halfWidth = width / 2;13             while ((halfHeight / inSampleSize) > reqHeight14                     && (halfWidth / inSampleSize) > reqWidth) {15                 inSampleSize *= 2;16             }17         }18         return inSampleSize;19     }20  21     // 如果是放大圖片,filter決定是否平滑,如果是縮小圖片,filter無影響22     private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,23             int dstHeight) {24         Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);25         if (src != dst) { // 如果沒有縮放,那麼不回收26             src.recycle(); // 釋放Bitmap的native像素數組27         }28         return dst;29     }30  31     // 從Resources中載入圖片32     public static Bitmap decodeSampledBitmapFromResource(Resources res,33             int resId, int reqWidth, int reqHeight) {34         final BitmapFactory.Options options = new BitmapFactory.Options();35         options.inJustDecodeBounds = true;36         BitmapFactory.decodeResource(res, resId, options); // 讀取圖片長款37         options.inSampleSize = calculateInSampleSize(options, reqWidth,38                 reqHeight); // 計算inSampleSize39         options.inJustDecodeBounds = false;40         Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 載入一個稍大的縮圖41         return createScaleBitmap(src, reqWidth, reqHeight); // 進一步得到目標大小的縮圖42     }43  44     // 從sd卡上載入圖片45     public static Bitmap decodeSampledBitmapFromFd(String pathName,46             int reqWidth, int reqHeight) {47         final BitmapFactory.Options options = new BitmapFactory.Options();48         options.inJustDecodeBounds = true;49         BitmapFactory.decodeFile(pathName, options);50         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);51         options.inJustDecodeBounds = false;52         Bitmap src = BitmapFactory.decodeFile(pathName, options);53         return createScaleBitmap(src, reqWidth, reqHeight);54     }55 }

圖片在記憶體中的大小

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.