android图片压缩总结
总结来看,图片有三种存在形式:硬盘上时是file,网络传输时是stream,内存中是stream或bitmap,所谓的质量压缩,它其实只能实现对file的影响,你可以把一个file转成bitmap再转成file,或者直接将一个bitmap转成file时,这个最终的file是被压缩过的,但是中间的bitmap并没有被压缩(或者说几乎没有被压缩,我不确定),因为bigmap在内存中的大小是按像素计算的,也就是width * height,对于质量压缩,并不会改变图片的像素,所以就算质量被压缩了,但是bitmap在内存的占有率还是没变小,但你做成file时,它确实变小了;
第一:质量压缩方法:此种压缩只能压缩文件并不能压缩bitmap。不建议使用
/**
* 质量压缩图片,图片占用内存减小,像素数不变,常用于上传
* @param image
* @param size 期望图片的大小,单位为kb
* @param options 图片压缩的质量,取值1-100,越小表示压缩的越厉害,如输入30,表示压缩70%
* @return
*/
private static Bitmap compressImage(Bitmap image,int size,int options) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 80, baos);
// 循环判断如果压缩后图片是否大于100kb,大于继续压缩
while (baos.toByteArray().length / 1024 > size) {
options -= 10;// 每次都减少10
baos.reset();// 重置baos即清空baos
// 这里压缩options%,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
// 把压缩后的数据baos存放到ByteArrayInputStream中
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
// 把ByteArrayInputStream数据生成图片
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
第二:图片按比例大小压缩方法(根据路径获取图片并压缩):
//图片按比例大小压缩方法(根据路径获取图片并压缩)。这个压缩方法可以完全压缩,无论是保存再file中还是bitmap中
public static Bitmap getimage(String srcPath,float pixelW, float pixelH) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = pixelW;//这里设置高度为800f
float ww = pixelH;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return bitmap;//压缩好比例大小后再进行质量压缩
}
再去google狂搜一发,得到以下一个结论:
Bitmap.compress方法确实可以压缩图片,但压缩的是存储大小,即你放到disk上的大小
我尝试过把品质设置为10,decode出来的Bitmap大小没变,但显示照片的质量非常差
BitmapFactory.decodeByteArray方法对压缩后的byte[]解码后,得到的Bitmap大小依然和未压缩过一样
int len = bm.getByteCount(); // 原始图片的byte[]数组大小
ByteArrayOutputStream out = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 80, out);
int compressedLen = out.toByteArray().length; // 这里out.toByteArray()所返回的byte[]数组大小确实变小了!
Bitmap compressedBm = BitmapFactory.decodeByteArray(out.toByteArray(), 0, compressedLen);
int newLen = compressedBm.getByteCount(); // 这里decode出来的图片byte[]数组大小和原始图片是一样的!并没有变小
延伸阅读
一.图片的存在形式
1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap:bitmap.getByteCount()