フォルダ内の画像を一括で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に使い方を書いてます)
ソースの詳しい解説はしないのですが、このソースを書くにあたって考えた点などを書いてみます。
sharp を使った理由
理由は以下のような感じです。
- Node.jsの画像処理ライブラリの中で一番情報が多そうだったから
- TypeScriptの型情報があったから
自分のUsecase的にいうと、Google製のSquooshのライブラリ版である「@squoosh/lib」のほうが合っていました。
というのも「@squoosh/lib」のほうだと可逆圧縮のときに「色数」も選択できるんですよね。(GUI版でいうところの「Reduce Colors」のことです)
なので更に高圧縮を実現できます。
ただ、今回は「TypeScriptでなにか作ってみたいな~」な気分だったのですが、「@squoosh/lib」にはTypeScriptの型情報がないので、sharpのほうで妥協した感じです。
nearLosslessというオプション
Webpには「nearLossless」というオプションがあります。
これ自分は知らなかったのですが「限りなく可逆圧縮に近い画質だけど非可逆圧縮だよ!」にできるオプションらしいです。
なので上のソースでは、pngのほうの圧縮も、厳密にいうと非可逆圧縮にしてます。
おわり
コメント