一.图片的存在形式
1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式。当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过55K的jpg文件加载到内存以Bitmap形式存在时,占用内存达到3M,关于Bitmap内存占用的问题我会再写一篇博客专门研究。
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数 toByteArray().length
Bitmap: bitmap.getByteCount()
二.常见的压缩方式
第一:我们先看下质量压缩方法:
1 /** 2 * 按质量压缩 3 * @param image 4 * @return 5 */ 6 public static Bitmap compressByQuality(Bitmap image) { 7 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 8 //质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 9 image.compress(Bitmap.CompressFormat.JPEG, 100, baos); 10 int options = 100; //压缩比例 11 //循环判断如果压缩后图片是否大于100kb,大于继续压缩 12 while ( baos.toByteArray().length / 1024>100) { 13 baos.reset();//重置baos 14 //这里压缩options%,把压缩后的数据存放到baos中 15 image.compress(Bitmap.CompressFormat.JPEG, options, baos); 16 options -= 10;//每次都减少10 17 } 18 //把压缩后的数据baos存放到ByteArrayInputStream中 19 ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); 20 //把ByteArrayInputStream数据生成图片 21 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null); 22 return bitmap; 23 }
第二:图片按比例大小压缩方法(根据路径获取图片并压缩):
1 /** 2 * 根据图片路径将图片读入内存,同时压缩 3 * @param srcPath 4 * @return 5 */ 6 public static Bitmap compressByPath(String srcPath) { 7 BitmapFactory.Options newOpts = new BitmapFactory.Options(); 8 newOpts.inJustDecodeBounds = true; //只读宽和高 9 Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空 10 11 newOpts.inJustDecodeBounds = false; 12 int w = newOpts.outWidth; 13 int h = newOpts.outHeight; 14 //手机分辨率,可以根据要求设置 15 float hh = 1280f; 16 float ww = 720f; 17 //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 18 int be = 1;//be=1表示不缩放 19 if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 20 be = (int) (newOpts.outWidth / ww); 21 } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 22 be = (int) (newOpts.outHeight / hh); 23 } 24 if (be <= 0) 25 be = 1; 26 newOpts.inSampleSize = be;//设置缩放比例 27 //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 28 bitmap = BitmapFactory.decodeFile(srcPath, newOpts); 29 return bitmap; 30 }
第三:图片按比例大小压缩方法(根据Bitmap图片压缩):
1 /** 2 * 按像素压缩 3 * @param image 4 * @return 5 */ 6 public static Bitmap compressByPixel(Bitmap image) { 7 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 8 image.compress(Bitmap.CompressFormat.JPEG, 100, baos); 9 //判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 10 if( baos.toByteArray().length / 1024>1024) { 11 baos.reset();//重置baos即清空baos 12 //这里压缩50%,把压缩后的数据存放到baos中 13 image.compress(Bitmap.CompressFormat.JPEG, 50, baos); 14 } 15 ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); 16 BitmapFactory.Options newOpts = new BitmapFactory.Options(); 17 //开始读入图片,此时把options.inJustDecodeBounds 设回true了 18 newOpts.inJustDecodeBounds = true; 19 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); 20 newOpts.inJustDecodeBounds = false; 21 int w = newOpts.outWidth; 22 int h = newOpts.outHeight; 23 //手机分辨率,可以根据要求设置 24 float hh = 1280f; 25 float ww = 720f; 26 //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 27 int be = 1;//be=1表示不缩放 28 if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 29 be = (int) (newOpts.outWidth / ww); 30 } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 31 be = (int) (newOpts.outHeight / hh); 32 } 33 if (be <= 0) 34 be = 1; 35 newOpts.inSampleSize = be;//设置缩放比例 36 //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 37 isBm = new ByteArrayInputStream(baos.toByteArray()); 38 bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); 39 return bitmap; 40 }