背景
前端项目中往往会有一个存放静态资源的目录,其中一些图片(比如svg)可能会被webpack打包到js文件中。
然而在多人团队协作场景,随着项目的不断迭代,这个图片资源库会逐渐臃肿,会出现图片被重复引入的问题,同一图片在项目下存在多份,会存在以下问题:
- 项目体积变大,部分图片被重复打包到js文件中;
- 同一图片被多次定义(有不同的名字),一旦图片修改需要在多个地方同时修改,不方便维护;
- 开发者难以判断项目中是否已经存在这张图片;
- 静态资源没有大小限制,一不留神就提交了大尺寸图片。
所以我们可以使用一个脚本自动扫描:
- 一键扫描出项目中的重复文件;
- commit卡点,重复图片禁止提交,大尺寸图片禁止提交;
- 降低开发者的维护心智。
方法
现在项目中重复图片有两种场景
- 完全一样的图片,指文件的所有内容(rgba像素信息 或 svg代码 )都完全相同;
- 长得一样 或 差不多,但是内容有差别 或 完全不同。
使用md5摘要文件内容的方法不可行
所以思路是将图片逐个进行像素级对比。
-
如果是svg,先转换为png图片;
-
将图片resize到
size*size( = 20 ),用于降低计算复杂度,同时可以统一图片尺寸,便于比较; -
(可选)转为灰度图,可以降低通道数,减少计算复杂度。但是会损失颜色信息,可选;
-
两个图片矩阵计算L1误差(其实就是相减)
- 由于node对GPU支持不友好,同时存在配置门槛,所以用 矩阵遍历相减 代替 并行矩阵运算。
-
当图片差异超过一定阈值时,就判断为重复
- 有像素差异超过
distance( = 10)的时候,认为这个像素点有差异; - 当有差异的数量超过一定比例
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;
}
其它
-
为什么不用深度学习?
有点杀鸡用牛刀的感觉,而且目前的算法速度大约在3-5s内,准确度也可以接受。
-
参数怎么选,比如distance、threshold、size
distance: 单个像素位置超过多少时,会被认为不一致
默认10
threshold: 像素差异超过百分之多少时,认为两张图片差异不一致
默认0.9
size: 图片在被比较前会被缩放到什么尺寸
默认20
这些参数可以根据实际使用体验进行自定义调整:
- 当感觉过于灵敏时,把很多不相同的当作了重复文件时:
可以将distance调小一点,threshold和size调大一点
- 当感觉过于迟钝时,把重复文件没有检测出来时:
可以将distance调大一点,threshold和size调小一点
使用
测试
在你的静态资源目录中,随便复制一张静态图片(你可以对图片稍加修改),然后将图片加入staged列表,并且提交(或者直接执行命令),查看是否报错。