CairoSVG:SVGを適切なサイズのPDF・PNGに書き出す
CairoSVGでSVGを変換し、出力幅や倍率を選びます。DPIと親要素の寸法を理解し、納品前にPNGのピクセル数とPDFのページ寸法を検証します。
目次
ラスター出力にはcairosvg.svg2png()、PDFにはcairosvg.svg2pdf()を使います。PNGの幅を指定するにはoutput_width、比率を保って拡大するにはscaleを使います。parent_widthは、パーセント指定の寸法を算出するコンテナーを提供します。dpiはピクセルと物理単位の関係を制御するため、変更するとPNGとPDFのサイズに異なる影響を与える場合があります。
以下の例では、小さなSVGのエンブレムを使い、各設定で生成されるファイルを確認します。ロゴの書き出しを自動化するデザイナーや、文書用の画像を準備する開発者に適しています。CairoSVGは既存のSVG内容を描画します。PNGのロゴを編集可能なパスへトレースする機能ではありません。
自己完結したSVGから始める
この例はPython 3.12.11とCairoSVG 2.9.1で実行しました。プロジェクトの環境に、バージョンを固定した変換ツールをインストールします。
python -m pip install "CairoSVG==2.9.1"CairoSVGには、ネイティブのCairoライブラリも必要です。インストールやインポートが失敗する場合は、インストールのドキュメントにあるOS別の説明に従ってください。
3本のパスで作った次の独自エンブレムをemblem.svgとして保存します。四角い開口部は塗りの規則の欠落を見つけやすくし、細い棒は細部の確認点になります。手書きのデモ画像であり、PerfectVectorで変換したものではありません。
<svg xmlns="http://www.w3.org/2000/svg"
width="240" height="120" viewBox="0 0 240 120">
<path fill="#176b63" fill-rule="evenodd"
d="M20 100 V20 H100 V100 Z M40 40 V80 H80 V40 Z"/>
<path fill="#e5a43a" d="M110 100 L160 20 L210 100 Z"/>
<path fill="#24435d" d="M220 20 H230 V100 H220 Z"/>
</svg>ルートの寸法は出力ビューポートを表し、viewBoxは画像内部の座標矩形を表します。ここでは両方とも縦横比が2:1です。自分のロゴに例を合わせる場合も、この関係を意図して設定してください。
1つのマスターを必要なサイズで書き出す
SVGの横にexport_emblem.pyとして保存し、python export_emblem.pyを実行します。
import cairosvg
cairosvg.svg2png(
url="emblem.svg",
write_to="emblem-480.png",
output_width=480,
)
cairosvg.svg2pdf(
url="emblem.svg",
write_to="emblem.pdf",
)今回のPNGは480 × 240ピクセルでした。PDFのページは180 × 90ポイントで、2.5 × 1.25インチに相当しました。これは用意した素材の測定結果であり、どのSVGでも同じ寸法になるわけではありません。
コマンドラインでの同等の操作は次のとおりです。
cairosvg emblem.svg --output-width 480 -o emblem-480.png
cairosvg emblem.svg -o emblem.pdfCairoSVGのAPIとコマンドラインのリファレンスでは、urlによる入力ファイル名、bytestringによるSVGのバイト列、write_toによるファイル出力を説明しています。CLIでは出力ファイル名の拡張子が形式を選びます。

問題に合った設定を選ぶ
似た名前のオプションは、それぞれ異なる問題に対応します。CairoSVGのサイズ指定リファレンスでは、親コンテナーと要求する出力寸法を区別しています。
| 要件 | Pythonのオプション | CLIのオプション | 確認点 |
|---|---|---|---|
| PNGの幅を正確に480ピクセルにする | output_width=480 | --output-width 480 | 高さと画像の比率 |
| 算出された出力寸法を2倍にする | scale=2 | --scale 2 | 両方の寸法が2倍か |
| パーセントで指定したルートの幅や高さを算出する | parent_width, parent_height | --width, --height | 指定したコンテナーに対する割合 |
| インチなどの物理単位を解釈する | dpi | --dpi | PNGのピクセル寸法とPDFの実寸を別々に確認 |
ピクセル寸法の元データで、各オプションを独立して実行しました。
| 設定 | PNGの寸法 | PDFのページ寸法 |
|---|---|---|
| 既定値 | 240 × 120 px | 180 × 90 pt |
output_width=480 | 480 × 240 px | 360 × 180 pt |
scale=2 | 480 × 240 px | 360 × 180 pt |
dpi=192 | 240 × 120 px | 90 × 45 pt |
最後の行が注意点です。DPIを2倍にしても、このピクセル寸法のSVGではPNGのピクセル数は増えませんでした。PDFでは、同じピクセル寸法がより小さな実寸になりました。納品要件がピクセル数の場合は、出力寸法を使ってください。
両方の出力寸法を指定するとキャンバスの矩形が決まりますが、ロゴが隙間なく詰まるとは限りません。SVGの縦横比の規則やviewBox内の空白も影響します。元の比率を保ちたい場合は、1つの出力寸法から始め、結果を確認してください。
パーセント寸法には親の寸法が必要
ルートにwidth="50%" height="50%"を使った素材のコピーでは、次の呼び出しで960 × 480ピクセルの親を指定します。
cairosvg.svg2png(
url="emblem-percent.svg",
parent_width=960,
parent_height=480,
write_to="emblem-percent.png",
)出力は480 × 240ピクセルとなり、親の幅と高さの半分でした。これが、parent_width=480とoutput_width=480を置き換えられない理由です。
SVGのサイズが未定義だとCairoSVGが報告する場合は、まずルートの寸法を確認します。用途に合う正の寸法を文書に与えるか、パーセント指定が親に依存する場合は親の寸法を指定します。ブラウザーでたまたま大きく表示されたことから、意図したページサイズを推測しないでください。
物理寸法では挙動が異なる
元のルートをwidth="2.5in" height="1.25in"に変更し、viewBoxを保持します。テストでは、dpi=96で240 × 120のPNG、dpi=192で480 × 240のPNGが生成されました。PDFはどちらも180 × 90ポイントのままでした。
ここでは元データが実寸を定義しているため、1インチあたりのピクセル数を増やすと、PDFの物理ページサイズを保持しながらラスターの解像度が上がります。同じ原理で、意図して作成したページにミリメートルやインチを使えます。ピクセル数が大きいからA4やレターサイズになると想定せず、書き出したPDFのページボックスを確認します。
文字、余白、複数の要素があるレポート内へロゴを配置する場合は、文書レイアウトの工程を使います。ReportLabのSVG配置ガイドではPDFを直接構築する方法を説明し、WeasyPrintのリソースとサイズの確認ではHTML文書を扱っています。
ベクターのまま残った部分も含めて書き出しを検証する
PillowでPNGのヘッダーを読み、pypdf 6.10.0でPDFのページボックスとコンテンツストリームを読みました。ピクセル寸法の元データから作った4つのPDFは、すべて描画パスの操作を含み、ページ画像はゼロでした。これは、画像を含まないこの単純な素材でベクター形状が保持されたことを確認するものです。任意のSVGの完全な再現性を証明するものではありません。
自分の出力寸法を確認するには、同じ環境へpillowとpypdfをインストールし、次を実行します。
from PIL import Image
from pypdf import PdfReader
with Image.open("emblem-480.png") as image:
print("PNG pixels:", image.size)
page = PdfReader("emblem.pdf").pages[0]
print("PDF points:", float(page.mediabox.width),
float(page.mediabox.height))
print("Page images:", len(page.images))PageObjectリファレンスではmediaboxとimagesを説明しています。画像数は役立つ診断情報ですが、すべての形状、フォント、効果が正しく残ったことは証明できません。
納品前に、次を確認します。
- PNGとPDFを開き、SVGとエンブレムを比較します。開口部、三角形、棒、余白を確認します。
- PNGのピクセル寸法とPDFの実寸を独立して検証します。
- 細い隙間や小さな細部も含め、実際に使うサイズで画像を確認します。
- 元のSVGを保持し、画像の変更や変換ツールの更新後に、これらの確認をやり直します。
CairoSVGのSVG対応ページでは、可能な場合にベクター出力を保持すると説明しています。埋め込まれたラスター画像は、ラスターのままです。SVGの入れ物にPNGが入っている場合は、埋め込み画像の診断で書き出し前に確認できます。
CairoSVGは静的なレンダラーです。アニメーション、スクリプト、高度なテキストレイアウト、多くのフィルターは対応する手順の範囲外です。ドキュメントにある対応フィルターはfeOffset、feBlend、feFloodだけです。他の効果に依存する画像は、結果を慎重に比較するか、それらの機能に対応したアプリから書き出します。変換呼び出しが成功しただけでは十分ではありません。
元データに必要な場合だけベクターマスターを復元する
ロゴがPNGやJPGでしか残っていない場合は、CairoSVGで書き出す前段階として、PerfectVectorでラスターをSVGへ変換できます。エディターで復元した形状、小さな開口部、ブランドの文字を確認し、自己完結したSVGのマスターを保存します。ロゴのベクター化手順では、その確認を説明しています。
編集可能なSVGがすでにあれば、直接書き出しに進めます。PNGに変換して再びトレースすると、有用な元の形状が失われます。写真は、意図する内容がラスターなら、そのままラスター画像として保持できます。
ラスターしかないロゴでは、PerfectVectorで自分の画像を試し、SVGの輪郭と開口部を確認してから、CairoSVGの出力のピクセル寸法と物理ページサイズを両方検証してください。
よくある質問
DPIを変えてもPNGのサイズが同じなのはなぜですか? SVGのルートがピクセル寸法なら、DPIを変えてもPNGのピクセル数が変わるとは限りません。この例では、240 × 120ピクセルのSVGは192 DPIでも同じサイズでした。出力ピクセル数を増やすにはoutput_widthまたはscaleを使います。
parent widthはoutput widthと同じですか? いいえ。parent_widthはパーセント寸法を算出するコンテナーを提供し、output_widthは最終出力幅を要求します。この例では、ルートの幅が50%でparent_widthが960の場合、480ピクセルと算出されました。
CairoSVGは必ず完全なベクターPDFを作りますか? いいえ。CairoSVGは可能な場合にベクター出力を保持しますが、SVGにラスター画像や非対応の機能が含まれる場合があります。拡張子を証拠とせず、PDFの内容と見た目を確認してください。
参考資料
- CairoSVGドキュメント — インストール、変換API、サイズ制御、描画の制限を説明しています。
- CairoSVGのSVG 1.1対応 — ベクター保持、埋め込み画像、非対応の機能を説明しています。
- pypdf PageObjectリファレンス — PDF確認に使うページボックスと画像のインターフェースを説明しています。

