HotPDF importa un file SVG in un PDF caricato o creato come Form XObject riutilizzabile tramite ImportSVGFormXObject, che restituisce il nome della risorsa del form creato. Il posizionamento è una chiamata separata, DrawSVGFormXObject, quindi una singola importazione può essere applicata su molte pagine a dimensioni diverse senza duplicare un solo byte della grafica
Questa separazione conta più di quanto sembri. Un logo rasterizzato a 300 DPI e inserito in 400 pagine equivale a 400 copie di un bitmap. Lo stesso logo come Form XObject è un unico oggetto referenziato 400 volte, resta nitido a qualsiasi zoom e viene stampato alla risoluzione del dispositivo anziché al DPI che sembrava sufficiente in fase di creazione
Perché un Form XObject invece di disegnare l'SVG ogni volta?
Un Form XObject è il meccanismo nativo del PDF per i contenuti riutilizzabili: un content stream autonomo con un proprio bounding box e un proprio dizionario delle risorse, invocato per nome. Importare un SVG al suo interno offre tre proprietà che il disegno diretto non garantisce. La grafica esiste una sola volta nel file. Ogni posizionamento è una piccola matrice e un'invocazione. E le forme restano vettoriali, quindi un visualizzatore a 800 percento di zoom disegna curve, non pixel
La sottigliezza sta nelle risorse. I font e gli stati grafici di un form devono risiedere nel dizionario /Resources proprio del form, non nelle risorse della pagina che risultava corrente al momento dell'importazione. HotPDF scrive i font Base 14 e le voci ExtGState di cui un form ha bisogno direttamente nel form stesso, perché un form che prende in prestito un nome dalla sua prima pagina ospite viene renderizzato correttamente lì, ma produce un nome di risorsa non risolto su ogni altra pagina su cui viene poi posizionato
Due ribaltamenti, uno per la geometria e uno per i glifi
Il sistema di coordinate SVG cresce verso il basso a partire dall'angolo in alto a sinistra; un Form XObject PDF usa lo spazio utente PDF, che cresce verso l'alto a partire dal basso a sinistra. La trasformazione del viewBox radice esegue un ribaltamento sull'asse Y affinché la geometria risulti corretta. Il testo richiede poi un secondo ribaltamento locale, perché un glifo disegnato in un frame già ribaltato risulterebbe capovolto
È la stessa correzione che compare in senso inverso quando una pagina PDF viene esportata come SVG, descritta in esportare pagine PDF in SVG. Un errore in questo punto è facile da notare in una grafica con testo e quasi invisibile in una senza, motivo per cui un logo con uno slogan è uno smoke test migliore di un logo da solo
uses
HPDFDoc;
var
Pdf: THotPDF;
SvgBytes: TBytes;
FormName: AnsiString;
Stats: THPDFSVGImportStatistics;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'catalogue.pdf';
Pdf.BeginDoc;
SvgBytes := LoadFileBytes('brand-logo.svg');
FormName := Pdf.ImportSVGFormXObject(SvgBytes, Stats);
if FormName = '' then
raise Exception.Create('SVG rejected - see the import statistics');
// Una sola importazione, molti posizionamenti: i byte della grafica esistono una sola volta
for I := 1 to 40 do
begin
if I > 1 then
Pdf.AddPage;
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 780, 120, 40);
end;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Come sopravvivono i collegamenti ipertestuali al passaggio?
Non possono sopravvivere all'interno del form, perché un Form XObject è contenuto, mentre le destinazioni dei link PDF sono annotazioni, che appartengono a una pagina. Un elemento <a> nell'SVG di origine non può quindi essere semplicemente copiato nel content stream del form
HotPDF risolve il problema mantenendo i rettangoli dei link come metadati nello spazio del form durante il parsing, e materializzandoli come annotazioni di link a livello di pagina a ogni posizionamento. DrawSVGFormXObject mappa quei rettangoli attraverso il rettangolo di destinazione che passate, quindi un form posizionato due volte a dimensioni diverse ottiene due set di aree cliccabili correttamente dimensionati. I rettangoli dei link vengono mappati solo tramite la dimensione radice e non entrano mai nel content stream, il che mantiene identica la grafica disegnata indipendentemente da quanti link porti. Passate AddLinks = False quando volete la grafica senza interattività, ad esempio su una pagina destinata solo alla stampa
Cosa rifiuta l'importatore, e perché è proprio questo il punto
SVG è un dialetto XML con supporto per script, riferimenti esterni ed espansione di entità, il che rende un file SVG arbitrario un input ostile allo stesso modo di un file HTML arbitrario. Il profilo di importazione adotta un comportamento fail-closed su tutto ciò che punta fuori dal documento: riferimenti a risorse esterne, script, attributi di gestori di eventi, DTD e qualsiasi url() che non sia un riferimento a frammento locale
Fail-closed significa che l'importazione fallisce anziché scartare silenziosamente il costrutto incriminato. Questa distinzione è importante per una pipeline batch, perché uno scarto silenzioso produce un documento a cui manca qualcosa che nessuno sa di dover cercare, mentre un rifiuto produce un file che potete mettere in quarantena e ispezionare. Se accettate upload SVG dagli utenti, questo è il comportamento che volete, e si abbina all'isolamento a livello di processo descritto in isolamento dei processi codec per immagini non attendibili
Vale la pena conoscere un confine interno se renderizzate anche font a colori. Il sottoinsieme SVG rigoroso usato per i glifi a colori OpenType SVG passa attraverso un punto di ingresso separato e mantiene il suo comportamento di fallimento originale, più restrittivo. L'importazione di grafica generica è un percorso distinto, quindi l'aggiunta del supporto per archi, trasparenza e CSS alla grafica importata non ha ampliato ciò che un glifo di font può contenere
Gradienti, maschere e la regola del no-raster
I gradienti vengono importati come bande di colore vettoriali delimitate, vincolate dal percorso di ritaglio della geometria originale, non come immagine rasterizzata. Le maschere usano lo stesso approccio: il contorno della maschera diventa un percorso di ritaglio vettoriale. Il risultato è che un'illustrazione ricca di gradienti resta indipendente dalla risoluzione e resta di piccole dimensioni, mentre un importatore che rasterizza produrrebbe un grande oggetto immagine la cui qualità è fissata al momento dell'importazione
Il compromesso riguarda la fedeltà nei casi estremi. Un'approssimazione a bande di un gradiente uniforme non è matematicamente identica al gradiente SVG, e una grafica con decine di maschere morbide sovrapposte apparirà più vicina all'originale se invece la renderizzate come immagine ad alta risoluzione. Per i modelli di shading supportati nativamente dal PDF, e su quando ricorrervi direttamente, vedere il rendering di shading assiali e radiali
// Leggere le statistiche di importazione indica cosa è effettivamente passato
Writeln(Format('nodes=%d css rules=%d gradients=%d masks=%d',
[Stats.NodeCount, Stats.CSSRuleCount, Stats.GradientCount,
Stats.MaskCount]));
Writeln(Format('text runs=%d links=%d form bytes=%d',
[Stats.TextRunCount, Stats.LinkCount, Stats.OutputBytes]));
// Posizionare lo stesso form a due dimensioni produce due set di link corretti
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 700, 240, 80);
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 320, 700, 120, 40);
// Posizionamento solo stampa: grafica senza aree cliccabili
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 60, 120, 40, False);
Come si colloca l'importazione SVG accanto alle altre vie vettoriali
Esistono tre vie di importazione vettoriale e non sono intercambiabili. L'importazione SVG è adatta per grafica prodotta da strumenti di design e per qualsiasi cosa provenga da una pipeline web. L'importazione di metafile, trattata in importazione vettoriale EMF e WMF, è adatta per contenuti generati da applicazioni Windows e da componenti di grafici che disegnano su un device context. Il disegno diretto tramite l'API di pagina è adatto per grafica calcolata dal vostro stesso codice, dove non esiste alcun formato intermedio
L'argomento della riutilizzabilità favorisce l'importazione SVG in particolare per gli elementi ripetuti. Carte intestate, loghi, filigrane, marchi di certificazione e linee decorative vengono tutti disegnati in modo identico su molte pagine, e ciascuno di essi è un solo oggetto form più un'invocazione per pagina. Misurate la differenza di dimensione del file su un documento reale prima di decidere che non conta: su un catalogo di 500 pagine con un logo vettoriale per pagina, il divario tra un form unico e 500 copie inline è di solito di diversi megabyte
L'importazione SVG, l'importazione di metafile e il disegno vettoriale diretto condividono lo stesso writer di content stream per Delphi e C++Builder; l'elenco completo delle funzionalità è disponibile sulla pagina del componente PDF HotPDF Delphi