杜绝重复图片-前端静态资源扫描方案

534 阅读3分钟

太长不看:github.com/ymssx/stati…

背景

前端项目中往往会有一个存放静态资源的目录,其中一些图片(比如svg)可能会被webpack打包到js文件中。

然而在多人团队协作场景,随着项目的不断迭代,这个图片资源库会逐渐臃肿,会出现图片被重复引入的问题,同一图片在项目下存在多份,会存在以下问题:

  • 项目体积变大,部分图片被重复打包到js文件中;
  • 同一图片被多次定义(有不同的名字),一旦图片修改需要在多个地方同时修改,不方便维护;
  • 开发者难以判断项目中是否已经存在这张图片;
  • 静态资源没有大小限制,一不留神就提交了大尺寸图片。

所以我们可以使用一个脚本自动扫描:

  • 一键扫描出项目中的重复文件;
  • commit卡点,重复图片禁止提交,大尺寸图片禁止提交;
  • 降低开发者的维护心智。

方法

现在项目中重复图片有两种场景

  1. 完全一样的图片,指文件的所有内容(rgba像素信息 或 svg代码 )都完全相同;
  2. 长得一样 或 差不多,但是内容有差别 或 完全不同。 使用md5摘要文件内容的方法不可行

所以思路是将图片逐个进行像素级对比。

  1. 如果是svg,先转换为png图片;

  2. 将图片resize到size * size ( = 20 ),用于降低计算复杂度,同时可以统一图片尺寸,便于比较;

  3. (可选)转为灰度图,可以降低通道数,减少计算复杂度。但是会损失颜色信息,可选;

  4. 两个图片矩阵计算L1误差(其实就是相减)

    1. 由于node对GPU支持不友好,同时存在配置门槛,所以用 矩阵遍历相减 代替 并行矩阵运算。
  5. 当图片差异超过一定阈值时,就判断为重复

    1. 有像素差异超过distance( = 10)的时候,认为这个像素点有差异;
    2. 当有差异的数量超过一定比例threshold ( = 0.9 ),认为这两张图片重复。
let count = 0;
for (let i = 0; i < len; i += 1) {
  if (Math.abs(oldView[i] - view[i]) < distance) {
    count += 1;
  }
}

if (count > len * threshold) {
  hasError = true;
}

其它

  1. 为什么不用深度学习?

有点杀鸡用牛刀的感觉,而且目前的算法速度大约在3-5s内,准确度也可以接受。

  1. 参数怎么选,比如distance、threshold、size

distance: 单个像素位置超过多少时,会被认为不一致

默认10

threshold: 像素差异超过百分之多少时,认为两张图片差异不一致

默认0.9

size: 图片在被比较前会被缩放到什么尺寸

默认20

这些参数可以根据实际使用体验进行自定义调整:

  • 当感觉过于灵敏时,把很多不相同的当作了重复文件时:

可以将distance调小一点,threshold和size调大一点

  • 当感觉过于迟钝时,把重复文件没有检测出来时:

可以将distance调大一点,threshold和size调小一点

使用

github.com/ymssx/stati…

测试

在你的静态资源目录中,随便复制一张静态图片(你可以对图片稍加修改),然后将图片加入staged列表,并且提交(或者直接执行命令),查看是否报错。