本文主要是介绍BitmapFactory压缩图片,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
我们编写的应用程序都是有一定内存限制的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常。所以在展示高分辨率图片或者上传图片的时候,最好先将图片进行压缩。下面看下我们如何对一张大图进行适当的压缩,让它能够以最佳大小显示的同时,还能防止OOM的出现。BitmapFactory是一个工具类,提供了多个解析方法(decodeByteArray, decodeFile, decodeResource等)用于创建Bitmap对象,我们应该根据图片的来源选择合适的方法。
- SD卡中的图片可以使用decodeFile方法: Bitmap android.graphics.BitmapFactory.decodeFile(String pathName,Options opts)
- 网络上的图片可以使用decodeStream方法: Bitmap android.graphics.BitmapFactory.decodeStream(InputStream is)
- 资源文件中的图片可以使用decodeResource方法: Bitmap android.graphics.BitmapFactory.decodeResource(Resources res, int id,Options opts)
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
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的值,这样可以保证最终图片的宽和高 // 一定都会大于等于目标的宽和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; }
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 读取图片长宽BitmapFactory.decodeResource(res, resId, options); // 调用上面定义的方法计算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用获取到的inSampleSize值再次解析图片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
然而,文档中inSampleSize的注释中有一个需要注意的一点。下面是原注释:
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1.Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2.
任何其他值将向下取得最大的2的整数次幂。比如inSampleSize=5或6或7,将取为4。
这样Bitmap是可以被压缩,只是压缩得到的Bitmap可能会比我们需要的大。需要怎么才能更好的压缩呢?Bitmap中还有一个方法:
Bitmap android.graphics.Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
现在我们写一个工具类,完成了如下过程:
- 将inJustDecodeBounds设为true,
- 调用decodexxxx()方法,读取图片长宽。
- 计算出inSampleSize的大小。
- 将inJustDecodeBounds设为false。
- 调用decodexxxx()方法得到一个可能大一点的缩略图A。
- 使用createScaseBitmap再次压缩A,将缩略图A生成我们需要的缩略图B。
- 回收缩略图A(如果A和B的比率一样,就不回收A)。
/*** 用于压缩图片* Created by lyh on 2016/2/3 0017.*/
public class BitmapUtils {/*** @description 计算图片的压缩比率** @param options 参数* @param reqWidth 目标的宽度* @param reqHeight 目标的高度* @return*/private 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 halfHeight = height / 2;final int halfWidth = width / 2;while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {inSampleSize *= 2;}}return inSampleSize;}/*** @description 通过传入的bitmap,进行压缩,得到符合标准的bitmap** @param src* @param dstWidth* @param dstHeight* @return*/private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {//如果inSampleSize是2的倍数,也就说这个src已经是我们想要的缩略图了,直接返回即可。if (inSampleSize % 2 == 0) {return src;}// 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为falseBitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);if (src != dst) { // 如果没有缩放,那么不回收src.recycle(); // 释放Bitmap的native像素数组}return dst;}/*** @description 从Resources中加载图片** @param res* @param resId* @param reqWidth* @param reqHeight* @return*/public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高BitmapFactory.decodeResource(res, resId, options); // 读取图片长宽options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 调用上面定义的方法计算inSampleSize值// 使用获取到的inSampleSize值再次解析图片options.inJustDecodeBounds = false;Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize); // 进一步得到目标大小的缩略图}/*** @description 从SD卡上加载图片** @param pathName* @param reqWidth* @param reqHeight* @return*/public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) {final BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(pathName, options);options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);options.inJustDecodeBounds = false;Bitmap src = BitmapFactory.decodeFile(pathName, options);return createScaleBitmap(src, reqWidth, reqHeight, options.inSampleSize);}
}
mImageView.setImageBitmap(
BitmapUtils.decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
这篇关于BitmapFactory压缩图片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!