sharp vs canvas vs jimp vs gm
Node.js 環境における画像処理ライブラリの選定
sharpcanvasjimpgm類似パッケージ:

Node.js 環境における画像処理ライブラリの選定

canvasgmjimpsharp は、Node.js 環境で画像の生成、変換、編集を行うための代表的なライブラリです。それぞれアプローチが異なり、sharp は高性能なネイティブバインディングを提供し、canvas はブラウザの Canvas API をサーバーで再現します。jimp は純粋な JavaScript で動作し依存関係が少なく、gm は GraphicsMagick または ImageMagick のシステムコマンドをラップします。プロジェクトの要件(速度、機能、デプロイ環境)に応じて適切な選択が必要です。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
sharp37,990,62332,044534 kB1214ヶ月前Apache-2.0
canvas4,751,57910,657469 kB4572ヶ月前MIT
jimp2,200,305-4.03 MB-2年前MIT
gm586,9476,980121 kB3681年前MIT

Node.js 画像処理ライブラリ完全比較:canvas vs gm vs jimp vs sharp

Node.js で画像処理を行う場合、canvasgmjimpsharp の 4 つが主要な選択肢となります。これらはすべて「画像を扱う」という点では共通していますが、内部アーキテクチャ、パフォーマンス、そして得意とするユースケースは大きく異なります。アーキテクトとして、単に「画像をリサイズしたい」という要件だけでなく、デプロイ環境の制約や処理規模を考慮して選定する必要があります。

🏗️ アーキテクチャとインストールの仕組み

ライブラリの内部構造を理解することは、トラブルシューティングやデプロイ設計において重要です。

sharp は、C++ で書かれた画像処理ライブラリ「libvips」のラッパーです。

  • ネイティブモジュールを含むため、インストール時にコンパイルが必要です。
  • 非常に高速ですが、環境によってはビルドツール(Python, Make など)が必要になることがあります。
# sharp のインストール
npm install sharp
# 環境によっては node-gyp によるビルドが走ります

canvas は、Cairo グラフィックスライブラリを使用しています。

  • ブラウザの HTML5 Canvas API を Node.js で実装したものです。
  • システムレベルで Cairo や Pango などの依存関係を必要とするため、Docker 環境などで追加のパッケージインストールが必要になることが多いです。
# canvas のインストール
npm install canvas
# Ubuntu などの場合、libcairo2-dev などのシステムパッケージが必要

jimp は、純粋な JavaScript(TypeScript)で書かれています。

  • ネイティブバインディングを持たないため、コンパイル不要でどこでも動きます。
  • 依存関係が少なく、インストールは簡単ですが、CPU 集約的な処理は JavaScript の速度制限を受けます。
# jimp のインストール
npm install jimp
# ネイティブモジュールのビルドは発生しません

gm は、GraphicsMagick または ImageMagick のコマンドラインツールをラップします。

  • Node.js 自体は処理を行わず、OS のコマンドを呼び出します。
  • 事前にシステムに GraphicsMagick または ImageMagick がインストールされている必要があります。
# gm のインストール
npm install gm
# 別途、OS に graphicsmagick または imagemagick のインストールが必須

⚡ パフォーマンスとメモリ効率

画像処理において、速度とメモリ使用量は直接的なコストに影響します。

sharp は圧倒的に高速です。

  • マルチコア CPU を活用し、ストリーミング処理にも対応しています。
  • 大量の画像を処理するバックエンドシステムでは事実上の標準です。
// sharp: 高速なリサイズと変換
import sharp from 'sharp';

await sharp('input.jpg')
  .resize(800, 600)
  .webp({ quality: 80 })
  .toFile('output.webp');

jimp は小規模な処理には十分ですが、速度は遅いです。

  • 画像サイズが大きくなると、処理時間が指数関数的に増える傾向があります。
  • メモリ使用量も多くなりがちです。
// jimp: 純粋な JS による処理
import Jimp from 'jimp';

const image = await Jimp.read('input.jpg');
await image.resize(800, 600);
await image.writeAsync('output.jpg');

canvas は描画に特化しており、写真処理には向きません。

  • 画像の読み込みや単純な変換よりも、コンテキストへの描画操作がメインです。
  • メモリ上でビットマップを保持するため、大きな画像を扱るとメモリを消費します。
// canvas: 描画コンテキストの使用
import { createCanvas } from 'canvas';

const canvas = createCanvas(800, 600);
const ctx = canvas.getContext('2d');
// 画像を描画して加工
const img = new Image();
img.src = 'input.jpg';
ctx.drawImage(img, 0, 0, 800, 600);

gm は安定していますが、sharp より遅いことが多いです。

  • プロセス生成のオーバーヘッドが発生します。
  • 複雑なパイプラインを組む際、sharp の方がコードが簡潔になります。
// gm: コマンドのラップ
import gm from 'gm';

gm('input.jpg')
  .resize(800, 600)
  .write('output.jpg', (err) => {
    if (err) console.error(err);
  });

🎨 機能比較:描画 vs 加工

「画像をどうしたいか」によって選ぶべきツールが変わります。

1. 写真の加工(リサイズ、圧縮、フォーマット変換)

この用途では sharp が最適です。WebP、AVIF などのモダンなフォーマットへの対応も早く、画質とファイルサイズのバランスを制御しやすいです。

// sharp: フォーマット変換と最適化
await sharp('input.png').avif({ quality: 50 }).toFile('output.avif');

jimp も可能ですが、AVIF などのサポートは限定的か、プラグイン依存になります。

// jimp: 基本的なフォーマット変換
const image = await Jimp.read('input.png');
await image.writeAsync('output.jpg'); // AVIF は標準では非対応の場合あり

2. テキストの描画と図形の合成

canvas が唯一の選択肢です。他のライブラリはテキストレンダリング機能が弱いか、ありません。

// canvas: テキスト描画
ctx.font = '30px Arial';
ctx.fillText('Hello World', 10, 50);
// これを画像として保存
const buffer = canvas.toBuffer('image/png');

sharp では、sharp 単体ではテキスト描画ができず、svg を経由するなどの工夫が必要です。

// sharp: SVG を経由したテキスト描画(工夫が必要)
const svgText = `<svg><text x="10" y="50" font-size="30">Hello</text></svg>`;
await sharp({ text: svgText }).png().toFile('text.png');

3. 複雑なフィルタとエフェクト

gm は ImageMagick の膨大な機能セットにアクセスできるため、特殊なエフェクトが必要な場合に有利です。ただし、その機能の多くは sharpcanvas で代替可能になっています。

// gm: ImageMagick の機能を使用
gm('input.jpg').blur(5).rotate(90).write('output.jpg');

🛠️ エラーハンドリングとストリーミング

プロダクション環境では、ストリーミング処理とエラーハンドリングが重要です。

sharp は Node.js の Stream インターフェースを完全にサポートしています。

  • 巨大なファイルをメモリにロードせずに処理できます。
// sharp: ストリーミング処理
import { pipeline } from 'stream';
import { createReadStream, createWriteStream } from 'fs';

pipeline(
  createReadStream('input.jpg'),
  sharp().resize(800, 600),
  createWriteStream('output.jpg'),
  (err) => { if (err) console.error(err); }
);

jimp は基本的にバッファベースです。

  • 全データをメモリに読み込んでから処理するため、メモリ不足のリスクがあります。
// jimp: バッファ読み込み
const image = await Jimp.read('input.jpg'); // 全量メモリへ

canvas も基本的にメモリ上で操作します。

  • ストリーミング出力は可能ですが、入力側はバッファ読み込みが一般的です。
// canvas: バッファからの読み込み
const img = new Image();
img.src = fs.readFileSync('input.jpg');

📊 選定のまとめ

特徴sharpcanvasjimpgm
速度⚡ 非常に高速🐢 普通🐌 遅い🐢 普通
依存関係🔧 ネイティブ (libvips)🔧 ネイティブ (Cairo)✅ なし (Pure JS)🔧 システム (ImageMagick)
主な用途写真加工、変換描画、テキスト、SVG簡易編集、手軽さ特殊なフィルタ
モダンフォーマット✅ WebP, AVIF, HEIC❌ 基本は PNG, JPEG⚠️ 限定的✅ 対応
テキスト描画⚠️ SVG 経由が必要✅ 標準機能❌ 非対応⚠️ 複雑

💡 結論:どのライブラリを選ぶべきか

新規プロジェクトで画像処理ライブラリを選定する際、以下の基準で決定することをお勧めします。

  1. 写真の最適化や変換が主目的なら sharp パフォーマンス、メモリ効率、サポートフォーマットのすべてにおいて現代的な標準です。AWS Lambda やコンテナ環境でも、レイヤーを適切に管理すれば問題なく動作します。

  2. 動的な画像生成(テキスト合成など)なら canvas ブラウザで Canvas を使った開発経験があれば、サーバー側でも同じ感覚でコードを書けます。OGP 画像の生成や、チャートの画像化に適しています。

  3. 環境制約でネイティブモジュールが使えないなら jimp コンパイル環境が用意できない場合や、処理する画像が小さく、速度を求めない場合に限り有効です。

  4. gm は既存資産の維持以外は避ける 新規採用するメリットは薄く、sharp で大半の機能がカバーできます。

技術選定では「できること」だけでなく「維持できること」が重要です。パフォーマンスとメンテナンス性のバランスが取れている sharp を第一候補とし、描画機能が必要なら canvas を併用するのが、現代の Node.js アプリケーションにおける堅実なアーキテクチャと言えます。

選び方: sharp vs canvas vs jimp vs gm

  • sharp:

    処理速度とメモリ効率が最優先の場合、sharp を選択してください。libvips ベースのアーキテクチャにより、他のライブラリより大幅に高速で、WebP や AVIF などの現代なフォーマットもサポートしています。大規模な画像処理パイプラインや、レスポンス時間が重要な API 構築に適しています。

  • canvas:

    画像の「描画」や「生成」が主な目的の場合、canvas が最適です。ブラウザの Canvas API と互換性があり、テキストの書き込み、図形の描画、SVG のラスタライズなどに強みがあります。チャート生成や動的な画像合成が必要な場合に選定します。

  • jimp:

    ネイティブモジュールのコンパイル問題を避けたい場合や、シンプルな編集機能だけで十分な場合は jimp を検討します。純粋な JavaScript で書かれており、システム依存がありません。ただし、処理速度は遅く、大容量の画像処理には向きません。

  • gm:

    既存のシステムで GraphicsMagick または ImageMagick が既に導入されており、その特定の機能が必要な場合に限り gm を使用します。新規プロジェクトでは、メンテナンス性やパフォーマンスの観点から sharp への移行を推奨します。

sharp のREADME

sharp

sharp logo

The typical use case for this high speed Node-API module is to convert large images in common formats to smaller, web-friendly JPEG, PNG, WebP, GIF and AVIF images of varying dimensions.

It can be used with all JavaScript runtimes that provide support for Node-API v9, including Node.js (^18.17.0 or >= 20.3.0), Deno and Bun.

Resizing an image is typically 4x-5x faster than using the quickest ImageMagick and GraphicsMagick settings due to its use of libvips.

Colour spaces, embedded ICC profiles and alpha transparency channels are all handled correctly. Lanczos resampling ensures quality is not sacrificed for speed.

As well as image resizing, operations such as rotation, extraction, compositing and gamma correction are available.

Most modern macOS, Windows and Linux systems do not require any additional install or runtime dependencies.

Documentation

Visit sharp.pixelplumbing.com for complete installation instructions, API documentation, benchmark tests and changelog.

Examples

npm install sharp
const sharp = require('sharp');

Callback

sharp(inputBuffer)
  .resize(320, 240)
  .toFile('output.webp', (err, info) => { ... });

Promise

sharp('input.jpg')
  .rotate()
  .resize(200)
  .jpeg({ mozjpeg: true })
  .toBuffer()
  .then( data => { ... })
  .catch( err => { ... });

Async/await

const semiTransparentRedPng = await sharp({
  create: {
    width: 48,
    height: 48,
    channels: 4,
    background: { r: 255, g: 0, b: 0, alpha: 0.5 }
  }
})
  .png()
  .toBuffer();

Stream

const roundedCorners = Buffer.from(
  '<svg><rect x="0" y="0" width="200" height="200" rx="50" ry="50"/></svg>'
);

const roundedCornerResizer =
  sharp()
    .resize(200, 200)
    .composite([{
      input: roundedCorners,
      blend: 'dest-in'
    }])
    .png();

readableStream
  .pipe(roundedCornerResizer)
  .pipe(writableStream);

Contributing

A guide for contributors covers reporting bugs, requesting features and submitting code changes.

Licensing

Copyright 2013 Lovell Fuller and others.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.