Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android處理大圖片

Android處理大圖片

編輯:關於Android編程

項目中經常碰到需要處理大圖片的問題,因為android對應用分配資源的限制,如果不進行相應的處理,容易造成OOM。

Android處理大圖的方法:

對於大圖先獲取出圖片的width和height, 然後根據view的width和height, 換算出圖片inSampleSize,,最後壓縮生成相應的圖片。

其中重要的兩個參數是:

/**
111         * If set to true, the decoder will return null (no bitmap), but
112         * the out... fields will still be set, allowing the caller to query
113         * the bitmap without having to allocate the memory for its pixels.
114         */
115        public boolean inJustDecodeBounds;
116
117        /**
118         * If set to a value > 1, requests the decoder to subsample the original
119         * image, returning a smaller image to save memory. The sample size is
120         * the number of pixels in either dimension that correspond to a single
121         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
122         * an image that is 1/4 the width/height of the original, and 1/16 the
123         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
124         * decoder uses a final value based on powers of 2, any other value will
125         * be rounded down to the nearest power of 2.
126         */
127        public int inSampleSize;

InJustDecodeBounds能在不分配資源給圖片的情況下獲取圖片的大小


inSampleSize計算圖片的壓縮比


開源項目xutils, Universal-Image-Loader和Foursquare對於大圖的處理都類似的


下面是Foursquare處理大圖的代碼:

public class ImageUtils {
    
    private ImageUtils() {
    }

    public static void resampleImageAndSaveToNewLocation(String pathInput, String pathOutput) 
        throws Exception 
    {
        Bitmap bmp = resampleImage(pathInput, 640);
        
        OutputStream out = new FileOutputStream(pathOutput);
        bmp.compress(Bitmap.CompressFormat.JPEG, 90, out); 
    }
    
    public static Bitmap resampleImage(String path, int maxDim) 
        throws Exception {
        
        BitmapFactory.Options bfo = new BitmapFactory.Options(); 
        bfo.inJustDecodeBounds = true; 
        BitmapFactory.decodeFile(path, bfo); 
    
        BitmapFactory.Options optsDownSample = new BitmapFactory.Options();
        optsDownSample.inSampleSize = getClosestResampleSize(bfo.outWidth, bfo.outHeight, maxDim);
    
        Bitmap bmpt = BitmapFactory.decodeFile(path, optsDownSample);
    
        Matrix m = new Matrix(); 
        
        if (bmpt.getWidth() > maxDim || bmpt.getHeight() > maxDim) {
            BitmapFactory.Options optsScale = getResampling(bmpt.getWidth(), bmpt.getHeight(), maxDim);
            m.postScale((float)optsScale.outWidth  / (float)bmpt.getWidth(), 
                        (float)optsScale.outHeight / (float)bmpt.getHeight()); 
        }
         
        int sdk = new Integer(Build.VERSION.SDK).intValue(); 
        if (sdk > 4) {
            int rotation = ExifUtils.getExifRotation(path);
            if (rotation != 0) { 
                m.postRotate(rotation); 
            }
        }
        
        return Bitmap.createBitmap(bmpt, 0, 0, bmpt.getWidth(), bmpt.getHeight(), m, true); 
    }
    
    private static BitmapFactory.Options getResampling(int cx, int cy, int max) {
        float scaleVal = 1.0f;
        BitmapFactory.Options bfo = new BitmapFactory.Options();
        if (cx > cy) {
            scaleVal = (float)max / (float)cx;
        }
        else if (cy > cx) {
            scaleVal = (float)max / (float)cy;
        }
        else {
            scaleVal = (float)max / (float)cx;
        }
        bfo.outWidth  = (int)(cx * scaleVal + 0.5f);
        bfo.outHeight = (int)(cy * scaleVal + 0.5f);
        return bfo;
    }
    
    private static int getClosestResampleSize(int cx, int cy, int maxDim) {
        int max = Math.max(cx, cy);
        
        int resample = 1;
        for (resample = 1; resample < Integer.MAX_VALUE; resample++) {
            if (resample * maxDim > max) {
                resample--;
                break;
            }
        }
        
        if (resample > 0) {
            return resample;
        }
        return 1;
    }
    
    public static BitmapFactory.Options getBitmapDims(String path) throws Exception {
        BitmapFactory.Options bfo = new BitmapFactory.Options(); 
        bfo.inJustDecodeBounds = true; 
        BitmapFactory.decodeFile(path, bfo); 
        return bfo;
    }
}

還有一個問題需要糾正:
看了幾篇關於處理大圖的文章都說不要調用BitmapFactory.decodeResource這個函數,因為這個函數在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多內存。
我看了BitmapFactory的源碼發現上面那個分析是錯誤的,decodeResource最終也是調用Jni去獲取圖片。請看下面時序圖。

\



						
		
	
				
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved