鲁班压缩原理(鲁班压缩算法讲解)

BATcoder技术群,让一部分人先进大厂

前华为面试官、独角兽公司技术总监。

想要加入BATcoder技术群,公号回复BAT即可。

https://blog.csdn.net/weixin_44005563

前言最近在研究图片压缩原理,看了大量资料,从上层尺寸压缩、质量压缩原理到下层的哈夫曼压缩,走成华大道,然后去二仙桥,全看了个遍,今天就来总结总结,做个技术分享,下面的内容可能会颠覆你对图片压缩的认知。图片基础知识首先带着几个疑问来看这一小节:1、位深和色深有什么区别,他们是一个东西吗?2、为什么Bitmap不能直接保存,Bitmap和PNG、JPG到底是什么关系?3、图片占用的内存大小公式:图片分辨率 * 每个像素点大小,这种说法正确吗?4、为什么有时候同一个 app,app >内的同个界面上的同张图片,但在不同设备上所耗内存却不一样?5、同一张图片,在界面上显示的控件大小不同时,它的内存大小也会跟随着改变吗?ARGB介绍ARGB颜色模型:最常见的颜色模型,设备相关,四种通道,取值均为[0,255],即转化成二进制位0000 0000 ~ 1111 1111。A:Alpha (透明度) R:Red (红) G:Green (绿) B:Blue (蓝)Bitmap概念Bitmap对象本质是一张图片的内容在手机内存中的表达形式。它将图片的内容看做是由存储数据的有限个像素点组成;每个像素点存储该像素点位置的ARGB值。每个像素点的ARGB值确定下来,这张图片的内容就相应地确定下来了。色彩模式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种颜色。位深与色深在windows上查看一张图片的信息会发现有位深度这个东西,但没看到有色深:

鲁班压缩原理(鲁班压缩算法讲解)这里介绍一下位深与色深的概念:色深:顾名思义,就是”色彩的深度”,指是每一个像素点用多少bit来存储ARGB值,属于图片自身的一种属性。色深可以用来衡量一张图片的色彩处理能力(即色彩丰富程度)。典型的色深是8-bit、16-bit、24-bit和32-bit等。上述的Bitmap.Config参数的值指的就是色深。比如ARGB_8888方式的色深为32位,RGB_565方式的色深是16位。色深是数字图像参数。位深度是指在记录数字图像的颜色时,计算机实际上是用每个像素需要的二进制数值位数来表示的。当这些数据按照一定的编排方式被记录在计算机中,就构成了一个数字图像的计算机文件。每一个像素在计算机中所使用的这种位数就是“位深度”,位深是物理硬件参数,主要用来存储。举个例子:某张图片100像素*100像素 色深32位(ARGB_8888),保存时位深度为24位,那么:

该图片在内存中所占大小为:100 * 100 * (32 / 8) Byte在文件中所占大小为 100 * 100 * ( 24/ 8 ) * 压缩率 Byte

[1, 0.5625) 即图片处于 [1:1 ~ 9:16) 比例范围内[0.5625, 0.5) 即图片处于 [9:16 ~ 1:2) 比例范围内[0.5, 0) 即图片处于 [1:2 ~ 1:∞) 比例范围内

简单解释一下:获取图片的比例系数,如果在区间 [1, 0.5625) 中即图片处于 [1:1 ~ 9:16)比例范围内,比例以此类推,如果这个系数小于0.5,那么就给它放到 [1:2 ~ 1:∞)比例范围内。判断图片最长边是否过边界值。

[1, 0.5625) 边界值为:1664 * n(n=1), 4990 * n(n=2), 1280 * pow(2, n-1)(n≥3)[0.5625, 0.5) 边界值为:1280 * pow(2, n-1)(n≥1)[0.5, 0) 边界值为:1280 * pow(2, n-1)(n≥1)

width / pow(2, n-1)height/ pow(2, n-1)

步骤三:这个感觉没什么用,还是计算压缩图片实际边长值,人家也说了,以第2步计算结果为准,其实就是晃你的,乍一看 ,这么多步骤,哈哈哈哈,唬你呢!计算压缩图片的实际文件大小,以第2、3步结果为准,图片比例越大则文件越大。size = (newW * newH) / (width * height) * m;

[1, 0.5625) 则 width & height 对应 1664,4990,1280 * n(n≥3),m 对应 150,300,300;[0.5625, 0.5) 则 width = 1440,height = 2560, m = 200;[0.5, 0) 则 width = 1280,height = 1280 / scale,m = 500;注:scale为比例值

步骤四:这个感觉也没什么用,这个m应该是压缩比。但整个过程就是验证一下压缩完之后,size的大小,是否超过了你的预期,如果超过了你的预期,将进行重复压缩。判断第4步的size是否过小。

[1, 0.5625) 则最小 size 对应 60,60,100[0.5625, 0.5) 则最小 size 都为 100[0.5, 0) 则最小 size 都为 100

解码前没有对内存做出预判质量压缩写死 60没有提供图片输出格式选择不支持多文件合理并行压缩,输出顺序和压缩顺序不能保证一致检测文件格式和图像的角度多次重复创建InputStream,增加不必要开销,增加OOM风险可能出现内存泄漏,需要自己合理处理生命周期图片要是有大小限制,只能进行重复压缩原框架用的还是RxJava1.0

技术改造方案

解码前利用获取的图片宽高对内存占用做出计算,超出内存的使用RGB-565尝试解码针对质量压缩的时候,提供传入质量系数的接口对图片输出支持多种格式,不局限于File利用协程来实现异步压缩和并行压缩任务,可以在合适时机取消协程来终止任务参考Glide对字节数组的复用,以及InputStream的mark()、reset()来优化重复打开开销利用LiveData来实现监听,自动注销监听。压缩前计算好大小,逆向推导出尺寸压缩系数和质量压缩系数现在已经出了RxJava3和协程,但大多数项目中已经有了线程池,要利用项目中的线程池,而不是导入一个三方库就建一个线程池而造成资源浪费

https://cloud.tencent.com/developer/article/1006307手写JPEG图像处理引擎我们都知道bitmap是在native层被创建的,在Bitmap.cpp文件中,创建的bitmap其实是创建了一个SKBitmap的对象,交给了skia引擎去处理。导入jpeglib.h的头文件会需要其他的.h头文件,具体如下:

?? 耗时2年,Android进阶三部曲第三部《Android进阶指北》出版!

?? 『BATcoder』做了多年安卓还没编译过源码?一个视频带你玩转!

?? 『BATcoder』我去!安装Ubuntu还有坑?

?? 重生!进阶三部曲第一部《Android进阶之光》第2版 出版!

发表评论

登录后才能评论