添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

前言:让我们手撸一个图片压缩库,对压缩工具鲁班进行升级改造。

在平常开发当中,我们一般是使用第三方的工具,不仅快,而且上手简单,基本不用我们动脑子,压缩我们用鲁班压缩,加载图片我们用Glide,这两大工具我想在座的基本上都用吧,不过我们要想提升自己,就要搞清楚深一点的东西,这里我将会带着大家做一款压缩工具,功能媲美鲁班压缩,而且还带有鲁班没有的功能,如输出指定格式等,在这个过程中我们要学会如何获取bitmap,第一篇已经罗列了多种从项目中取图片转bitmap,这里就不多说了。当我们拿到bitmap我们要知道的事情还有很多,比如图片的色彩模式,一个像素点大小,什么是色深,位深等。绝对让你有收获,干货满满,冲呀。

1、图片相关概念
1.1 ARGB介绍
1.2 Bitmap概念
1.3 色彩模式
1.4 色深和位深
1.5 内存中Bitmap的大小
1.6 系统一般分配的大小
2、图片压缩方式
3、压缩的常见方式
3.1、质量压缩
3.2、采样压缩
3.2.1 临近采样(临近点插值算法)
3.2.2 双线性采样(双线性内插值算法)
3.2.3 双线性采样对比邻近采样的优势在于:
4、微信和鲁班压缩对比

1、图片相关概念

1.1 ARGB介绍

ARGB颜色模型:最常见的颜色模型,设备相关,四种通道,取值均为[0,255],即转化成二进制位0000 0000 ~ 1111 1111。
A:Alpha (透明度) R:Red (红) G:Green (绿) B:Blue (蓝)

1.2 Bitmap概念

Bitmap对象本质是一张图片的内容在手机内存中的表达形式。它将图片的内容看做是由存储数据的有限个像素点组成;每个像素点存储该像素点位置的ARGB值。每个像素点的ARGB值确定下来,这张图片的内容就相应地确定下来了。

1.3 色彩模式

Bimap.Config下
  • ALPHA_8 =>8位(1B)
  • RGB_565 =>16位(2B)
  • ARGB_4444 =>16位(2B)
  • ARGB_8888 =>32比特位(4字节,4B)
  • RGBA_F16 =>64位(8B)
  • Bitmap.Config是Bitmap的一个枚举内部类,它表示的就是每个像素点对ARGB通道值的存储方案。取值有以下四种:
    ALPHA_8:每个像素占8位(1个字节),存储透明度信息,没有颜色信息。
    RGB_565:没有透明度,R=5,G=6,B=5,,那么一个像素点占5+6+5=16位(2字节),能表示2^16种颜色。
    ARGB_4444:由4个4位组成,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位 (2字节),能表示2^16种颜色。
    ARGB_8888:由4个8位组成,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位(4字节),能表示2^24种颜色。
    1 byte(字节) = 8bit(位)
    1 KB = 1024 byte(字节)

    1.4 色深和位深

  • 色深:每一个像素点用多少bit来存储ARGB值
  • 位深:每个像素点在计算机中所使用的二进制数值位数叫做位深度,主要用于存储
  • 1.5 内存中Bitmap的大小

    从网络下载,asset,sd卡取的图片计算公式
    分辨率 * 每个像素点的大小(如1080*1920*4B = xxx ) (32/8=4)
    从res内不同资源目录下
    decodeResource()会经过一次分辨率的转换,再计算大小
    新分辨率 = 原图横向分辨率 * (设备的 dpi / 目录对应的 dpi ) * 原图纵向分辨率 * (设备的 dpi / 目录对应的 dpi )。

    1.6 系统一般分配的大小

    maxMemory() 返回Java虚拟机将尝试使用的最大内存量。如果没有固有的限制,则值为Long。将返回MAX_VALUE。
    虚拟机将尝试使用的最大内存量,以字节为单位
    // 获取应用程序最大可用内存(以字节为单位,/1024/1024=M  华为p20 pro是384M) 		int maxMemory = (int) Runtime.getRuntime().maxMemory(); 		int cacheSize = maxMemory / 8;   // 设置图片缓存大小为程序最大可用内存的1/8 		mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 			@Override 			protected int sizeOf(String key, Bitmap bitmap) { 				return bitmap.getByteCount(); 			}  ----------------------其他获取方式-------------------- ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); //最大分配内存,单位M int memoryClass = activityManager.getMemoryClass(); Log.e("memoryclass=",String.valueOf(memoryClass)); //最大分配内存获取方法2 float maxMemory = (float) (Runtime.getRuntime().maxMemory() * 1.0/ (1024 * 1024)); //当前分配的总内存 float totalMemory = (float) (Runtime.getRuntime().totalMemory() * 1.0/ (1024 * 1024)); //剩余内存 float freeMemory = (float) (Runtime.getRuntime().freeMemory() * 1.0/ (1024 * 1024)); Log.e("memoryclass=maxMemory",String.valueOf(maxMemory)); Log.e("memoryclass=totalMemory",String.valueOf(totalMemory)); Log.e("memoryclass=freeMemory",String.valueOf(freeMemory));

    2、图片压缩方式

  • 设置图片格式
  • png:无损的压缩图片格式
  • jpeg:有损的压缩图片格式,不能透明设置。
  • webp:同时提供了有损和无损图片格式。无损的格式要比png小26%,有损的比jpeg大25%-30%。
  • 采样率压缩
  • 减少图片的像素,缩略图
  • JNI调用JPEG库
  • webp:是一种同时提供了有损压缩和无损压缩的图片格式,派生自视频编码格式VP8,从谷歌官网来看,无损webp平均比png小26%,有损的webp平均比jpeg小25%~34%,无损webp支持Alpha通道,有损webp在一定的条件下同样支持,有损webp在Android4.0(API 14)之后支持,无损和透明在Android4.3(API18)之后支持
    采用webp能够在保持图片清晰度的情况下,可以有效减小图片所占有的磁盘空间大小
    Bitmap.compress(Bitmap.CompressFormat.JPEG,quality,outputStream) 其中 Bitmap.CompressFormat.JPEG Bitmap.CompressFormat.PNG  无损,无法再质量压缩? Bitmap.CompressFormat.WEBP  可优化30%,比JPEG更加省空间  quality:0-100,1最小体积,100 最高质量,体积也是最大 outputStream:  ByteArrayOutputStream 一个输出流,压缩后的流,如果要保存成图片文件,就保存此流

    3.2、采样压缩

  • 临近采样(临近点插值算法)
  • 双线性采样(双线性内插值算法)
  • 3.2.1 临近采样(临近点插值算法)

    使用了BitmapFactory.options  下的 inSampleSize:采样压缩系数  如果是2,直接缩放宽高为原先 二分之一 (1/2) 该方式比较粗暴,2个像素取一个。宽高都减少了,自然内存也降低了。 ------------------------------------------------------------------------------     public static void ljCom(InputStream open){         BitmapFactory.Options options = new BitmapFactory.Options(); //或者 inDensity 搭配 inTargetDensity 使用,算法和 inSampleSize 一样         options.inSampleSize = 2; //设置图片的缩放比例(宽和高) , google推荐用2的倍数: //        Bitmap bitmap = BitmapFactory.decodeFile("app/src/main/assets/wx.png"); //        Bitmap compress = BitmapFactory.decodeFile("app/src/main/assets/wx.png", options);          Bitmap mbitmap = BitmapFactory.decodeStream(open, null, options);          Log.e("双线性采样","----压缩后----》"                 +"n内存大小》"+mbitmap.getByteCount()                 +"n宽度》"+mbitmap.getWidth()                 +"n高度》"+mbitmap.getHeight());      }

    3.2.2 双线性采样(双线性内插值算法)

    双线性采样(Bilinear Resampling)在 Android 中的使用方式一般有两种:
    Bitmap bitmap = BitmapFactory.decodeFile("xxx.png"); Bitmap compress = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/2, bitmap.getHeight()/2, true); 或者直接使用 matrix 进行缩放  Bitmap bitmap = BitmapFactory.decodeFile("xxx.png"); Matrix matrix = new Matrix(); matrix.setScale(0.5f, 0.5f); bm = Bitmap.createBitmap(bitmap, 0, 0, bit.getWidth(), bit.getHeight(), matrix, true);
    看源码可以知道createScaledBitmap函数最终也是使用第二种方式的matrix进行缩放,双线性采样使用的是双线性內插值算法,这个算法不像邻近点插值算法一样,直接粗暴的选择一个像素,而是参考了源像素相应位置周围2x2个点的值,根据相对位置取对应的权重,经过计算之后得到目标图像。
    双线性内插值算法在图像的缩放处理中具有抗锯齿功能, 是最简单和常见的图像缩放算法,当对相邻2x2个像素点采用双线性內插值算法时,所得表面在邻域处是吻合的,但斜率不吻合,并且双线性内插值算法的平滑作用可能使得图像的细节产生退化,这种现象在上采样时尤其明显。
    /**  * 双线性采样  * */ public static void sxxCon(Bitmap bitmap){     Log.e("双线性采样","----压缩前----》"             +"n内存大小》"+bitmap.getByteCount()             +"n原图宽度》"+bitmap.getWidth()             +"n原图高度》"+bitmap.getHeight());     //等比例缩放压缩     Bitmap mbitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/2, bitmap.getHeight()/2, true);     Log.e("双线性采样","----压缩后----》"             +"n内存大小》"+mbitmap.getByteCount()             +"n宽度》"+mbitmap.getWidth()             +"n高度》"+mbitmap.getHeight()); } /**  * 双线性采样  * */ public static void sxxCon2(Context context,Bitmap bitmap){     Log.e("双线性采样","----压缩前----》"             +"n内存大小》"+bitmap.getByteCount()             +"n宽度》"+bitmap.getWidth()             +"n高度》"+bitmap.getHeight());     Matrix matrix = new Matrix();     matrix.setScale(0.6f, 0.6f);     Bitmap mbitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);     Log.e("双线性采样","----压缩后----》n"             +"n内存大小》"+mbitmap.getByteCount()             +"n宽度》"+mbitmap.getWidth()             +"n高度》"+mbitmap.getHeight());     saveBitmapAsPng2(context,mbitmap,"aaq"); }

    3.2.3 双线性采样对比邻近采样的优势在于:

    它的系数可以是小数,而不一定是整数,在某些压缩限制下,效果尤为明显
    处理文字比较多的图片在展示效果上的差别,双线性采样效果要更好

    4、微信和鲁班压缩对比