国内在线压缩gif都收费?那就自己写一个😏😏😏

昨晚在写文章的时候在录 gif 图,可能动图的元素太多了吧,几秒钟录出来的内容就 30 多 mb 了,在掘金里上传的时候就直接被限制掉了:

国内在线压缩gif都收费?那就自己写一个😏😏😏

emmmm,这样子怎么玩啊,没办法,那就只有找一些在线压缩 gif 的网站呗,随便找了一个看看:

国内在线压缩gif都收费?那就自己写一个😏😏😏

如果我要上传的文件是小于 5MB 的我也不用找你了,脑子一转,突然想到我特么也是一个前端呀,我也可以搞一个啊,那就搞一个呗。

全局安装 gifsicle

Gifsicle 是一个命令行工具,用于创建、编辑、分析和优化 GIF 图像文件。它提供了一系列功能,如优化 GIF 以减小文件大小、创建动画 GIF、提取和插入 GIF 帧、转换不同的图像格式到 GIF,以及更多的高级编辑功能。

Gifsicle 特别适合于需要批量处理 GIF 文件或在脚本中自动化 GIF 处理的情况。用户可以通过命令行界面使用 Gifsicle,这意味着它不提供图形用户界面,但它的功能强大且灵活,适合高级用户和开发人员。

要想使用,你需要再你的电脑上安装 Gifsicle,如果你使用的是 MacOS,可以通过 Homebrew 安装:

brew install gifsicle

如果是其他操作系统的可自行查阅 官网

使用 NodeJs 编写脚本

安装好 Gifsicle 后,我们可以使用 Node 来执行相关的命令,这样就可以避免了我们直接在终端中输入命令了,而且我们还可以对这些文件进行逻辑判断了。

在这里我们使用 child_process 模块在 Node.js 脚本中调用 Gifsicle 命令。

首先是我们应该明白我们的需求,是大于 20MB 的 gif 文件是需要压缩的,而其他是不需要的,首先我们应该编写一个函数来判断文件的大小:

function getFileSizeInMegabytes(filePath) {
  const stats = fs.statSync(filePath);
  return stats.size / (1024 * 1024);
}

知道了文件的大小了之后我们就可以进行压缩的操作了。这里我们采用的是递减的方式对文件进行压缩,而不是一开始就对文件进行压缩,要对文件大小最接近到 20MB 的范围之内。

const { exec } = require("child_process");
const fs = require("fs");

function getFileSizeInMegabytes(filePath) {
  const stats = fs.statSync(filePath);
  return stats.size / (1024 * 1024);
}

function compressGIF(inputGif, outputGif, maxTargetSizeMB) {
  const originalSizeMB = getFileSizeInMegabytes(inputGif);

  // 如果原始文件大小已经小于等于20MB,则不进行压缩
  if (originalSizeMB <= maxTargetSizeMB) {
    console.log("原始文件大小已满足要求,无需压缩。");
    return;
  }

  let scale = 0.95; // 初始缩放比例
  const minScale = 0.1; // 最小缩放比例,防止过度压缩
  let step = 0.05; // 初始调整步长

  const attemptCompression = () => {
    const command = `gifsicle --optimize=3 --scale=${scale.toFixed(
      2
    )} -o ${outputGif} ${inputGif}`;

    exec(command, (error) => {
      if (error) {
        console.error(`执行出错: ${error}`);
        return;
      }

      const outputFileSizeMB = getFileSizeInMegabytes(outputGif);
      console.log(
        `压缩比例: ${scale.toFixed(2)}, 文件大小: ${outputFileSizeMB.toFixed(
          2
        )}MB`
      );

      // 如果压缩后的文件大小仍然大于20MB
      if (outputFileSizeMB > maxTargetSizeMB) {
        scale -= step; // 减小缩放比例
        if (scale < minScale) {
          console.error("已达到最小缩放比例,无法进一步压缩。");
          return;
        }
        attemptCompression(); // 递归调用,继续尝试
      } else {
        console.log("文件大小已降至20MB以下,完成压缩。");
      }
    });
  };

  attemptCompression();
}

// 使用示例
compressGIF("input.gif", "output.gif", 20);

在上面的这段代码当中,使用 child_process 模块中的 exec 函数:用于执行外部命令,这里用于调用 gifsicle 命令行工具。使用 fs 模块:用于访问文件系统,这里用于获取文件大小。

compressGIF 函数是是进行文件压缩的核心逻辑:

  1. 设置初始缩放比例 scale 为 0.95,即首次压缩时将图片尺寸缩减至原始的 95%。为避免压缩导致质量损失过大,设定最小缩放比例 minScale 为 0.1。每次压缩后,通过调整步长 step 值 0.05 来微调缩放比例。

  2. 使用 gifsicle 工具压缩 GIF 时,命令行中设置了优化级别–optimize=3 和缩放比例(使用 scale.toFixed(2)确保两位小数精度)。指定了输出和输入文件的路径。执行命令后,会检验输出文件的体积。如果仍超过目标值,则降低缩放比例后继续尝试。若缩放比例小于设定的最小值,将报错并终止流程。文件体积一旦达标或以下,便输出完成提示,结束压缩过程。

这段代码通过调整缩放比例和递归尝试,直到找到一个合适的缩放比例,使得压缩后的 GIF 文件大小不超过用户指定的最大大小。这种方法允许动态调整压缩强度,以适应不同的文件和压缩需求。

接下来执行终端命令来看看运行效果,如下图所示:

国内在线压缩gif都收费?那就自己写一个😏😏😏

这样我们就可以对 gif 文件的内容进行成功压缩了,如果你还想对文件进行压缩的话,你还可以继续对压缩比例为 0.80 和 0.75 这个区间进行二分查找,查找到最逼近的那个 20MB 的那个比例。

总结

在上面的内容中我们只是简单地使用了 gifsicle 来实现 gif 压缩,它还可以实现更多的功能,如果感兴趣的朋友可以对它进行开发出更多有趣的功能。

原文链接:https://juejin.cn/post/7329353489678909479 作者:Moment

(0)
上一篇 2024年1月30日 上午10:11
下一篇 2024年1月30日 上午10:22

相关推荐

发表回复

登录后才能评论