微信32Kb图片压缩方案[微信]
网络上关于如何针对图片进行有效合理的压缩其实已经有很多成熟的解决方案了,我这里要说的是针对微信 32KB
限制的压缩方案,这也是在 SocialSdkLibrary 中采用的,经过了很多细节的测试,当然这可能不是最好的方法,欢迎一起讨论。
假如希望得到一个大小为 maxSize
大小的图片,整个压缩过程分为如下几个步骤:
- 获取图片的宽高,这个很简单使用
options.inJustDecodeBounds
可以实现。 - 利用
bitmap
的宽高,通过w*h < maxSize
为标准大致计算目标图片宽高,这里的计算是不精确的 - 使用近似的目标宽高
decode
目标图片,经过此步之后拿到的bitmap
会稍微大于maxSize
。 - 细节调整,利用
matrix.scale
每次缩小为原来的0.9
,循环逼近目标大小。
计算原始宽高
这里就是最基本的方法,但是因为流程的完整,还是记录下。
1 | public static Size getBitmapSize(String filePath) { |
计算近似宽高
首先说一下为什么要有这一步:
- 为了尽量少的占用内存,我们获取的图片只是用来在打开微信时展现一个缩略图,而实际的图片大小是无法预估的,不能盲目拿到内存中,因此我们要先计算一个大致的尺寸;
- 最后一步中,我们将会采用循环压缩的方式逼近目标大小,先进行这步压缩,也是为了减少最后循环的次数;
这一步骤的目标就是获取到一个稍微大于 32KB
的图片,后面再进行细节微调。
那么接下来如何计算一个合适的宽高,我们简单的这样约束 32kb = w * h
,虽然这样并不完全合理,因为最终 byte[]
的长度和宽高并没有绝对的关系,不过之前也说过了,这步是不精确的,目标是一个大于稍微 32KB
的 bitmap
;
于是可以得到如下关系,为了好理解,就用汉字标识:
1 | 比例(>1) = 较长边 / 较短边 |
经过上面的关系,可以按照比例计算出 较短边
和 较长边
,代码如下,简单看下:
1 | /** |
第一次采样获取目标图片
拿到目标尺寸之后,根据目标尺寸和原始图片尺寸,计算对应的 inSimpleSize
,对图片进行第一次的 decode
。
同样因为这一步不是一个那么精确的操作,因此对于大小比较小的图片(这里定的是 400*400
)就不进行压缩了,怕压的太厉害,其他的就是按照常规的采样获取到一个 bitmap
;
需要注意的是由于图片大小和图片尺寸没有绝对的关系,所以要给一个更高的上限,我们在调用 calculateSize()
使用的不是 32KB
,而是用了他的 5 倍,这样可以保证图片最终稍微大于 32KB
;
1 | /** |
循环逼近目标大小
此时我们拿到了一个大小稍微大于 32KB
的 bitmap
,接下来需要循环压缩该 bitmap
使最终得到 byte[]
小于 32KB
;
这里使用 Matrix
的 setScale()
方法,每次将图片缩小为原来的 0.9
,并且不断检测大小,直到达到标准。
1 | public static byte[] getStaticSizeBitmapByteByBitmap(Bitmap srcBitmap, int maxSize, Bitmap.CompressFormat |
最后
测试图片压缩的结果:
1 | 测试图片大小 14.58M |
可以看到当图片很大时,会造成压缩次数过多,而且出来的图片被压缩的更厉害,而平常更常见的网络图(通常几百K)拍摄图(通常2-4M)可以达到不错的压缩效果。
目前维护的几个项目,求 ✨✨✨✨
- SocialSdk 登录分享功能原生接入
- LightAdapter 轻量级适配器
- ImageEditor 图片处理,裁剪旋转,贴纸涂鸦,滤镜等
- WeexCube Weex 容器方案
- Kotlin 学习系列总结,共计 22 篇
- 本文链接: http://cdevlab.top/article/d5d0a5d2/
- 版权声明: 版权所有,转载请注明出处!