フォルダ内の画像を一括で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のほうの圧縮も、厳密にいうと非可逆圧縮にしてます。
おわり
コメント