质量监控-图片减包

文章连接html

通过多个版本迭代,项目在release配置下的打包体积依旧轻松破百,应用体积过大致使的问题包括:python

  • 更长的构建时间,换个词就是加班
  • TEXT段体积过大会致使审核失败
  • 用户不肯意下载应用

一般来讲,资源文件能在应用体积包中占据1/3或者更多的体积,相比起代码(5kb/千行)的平均占用来讲,对图片进行减包是最直接高效的手段,对图片资源的处理方式包括四种:算法

  1. 经过请求下载大图
  2. 使用工具压缩图片
  3. 查找删除重复图片
  4. 查找复用类似图片

考虑到因为项目开发分工的问题,方式1须要推进落地,因此本文不讨论这种处理方式。其余三种都能经过编写脚本实现自动化处理数组

图片压缩

图片压缩分为有损压缩无损压缩两类,有损压缩放弃了一部分图片的质量换取更高的压缩比。网上主流的压缩工具备tinypngpngquantImageAlphaImageOptim等,分别采用了一种或者多种压缩技术完成图片压缩app

为何png可以无损压缩

因为png格式的灵活性,同一张图片可使用多种方式进行表示,不一样方式占用的大小不同。通常的软件会采用效率更高的方式来表示图片,因此这种状况下png图片存在巨大的优化空间。一般来讲,从png文件中能去除的数据包括:工具

  • iTXttEXtzTXt这些能够存储任意文本的数据区段
  • iCCP数据区段存储的profile等等
  • photoshop导出的png图片存在大量的额外信息

png图片有两种类型的数据块,一种是必不可缺的数据块称为关键数据块。另外一种叫作辅助数据块png文件格式规范指定的辅助数据块包括:测试

  • 背景颜色数据块bKGD
  • 基色和白色数据块cHRM
  • 图像γ数据块gAMA
  • 图像直方图数据块hIST
  • 物理像素尺寸数据块pHYs
  • 样本有效位数据块sBIT
  • 文本信息数据块tEXt
  • 图像最后修改时间数据块tIME
  • 图像透明数据块tRNS
  • 压缩文本数据块zTXt

其中tEXtzTXt数据段中存在的数据包括:优化

关键字
Title 图像名称
Author 图像做者
Description 图像说明
Copyright 版权声明
CreationTime 原图创做时间
Software 创做图像使用的软件
Disclaimer 弃权
Warning 图像内容警告
Source 创做图像使用的设备
Comment 注释信息

由上可见,辅助数据块在png文件中可能占据了极大的篇幅,正是这些数据块构成了png的无损压缩条件spa

tinypng

tinypng采用了一种称做Quantization的压缩技术,经过合并图片中类似的颜色,将24bit的图片文件压缩成8bit图片,同时去除图片中没必要要的元数据,图片最高能达到70%以上的压缩率。截止文章完成以前,tinypng仅提供了线上压缩功能,暂未提供工具下载命令行

pngquant

根据官方介绍,pngquant24bit以上的图片转换成8bit的保留透明度通道的压缩图片,压缩算法的压缩比很是显著,一般都能减小70%的大小。pngquant提供了命令行工具来完成解压任务:

pngquant --quality=0-100 imagepath
复制代码

命令行更多调试参数能够在官网参阅

ImageAlpha

ImageAlpha是一个macOS系统下的有损图片压缩工具,内置了pngquantpngnq-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须要注意两点:

  1. 压缩后的图片命名会自动添加-fs8后缀,须要使用mv命令实现替换
  2. 有损压缩会修改关键数据块,可能致使压缩图片尺寸增大,须要过滤

在使用有损压缩时须要注意单张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聊天截图生成的pngtinypng压缩率很是高,而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
复制代码

所以将图片划分红连串的一维数据,以此计算出图片的方差,经过方差匹配能够实现一个简单的图片类似度判断工具,实现前还要注意两点:

  1. 图片RGB色彩值会致使方差的计算变得复杂,因此转成灰度图能够下降难度
  2. 不一样尺寸须要缩放到相同尺寸进行计算

最终将图片转换成一维数据列表的代码以下:

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色值不一样但灰度值相同的状况致使判断失准,能够考虑两种方案提升算法的检测准确率:

  1. 在不修改以灰度值计算方差的方案下,构建以列平均像素值为单位的一维列表计算另外一个方差,两个方差值一并作判断
  2. 摒弃灰度值方差方案,每一行分别生成RGB三种色彩平均值的一维列表,计算出三个方差进行匹配检测

效果

通过两轮图片减包处理后,整个项目资源产生的减包量约有20M,其中经过文中的三种手段产生的减包量在6.5M左右,总体上来看产出仍是比较可观的

关注个人公众号获取更新信息
相关文章
相关标签/搜索