内容简介:经过多个版本迭代,项目在通常来说,资源文件能在应用体积包中占据考虑到由于项目开发分工的问题,
经过多个版本迭代,项目在 release
配置下的打包体积依旧轻松破百,应用体积过大导致的问题包括:
加班 TEXT
通常来说,资源文件能在应用体积包中占据 1/3
或者更多的体积,相比起代码 (5kb/千行)
的平均占用来说,对图片进行减包是最直接高效的手段,对图片资源的处理方式包括四种:
- 通过请求下载大图
- 使用 工具 压缩图片
- 查找删除重复图片
- 查找复用相似图片
考虑到由于项目开发分工的问题, 方式1
需要推动落地,所以本文不讨论这种处理方式。其他三种都能通过编写脚本实现自动化处理
图片压缩
图片压缩分为 有损压缩
和 无损压缩
两类, 有损压缩
放弃了一部分图片的质量换取更高的压缩比。网上主流的压缩工具有 tinypng
、 pngquant
、 ImageAlpha
和 ImageOptim
等,分别采用了一种或者多种压缩技术完成图片压缩
为什么png能够无损压缩
由于 png
格式的灵活性,同一张图片可以使用多种方式进行表示,不同方式占用的大小不一样。一般的软件会采用效率更高的方式来表示图片,所以这种情况下 png
图片存在巨大的优化空间。通常来说,从 png
文件中能去除的数据包括:
-
iTXt
、tEXt
和zTXt
这些可以存储任意文本的数据区段 -
iCCP
数据区段存储的profile
等等 -
photoshop
导出的png
图片存在大量的额外信息
png
图片有两种类型的数据块,一种是必不可缺的数据块称为 关键数据块
。另一种叫做 辅助数据块
, png
文件格式规范指定的辅助数据块包括:
- 背景颜色数据块
bKGD
- 基色和白色数据块
cHRM
- 图像
γ
数据块gAMA
- 图像直方图数据块
hIST
- 物理像素尺寸数据块
pHYs
- 样本有效位数据块
sBIT
- 文本信息数据块
tEXt
- 图像最后修改时间数据块
tIME
- 图像透明数据块
tRNS
- 压缩文本数据块
zTXt
其中 tEXt
和 zTXt
数据段中存在的数据包括:
关键字 | |
---|---|
Title | 图像名称 |
Author | 图像作者 |
Description | 图像说明 |
Copyright | 版权声明 |
CreationTime | 原图创作时间 |
Software | 创作图像使用的软件 |
Disclaimer | 弃权 |
Warning | 图像内容警告 |
Source | 创作图像使用的设备 |
Comment | 注释信息 |
由上可见,辅助数据块在 png
文件中可能占据了极大的篇幅,正是这些数据块构成了 png
的无损压缩条件
tinypng
tinypng
采用了一种称作 Quantization
的压缩技术,通过合并图片中相似的颜色,将 24bit
的图片文件压缩成 8bit
图片,同时去除图片中不必要的元数据,图片最高能达到 70%
以上的压缩率。截止文章完成之前, tinypng
仅提供了线上压缩功能,暂未提供工具下载
pngquant
根据官方介绍, pngquant
将 24bit
以上的图片转换成 8bit
的保留透明度通道的压缩图片,压缩算法的压缩比非常显著,通常都能减少 70%
的大小。 pngquant
提供了命令行工具来完成解压任务:
pngquant --quality=0-100 imagepath
命令行更多调试参数可以在 官网 参阅
ImageAlpha
ImageAlpha
是一个 macOS
系统下的有损图片压缩工具,内置了 pngquant
、 pngnq-s9
等多个压缩工具,多数情况下通过将图片降至 8bit
来获取高压缩比。由于 ImageAlpha
的可视化界面无法批量处理图片,直接使用提供的命令工具可以实现批量压缩图片:
for file in $(ls $1); do imagepath=$1"/"$file if [ -d imagepath ] then /// 路径为文件夹 else if [[ $file == *.png ]] then beforeSize=`ls -l $imagepath | awk '{print $5}'` /Applications/ImageAlpha.app/Contents/MacOS/pngquant $imagepath afterSize=`ls -l ${imagepath/.png/-fs8.png} | awk '{print $5}'` if [[ $afterSize -lt $beforeSize]] then mv ${imagepath/.png/-fs8.png} $imagepath fi fi fi done
使用 ImageAlpha
需要注意两点:
- 压缩后的图片命名会自动添加
-fs8
后缀,需要使用mv
命令实现替换 - 有损压缩会修改
关键数据块
,可能导致压缩图片尺寸增大,需要过滤
在使用 有损压缩
时需要注意单张 png
图片是可以被多次压缩的,但这会导致图片的清晰度和色彩都受到影响,不建议对图片超过一次以上的 有损压缩
ImageOptim
ImageOptim
是介绍的四种工具中唯一的 无损压缩
,它采用了包括 去除exif信息
、 重新排列像素存储方式
等手段实现图片的压缩。 无损
代表着一张图片被 ImageOptim
压缩后,后续无法再次进行压缩,同时它的压缩比往往比不上其他的 有损压缩
方案,但最大程度上保证了图片的原始清晰度和色彩
for file in $(ls $1); do imagepath=$1"/"$file if [ -d imagepath ] then /// 路径为文件夹 else if [[ $file == *.png ]] then /Applications/ImageOptim.app/Contents/MacOS/ImageOptim $imagepath fi fi done
ImageOptim
同样存在可视化的工具并且支持批量压缩图片
多方案对比
考虑到 ImageAlpha
几乎都是使用 pngquant
作为压缩工具,因此只列出三种压缩工具的对比:
原始尺寸 | 压缩工具 | 压缩后尺寸 | 压缩比 |
---|---|---|---|
319.5KB | tinypng | 120.5KB | 62% |
319.5KB | ImageAlpha-pngquant | 395KB | -24% |
319.5KB | ImageOptim | 252KB | 21% |
测试图片采用 qq
聊天截图生成的 png
, tinypng
压缩率非常高,而 pngquant
的表现不尽人意
删除重复图片
通常来说,出现重复图片的原因包括 模块间需求开发没有打通
或是 缺少统一的图片命名规范
。通过图片 MD5
摘要是识别重复图片的最快方法,以 python
为例,匹配重复图片的代码如下:
md5list = {} for file in files: if os.path.isdir(file.path): continue md5obj = hashlib.md5() fd = open(file.path, 'rb') while True: buff = fd.read(2048) if not buff: break md5obj.update(buff) fd.close() filemd5 = str(md5obj.hexdigest()).lower() if filemd5 in md5list: md5list[filemd5].add(file.path) else: md5list[filemd5] = set([file.path]) for key in md5list: list = md5list[key] if len(list) > 1: print (list)
在遍历中以文件 MD5
字符串作为 key
,维护具备相同 MD5
的图片路径,最后遍历这个 map
查找存在一个以上路径的数组并且输出
寻找相似图片
相似图片在图片内容、色彩上都十分的接近,多数时间可以考虑复用这些图片,但相似图片的问题在于无法通过 MD5
直接匹配。为了确认两个图片是否相似,要使用简单的一个数学公式来帮忙查找:
方差。在概率论和统计学中,一个随机变量的方差描述的是它的离散程度,也就是该变量离其期望值的距离
举个例子,甲同学五次成绩分别是 65, 69, 81, 89, 96
,乙同学五次成绩是 82, 80, 77, 81, 80
,两个人平均成绩都是 80
,但是引入方差公式计算:
甲: ((65-80)^2 + (69-80)^2 + (81-80)^2 + (89-80)^2 + (96-80)^2) / 5 = 136.8 乙: ((82-80)^2 + (80-80)^2 + (77-80)^2 + (81-80)^2 + (80-80)^2) / 5 = 2.8
平均值相同的情况下,方差越大,说明数据偏离期望值的情况越严重。方差越接近的两个随机变量,他们的变化就越加趋同,获取方差代码如下:
def getVariance(nums): variance = 0 average = sum(nums) / len(nums) for num in nums: variance += (num - average) * (num - average) / len(nums) return variance
因此将图片划分成连串的一维数据,以此计算出图片的方差,通过方差匹配可以实现一个简单的图片相似度判断工具,实现前还要注意两点:
RGB
最终将图片转换成一维数据列表的代码如下:
def getAverageList(img): commonlength = 30 img = cv2.resize(img, (commonlength, commonlength), interpolation=cv2.INTER_CUBIC) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) res = [] for idx in range(commonlength): average = sum(gray[idx]) / len(gray[idx]) res.append(average)
将图片转成灰度图后,仍然可能存在 RGB
色值不同但灰度值相同的情况导致判断失准,可以考虑两种方案提高算法的检测准确率:
- 在不修改以灰度值计算方差的方案下,构建以
列平均像素值
为单位的一维列表计算另一个方差,两个方差值一并做判断 - 摒弃灰度值方差方案,每一行分别生成
R
、G
、B
三种色彩平均值的一维列表,计算出三个方差进行匹配检测
效果
经过两轮图片减包处理后,整个项目资源产生的减包量约有 20M
,其中通过文中的三种手段产生的减包量在 6.5M
左右,整体上来看产出还是比较可观的
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。