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了。
示例代码如下:
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
复制代码
这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了。
有了宽,高的信息,我们怎样在图片不变形的情况下获取到图片指定大小的缩略图呢? 比如我们需要在图片不变形的前提下得到宽度为200的缩略图。 那么我们需要先计算一下缩放之后,图片的高度是多少
- int height = options.outHeight * 200 / options.outWidth;
- options.outWidth = 200;
- options.outHeight = height;
- options.inJustDecodeBounds = false;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
- image.setImageBitmap(bmp);
复制代码
这样虽然我们可以得到我们期望大小的ImageView 但是在执行BitmapFactory.decodeFile(path, options);时,并没有节约内存。要想节约内存,还需要用到BitmapFactory.Options这个类里的 inSampleSize 这个成员变量。 我们可以根据图片实际的宽高和我们期望的宽高来计算得到这个值。
- inSampleSize = options.outWidth / 200;
另外,为了节约内存我们还可以使用下面的几个字段:
- options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默认是Bitmap.Config.ARGB_8888
- options.inPurgeable = true;
- 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
BitmapFactory.Options详解相关推荐
- Android中BitmapFactory.Options详解
在Android中,BitmapFactory相信大家都很熟悉了,这个类里面的所有方法都是用来解码创建一个Bitmap,其中有一个重要的类是Options,此类用于解码Bitmap时的各种参数控制,那 ...
- Http:Get、Post、Put、Delete、Head、Options详解
2019独角兽企业重金招聘Python工程师标准>>> 一.概述 Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE.URL全称是 ...
- Cucumber之五Cucumber Options详解
英文视频教程地址是百度网盘,后续会放到微信公众号:[软测小生]里面,请关注公号更新相关文章和视频资源. ****************************分割线***************** ...
- udhcp源码详解(五) 之DHCP包--options字段
中间有很长一段时间没有更新udhcp源码详解的博客,主要是源码里的函数太多,不知道要不要一个一个讲下去,要知道讲DHCP的实现理论的话一篇博文也就可以大致的讲完,但实现的源码却要关心很多的问题,比如说 ...
- Bitmap详解(上)常用概念和常用API
前言: 图片的操作我相信大家都操作过,在算法层面大家往往都是把图片转成MAT矩阵处理的,而Android 开发层面大多数都是bitmap位图操作.接下来我将分算法层面以及android层面来讲解一下图 ...
- 各种图片编码格式详解
感谢xiangism 常见的图片格式有bmp, jpg(jpeg), png, gif, webp等. 图像基本数据结构 要讲图片格式还先得从图像的基本数据结构说起.在计算机中, 图像是由一个个像素点 ...
- Android多点触控详解
本文转载自GcsSloop的 安卓自定义View进阶-多点触控详解 的文章 Android 多点触控详解,在前面的几篇文章中我们大致了解了 Android 中的事件处理流程和一些简单的处理方案,本次带 ...
- android相册和拍照并裁剪图片大小,Android 拍照并对照片进行裁剪和压缩实例详解...
Android 拍照并对照片进行裁剪和压缩实例详解 本文主要介绍 Android 调用摄像头拍照并对照片进行裁剪和压缩,文中给出了主要步骤和关键代码. 调用摄像头拍照,对拍摄照片进行裁剪,代码如下. ...
- (4.6.31)Android Bitmap 详解
文章目录 一.从相册加载一张图片 1.1 打开相册加载图片 1.2 根据Uri得到Bitmap 二.Bitmap 内存计算方式 2.1 density 和 densityDpi 2.2 getByte ...
最新文章
- 1061 Dating
- struts2 mysql 乱码_struts2项目插入中文到mysql数据库乱码的解决方法
- Linux mmap
- leetcood学习笔记-112-路径总和
- 学习iptables
- mysql inet_aton 与 inet_ntoa 方法
- 循序渐进之Spring AOP(5) - 创建切面
- EViews10.0程序安装及注意事项
- Qt获取本地ip地址
- CTF古典密码:移位密码
- 矢量网络分析仪(矢网)组成和原理简介
- 网络编程之(转载自:https://www.cnblogs.com/clschao/articles/9593164.html)
- hadoop培训感想
- 2016一路有你,2017一起同行
- android的随机之魂
- 云计算学习笔记1——并行计算
- Elasticsearch的使用RestHighLevelClient
- Mac配置mysql环境
- 安装Linux Mint 17后要做的20件事
- STM32(1)跑马灯
热门文章
- echart多个柱状图 设置y轴显示_Echart可视化学习笔记(五)
- Cocos Creator教程 ——(二)UI系统介绍(上)
- leetcode - 1201. 丑数 III
- 时域补零对于DFT谱的影响
- C++字符串转化为数字的库函数
- php 显示中文utf,php adodb 从mysql数据库中输出中文显示到utf编码网页乱码问题
- 事件CEvent的使用
- 【入门4】数组 (今天刷洛谷了嘛)
- 【编撰】Directfb 深入 002 DirectFB内存分配与管理:surface pool
- python死机_请问下为什么我用PYTHON写编译器一旦用READ就死机