Android中有多种图片压缩的方式,如质量压缩、采样率压缩、RGB565压缩、尺寸缩放压缩等
Android图片主以bitmap形式存在,其内存大小的计算公式为:图片宽度×图片高度×一个像素点所占字节数
所以减小这三个参数的任一参数都可减小bitmap所占的内存大小
一、质量压缩
保持图片像素的前提下改变图片的位深及透明度
该方法使用的是bitmap.compress(Bitmap.CompressFormat format, int quality, OutputStream stream),该方法是将位图的压缩版本写入指定的输出流。第一个参数为图片压缩格式,有CompressFormat .PNG、CompressFormat .JPEG等,需注意的是这里的PNG图片为无损的,是无法压缩的;第二个参数quality就为压缩数,设置为0-100之间,参数为100时不对图片压缩;第三个参数为输出流,位图的压缩版本就是写入该流中。
private byte[] bitmapCompress(Bitmap bitmap){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int quality = 100;
//循环判断如果压缩后图片是否大于100kb,大于继续压缩,这里的要求数值可根据需求设置
while ( baos.toByteArray().length / 1024>1000) {
//重置baos即清空baos
baos.reset();
//这里压缩quality%,把压缩后的数据存放到baos中
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
quality -= 10;//每次都减少10
}
//转为字节数组返回
byte[] bytes = baos.toByteArray();
return bytes;
}
若通过BitmapFactory.decodeByteArray(bytes,0,bytes.length)重新获得一个bitmap,你会发现bitmap和原来的还是一样大小并没有压缩,因为该方法压缩并没有改变bitmap内存计算公式中的任何一个参数,所以大小是没有改变的,但是打印bytes.length()你会发现大小会根据quality的变小而变小。我理解的是虽然该方法没有将bitmap内存占用变小,但是bytes.length()变小可用来作二进制图片传输,如微信分享等。
二、采样率压缩
设置图片的采样率,降低图片像素
该方法是通过设置BitmapFactory.Options中的inJustDecodeBounds来压缩图片,如果设置该值>1,请求解码器对原始图像进行子采样,返回较小的图像以保存内存。
private Bitmap sampleCompress(String path){
BitmapFactory.Options options = new BitmapFactory.Options();
//该参数设为true,则获取时bitmap返回为空,避免bitmap内存分配
options.inJustDecodeBounds = true;
//获取bitmap参数信息
BitmapFactory.decodeFile(path,options);
int inSampleSize = 1;
//循环判断如果压缩后图片是否大于1024kb,大于继续压缩,这里的要求数值可根据需求设置
while (getImageMemory(options.outWidth, options.outHeight, inSampleSize) > 1024) {
inSampleSize += 1;
}
//将参数设为false,则获取时bitmap返回不为空
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeFile(path,options);
}
//24位位图内存大小计算
private static int getImageMemory(int width, int height, int inSampleSize) {
//bitmap内存计算公式
return (width / inSampleSize) * (height / inSampleSize) * 3 / 1024;
}
设置inSampleSize的值,该值为int类型,假如设为2,则宽和高都为原来的1/2,宽高都减少了,根据计算公式则bitmap占用内存也就自然减小了。BMP文件的图像深度可选lbit、4bit、8bit及24bit。
如果图片大小是800*600的位图,8位,则这个位图所占空间为:800*600*8/(8*1024*1024)=0.457M
图片大小是800*600的位图,24位,则这个位图所占空间为 800*600*24/(8*1024*1024)=1.37M
三、RGB565压缩
改变一个像素点占用字节数
其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。
ALPHA_8 表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度
ARGB_4444 表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节
ARGB_8888 表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节
RGB_565 表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节
private Bitmap argbCompress(String path){
BitmapFactory.Options options = new BitmapFactory.Options();
//如果这是非空的,解码器将尝试解码到这个颜色空间中。原图为ARGB_8888,设置其为RGB_565
options.inPreferredConfig = Bitmap.Config.RGB_565;
return BitmapFactory.decodeFile(path,options);
}
最后得到的图片内存占用为原来图片大小的一半 ,长度和宽度没发生变化。RGB_565对不要求透明度的图来说视觉影像不大。
四、尺寸缩放压缩
改变图片尺寸大小,缩小图片所占内存
该方法通过bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)来改变图片尺寸。第一个参数为资源bitmap;第二个参数为目标宽度;第三个参数为目标高度,第四个参数为过滤器,如果源应该被过滤,则为true。
Bitmap bm = bitmap.createScaledBitmap(bitmap,100,100,true);
所得到的bm比原来的bitmap内存小了,因为尺寸变小了,变成了期望的100*100。