コンテンツにスキップ

グラフィックス: パス + シェーディング + 変換プリミティブ

Graphics モジュールは、描画の意図を PDF グラフィックスオペレーターへ変換します。パス、線スタイル、色空間、変換、シェーディング、パターン、ハーフトーン、画像の読み込みを扱います。

Terminal window
composer require nextpdf/core:^3

Graphics は、ベクターおよびラスターの描画レイヤーです。ContentStream モジュールと Writer モジュールによって PDF にシリアライズされるオペレーターシーケンスを生成します。コンテンツストリームは、ページのコンテンツをグラフィックスオペレーターの順序付きシーケンスとしてエンコードします(ISO 32000-2 §8)。このモジュールはそれらのオペレーターを出力します。ファイルの書き込みは行いません。

DrawingEngine が主要な操作面です。これは fluent な、状態を持つビルダーです。各セッターは self を返し、グラフィックスステートの変更またはパス描画オペレーターを蓄積して、getStream() で読み出せる内部バッファに追加します。このエンジンは PDF のグラフィックスステートを直接モデル化します。線幅、線スタイル、ストロークおよび塗りつぶしの色、アルファとブレンドモード、マイター制限、ソフトマスク、クリッピング、オーバープリント、フラットネス、スムースネス、レンダリングインテント、ブラックジェネレーション、下色除去のそれぞれが、文書化されたオペレーターに対応します。色に関連するセッターは Color 値オブジェクト、または明示的な ColorSpace を受け取るため、デバイス色空間と CIE ベースの色空間は 1 つの呼び出し形式を共有します。

エンジンの周辺には 3 つのファミリーがあります。1 つ目は画像入力です。ImageLoader は、ファイルまたはメモリ内の blob をデコードして ImageLoadResult にします。ImageRegistry は、デコード済み画像を重複排除して MemoryReport で追跡するため、大規模なドキュメントでもメモリ予算内に収められます。2 つ目はベクターのインポートです。SvgParserEpsParser は、外部のベクター形式を同じオペレーターストリームに変換し、レイアウト用に getBoundingBox() を公開します。3 つ目はデバイス色の忠実性です。シェーディング(ShadingManagerType2/Type3 とメッシュファミリー)、パターン(PatternFill)、ハーフトーン(Type1/Type5/Type6/ Type10/Type16)、伝達関数、ICC ベースの色空間です。

TransformEngine は、座標変換に特化したコンパニオンです。変換を startTransform()stopTransform() で囲むと、これらが qQ の save/restore ペアを出力します。名前付きのアフィンヘルパーとして、scaletranslaterotateskewmirrorHmirrorV を提供し、それぞれがオプションのピボットを受け取ります。変換行列は、内部の座標空間をターゲットの座標空間にマッピングします。これは ISO 32000-2 がシェーディングのドメインに適用するモデルと同じです(§8.7.4)。

色管理は ADR-012 に従います。ICCBased および CIE ベースの色空間は、デバイス色フォールバックに依存するのではなく、明示的な cs/CS コンテンツストリームオペレーターを出力します。ICC プロファイルは、ISO 32000-2 §8.6.5.5 に従い、正しいコンポーネント数で ICCBased ストリームにラップされます。

クラス主なメソッド役割
DrawingEnginegetStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient()状態を持つパス + グラフィックスステートのオペレータービルダー
TransformEnginestartTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream()アフィン座標変換
ImageLoaderload(string $filePath), loadFromString(string $data, string $mimeType)画像デコード結果としての ImageLoadResult
ImageRegistryload(), loadFromString(), getMetadata(), memoryUsage(), reset()メモリレポート機能を備えた重複排除画像キャッシュ
SvgParserparse(), parseFile()SVG からオペレーターストリームへの変換
EpsParserparse(), parseFile(), getBoundingBox()EPS からオペレーターストリームへの変換
ShadingManagerシェーディングの登録 + ディクショナリの出力軸状 (Axial)、放射状 (radial)、メッシュのシェーディング
Halftone (抽象)halftoneType(), toDict(), hasStream(), getStream()Type 1/5/6/10/16 ハーフトーンスクリーン

完全な PHPDoc テーブルを生成するには、composer docs:generate-api-php -- --module=Graphics を実行します。

ソース:examples/06-colors-and-drawing.php

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\Color;
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\LineStyle;
$engine = new DrawingEngine();
$engine
->setLineWidth(1.5)
->setDrawColor(Color::rgb(0, 51, 102))
->setFillColor(Color::rgb(230, 240, 250))
->rect(20.0, 20.0, 160.0, 80.0)
->line(20.0, 110.0, 180.0, 110.0, new LineStyle(dash: [3.0, 2.0]));
$contentStreamBytes = $engine->getStream();

この例では、メモリレポート機能を備えた画像レジストリと変換ブラケットを組み合わせます。examples/07-images.phpexamples/21-transforms.php で使用されている構造を反映しています。

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Graphics\TransformEngine;
$registry = new ImageRegistry();
$image = $registry->load('/srv/assets/logo.png');
$report = $registry->memoryUsage();
if ($report->bytes > 32 * 1024 * 1024) {
// Decoded image cache exceeded the budget — reset before the next page.
$registry->reset();
}
$transform = new TransformEngine();
$transform
->startTransform()
->translate(40.0, 700.0)
->scale(0.5, 0.5)
->stopTransform();
$engine = new DrawingEngine();
$engine->reset();
$page = $transform->getStream() . $engine->getStream();
  • DrawingEngine は状態を持ちます。独立したページの間では reset() を呼び出してください。そうしないと、直前のグラフィックスステートが次のストリームに漏れ込みます。
  • TransformEngine は、対応する startTransform()/stopTransform() のペアを必要とします。ブラケットの対応が取れていないと、ぶら下がった q が残り、Writer の下流で save/restore スタックが破損します。
  • setSoftMask()setOverprint()setBlackGeneration()setUnderColorRemoval() は、拡張グラフィックスステートのマーカーを書き込みます。その機能を許可しないプロファイルでは、これらは無効になります。視覚的な結果に依存する前に、プロファイルのガードを確認してください。
  • ImageRegistry はコンテンツ単位で重複排除します。バイト列が同一である 2 つのパスは、1 つのオブジェクトを共有します。load() 呼び出しごとに 1 つの PDF 画像が生成されると想定しないでください。
  • EpsParser::getBoundingBox() は、ページボックスではなく、解析されたバウンディングボックスを返します。EPS がターゲットの矩形からはみ出す場合は、独自のクリッピングを適用してください。
  • ブラックポイント補正は推奨ベースかつマーカーベースです。それ自体がピクセルを変換することはありません。

プロデューサー側には 2 つの変更があり、いずれも破壊的変更です。どちらも、以前はサイレントだった破損を、呼び出し箇所で明示的に失敗する挙動に変えます。

入力検証は例外をスローするようになりました(移行に関する注記)。 描画入力は、オペレーターストリームに到達する前に検証され、不正な値は InvalidArgumentException で拒否されます。以前 NaNInfinity、または範囲外の値を渡していた呼び出し元は、サイレントに破損したオペレーターを生成していましたが、同じ入力では例外が発生するようになりました。検証される制約は次のとおりです。

  • 色のアルファは有限で、かつ [0, 1] の範囲内でなければなりません。
  • CTM オペランド、テンプレートの寸法、グラデーション頂点の座標、メッシュパッチの座標は有限でなければならず、NaNInfinity は許可されません。
  • グラデーションパッチのエッジフラグは {0, 1, 2, 3} のいずれかでなければなりません。
  • Type 2/3/4 の関数パラメーターとハーフトーンパラメーターは、境界チェックの対象です。
  • 色材(colourant)の名前はエスケープされます。
  • OCG(オプショナルコンテンツ)のレイヤー名は空であってはなりません。

アップグレード前に、上流のデータから座標やアルファを計算している呼び出し箇所を監査してください。以前は通過していた値が、現在はハードエラーになります。

ICCBased の /N はデフォルトでフェイルクローズです。 プレーン PDF 出力では、/N コンポーネント数が {1, 3, 4} の範囲外である ICCBased 色空間を拒否し、宣言された /N を、埋め込みプロファイルおよび /Alternate 空間と照合します。これは、ISO 32000-2 §8.6.5.5 の ICCBased ストリームに関する規則に従っており、このストリームは /N/Alternate 空間とともに保持します。N チャンネルの ICC プロファイル(例えば N = 6 のヘキサクローム(hexachrome)プロファイル)は、PDF/A または PDF/X プロファイルが有効で、IccConformancePolicy::ProfileGated によってオプトインされている場合にのみ保持されます。これはコンポーネント数に対する構造的なゲートであり、PDF/A または PDF/X の認証を主張するものではありません。

オペレーターの出力は描画呼び出しの数に対して線形です。バッファへの O(n) の追加であり、リフローはありません。画像デコードのコストは、レジストリではなく、コーデックとピクセル数によって左右されます。大規模なドキュメントでは、レジストリのコンテンツハッシュによる重複排除が主要な手段になります。再利用される素材は、1 回のデコードと 1 つの PDF オブジェクトで済みます。このモジュールの参照ワークロードに対する performance_budget は、ウォール時間 1500 ms、ピーク 64 MB です。デコード済み画像のフットプリントを観測するには ImageRegistry::memoryUsage() を使用し、ページグループの間で解放するには reset() を使用します。

SvgParserEpsParser は、信頼できないベクター入力を処理します。どちらも、悪意のあるデータを扱うパーサーとして扱ってください。parse() を呼び出す前に、入力サイズの制限を適用してください。ソースがユーザー提供の場合は、制約付きのワーカーで抽出を実行してください。EPS は PostScript の方言です。パーサーは制約付きのサブセットを変換するだけで、汎用インタープリターを実行することはありませんが、それでも入力サイズと解析時間を制限すべきです。画像ローダーはサードパーティのコーデックをデコードします。ランタイムの画像拡張を最新に保ち、デコードされる寸法に上限を設けてください。信頼境界とワーカー分離のガイダンスについては、/modules/core/security/ のエンジン脅威モデルを参照してください。

このモジュールは、ISO 32000-2 §8 に準拠した PDF グラフィックスオペレーター構造、§8.6.5.5 に準拠した ICCBased 色空間ディクショナリ、Domain ・ Function ・ Matrix ・ BBox が §8.7.4 に従うシェーディングディクショナリを出力します。これらは実装上の事実です。オペレーターとディクショナリの形状は src/Graphics/ によって生成され、tests/Unit/Graphics/tests/Golden/PdfWriter/PdfWriterShadingGoldenBaselineSmokeTest および PdfWriterExtGStateGoldenSmokeTest のベースラインによって検証されます。これらは、エンドツーエンドの PDF 2.0 または PDF/X 適合性を表明するものではありません。ドキュメント全体の適合性は、/modules/core/conformance/ で説明されているオラクルおよびゴールデンスイートによって、別途検証されます。ICC OutputIntents のプロファイル動作は、このモジュール単独ではなく、ADR-011 と ADR-012 によって決定されます。