Headless Chrome を使用して SVG を PNG に変換する
imgix が SVG ファイルのラスタライズをサポートしている にもかかわらず、内部的に SVG ファイルを PNG に変換する必要がある場合があります。
この記事では、Headless Chrome を使用して SVG を PNG に変換する実装例を示します。
これは、foreignObject
やカスタムフォントを持つ text
要素など、多くの画像処理ライブラリでサポートされていない要素を含む SVG ファイルをラスタライズする必要がある場合や、特定のフレームのみをキャプチャする必要があるアニメーション付きの SVG ファイルがある場合に便利です。
前提条件
他のクラウドプロバイダーでも同様のソリューションを作成することは可能ですが、この例では AWS サービスを使用します。
- SVG および PNG ファイルを保存するための S3 バケット
- AWS Lambda (ランタイム: Node.js 20.x)
- カスタマイズされた Chromium フォーク
- Headless Chrome ブラウザを制御するための Puppeteer-core
実装
ステップ 1: Lambda レイヤーを作成する
Chromium バイナリを含む Lambda レイヤーを作成します。
このステップは、デフォルトの Lambda 環境にはサイズ制限があり、Chromium バイナリを直接アップロードできないため必要です。
git clone --depth=1 https://github.com/Sparticuz/chromium.git && \
cd chromium && \
make chromium.zip && \
mv chromium.zip ..
作成された chromium.zip
ファイルのサイズは約 64MB です。
chromium.zip
ファイルを S3 バケットにアップロードし、Lambda レイヤーを作成します。
ランタイムには最新の Node.js 20.x バージョンを選択します。
ステップ 2: Lambda 関数を作成する
以下の設定で新しい Lambda 関数を作成します。
- ランタイム: Node.js 20.x
- メモリ: 1024MB (必要に応じて調整)
- タイムアウト: 5 分 (必要に応じて調整)
- 前に作成した Lambda レイヤーを追加
- S3 バケットからの読み取りおよび書き込みの必要な権限を Lambda 関数に付与
ステップ 3: Lambda 関数のコードを作成する
ローカルマシンに以下のプロジェクトを作成します。
- package.json
- index.mjs
{
"type": "module",
"dependencies": {
"aws-sdk": "^2.1036.0",
"puppeteer-core": "^10.1.0"
}
}
Warning
簡単なデモンストレーションの目的で、トリガーのsuffixオプションを使用して
.svg
拡張子のファイルのみを処理しています。プロダクション環境では、
ファイル拡張子以外のファイルタイプを区別できるより堅牢な方法を
検討することをお勧めします。
import chromium from "@sparticuz/chromium"
import puppeteer from "puppeteer-core"
import AWS from "aws-sdk"
const s3 = new AWS.S3()
export const handler = async (event) => {
const bucket = event.Records[0].s3.bucket.name
const key = event.Records[0].s3.object.key
// S3 から SVG ファイルをダウンロード
const svgData = await s3.getObject({ Bucket: bucket, Key: key }).promise()
let browser = null
try {
browser = await puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath(),
headless: chromium.headless,
})
const page = await browser.newPage()
await page.setContent(svgData.Body.toString("utf-8"))
await page.waitForSelector("svg")
const screenshot = await page.screenshot({ type: "png" })
const outputKey = key.replace(".svg", ".png")
await s3
.putObject({
Bucket: bucket,
Key: outputKey,
Body: screenshot,
ContentType: "image/png",
})
.promise()
return {
statusCode: 200,
body: `Successfully converted ${key} to PNG and uploaded to ${bucket}/${outputKey}`,
}
} catch (error) {
console.error("Error:", error)
return {
statusCode: 500,
body: `Failed to convert ${key} to PNG: ${error.message}`,
}
} finally {
if (browser !== null) {
await browser.close()
}
}
}
次に、svg-to-png
ディレクトリ内で以下のコマンドを実行し、依存関係をインストールして必要なファイルを zip 化します。
npm install && \
zip -r svg-to-png.zip index.mjs node_modules package.json
svg-to-png.zip
ファイルを Lambda 関数の “コードソース” > “アップロード元” > “zip
ファイル” にアップロードします。
ステップ 4: S3 イベントトリガーを設定する
SVG ファイルを処理するために Lambda 関数に S3 イベントトリガーを設定します。
- “トリガーを追加” に移動
- S3 を選択し、希望のバケットを選択
- イベントタイプには “すべてのオブジェクト作成イベント” を選択
- プレフィックスまたはサフィックスオプションには希望の値を入力(例: プレフィックスの場合は
svgs/
、サフィックスの場合は.svg
)
ステップ 5: Lambda 関数をテストする
SVG ファイルを S3 バケットにアップロードし、変換ステータスのために Lambda 関数のログを確認します。
Chromium を実行しているため、変換プロセスに数秒から数分かかることがあります。
PNG ファイルが同じ S3 バケットに作成され、foreignObject
要素を含む期待されるコンテンツがあることを確認します。
結論
このチュートリアルでは、Headless Chrome と AWS Lambda を使用して SVG ファイルを PNG に変換する方法を示しました。これは、foreignObject
やカスタムフォントを持つ text
要素など、多くの画像処理ライブラリでサポートされていない要素を含む SVG ファイルをラスタライズする必要がある場合に便利です。Headless ブラウザを使用することで、ブラウザのレンダリングエンジンを利用してこれらの複雑な SVG を正確にレンダリングできます。
一度 Lambda 関数を設定すれば、複数の SVG ファイルを同時に処理するソリューションに簡単にスケールアップできます。
その後、imgix を使用して PNG ファイルを提供し、必要に応じてさらなる変換や最適化を適用できます。