BitmapFactory.Options详解

 2023-09-09 阅读 15 评论 0

摘要:在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时,遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。怎么避免它呢? 这就用到了我们上面提到的BitmapFactory.Options这个类。 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 HashMessageDigest digest = java.security.MessageDigest.getInstance("MD5");digest.update(urlString.getBytes());byte messageDigest[] = digest.digest();// Create Hex StringStringBuffer 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 methodreturn urlString.replaceAll("[^A-Za-z0-9]", "#");}

 

 

转载于:https://www.cnblogs.com/Yang2/p/3584948.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/22768.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息