category icon
2022-04-13
Node.js

【劣化具合の検証】JPEG圧縮を100万回繰り返してみた。

Node.js
16.14.2
sharp
0.30.3
profile
hikaru
Software Developer / DIY'er

結果は 目視で差異はない! でした。左側が JPEG 圧縮『1回』、右側が JPEG 圧縮『100万回』です。目視での差異はなさそうです。
もっと劇的に差が出ると思っていたので、これはこれでビックリです。

検証内容

手作業で 100 万回 JPEG 圧縮を試すのもナチュラルに狂ってて一興かと思いましたが、仮に1秒に1回圧縮できたとしても 228 時間(11日半)かかることが分かったので、今回はプログラムを書きました。(プログラムって素晴らしい)

プログラムは Node.js 環境で動作する TypeScript のコードです。JPEG 圧縮には sharp というライブラリを使用しています。

以下にメインコードを載せます。

main.ts (コード全体)
import * as sharp from "sharp";

async function main() {
  // 元の画像を読み込んでバッファーとして保持
  let buffer = await sharp(`./assets/src.jpg`).toBuffer();

  // 100万回試行する
  for (let i = 0; i < 1000000; i++) {
    // jpeg圧縮を行う
    buffer = await sharp(buffer)
      .jpeg({ quality: 30 })
      .toBuffer();

    // ログ表示
    console.log(`  i="${i}"`);
  }

  // jpeg圧縮を行った画像を保存する
  await sharp(buffer).toFile(`out.jpg`);
}

main();

(1) import 部分

main.ts
import * as sharp from "sharp";

JPEG 圧縮を行うために sharp というパッケージをインポートしています。
sharp は Node.js で様々な画像処理を行うためのライブラリですが、今回はファイルの読み込み・JPEG圧縮・保存処理を任せています。

(2) 画像ファイルの読み込み

main.ts
// 元の画像を読み込んでバッファーとして保持
let buffer = await sharp(`./assets/src.jpg`).toBuffer();

sharp で、元となる画像ファイルを読み込んで、バッファー形式でメモリ上に保持しています。

(3) 100万回 JPEG 圧縮を行う

main.ts
// 100万回試行する
for (let i = 0; i < 1000000; i++) {
  // jpeg圧縮を行う
  buffer = await sharp(buffer)
    .jpeg({ quality: 30 })
    .toBuffer();

  // ログ表示
  console.log(`  i="${i}"`);
}

for 文で 100 万回繰り返しています。.jpeg({ quality: 30 }) で JPEG 品質を指定して圧縮を行い、.toBuffer() でメモリ上で保持できる形式にしています。

プログラムを駆使しても 100 万回の JPEG 圧縮には時間がかかるので、console.log( … ) にて試行回数を表示しています。

(4) 画像ファイルの保存

main.ts
// jpeg圧縮を行った画像を保存する
await sharp(buffer).toFile(`out.jpg`);

100 万回 JPEG 圧縮が終わった画像データをファイルに保存しています。

おわりに

結果は冒頭に記載した通り、目視での差異は見られませんでした。試す前は『圧縮を繰り返すことで、どんどん劣化する』と思っていただけに以外な結果でした。

なお、今回検証のために作成したプログラムは GitHub でも公開してあります。
MIT ライセンスとしていますので、ご自由にお使いください。