HotPDF importerer en SVG-fil i et indlæst eller oprettet PDF-dokument som et genanvendeligt Form XObject via ImportSVGFormXObject, som returnerer ressourcenavnet på den oprettede formular. At placere den er et separat kald, DrawSVGFormXObject, så én import kan stemples på mange sider i forskellige størrelser uden at duplikere en eneste byte af grafikken
Denne opdeling betyder mere, end det lyder som. Et logo rasteriseret ved 300 DPI og indsat på 400 sider er 400 kopier af et bitmap. Det samme logo som et Form XObject er ét objekt, der refereres 400 gange, det forbliver skarpt ved enhver zoom, og det udskrives ved enhedens opløsning i stedet for ved hvilken DPI, der virkede tilstrækkelig på opbygningstidspunktet
Hvorfor et Form XObject i stedet for at tegne SVG'en hver gang?
Et Form XObject er PDF's egen mekanisme til genanvendeligt indhold: en selvstændig content stream med sin egen bounding box og resource dictionary, der påkaldes ved navn. At importere SVG til et sådant giver dig tre egenskaber, som direkte tegning ikke giver. Grafikken findes kun én gang i filen. Hver placering er blot en matrix og en påkaldelse. Og formerne forbliver vektorer, så en fremviser ved 800 procent zoom tegner kurver, ikke pixels
Finessen ligger i ressourcerne. En formulars skrifttyper og grafiktilstande skal ligge i formularens egen /Resources dictionary, ikke i ressourcerne for den side, der tilfældigvis var aktiv på importtidspunktet. HotPDF skriver de Base 14-skrifttyper og de ExtGState-poster, en formular har brug for, ind i formularen selv, fordi en formular, der låner et navn fra sin første værtsside, gengives korrekt dér og giver et uløst ressourcenavn på enhver anden side, den senere placeres på
To spejlvendinger: én for geometri og én for glyffer
SVG's koordinatsystem vokser nedad fra øverste venstre hjørne; et PDF Form XObject bruger PDF-brugerrum, som vokser opad fra nederste venstre hjørne. Rodens viewBox-transformation udfører én spejlvending om Y-aksen, så geometrien lander korrekt. Tekst kræver derefter en anden, lokal spejlvending, fordi en glyf tegnet i en allerede spejlvendt ramme ville stå på hovedet
Dette er den samme korrektion, der optræder omvendt, når en PDF-side skrives ud som SVG, beskrevet i eksport af PDF-sider til SVG. At gøre det forkert er let at få øje på i grafik med tekst og næsten usynligt i grafik uden, hvilket er grunden til, at et logo med en tagline er en bedre smoketest end et logo alene
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');
// Én import, mange placeringer: grafikbyttene findes kun én gang
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;
Hvordan overlever hyperlinks turen?
De kan ikke overleve inde i formularen, fordi et Form XObject er indhold, og PDF-linkmål er annotationer, som hører til en side. Et <a>-element i kilde-SVG'en kan derfor ikke bare kopieres ind i formularens content stream
HotPDF løser dette ved at bevare linkrektangler som metadata i formularrum under parsing og materialisere dem som linkannotationer på sideniveau ved hver placering. DrawSVGFormXObject mapper disse rektangler gennem det målrektangel, du angiver, så en formular placeret to gange i forskellige størrelser får to korrekt dimensionerede sæt hit-områder. Linkrektangler mappes udelukkende gennem rodstørrelsen og kommer aldrig ind i content stream'en, hvilket holder den tegnede grafik identisk uanset hvor mange links den bærer. Angiv AddLinks = False, når du ønsker grafikken uden interaktivitet, for eksempel på en side kun til print
Hvad importeren afviser, og hvorfor det er pointen
SVG er en XML-dialekt med scripting, eksterne referencer og entity expansion, hvilket gør en vilkårlig SVG-fil til en fjendtlig input på samme måde som en vilkårlig HTML-fil er det. Importprofilen er fail-closed over for alt, der rækker uden for dokumentet: eksterne ressourcereferencer, scripts, event handler-attributter, DTD'er og enhver url(), der ikke er en lokal fragmentreference
Fail-closed betyder, at importen fejler i stedet for stiltiende at droppe den problematiske konstruktion. Den forskel betyder noget for en batch-pipeline, fordi et stiltiende drop giver et dokument, der mangler noget, som ingen kender til, mens en afvisning giver en fil, du kan sætte i karantæne og undersøge. Hvis du accepterer SVG-uploads fra brugere, er dette den adfærd, du ønsker, og den går hånd i hånd med den procesniveau-isolation, der er beskrevet i codec-procesisolation for utroværdige billeder
Én intern grænse er værd at kende, hvis du også gengiver farveskrifttyper. Den strenge SVG-delmængde, der bruges til OpenType SVG-farveglyffer, kører gennem et separat indgangspunkt og bevarer sin oprindelige, snævrere fejladfærd. Generel grafikimport er en separat sti, så tilføjelse af understøttelse af buer, transparens og CSS til importeret grafik udvidede ikke, hvad en skrifttypeglyf må indeholde
Gradienter, masker og no-raster-reglen
Gradienter importeres som afgrænsede vektor-farvebånd, begrænset af den oprindelige geometris beskæringsvej, ikke som et rasteriseret billede. Masker bruger samme fremgangsmåde: maskens omrids bliver en vektor-beskæringsvej. Resultatet er, at en gradienttung illustration forbliver opløsningsuafhængig og forbliver lille, hvor en rasteriserende importer ville producere et stort billedobjekt, hvis kvalitet er fastlåst på importtidspunktet
Prisen er præcision i de ekstreme tilfælde. En båndinddelt tilnærmelse af en jævn gradient er ikke matematisk identisk med SVG-gradienten, og grafik med dusinvis af overlappende soft masks vil ligne originalen mere, hvis du i stedet gengiver den som et højopløsningsbillede. For de shading-modeller, PDF understøtter nativt, og hvornår man skal gribe direkte til dem, se gengivelse af aksiale og radiale shadings
// Læsning af importstatistikken viser dig, hvad der faktisk kom igennem
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]));
// Placering af samme formular i to størrelser giver to korrekte linksæt
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 700, 240, 80);
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 320, 700, 120, 40);
// Placering kun til print: grafik uden hit-områder
Pdf.CurrentPage.DrawSVGFormXObject(FormName, 40, 60, 120, 40, False);
Hvor SVG-import passer ind blandt de andre vektorruter
Der findes tre vektor-importruter, og de er ikke indbyrdes udskiftelige. SVG-import er rigtig til grafik produceret af designværktøjer og til alt, der kommer fra en webpipeline. Metafil-import, som er dækket i EMF- og WMF-vektorimport, er rigtig til indhold genereret af Windows-applikationer og af diagramkomponenter, der tegner til en enhedskontekst. Direkte tegning via side-API'en er rigtig til grafik, din egen kode beregner, hvor der slet ikke findes et mellemformat
Genanvendelighedsargumentet taler specifikt for SVG-import ved gentagne elementer. Brevhoveder, logoer, vandmærker, certificeringsmærker og dekorative linjer tegnes alle identisk på mange sider, og hver af dem er ét formularobjekt plus én påkaldelse pr. side. Mål forskellen i filstørrelse på et rigtigt dokument, før du beslutter, at det ikke betyder noget: på et katalog på 500 sider med et vektorlogo pr. side er forskellen mellem én formular og 500 indlejrede kopier som regel adskillige megabyte
SVG-import, metafil-import og direkte vektortegning deler den samme content stream writer til Delphi og C++Builder; den komplette funktionsliste findes på HotPDF Delphi PDF component-siden