フォルダ内の画像ファイルを一括でwebpに変換するNode.js+TypeScriptサンプル

フォルダ内の画像を一括でWebpに変換したいと思いました。

さらに変換する際に

  • pngファイル → 可逆圧縮なwebp
  • jpegファイル → 非可逆圧縮なwebp

というふうにjpgとpngでそれぞれ「可逆圧縮」と「非可逆圧縮」を切り替えたいと思いました。

 

ですが、これを実現するツールが見つからなかったので自分でつくりました。

どうせなのでブログ記事のネタにしたろと思って、ソースも載せてみます。

 

index.ts

 import { searchFiles } from "./serachFiles";
import { promises as fs } from "fs";
import sharp, { WebpOptions } from "sharp";

(async () => {
  const SERACH_TARGET_DIR = "./input";
  const imageFileInfos = await searchFiles(SERACH_TARGET_DIR);
  for (const { dirName, fileName, ext } of imageFileInfos) {
    const webpOption: WebpOptions = {};
    switch (ext) {
      case ".jpeg":
      case ".jpg":
        webpOption.lossless = false;
        break;
      case ".png":
        webpOption.nearLossless = true;
        break;
    }
    await sharp(`./${dirName}/${fileName}`)
      .webp(webpOption)
      .toFile(`./${dirName}/${fileName.split(".")[0]}.webp`);
    await fs.unlink(`./${dirName}/${fileName}`) //圧縮前の画像を削除したくない場合はコメントアウトする
  }
})();

 

searchFiles .ts

import { promises as fs } from "fs";
import path from "path";

type SerachFile = {
  dirName: string;
  fileName: string;
  ext: string;
};
const SERACH_EXT_LIST = [".jpg", ".jpeg", ".png"];
export const searchFiles = async (dirPath: string): Promise<SerachFile[]> => {
  const allDirents = await fs.readdir(dirPath, { withFileTypes: true });

  const files: SerachFile[] = [];
  for (const dirent of allDirents) {
    if (dirent.isDirectory()) {
      const newDirPath = path.join(dirPath, dirent.name);
      const newFiles: SerachFile[] = await searchFiles(newDirPath);
      files.push(...newFiles);
    }
    if (dirent.isFile() && SERACH_EXT_LIST.includes(path.extname(dirent.name))) {
      files.push({
        dirName: path.join(dirPath),
        fileName: dirent.name,
        ext: path.extname(dirent.name),
      });
    }
  }
  return files;
};

 

GitHubにもアップしてます。(README.mdに使い方を書いてます)

penpendayo/webp-nodejs

ソースの詳しい解説はしないのですが、このソースを書くにあたって考えた点などを書いてみます。

sharp を使った理由

理由は以下のような感じです。

  • Node.jsの画像処理ライブラリの中で一番情報が多そうだったから
  • TypeScriptの型情報があったから

 

自分のUsecase的にいうと、Google製のSquooshのライブラリ版である「@squoosh/lib」のほうが合っていました。

というのも「@squoosh/lib」のほうだと可逆圧縮のときに「色数」も選択できるんですよね。(GUI版でいうところの「Reduce Colors」のことです)

なので更に高圧縮を実現できます。

ただ、今回は「TypeScriptでなにか作ってみたいな~」な気分だったのですが、「@squoosh/lib」にはTypeScriptの型情報がないので、sharpのほうで妥協した感じです。

nearLosslessというオプション

Webpには「nearLossless」というオプションがあります。

これ自分は知らなかったのですが「限りなく可逆圧縮に近い画質だけど非可逆圧縮だよ!」にできるオプションらしいです。

なので上のソースでは、pngのほうの圧縮も、厳密にいうと非可逆圧縮にしてます。

 

おわり

Node.js
スポンサーリンク
この記事を書いた人
penpen

1991生まれ。WEBエンジニア。

技術スタック:TypeScript/Next.js/Express/Docker/AWS

フォローする
フォローする

コメント

タイトルとURLをコピーしました