PerfectVector
著者: Irene Kim2 分で読める

PDFKitのSVG:ベクターロゴをラスター化せず配置する

完全なSVGロゴをPDFKit文書に挿入し、ポイントでサイズを設定します。保存したPDFのパス、開口部、欠けた機能、埋め込み画像を確認します。

目次

Nodeで生成するPDFに完全なSVGロゴを置くには、PDFKitと svg-to-pdfkit を使い、SVGマークアップを SVGtoPDF(doc, svg, x, y, options) に渡します。PDFKitの組み込みの doc.path() は、pathの d 属性値などSVGパスデータを受け付けます。周囲のSVG文書、他の形状、スタイルは読み込みません。

複数の色と中央の開口部があるロゴでは、この違いが重要です。1パスだけコピーすると、図形の一部を落とす場合があります。ロゴ全体をPNGにすればラスターの見た目を保持しますが、必要だったパスのPDF出力は失われます。

このガイドはオリジナルの紋章、完全なNodeスクリプト、保存したPDFの調査を使います。編集可能なベクターロゴがすでにあれば元データとして保持します。ラスターの復元は、この読み込みより前の工程です。

完全なSVG挿入か単一パスかを選ぶ

PDFKitのベクターの説明は、パスの解析と周囲の描画メソッドを扱います。別のSVG-to-PDFKitライブラリーは、完全なSVGマークアップを扱います。

入力方法自分で担う作業
複数形状の完全なSVGSVGtoPDF(doc, svgText, x, y, options)サイズ、読み込んだ機能、完成PDFの確認
1パスの d 値doc.path(pathData) の後にfillまたはstroke描画色、変換、他の形状を自分で指定
ビットマップのままにするPNGやJPEGdoc.image(...)配置と実効解像度の確認

PDFKitの画像ドキュメントは、doc.image() にPNGとJPEGを掲載しています。完全なSVG読み込みと扱わないでください。

たとえば次は有効なpath APIの使用です。

doc.save();
doc.fillColor('#eeaa42');
doc.path('M125 100L175 20L225 100Z').fill();
doc.restore();

紋章の三角形を、そのパス座標に描きます。元ファイルの別の部分の青緑色の輪や棒は復元しません。それらを一緒に扱うなら、以下の文書全体の方法を使います。

ブラウザーでjsPDFを使うPDFなら、別のjsPDFのSVG手順に従います。Reactコンポーネントの文書にはReact-pdfのSVGロゴ手順を使います。PythonならReportLabの読み込みとサイズ確認とfpdf2の直接SVG配置を比較してください。

固定したパッケージで小さな例を実行する

PDFKit 0.20.2 とSVG-to-PDFKit 0.1.8 で実行しました。テストした依存関係の組み合わせです。どちらかを更新したら自分の出力を確認します。

新しいNodeプロジェクトにインストールします。

npm install --save-exact pdfkit@0.20.2 svg-to-pdfkit@0.1.8

次を logo.svg として保存します。輪と穴は fill-rule="evenodd" の1パスを共有し、金色の三角形と青緑色の棒は別の形状です。フォント、画像、効果はありません。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 120">
  <path fill="#147d78" fill-rule="evenodd"
    d="M110 60A50 50 0 1 1 10 60A50 50 0 1 1 110 60Z
       M85 60A25 25 0 1 1 35 60A25 25 0 1 1 85 60Z"/>
  <path fill="#eeaa42" d="M125 100L175 20L225 100Z"/>
  <rect x="227" y="20" width="8" height="80" fill="#147d78"/>
</svg>

同じ場所に次を place-logo.cjs として保存し、node place-logo.cjs を実行します。

const fs = require('node:fs');
const { finished } = require('node:stream/promises');
const PDFDocument = require('pdfkit');
const SVGtoPDF = require('svg-to-pdfkit');
 
async function main() {
  const svg = fs.readFileSync('logo.svg', 'utf8');
  const doc = new PDFDocument({ size: [800, 450], margin: 0 });
  const output = fs.createWriteStream('logo.pdf');
  doc.pipe(output);
  const warnings = [];
  SVGtoPDF(doc, svg, 72, 150, {
    width: 180, height: 90,
    preserveAspectRatio: 'xMinYMin meet',
    warningCallback: message => warnings.push(message),
  });
  SVGtoPDF(doc, svg, 432, 150, {
    width: 90, height: 45,
    preserveAspectRatio: 'xMinYMin meet',
    warningCallback: message => warnings.push(message),
  });
  doc.end();
  await finished(output);
  fs.writeFileSync('warnings.json', JSON.stringify(warnings, null, 2));
  if (warnings.length) process.stderr.write(warnings.join('\n') + '\n');
}
main().catch(error => {
  process.stderr.write(error.stack + '\n');
  process.exitCode = 1;
});

PDFKitはストリームを作ります。doc.end() が文書を完了し、スクリプトは出力ストリームが終了するのを待ってから戻ります。入門ドキュメントはストリームモデルと、1インチ72ポイントのPDFポイントによるページ寸法を説明します。

2つの配置ビューポートは 180 × 90 pt と 90 × 45 pt、すなわち 2.5 × 1.25インチ と 1.25 × 0.625インチ です。両方とも元viewBoxの2:1に合います。形状はviewBox内に余白を持つので、見える境界はビューポートより小さくなります。近くの文字とロゴを揃えるときはキャンバスと色付き図形を別々に測ります。

読み込みツールは width と height を初期ビューポートとして説明し、preserveAspectRatio がその内部の収まりを制御します。ページサイズの既定値に頼らないよう、この例は比率を合わせて寸法を明示します。予想外に小さいロゴへの一般的な修正として assumePt を使わず、先に元寸法、viewBox、目標ビューポートを確認してください。

PDFと見た目を確認する

最小の logo.pdf は 800 × 450 pt の1ページでした。pypdf 6.10.0 で、3次曲線操作24個、偶奇塗り操作2個、ページ画像0個を確認しました。ページのリソースにフォントやXObjectはなく、この例で読み込みツールの警告はありませんでした。

この結果は、画像のないオリジナル紋章がテストした版でPDF形状として描かれたという限定した結論を裏づけます。任意のSVGがすべてベクターPDFになると示すものではありません。埋め込み写真のあるロゴには別途確認が必要です。

Popplerでラベル付きの版も描画しました。同じSVGと2つのビューポートサイズを使い、配置を比較パネルへ移しています。両方の輪から淡い背景が見え、三角形と細い棒は輪と分かれたままです。

180 × 90ポイントと90 × 45ポイントのビューポートで青緑色の輪、金色の三角形、青緑色の棒を表示するPDF描画
2つの配置サイズでPDFから描画したオリジナル紋章。Web画像はラスタープレビューです。別途PDFを調査し、描画操作があり、埋め込み画像はないことを確認しました。

鮮明な拡大だけは弱い証拠です。十分大きなビットマップも鮮明に見えます。逆にレポートのどこかに曲線操作があっても、そのロゴがラスター化されていないとは分かりません。写真やグラフを含む文書を調べる前に、小さなテストPDFで図形を分離してください。

自分のロゴでは両方を確認します。

  1. PDF調査ツールでページ内容と参照オブジェクトを確認します。ロゴを描く場所の描画命令を探し、画像オブジェクトも把握します。複雑なPDFはForm XObject内に内容を置く場合があり、最上位の数だけでは不十分です。
  2. 保存したPDFを予定ビューアーで開いて元データと比較します。実際の納品サイズで穴、別々の色、クリッピング、余白、細部を確認します。

元のSVGをPDF生成コードの隣に保持します。元データがピクセルを包むだけなら、拡張子から形状を判断する前に埋め込み画像の診断を使います。

フォントと効果を検証した手順内に保つ

SVG-to-PDFKitは非対応機能にフィルターと foreignObject を挙げ、フォント登録とコールバックの要件も説明しています。小さなサーバー側ロゴには明示的なSVG描画属性を使い、描画結果とともに警告を確認します。渡したSVG要素にブラウザーの計算済みCSSを使うのは別の選択肢で、このNodeスクリプトにマークアップを渡すことと同じではありません。ライブラリーの機能とフォントの説明を参照します。

紋章は意図的に文字を避けています。実際の文字には、予定するフォントを渡してテストするか、承認したアウトライン文字をベクターマスターに保ちます。PDFKitのフォントの説明は埋め込みと登録を扱います。文書文字とロゴのアウトラインは編集要件が異なり、文字のスクリーンショットのトレースは元フォントを特定しません。

読み込みツールが再現できない効果にブランド記号が依存するなら、適した形状で再構築するか、別の書き出し手順を選んで検証します。パスより見た目が重要ならラスター挿入も有効です。それをベクター保持の書き出しと説明しないでください。

この例はRGB色です。パスの保持だけでは印刷業者の色、PDF/X、製版要件への適合は分かりません。受け取り側に確認してください。ロゴ形式ガイドは編集可能なマスターと納品ファイルを分ける助けになります。

挿入前にラスターだけのロゴを復元する

元のロゴがPNGやJPGだけなら、PDFKit工程前にPerfectVectorのロゴベクター化ツールでSVG候補を作れます。輪郭、小さな開口部、別の色領域を元画像と比較し、同じ配置とPDF確認を行います。

元のベクターがあれば使います。損傷した文字や正確なブランド形状には、編集ソフトで該当部分を打ち直すか描き直します。ロゴベクター化ガイドはこの判断を説明します。PerfectVectorは図形パスを準備し、PDFKitと読み込みツールは文書配置を扱います。この記事の紋章は手書きベクター図形で、変換結果の測定ではありません。

よくある質問

PDFKitはdoc.path()で完全なSVGを読み込めますか? いいえ。pathメソッドはSVGパスデータを読みます。この手順の完全な文書にはSVG-to-PDFKitを使うか、各形状を自分で描いてスタイル設定します。

SVG-to-PDFKitはラスター画像なしのPDFを保証しますか? いいえ。画像なしのテスト紋章は描画操作とページ画像0個を生成しました。特に埋め込み画像や非対応機能を含む場合、自分の入力と出力PDFを確認してください。

見えるロゴが指定の幅と高さより小さいのはなぜですか? それらのオプションは読み込みビューポートを定義します。元のviewBox内の空白もレイアウトの一部で、縦横比の収め方でも空間が残る場合があります。要求するPDFサイズを変える前に図形の境界を確認します。

参考資料

  1. PDFKit — ベクターグラフィックス — SVGパスデータの解析、描画操作、描画状態を説明しています。
  2. SVG-to-PDFKit — 使用と制限 — 完全なSVG挿入、ビューポート設定、警告、フォント、対応機能を定義しています。
  3. PDFKit — 画像 — image APIが受け付けるビットマップ形式を掲載しています。
  4. PDFKit — 入門 — 文書ストリーム、完了、PDFポイントでのページサイズを説明しています。
  5. PDFKit — フォント — フォント埋め込みと名前付き登録を説明しています。

文書のロゴがラスター画像から始まるなら、PerfectVectorでSVG候補を作成し、開口部と輪郭を確認してください。その後、必要なPDFサイズで配置し、保存したファイルを確認します。

ブログのその他の記事

編集しやすい
よりきれいなSVGから始めましょう