始めるチュートリアル開発者ガイドヘッドレス Chrome を使用して SVG を PNG に変換する

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
package.json
{
  "type": "module",
  "dependencies": {
    "aws-sdk": "^2.1036.0",
    "puppeteer-core": "^10.1.0"
  }
}

Warning

簡単なデモンストレーションの目的で、トリガーのsuffixオプションを使用して .svg 拡張子のファイルのみを処理しています。プロダクション環境では、 ファイル拡張子以外のファイルタイプを区別できるより堅牢な方法を 検討することをお勧めします。

index.mjs
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 イベントトリガーを設定します。

  1. “トリガーを追加” に移動
  2. S3 を選択し、希望のバケットを選択
  3. イベントタイプには “すべてのオブジェクト作成イベント” を選択
  4. プレフィックスまたはサフィックスオプションには希望の値を入力(例: プレフィックスの場合は 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 ファイルを提供し、必要に応じてさらなる変換や最適化を適用できます。

参考資料