Salta ai contenuti

Graphics: primitive di tracciato + sfumature + trasformazioni

Il modulo Graphics traduce l’intento di disegno in operatori grafici PDF. Copre tracciati, stili di linea, spazi colore, trasformazioni, sfumature, pattern, retini e caricamento delle immagini.

Terminal window
composer require nextpdf/core:^3

Graphics è il livello dedicato al disegno vettoriale e raster. Produce le sequenze di operatori che i moduli ContentStream e Writer serializzano in un PDF. Un content stream codifica il contenuto della pagina come sequenza ordinata di operatori grafici: ISO 32000-2 §8. Il modulo emette tali operatori. Non scrive il file.

DrawingEngine è la superficie principale. È un builder fluente e con stato. Ogni setter restituisce self, accumula una modifica dello stato grafico o un operatore relativo ai tracciati e accoda tutto a un buffer interno leggibile con getStream(). Il motore modella direttamente lo stato grafico del PDF: spessore della linea, stile della linea, colore di traccia e di riempimento, alfa e modalità di fusione, limite di smussatura, maschera morbida, ritaglio, sovrastampa, planarità, levigatezza, intento di rendering, generazione del nero e rimozione del sottocolore corrispondono ciascuno a un operatore documentato. I setter relativi al colore accettano un value object Color o un ColorSpace esplicito, così gli spazi device e quelli basati su CIE condividono un’unica forma di chiamata.

Tre famiglie di componenti affiancano il motore. La prima gestisce l’input delle immagini. ImageLoader decodifica un file o un blob in memoria e restituisce un ImageLoadResult. ImageRegistry deduplica le immagini decodificate e ne tiene traccia con un MemoryReport, così i documenti di grandi dimensioni restano entro il budget di memoria. La seconda famiglia riguarda l’importazione vettoriale. SvgParser ed EpsParser traducono formati vettoriali esterni nello stesso flusso di operatori, esponendo getBoundingBox() per l’impaginazione. La terza famiglia riguarda la fedeltà del device-color: sfumature (ShadingManager, le famiglie Type2/Type3 e mesh), pattern (PatternFill), retini (Type1/Type5/Type6/ Type10/Type16), funzioni di trasferimento e spazi colore basati su ICC.

TransformEngine è un complemento mirato per le trasformazioni di coordinate. Delimita una trasformazione tra startTransform() e stopTransform(), che emettono la coppia save/restore q e Q. Offre helper per trasformazioni affini con nome — scale, translate, rotate, skew, mirrorH, mirrorV — ciascuno con un pivot opzionale. La matrice di trasformazione mappa uno spazio di coordinate interno nello spazio di coordinate di destinazione. È lo stesso modello che ISO 32000-2 applica ai domini delle sfumature — §8.7.4.

La gestione del colore segue l’ADR-012: gli spazi colore ICCBased e quelli basati su CIE emettono operatori di content stream cs/CS espliciti, invece di affidarsi al fallback su device-color. I profili ICC vengono incapsulati in un flusso ICCBased con il numero di componenti corretto, secondo ISO 32000-2 §8.6.5.5.

ClasseMetodi principaliRuolo
DrawingEnginegetStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient()Builder con stato per operatori di tracciato + stato grafico
TransformEnginestartTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream()Trasformazioni di coordinate affini
ImageLoaderload(string $filePath), loadFromString(string $data, string $mimeType)Decodifica le immagini in ImageLoadResult
ImageRegistryload(), loadFromString(), getMetadata(), memoryUsage(), reset()Cache di immagini con deduplica e reportistica della memoria
SvgParserparse(), parseFile()Traduce SVG nel flusso di operatori
EpsParserparse(), parseFile(), getBoundingBox()Traduce EPS nel flusso di operatori
ShadingManagerregistrazione delle sfumature + emissione del dizionarioSfumature assiali, radiali e mesh
Halftone (astratta)halftoneType(), toDict(), hasStream(), getStream()Retini di mezzatinta di tipo 1/5/6/10/16

Eseguire composer docs:generate-api-php -- --module=Graphics per ottenere la tabella PHPDoc completa.

Sorgente: 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();

Questo esempio collega un registro di immagini con reportistica della memoria e un blocco di trasformazione. Rispecchia la struttura usata in examples/07-images.php ed examples/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 mantiene stato. Chiamare reset() tra pagine indipendenti, altrimenti lo stato grafico precedente si propaga nel flusso successivo.
  • TransformEngine richiede una coppia startTransform()/stopTransform() corrispondente. Un blocco non bilanciato lascia un q pendente e corrompe lo stack save/restore a valle nel Writer.
  • setSoftMask(), setOverprint(), setBlackGeneration() e setUnderColorRemoval() scrivono marcatori di stato grafico esteso. Restano inerti con un profilo che rifiuta la funzionalità. Verificare il guard del profilo prima di fare affidamento sul risultato visivo.
  • ImageRegistry deduplica in base al contenuto. Due percorsi con byte identici condividono un unico oggetto. Non presumere un’unica immagine PDF per ogni chiamata a load().
  • EpsParser::getBoundingBox() restituisce il bounding box analizzato, non il box di pagina. Applicare un proprio ritaglio se l’EPS deborda dal rettangolo di destinazione.
  • La compensazione del punto di nero ha valore advisory ed è basata su marcatori. Da sola non trasforma i pixel.

Due modifiche lato producer sono breaking. Entrambe trasformano una corruzione prima silenziosa in un errore esplicito nel punto di chiamata.

La convalida dell’input ora solleva un’eccezione (nota di migrazione). L’input di disegno viene convalidato prima di raggiungere il flusso di operatori; i valori malformati vengono rifiutati con InvalidArgumentException. I chiamanti che in precedenza passavano NaN, Infinity o valori fuori intervallo producevano silenziosamente operatori corrotti; lo stesso input ora solleva un’eccezione. I vincoli verificati sono:

  • L’alfa del colore deve essere un valore finito e compreso in [0, 1].
  • Gli operandi della CTM, le dimensioni dei template, le coordinate dei vertici delle sfumature e le coordinate delle mesh-patch devono essere finiti — senza NaNInfinity.
  • Il flag di bordo di una gradient-patch deve essere uno tra {0, 1, 2, 3}.
  • I parametri delle funzioni di tipo 2/3/4 e i parametri dei retini sono soggetti a controlli sui limiti.
  • I nomi dei coloranti sono sottoposti a escape.
  • Il nome di un layer OCG (contenuto opzionale) non deve essere vuoto.

Verificare prima dell’aggiornamento i punti di chiamata che calcolano coordinate o alfa a partire da dati a monte: un valore che prima veniva accettato è ora un errore irreversibile.

ICCBased /N è fail-closed per impostazione predefinita. L’output Plain-PDF rifiuta uno spazio colore ICCBased il cui numero di componenti /N è al di fuori di {1, 3, 4} e riconcilia il /N dichiarato con il profilo incorporato e lo spazio /Alternate. Ciò segue la regola di ISO 32000-2 §8.6.5.5 per il flusso ICCBased, che include /N insieme a uno spazio /Alternate. Un profilo ICC a N canali (per esempio un profilo hexachrome con N = 6) viene mantenuto solo quando è attivo un profilo PDF/A o PDF/X, con opt-in tramite IccConformancePolicy::ProfileGated. Questo è un gate strutturale sul numero di componenti, non una dichiarazione di certificazione PDF/A o PDF/X.

L’emissione degli operatori è lineare rispetto al numero di chiamate di disegno — O(n) accodamenti a un buffer, senza reflow. Il costo di decodifica delle immagini è dominato dal codec e dal numero di pixel, non dal registro. La deduplica basata su content-hash del registro è la leva principale per i documenti di grandi dimensioni: gli asset riutilizzati costano una sola decodifica e un solo oggetto PDF. Il performance_budget per il carico di lavoro di riferimento di questo modulo è di 1500 ms di tempo reale e 64 MB di picco. Usare ImageRegistry::memoryUsage() per osservare l’impronta delle immagini decodificate e reset() per rilasciarla tra gruppi di pagine.

SvgParser ed EpsParser elaborano input vettoriale non attendibile. Trattare entrambi come parser esposti a dati ostili. Applicare limiti alla dimensione dell’input prima di chiamare parse(). Eseguire l’estrazione in un worker vincolato quando la sorgente è fornita dall’utente. EPS è un dialetto PostScript. Il parser traduce un sottoinsieme vincolato e non esegue un interprete generico, ma occorre comunque limitare la dimensione dell’input e il tempo di analisi. I loader di immagini decodificano codec di terze parti. Mantenere aggiornate le estensioni per immagini del runtime e limitare le dimensioni decodificate. Consultare il modello di minaccia del motore in /modules/core/security/ per il confine di fiducia e le indicazioni sull’isolamento dei worker.

Il modulo emette strutture di operatori grafici PDF coerenti con ISO 32000-2 §8, dizionari di spazio colore ICCBased secondo §8.6.5.5 e dizionari di sfumatura il cui Domain, Function, Matrix e BBox seguono §8.7.4. Si tratta di proprietà dell’implementazione: le forme degli operatori e dei dizionari sono prodotte da src/Graphics/ e verificate da tests/Unit/Graphics/ oltre che dalle baseline tests/Golden/PdfWriter/PdfWriterShadingGoldenBaselineSmokeTest e PdfWriterExtGStateGoldenSmokeTest. Non costituiscono una dichiarazione di conformità end-to-end a PDF 2.0 o PDF/X. La conformità dell’intero documento è convalidata separatamente dalle suite oracle e golden descritte in /modules/core/conformance/. Il comportamento del profilo per gli OutputIntent ICC è deciso dall’ADR-011 e dall’ADR-012, non dal solo modulo.