浅谈图片压缩方式
刚毕业开始工作,在项目开发中,一个很棘手的问题就是图片的压缩,上传速度太慢!所以现在闲下来有时间就想学习一下这方面的知识……参考网上的一些大神分享的干粮,如果有错的地方请大神毫不犹豫的指出!哈哈
压缩格式:
- 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个字节
获取图片所占内存
public static int getBitmapSize(Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//API 19
return bitmap.getAllocationByteCount();
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {//API 12
return bitmap.getByteCount();
}
//在低版本中用一行的字节x高度
return bitmap.getRowBytes() * bitmap.getHeight();
}
SampleSize取样压缩(分辨率压缩、体积压缩)
private Bitmap compressBitmap(String path,int width,int height){
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(path,options);
options.inSampleSize=caculateInSampleSize(options,width,height);
options.inJustDecodeBounds=false;
Bitmap bitmap=BitmapFactory.decodeFile(path,options);
Log.e("BitmapSize","压缩后:"+getBitmapSize(bitmap)/1024);
return bitmap;
}
/**
* 获取压缩比
*/
private int caculateInSampleSize(BitmapFactory.Options options,int width,int height){
int outWidth=options.outWidth;
int outHeight=options.outHeight;
int InSampleSize=1;
if(outWidth>width || outHeight>height){
int maxWidth=Math.round(outWidth*1.0f/width);
int maxHeight=Math.round(outHeight*1.0f/height);
InSampleSize=Math.max(maxHeight,maxWidth);
}
return InSampleSize;
}
质量压缩
private Bitmap compressBtye(Bitmap bitmap,int maxFileSize){
ByteArrayOutputStream out=new ByteArrayOutputStream();
int options=100;
//质量压缩方法,把压缩后的数据存放到out中 (100表示不压缩,0表示压缩到最小)
//以jpeg格式压缩后, 原来图片中透明的元素将消失,图片很可能会失真
bitmap.compress(Bitmap.CompressFormat.JPEG,options,out);
//获取大小
int outSize=out.toByteArray().length;
while (outSize/1024 > maxFileSize){
out.reset();//重置out即让下一次的写入覆盖之前的内容
options=Math.max(30,options-10);//30为个人预设最小压缩比(30以下会失真)
bitmap.compress(Bitmap.CompressFormat.JPEG,options,out);
outSize=out.toByteArray().length;
if(options==30)
break;
}
ByteArrayInputStream in=new ByteArrayInputStream(out.toByteArray());
bitmap=BitmapFactory.decodeStream(in);
Log.e("BtyeBitmap","100质量压缩后:"+getBitmapSize(bitmap)/1024);
return bitmap;
}
方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素;bitmap.getByteCount()是计算它的像素所占用的内存。所以当你想把体积压缩后得到的bitmap直接进行质量压缩是无效的,内存大小并不会变化。亲测,如图:我原图大小为3888k,进过体积压缩后为60k,然而质量压缩前得到outSize的值为11k,maxFileSize设为10,压缩比为90,得到的bimap内存大小还是60。所以out.toByteArray().length得到的值和getByteCount()得到的值是不同的!图片质量压缩改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩的file为Bitmap时, 它占用的内存并不会少!
Matrix压缩法(体积压缩、矩阵压缩)
private Bitmap MatrixBitmap(String path,int width,int height){
Bitmap bitmap=BitmapFactory.decodeFile(path);
int outWidth=bitmap.getWidth();
int outHeight=bitmap.getHeight();
//缩放比
float reWidth=width*1.0f/outWidth;
float reHeight=height*1.0f/outHeight;
float max=Math.max(reWidth,reHeight);
Log.e("BitmapSize","压缩max:"+max);
Matrix matrix=new Matrix();
matrix.postScale(max,max);
Bitmap bm=Bitmap.createBitmap(bitmap,0,0,outWidth,outHeight,matrix,true);
if(!bitmap.isRecycled()){//Android2.3以后系统不建议手动调用,系统会自动GC
bitmap.recycle();
}
Log.e("BitmapSize","Matrix压缩后:"+getBitmapSize(bm)/1024);
return bm;
}
如图,Matrix压缩与SampleSize压缩方式效果差别不大。但因为SampleSize压缩比InSampleSize的值必须是2的次方,而Matrix压缩的压缩比可以使float型,所以个人感觉Matrix压缩稍微好一些。
小总结:
体积压缩和质量压缩都会减少file流的大小,有利于快速上传!但只有体积压缩(分辨率压缩)才会减少图片所占内存的大小!