关于图片压缩大体分为两类:第一类是质量压缩,第二类是尺寸压缩(像素压缩)。
质量压缩
一:原理:
图片的质量压缩是通过改变色深和透明度让图片进行重组来进行压缩,只是改变其存储的形式的大小,不改变像素,也就不改变其在内存中的大小。一般是在质量压缩获得流之后,对流直接进行操作,用于不失真压缩,上传图片等。
二:实现方法:
Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
1.第一个参数表示指定的Bitmap被压缩成的图片格式,只支持JPEG,PNG,WEBP三种格式。
2.第二个参数表示压缩后的图片质量,范围为0~100(0表示压缩后质量最差;100表示压缩后质量最好,相当于没有压缩)。png格式的图片是无损的,所以会忽略这个值。
3.第三个参数表示压缩后的图片保存到的输出流。
三:具体实现代码:
/**
* 通过降低图片质量进行压缩
* @param bitmap 需要压缩的图片位图对象
* @param maxSize 压缩后图片大小的最大值,单位为KB
* @param savePath 压缩后图片保存的路径
* @return
*/
public static void compressImageByQuality(Bitmap bitmap, int maxSize, String savePath){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//100表示不压缩
int options = 100;
while(baos.toByteArray().length / 1024 > maxSize){
baos.reset();
options -= 10;
if(options < 0){
options = 0;
}
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//压缩options%
if(options == 0){
break;
}
}
FileOutputStream fos = null;//将压缩后的图片保存的本地的指定路径中
try {
fos = new FileOutputStream(new File(savePath));
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
尺寸压缩
尺寸压缩是指根据图片大小按比例进行压缩,像素会压缩,内存中所占大小会减小。
一:几种创建Bitmap对象的方法:
1.sd卡中的图片:
BitmapFactory.decodeFile(String pathName, Options opts);
2.网络上的图片:
BitmapFactory.decodeResource(Resources res, int id, Options opts)
3.资源中的图片:
BitmapFactory.decodeResource(Resources res, int id, Options opts)
二:方法参数说明:
BitmapFactory.Options参数的inJustDecodeBounds属性设置为ture,禁止为bitmap分配内存,返回值Bitmap是null,但是根据BitmapFactory.Options参数的outWidth、outHeight和outMimeType属性在加载图片之前就可以获取到图片的长宽值,MIME类型。
根据压缩后需要的宽高获取合适的inSampleSize的值,设置inSampleSize属性进行压缩,就可以得到压缩后的图片。
其中inSampleSize只能是2的整数次幂,如果不是的话,向下取得最大的2的整数次幂。(inSampleSize为7的话,长宽各压缩为原来的1/2同理inSampleSize为9的话,长宽各压缩为原来的1/3)
三:具体实现代码:
/**
* 获取合适的inSampleSize的大小
* @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;
}
/**
* 从资源中获取图片并进行压缩
* @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;//禁止占用内存,获取options参数值
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight); // 计算inSampleSize
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
/**
* 从sd卡中获取图片进行压缩
* @param pathName 图片所在路径
* @param reqWidth 要求压缩后的宽度
* @param reqHeight 要求压缩后的宽度
* @return 返回压缩后的Bitmap
*/
public static Bitmap decodeSampledBitmapFromFd(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;
return BitmapFactory.decodeFile(pathName, options);
}
小结
质量压缩不改变像素不会改变内存大小,用于不失真压缩上传图片。
尺寸压缩会改变内存大小,其中Options.insampleSize属性表示向下取得最大的2的整数次幂。用于缩略图等。