先週、同僚が 12 MB の PNG スクリーンショットを Linear のチケットに貼り付けてきました。エディタは一瞬固まり、スマホで確認していたレビュアーはサムネイルが表示されるまで 4 秒待たされる始末。失われた人間の注意は、おそらくこの日 90 秒——ただし、この後そのチケットを開く全員にこれが掛け算されていきます。直すのに必要な作業は 1 分足らず。ただしそれは、社内ダッシュボードのスクリーンショットを見知らぬサーバーに先にアップロードせずに済む場合の話です。

このガイドでは、ブラウザだけで完結する画像圧縮の手順、各フォーマットがそういう振る舞いをする理由、そして経験豊富なエンジニアでもハマる数少ない落とし穴を解説します。対応するツールはこちら:Image Compressor →

圧縮すべきとき、放っておくべきとき

「明らかに圧縮すべき」から「そのままにしておくべき」まで、スペクトルが存在します。

元画像対処理由
Slack / Linear / Notion に貼る 12 MB の PNG スクリーンショットWebP q75 または JPEG q80 に圧縮、長辺 1920 にリサイズスクリーンショットは視覚的に情報量が多いものの、わずかな圧縮には十分耐える。1920 では読者は違いに気付かない
マーケティングページに載せる、DSLR で撮った 24 MP の JPEGWebP q80 に圧縮、長辺 2560 にリサイズLCP の改善効果が大きい。原本は別途アーカイブされている前提
透過ありの 32 KB の PNG ロゴPNG のまま保持、必要なら oxipng を通す32 KB の可逆 PNG を再エンコードすると、かえって肥大化することが多い
200 KB のアニメーション GIFffmpeg で MP4 / WebM に変換する本当に必要なのはフレームを理解した再エンコード
ピクセル単位の精度が必要な QR コードやバーコードPNG のまま保持非可逆圧縮はエッジを潰し、デコーダが読めなくなる
美術館の印刷に使うアーカイブ用写真TIFF / RAW のまま保持アーカイブ用途に非可逆フォーマットは不適切

Image Compressor ツールがきれいにカバーするのは 1〜3 行目です。4〜6 行目は意図的に対象外としています。理由と代替手段については、このガイドの残りで説明していきます。

画像圧縮の背後にあるメンタルモデル

ほぼすべての挙動は、2 つのアイデアで説明がつきます。

非可逆圧縮は知覚情報を捨てている

JPEG と WebP の非可逆モードは、すべてのピクセルを保存しているわけではありません。8×8(JPEG)あるいはそれより大きな(WebP)タイルに分割して周波数領域に変換し、高周波の係数を大胆に量子化することで、人間の視覚がその欠落に気付かないことに賭けるのです。品質 75 は広く知られた実用デフォルトで——web.dev の画像ガイダンス は 70〜85 のレンジに着地し、Next.js の <Image>75 をデフォルト品質として採用しています。60 を下回ると肌や空の階調にバンディングが目立ち始め、90 を超えるとファイルサイズが縮まなくなる一方で、知覚される品質はほとんど変わりません。75 は、得られるメリットの大半をカーブ上で捉えるポイントなのです。

可逆圧縮はバイトを並べ直しているだけ

PNG と WebP の可逆モードはすべてのピクセルを保存します。フィルタ(PNG なら Sub・Up・Average・Paeth、WebP なら予測子+エントロピー符号化)を適用し、その結果を汎用のバイト圧縮器に通します。「品質」のつまみは存在せず、エンコーダがどれだけ頑張るかという軸しかありません。ブラウザはこのつまみを JavaScript に公開していないため、出力に PNG を選ぶと本ツールの品質スライダーが無効化されます。可逆圧縮をさらに突き詰めたい場合は、ローカルで oxipngpngquant を実行してください。

現場の開発者向けフォーマット早見表

フォーマット向いている用途避けるべき用途透過ブラウザ対応
JPEG写真、ヒーロー画像、連続諧調のもの全般エッジのシャープな UI スクリーンショット、透過が必要なものなし全環境
PNGUI スクリーンショット、図、ロゴ、透過オーバーレイ写真(同等の知覚品質では JPEG の 4〜10 倍のサイズになる)あり全環境
WebP新規 Web 案件のデフォルトIE 11 にまだ配信している環境あり(可逆 + 非可逆)すべてのモダンブラウザ。グローバルで約 96%
AVIF同等品質で WebP より小さい。対象ブラウザが対応していれば最適古い Safari(< 16)や古い Android ブラウザありcaniuse 基準で約 92%。ブラウザ側エンコードは依然として部分的
GIFどうしてもインラインで動かしたい極小アニメーション200 KB を超えるもの。モダンな代替手段の方が優秀単色キー全環境
HEICApple 端末のカメラロールクロスプラットフォーム配信ありSafari のみ。Chrome / Firefox ではデコード不可
TIFF / RAWアーカイブ、プロの編集作業Web 配信あり(TIFF)ブラウザはそもそもデコードできない

Image Compressor は上記の最初の 3 つに加え、単一フレームの GIF 入力を扱います。HEIC・TIFF・RAW については、ローカルで exiftoolImageMagick・macOS なら sips を使ってください。重量級の WASM ポートを抱え込まない限り、ブラウザは物理的にこれらのフォーマットをデコードできません。

そもそもなぜブラウザで圧縮するのか

ブラウザでこの作業を行うのが正解になるのは、具体的には次の 3 つの状況です。

プライバシー。 社内ダッシュボード、コードエディタのスクリーンショット、カスタマーサポートのチケット、URL バーにセッション Cookie が写り込んでいる画像——いずれもサードパーティの圧縮サービスに触れさせるべきではありません。最も人気のあるホスト型圧縮サービス(TinyPNG、iLoveIMG、Compressor.io)は、画像を一定期間サーバー上に保存します。これは多くの EU チームにとって GDPR のデータ処理要件と相容れず、ほとんどの大企業の内部データ分類ポリシーとも整合しません。クライアントサイドで圧縮すれば、バイトは自分のマシンから出ていきません。

EXIF 漏洩。 スマートフォンで撮った写真には、GPS 座標、カメラのモデル、タイムスタンプ、ときには端末のシリアル番号まで EXIF に書き込まれています。「とりあえず圧縮するだけ」のつもりでサードパーティに上げると、原理的にはそれらすべてを相手に読まれます。Image Compressor は createImageBitmapimageOrientation: 'from-image' で呼び出して EXIF 由来の回転を反映し、その後 Canvas で再エンコードします。Canvas を経由すると、副作用としてその他のメタデータは剥がれ落ちます。EXIF の中身を細かく確認したい、あるいは特定タグだけ外科的に削除したい場合は、EXIF Metadata Viewer でタグ単位の制御ができます。

オフライン / エアギャップ環境での作業。 機内モードでツールを試してみてください——ちゃんと動きます。閉じた社内ネットワークの中でも ZeroTool が役立つのは、これと同じ性質によるものです。

ツールは実際にどう動いているか

圧縮器全体で約 200 行の素の JavaScript です。注目すべき部分は次のとおり。

// 1. EXIF の向きを反映した状態でデコード
const bitmap = await createImageBitmap(file, {
  imageOrientation: 'from-image',
});

// 2. 目標サイズを計算(アスペクト比は維持)
const { w, h } = scaleToLong(bitmap.width, bitmap.height, maxLongEdge);

// 3. OffscreenCanvas に描画する(DOM canvas より速い)
const canvas = new OffscreenCanvas(w, h);
const ctx = canvas.getContext('2d');

// 4. JPEG 出力ならまず白で塗りつぶす(アルファチャンネルがないため)
if (outMime === 'image/jpeg') {
  ctx.fillStyle = '#ffffff';
  ctx.fillRect(0, 0, w, h);
}
ctx.drawImage(bitmap, 0, 0, w, h);
bitmap.close();

// 5. 指定された品質でエンコード
const blob = await canvas.convertToBlob({
  type: outMime,
  quality: outMime === 'image/png' ? undefined : quality / 100,
});

ここには 3 つの重要な細部があり、ほとんどの実装でつまずくポイントになっています。

imageOrientation: 'from-image' は、2026 年時点で EXIF 回転を尊重するための定石です。古いやり方——<img> 要素の CSS image-orientation: from-image のデフォルト挙動に頼る——は、ブラウザによって対応時期がバラバラ(Chrome 81、Firefox 26、Safari 13.1)で、Image オブジェクトを Canvas に流し込んだ場合のデフォルト挙動もバージョン間で揃っていませんでした。createImageBitmap を使えば、Canvas が読み込む時点で既にビットマップが正しい向きになっており、横向きで撮った写真がデコーダの癖に関係なく正しい向きで出力されます。

JPEG に描く前に白で塗りつぶす のは、Canvas のデフォルト背景が透明で、JPEG はアルファを保存できないからです。fillRect がないと、PNG の透過部分はフレームバッファを RGBA(0,0,0,0) で初期化するブラウザでは、得体の知れない黒っぽいピクセルとして現れます。視覚的に安全なデフォルトは白です。マーケティング素材で別の背景色を使いたい場合は、ソースを PNG で保存し、CSS かコンポジタ側で色を選ぶようにしてください。

PNG で品質スライダーを無効化している のは手抜きではなく、フォーマットの性質を反映しています。PNG の圧縮は可逆で、ブラウザの PNG エンコーダは quality 引数を無視するのです。ブラウザのツールから PNG をさらに小さくしたいなら、非可逆フォーマットに切り替えるか、サイズを縮めるしかありません。ピクセルを保ったままの最適化(oxipng -o maxpngcrushzopflipng)には、デスクトップツールを使ってください。

よくある落とし穴

ツールを 10 分使うと出てくる疑問群です。

「圧縮したら PNG が大きくなった」

原因は 2 つあります。元の PNG が既に強く最適化されている(Apple のスクリーンショットツール、最近の Figma エクスポート、oxipng を通したもの)、あるいは出力フォーマットを PNG から非常に高品質の JPEG に切り替えたか。本ツールは出力が大きくなった場合に赤いパーセンテージを表示するので、悪い方を捨てればよい設計になっています。経験則として、元が 200 KB 未満の PNG スクリーンショットなら PNG のままにしておく、1 MB を超える写真系 JPEG なら品質 75 で再エンコードすればほぼ確実に 60% 削れて、知覚的な劣化は出ません。

「同じ品質値なのに WebP の方が JPEG より見栄えが悪い」

品質の数値はフォーマット間で互換ではありません。品質 75 の WebP は、視覚的にはおおむね品質 82 の JPEG と同等です。ほとんどのエンコーダで WebP のデフォルトが 75 になっているのには理由があります——このフォーマットは、75 の時点で写真への圧縮がほぼ知覚不能になるよう設計されているのです。同じ品質値で WebP と JPEG を比べると、実効的にはより高い設定で走っている JPEG の方が 見た目 には少しクリーンになりがちです。比較するなら同等のファイルサイズで——同じバイト数なら、知覚品質ではほぼ常に WebP が勝ちます。

「品質 75 でスクリーンショットの細い文字がにじむ」

非可逆圧縮はシャープな遷移を嫌います。アンチエイリアスのかかったテキスト、シンタックスハイライトされたコード、細いグリッド線を含む UI スクリーンショットは、写真よりも遥かに早く崩れます。スクリーンショットには PNG 出力を優先し、より小さなファイルが必要なら長辺リサイズで対応してください。どうしても JPEG が必要なら、品質を 90 まで引き上げてファイルサイズの増加は受け入れます。

「圧縮後に EXIF の向き情報が消えている」

仕様どおりの挙動です。Canvas での再エンコードは、副作用としてあらゆるメタデータを剥がします。出力に EXIF を残したい場合は、圧縮後に exiftool のような CLI でタグをコピーし戻してください。Web 配信ではむしろこちらが望ましい挙動です——メタデータが削ぎ落とされた方がサイズは小さく、GPS 座標が漏れる心配もありません。

「200 MB の生スキャンを投入したらタブが固まった」

本ツールは単一ファイルを 50 MB に制限しており、これはモバイルブラウザのメモリ枯渇を防ぐためです。デスクトップなら通常はもっと耐えますが、すべてのビューポートで同じ上限を適用することで失敗モードを予測可能に保っています。これより大きい入力は、まず convert input.tif -resize 4000x output.png(ImageMagick)などで縮小し、中間ファイルをブラウザに持ち込んでください。

他ツールとの比較

ツールバイトの行き先対応フォーマット無料特徴
ZeroTool Image Compressorブラウザ内に留まるJPEG / PNG / WebP / GIF(先頭フレームのみ)無料長辺リサイズ、EXIF の向き処理、1 バッチ内の複数ファイル並列処理
Squooshブラウザ内に留まるJPEG / PNG / WebP / AVIF / OxiPNG / MozJPEG無料エンコーダの詳細つまみが豊富(クロマサブサンプリング、MozJPEG のパス数)。1 ファイルずつの処理
TinyPNGサーバーにアップロードPNG / JPEG / WebP、新プランでは AVIF も無料枠ありサーバーサイドでスクリーンショットに最適化。社内画像を送る前に同社のデータ取り扱いポリシーを要確認
ImageOptim(macOS)マシン内に留まるPNG / JPEG / WebP / SVG / GIF無料可逆チューニングの完成度は群を抜く。デスクトップ専用
cwebp / mozjpeg CLIマシン内に留まるそれぞれ単一フォーマット無料最大限の制御。スクリプト化可能

ざっくりとしたトレードオフはこうです——ブラウザベースのツール(ZeroTool、Squoosh)はバイトを外に出さず、日常的な Web 業務の大部分をカバーします。CLI 系は最後の数%まで絞り出せて、CI でスクリプト化できます。ホスト型サービスは、どうせ公開 Web 上に置く公開マーケティング素材なら手軽です。

コードから同じことを実現する

ブラウザ圧縮を自前のアプリ(ファイルアップロードのウィジェット、ドラッグ&ドロップのアバター、バックエンドに送る前のオンデバイス前処理)に組み込みたい場合の最小 JavaScript はこちらです。

async function compress(file, { format = 'image/webp', quality = 0.75, maxLong = 1920 } = {}) {
  const bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' });
  const scale = Math.min(maxLong / bitmap.width, maxLong / bitmap.height, 1);
  const w = Math.round(bitmap.width * scale);
  const h = Math.round(bitmap.height * scale);

  const canvas = new OffscreenCanvas(w, h);
  const ctx = canvas.getContext('2d');
  if (format === 'image/jpeg') {
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, w, h);
  }
  ctx.drawImage(bitmap, 0, 0, w, h);
  bitmap.close();

  return await canvas.convertToBlob({ type: format, quality });
}

Python のバックエンド / バッチ処理ならこう。

from PIL import Image, ImageOps

def compress(path: str, out: str, quality: int = 75, max_long: int = 1920) -> None:
    img = ImageOps.exif_transpose(Image.open(path))
    img.thumbnail((max_long, max_long), Image.LANCZOS)
    img.save(out, quality=quality, optimize=True)

ImageMagick を使ったシェルパイプラインなら次のとおり。

mogrify -resize 1920x1920\> -quality 75 -strip *.jpg

\> を付けることで 1920 より小さい画像はそのまま残り、-strip で EXIF が削除されます。

さらなる参考資料

ZeroTool 上の関連ツール

  • WebP Converter — UI をシンプルに保ったまま、ピンポイントでフォーマット変換だけしたいとき
  • SVG Optimizer — ベクター画像はラスタ圧縮できないので、SVG ソース自体を最適化する
  • Image to Base64 — 画像をデータ URL としてインライン化する
  • EXIF Metadata Viewer — 圧縮前にメタデータを確認し、必要に応じて外科的に削除する
  • Favicon Generator — 元画像からファビコンを生成したいとき