图片压缩

参考:
https://github.com/Curzibn/Luban
https://github.com/zetbaitsu/Compressor
https://www.jianshu.com/p/3ac26611bc0d

一、图片的存在形式

  1. 文件形式(即以二进制形式存在于硬盘上)
  2. 流的形式(即以二进制形式存在于内存中)
  3. Bitmap形式 (位图图像(bitmap), 亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。)

这三种形式的区别:
文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大,
我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的。

二、Android中图片形式

Android中图片是以位图(BitMap)形式存在的,位图常见的文件格式有:

.bmp
.jpg
.gif
.png

一张图片(BitMap)占用的内存主要和以下几个因数有关:图片长度,图片宽度,单位像素占用的字节数。

一张图片(BitMap)占用的内存=图片长度x图片宽度x单位像素占用的字节数

位图(BitMap)的优缺点:

位图(BitMap)色彩变化丰富,可以改变任何形状的区域的色彩显示效果,相应的,要实现的效果越复杂,需要的象素数越多,图像文件的大小长宽和体积[存储空间]越大。

位图的一个缺点是放大和缩小都会引起像素的增加和减小,这样会使得原由的图象的线条和形状变的参差不齐,与原图像相比出现失真;出现”锯齿形“。位图的另一个缺点就是数据量太大(如:长和宽分别为1024像素和768像素得24位色彩深度的图象就需要(1024×768×24÷8)=2304K个字节存储文件)。

三、图片常用的压缩格式

图片常用的编码格式

图片常用的编码格式

其中,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个字节

我们在做压缩处理的时候,可以先通过改变Bitmap的图片编码格式,来达到压缩的效果,其实压缩最主要就是要么改变其宽高,要么就通过减少其单个像素占用的内存。

四、常用的压缩方法

1.质量压缩

 ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int quality = Integer.valueOf(editText.getText().toString());
            bit.compress(CompressFormat.JPEG, quality, baos);
            byte[] bytes = baos.toByteArray();
            bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

            Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
                    + "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight()
                    + "bytes.length=  " + (bytes.length / 1024) + "KB"
                    + "quality=" + quality);

质量压缩不会减少图片的像素,它是在保持像素的前提下改变图片的位深及透明度,来达到压缩图片的目的,图片的长,宽,像素都不会改变,那么bitmap所占内存大小是不会变的。
  我们可以看到有个参数:quality,可以调节你压缩的比例,但是还要注意一点就是,质量压缩对png格式这种图片没有作用,因为png是无损压缩。

2.采样率压缩

          BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 2;
            bm = BitmapFactory.decodeFile(Environment
                    .getExternalStorageDirectory().getAbsolutePath()
                    + "/Camera/test.jpg", options);

            Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
                    + "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight());

采样率压缩其原理是缩放bitamp的尺寸,通过调节其inSampleSize参数,比如调节为2,宽高会为原来的1/2,内存变回原来的1/4.

3.缩放法压缩(martix)

  Matrix matrix = new Matrix();
            matrix.setScale(0.5f, 0.5f);
            bm = Bitmap.createBitmap(bit, 0, 0, bit.getWidth(),
                    bit.getHeight(), matrix, true);

            Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
                    + "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight());

放缩法压缩使用的是通过矩阵对图片进行裁剪,也是通过缩放图片尺寸,来达到压缩图片的效果,和采样率的原理一样。

4.RGB_565压缩

 BitmapFactory.Options options2 = new BitmapFactory.Options();
            options2.inPreferredConfig = Bitmap.Config.RGB_565;

            bm = BitmapFactory.decodeFile(Environment
                    .getExternalStorageDirectory().getAbsolutePath()
                    + "/Camera/test.jpg", options2);

            Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024 / 1024)
                    + "M宽度为" + bm.getWidth() + "高度为" + bm.getHeight());

RGB_565压缩是通过改用内存占用更小的编码格式来达到压缩的效果。Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。一般不建议使用ARGB_4444,因为画质实在是辣鸡,如果对透明度没有要求,建议可以改成RGB_565,相比ARGB_8888将节省一半的内存开销。

5.createScaledBitmap

    bm = Bitmap.createScaledBitmap(bit, 150, 150, true);

            Log.i("wechat", "压缩后图片的大小" + (bm.getByteCount() / 1024) + "KB宽度为"
                    + bm.getWidth() + "高度为" + bm.getHeight());

这里是将图片压缩成用户所期望的长度和宽度,但是这里要说,如果用户期望的长度和宽度和原图长度宽度相差太多的话,图片会很不清晰。

此方法与第3种方法实现方式类似,其源码如下:

public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) { 
  Matrix m; 
  synchronized (Bitmap.class) { // small pool of just 1 matrix 
  m = sScaleMatrix; 
  sScaleMatrix = null;
 }
  if (m == null) { 
    m = new Matrix(); 
  }
  final int width = src.getWidth(); 
  final int height = src.getHeight(); 
  final float sx = dstWidth / (float)width; 
  final float sy = dstHeight / (float)height; m.setScale(sx, sy); 
  Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
   synchronized (Bitmap.class) { // do we need to check for null? why not just assign everytime?
  if (sScaleMatrix == null) {
    sScaleMatrix = m; 
    } 
  }
   return b;
}

以上就是5种图片压缩的方法,这里需要强调,他们的压缩仅仅只是对Android中的Bitmap来说的。如果将这些压缩后的Bitmap另存为sd中,他们的内存大小并不一样。
  Android手机中,图片的所占的内存大小和很多因素相关,计算起来也很麻烦。为了计算出一个图片的内存大在这里插入代码片小,可以将图片当做一个文件来间接计算,用如下的方法:

       File file = new File(Environment.getExternalStorageDirectory()
         .getAbsolutePath() + "/Camera/test.jpg");

         Log.i("wechat", "file.length()=" + file.length() / 1024);

或者

   FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            Log.i("wechat", "fis.available()=" + fis.available() / 1024);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

上面两个方法计算的结果是一样的。

五、总结

Bitmap所占用的内存 = 图片长度 x 图片宽度 x 一个像素点占用的字节数。3个参数,任意减少一个的值,都能达到了压缩的效果,只是效果不尽相同。
  另外我们这里的介绍的压缩方法只是针对在运行加载的bitmap占用内存的大小。我们在做App内存优化的时候,一般可以从这两个方面入手,一个内存泄漏,另外一个是Bitmap压缩了,在要求像素不高的情况下,可以对Bitmap进行压缩,并且针对一些只使用一次的Bitmap,要做好recycle的处理。

参考链接:
1、Android 位图(Bitmap)与矢量图
2、Android图片占用内存大小及加载解析
3、bitmap的六种压缩方式,Android图片压缩
4、Android Bitmap的常用压缩方式
5、Android图片缓存之Bitmap详解
6、传递Bitmap + 图片压缩处理 并保存 + 壁纸设置 总结
7、Android压缩图片到100K以下并保持不失真的高效方法
8、android图片压缩不失真实战

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值