こんにちは。今回は、Node.js環境で使える高速な画像処理ライブラリ「sharp」を使って、PNG画像を生成する方法を詳しく紹介していきます。
WebアプリやAPI開発において、サーバーサイドで動的に画像を生成するシーンは意外と多くあります。たとえば次のようなケースです:
- テキスト入りサムネイル画像の自動生成
- OGP(Open Graph Protocol)画像のダイナミック生成
- QRコードやバーコードを画像として出力
- PDFからページごとに画像化する処理の一環
こうした場面で「sharp」は非常に頼れる存在です。この記事では、sharpでPNG画像を生成・加工し、ファイルとして保存するまでの具体的な流れを解説します。
sharpとは?
sharpは、Node.js上で使える高性能な画像処理ライブラリです。特徴としては:
- C++ベースのlibvipsを利用しているため、非常に高速かつ省メモリ
- JPEG、PNG、WebP、AVIF、TIFFなど多くの画像フォーマットをサポート
- リサイズ、トリミング、回転、フォーマット変換、合成など多彩な機能
- Promiseベースで非同期処理に対応
npmで簡単に導入でき、バックエンド処理だけでなく、静的サイトジェネレータやバッチ処理でも重宝します。
npm install sharp
sharpでPNG画像を生成する基本コード
まず、シンプルに「空のPNG画像を作成する」コードから見てみましょう。
const sharp = require('sharp'); // 透明な400x300のPNG画像を生成 sharp({ create: { width: 400, height: 300, channels: 4, background: { r: 255, g: 255, b: 255, alpha: 0 } // 完全に透明 } }) .png() .toFile('output.png') .then(() => { console.log('PNG画像が生成されました'); }) .catch(err => { console.error('エラー:', err); });
このように、create
オプションで空の画像を定義し、それを.png()
で出力しています。背景色をalpha: 1
にすれば白背景になります。
テキストや画像を合成してサムネイル画像を生成する
もっと実用的な例として、画像上にテキストや他の画像を合成してOGP画像のようなものを生成してみます。
1. ベース画像の作成
const sharp = require('sharp'); const width = 800; const height = 418; const background = { create: { width, height, channels: 4, background: '#282c34' } }; const base = sharp(background).png();
2.テキストの画像を作成(SVG形式で)
const titleSvg = ` <svg width="${width}" height="${height}"> <style> .title { fill: white; font-size: 48px; font-family: sans-serif; } </style> <text x="50" y="100" class="title">SharpでOGP画像を作成してみた!</text> </svg> `; const titleBuffer = Buffer.from(titleSvg);
3.合成してPNG画像として出力
base .composite([ { input: titleBuffer, top: 0, left: 0 } ]) .png() .toFile('ogp.png') .then(() => { console.log('OGP風画像が生成されました'); });
このように、SVGでテキストを記述してからsharpで画像上に合成することで、簡単にダイナミックなサムネイルが作成できます。
PNG圧縮率を変えるオプション:.png({ compressionLevel })
PNGは可逆圧縮形式であり、品質を犠牲にせずにファイルサイズを最適化できます。sharpでは、.png()
に次のようなオプションを渡すことで圧縮率を制御可能です。
.png({ compressionLevel: 9 }) // 最も高圧縮
compressionLevel
は0
〜9
の範囲で指定できます:
0
: 圧縮なし(最速、ファイルサイズ大)9
: 最大圧縮(最も遅いがファイルサイズ小)
たとえばバッチ処理でサイズ最小化を優先する場合はcompressionLevel: 9
を、リアルタイムな生成が必要な場合は5
〜6
程度がおすすめです。
バッファで返す / Base64エンコードでWebに埋め込む
PNG画像をファイルとして保存せず、バッファ形式で得てWebに埋め込みたい場合もあります。
const buffer = await sharp({ create: { width: 200, height: 200, channels: 4, background: '#00f' } }).png({ compressionLevel: 6 }).toBuffer(); const base64 = buffer.toString('base64'); const dataUrl = `data:image/png;base64,${base64}`; console.log(dataUrl); // HTMLのimgタグに埋め込める
生成したPNG画像をdata:image/png;base64,...
形式でHTMLやOGP用メタタグに直接埋め込めるため、CDNを使わず画像を渡したいときに便利です。
使用上の注意点
- 圧縮率を高くすると処理時間が伸びるため、用途に応じたバランスが必要です。
- PNGは可逆形式のため、画質は劣化しませんが、写真用途にはWebPやJPEGの方がサイズが小さく済むケースがあります。
- 圧縮オプション以外にも、alphaチャンネルを含むかどうかでもファイルサイズは大きく変わります。
応用:QRコードやバーコードと連携
「sharp」は画像の合成にも強いため、別のライブラリ(たとえばqrcode
やbwip-js
)と組み合わせて、QRコードを含んだPNG画像を自動生成することもできます。
const QRCode = require('qrcode'); QRCode.toBuffer('https://example.com').then(qrBuffer => { sharp({ create: { width: 500, height: 500, channels: 4, background: '#ffffff' } }) .composite([{ input: qrBuffer, top: 100, left: 100 }]) .png({ compressionLevel: 6 }) .toFile('qr_image.png'); });
こういった自動化処理は、Eコマースやチケットサービスでも活用できますね。
生成した画像を共有するなら:file-binがおすすめ
今回のようにsharpで生成したPNG画像を手軽に共有したいときにおすすめなのが、**Shota Ninomiya氏が開発中のファイル共有サービス「file-bin」**です。
file-binの特徴:
- ゲストユーザーでも最大10MBまでアップロード可能
- ログインユーザーは大容量ファイルも利用可能
- アップロード時にエンドツーエンド暗号化(E2EE)&圧縮を自動実行
- ダウンロードリンクにOGP画像や説明文(メタデータ)を設定可能
「生成したPNGをアップロード → SNSで即共有」という流れがスムーズに行えるため、開発中のツールやプロトタイプ共有にも最適です。
今後のアップデートでは、ダウンロード通知やアクセス制限機能なども追加予定とのことで、セキュリティに配慮しつつ画像を共有したいユーザーには非常に心強いサービスとなりそうです。
ベータ版を公開中です!フィードバックをしてくださる方を募集中です!
まとめ
この記事では、JavaScriptライブラリ「sharp」を使ってPNG画像を生成・加工・出力する一連の流れを解説しました。
sharpのポイント:
- 高速かつ高機能な画像処理ライブラリ
- PNGの背景・テキスト合成・他画像との合成が簡単
.png({ compressionLevel })
で圧縮率を制御できる- ファイル保存、Base64埋め込み、API出力など応用自在
- QRコード・OGP生成にも相性抜群
- 共有はfile-binのような暗号化サービスと連携すると便利
sharpは、サーバーサイドでの画像処理における最強の相棒といっても過言ではありません。特にPNG生成では、透明背景や高圧縮による活用の幅が広がるため、アイデア次第でいろいろな場面に応用できるでしょう。
何か気になる点やsharpの応用例があれば、コメントで教えてください!file-binに関しても、別記事で詳しく取り上げていく予定です。
コメントを残す