zoukankan      html  css  js  c++  java
  • BitmapFactory.Options详解

    在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。怎么避免它呢? 这就用到了我们上面提到的BitmapFactory.Options这个类。

    BitmapFactory.Options这个类,有一个字段叫做 inJustDecodeBounds 。SDK中对这个成员的说明是这样的: If set to true, the decoder will return null (no bitmap), but the out… 也就是说,如果我们把它设为true,那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你,这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。

     

    示例代码如下:

    1. BitmapFactory.Options options = new BitmapFactory.Options();
    2. options.inJustDecodeBounds = true;
    3. Bitmap bmp = BitmapFactory.decodeFile(path, options);

    复制代码

    这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。

    有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢? 比如我们需要在图片不变形的前提下得到宽度为200的缩略图。 那么我们需要先计算一下缩放之后,图片的高度是多少 

    1. int height = options.outHeight * 200 / options.outWidth;
    2. options.outWidth = 200;
    3. options.outHeight = height; 
    4. options.inJustDecodeBounds = false;
    5. Bitmap bmp = BitmapFactory.decodeFile(path, options);
    6. image.setImageBitmap(bmp);

    复制代码

    这样虽然我们可以得到我们期望大小的ImageView 但是在执行BitmapFactory.decodeFile(path, options);时,并没有节约内存。要想节约内存,还需要用到BitmapFactory.Options这个类里的 inSampleSize 这个成员变量。 我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。

    1. inSampleSize = options.outWidth / 200;

    另外,为了节约内存我们还可以使用下面的几个字段:

    1. options.inPreferredConfig = Bitmap.Config.ARGB_4444;    // 默认是Bitmap.Config.ARGB_8888
    2. options.inPurgeable = true;
    3. options.inInputShareable = true;

    BitmapFactory.Options.inSampleSize

    设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。例如:

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = 4;
    Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

    设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。

    BitmapFactory.Options opts = new BitmapFactory.Options();
    
    opts.inJustDecodeBounds = true;
    
    Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

    设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。

    查看Android源码,我们得知,为了得到恰当的inSampleSize,Android提供了一种动态计算的方法。

    public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }
        return roundedSize;
    }
    
    private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;
        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }
        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    } 
    
    使用该算法,就可动态计算出图片的inSampleSize。
    
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imageFile, opts);
    opts.inSampleSize = computeSampleSize(opts, -1, 128*128);  
    opts.inJustDecodeBounds = false;
    try {
       bmp = BitmapFactory.decodeFile(imageFile, opts);
       imageView.setImageBitmap(bmp);
    } catch (OutOfMemoryError err) {
    }

    源代码如下:

        public static Bitmap createImageThumbnail(String filePath){
             Bitmap bitmap = null;
             BitmapFactory.Options opts = new BitmapFactory.Options();
             opts.inJustDecodeBounds = true;
             BitmapFactory.decodeFile(filePath, opts);
    
             opts.inSampleSize = computeSampleSize(opts, -1, 128*128);
             opts.inJustDecodeBounds = false;
    
             try {
                 bitmap = BitmapFactory.decodeFile(filePath, opts);
             }catch (Exception e) {
                // TODO: handle exception
            }
            return bitmap;
        }
    
        public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
            int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
            int roundedSize;
            if (initialSize <= 8) {
                roundedSize = 1;
                while (roundedSize < initialSize) {
                    roundedSize <<= 1;
                }
            } else {
                roundedSize = (initialSize + 7) / 8 * 8;
            }
            return roundedSize;
        }
    
        private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {
            double w = options.outWidth;
            double h = options.outHeight;
            int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
            int upperBound = (minSideLength == -1) ? 128 :(int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
            if (upperBound < lowerBound) {
                // return the larger one when there is no overlapping zone.
                return lowerBound;
            }
            if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
                return 1;
            } else if (minSideLength == -1) {
                return lowerBound;
            } else {
                return upperBound;
            }
        }

    项目实战代码:

    /**
         * 不full load图片,先根据一定的算法缩小再load
         * 
         * @param path
         * @return
         */
        public static Bitmap loadBitmapFromFile(String path, int thumbWidth, int thumbHeight) {
            Bitmap bmp = null;
            
            BitmapFactory.Options opts = new BitmapFactory.Options();
            /*
             * 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。
             * 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize
             */
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, opts);
            
            opts.inSampleSize = calculateInSampleSize(opts, thumbWidth, thumbHeight);
            //这里一定要将其设置回false,因为之前我们将其设置成了true     
            opts.inJustDecodeBounds = false;
            
            try {
                bmp = BitmapFactory.decodeFile(path, opts);
            } catch (OutOfMemoryError e) {
                Logger.e(TAG, e.getMessage());
            }
            
            return bmp;
        }
        
        //计算图片的缩放值
        public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
            final int height = options.outHeight;
            final int width = options.outWidth;
            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;
        }
        
        
        /**
         * 不full load图片,先根据一定的算法缩小再load
         * 
         * @param path
         * @return
         */
        public static Bitmap loadBitmapFromFile(String path) {
            Bitmap bmp = null;
            
            BitmapFactory.Options opts = new BitmapFactory.Options();
            /*
             * 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。
             * 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize
             */
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, opts);
            
            opts.inSampleSize = computeSampleSize(opts, -1, 512 * 512);
            //这里一定要将其设置回false,因为之前我们将其设置成了true     
            opts.inJustDecodeBounds = false;
            
            try {
                bmp = BitmapFactory.decodeFile(path, opts);
            } catch (OutOfMemoryError e) {
                Logger.e(TAG, e.getMessage());
            }
            
            return bmp;
        }
        
        public static Bitmap loadBitmapFromUrl(Context ctx, String url) {
            File path =  ctx.getCacheDir();
            String hashedURLString = hashURLString(url);
            
            String finalPath = new File(path, hashedURLString).getAbsolutePath();
            
            boolean ok = FileUtils.saveUrl(finalPath, url);
            if (ok) {
                return loadBitmapFromFile(finalPath);
            }
            
            return null;
        }    
        /**
         * 将图片先放到临时空间中,再读取图片。full load
         * 
         * @param path
         * @return
         */
        public static Bitmap loadBitmapFromFileX(String path) {
            BitmapFactory.Options bfOptions = new BitmapFactory.Options();
            bfOptions.inDither = false;
            bfOptions.inPurgeable = true;
            bfOptions.inTempStorage = new byte[12 * 1024];
            File file = new File(path);
            FileInputStream fs = null;
    
            Bitmap bmp = null;
    
            try {
                fs = new FileInputStream(file);
                bmp = BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
            } finally {
                try {
                    if (fs != null) {
                        fs.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return bmp;
        }
        
        public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
            int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
    
            int roundedSize;
            if (initialSize <= 8) {
                roundedSize = 1;
                while (roundedSize < initialSize) {
                    roundedSize <<= 1;
                }
            } else {
                roundedSize = (initialSize + 7) / 8 * 8;
            }
    
            return roundedSize;
        }
    
        private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
            double w = options.outWidth;
            double h = options.outHeight;
    
            int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
            int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
    
            if (upperBound < lowerBound) {
                return lowerBound;
            }
    
            if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
                return 1;
            } else if (minSideLength == -1) {
                return lowerBound;
            } else {
                return upperBound;
            }
        }
        
        private static String hashURLString(String urlString) {
            try {
                // Create MD5 Hash
                MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
                digest.update(urlString.getBytes());
                byte messageDigest[] = digest.digest();
                
                // Create Hex String
                StringBuffer hexString = new StringBuffer();
                for (int i=0; i<messageDigest.length; i++)
                    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
                return hexString.toString();
                
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            
            //fall back to old method
            return urlString.replaceAll("[^A-Za-z0-9]", "#");
        }
  • 相关阅读:
    不常用的cmd命令
    js获取宽度
    Marshaling Data with Platform Invoke 概览
    Calling a DLL Function 之三 How to: Implement Callback Functions
    Marshaling Data with Platform Invoke 之四 Marshaling Arrays of Types
    Marshaling Data with Platform Invoke 之一 Platform Invoke Data Types
    Marshaling Data with Platform Invoke 之三 Marshaling Classes, Structures, and Unions(用时查阅)
    Calling a DLL Function 之二 Callback Functions
    WCF 引论
    Marshaling Data with Platform Invoke 之二 Marshaling Strings (用时查阅)
  • 原文地址:https://www.cnblogs.com/Yang2/p/3584948.html
Copyright © 2011-2022 走看看