HotPDF eksporterer en side fra ethvert innlastet PDF-dokument til frittstående SVG-markup med ett enkelt kall, BuildLoadedPageSVG, som returnerer det komplette SVG-dokumentet som en streng. Den eksporterte markupen inneholder sidegeometrien, tekst som ekte SVG-text-elementer, innebygde rasterbilder og strekestilstanden PDF-operatorene hadde etablert ved hver tegneoperasjon
Det er nettopp der de fleste hjemmesnekrede konverterere stille bryter sammen. Å gjøre om en PDF-side til SVG ser ut som et koordinatproblem, men viser seg å være et tilstandsproblem. PDF er en stack-maskin der grafikktilstanden endres etter hvert som innholdsstrømmen tolkes; SVG er et deklarativt tre der hvert element bærer sine egne presentasjonsattributter. Alt tolkeren ikke klarer å ta et øyeblikksbilde av idet et element skrives ut, er ganske enkelt borte fra resultatet, og feilen er stille: du får gyldig SVG som gjengir en side med subtile feil
Hvorfor konverteres ikke en PDF-side bare rett over til SVG?
Tre grunnleggende forskjeller gjør konverteringen ikke-triviell, og alle tre gir resultater som ser plausible ut helt til du sammenligner dem side om side med originalen. Den første er y-aksen. PDF-brukerrommet vokser oppover fra sidens nedre venstre hjørne; SVG vokser nedover fra øvre venstre hjørne. En enkelt sideomfattende vending retter opp tegnekoordinatene, men ødelegger samtidig hvert eneste glyf, fordi det å vende hele lerretet også speilvender bokstavformene
Den andre forskjellen er arv. I PDF legger q og Q en grafikktilstand på og av en stakk, og den omfatter linjebredde, endestrek, hjørneutforming, gjæringsgrense, strekmønster, strekfase og alfa. I SVG arver et element som ikke navngir en attributt, denne fra en overordnet gruppe, noe som er en helt annen omfangsregel. En eksportør som bare følger med på gjeldende transformasjonsmatrise og glemmer strekestilstanden, lar tilstanden som gjenopprettes etter en Q, lekke inn i elementene som følger etter
Den tredje er at PDF uttrykker flere ting gjennom konvensjon i stedet for gjennom verdi. Endestreker og hjørneutforminger er heltall, null linjebredde betyr en hårfin strek i enhetsrommet i stedet for en usynlig strek, og stjernevariantene av tegneoperatorene endrer fyllregelen i stedet for fargen. Hver av disse trenger en oversettelse, ikke en kopi
Ett kall for det vanlige tilfellet
For den vanlige oppgaven å eksportere sider til en nettleser, et diff-verktøy eller en designoverlevering, består API-flaten av én enkelt funksjon. BuildLoadedPageSVG tar imot en nullbasert sideindeks mot det gjeldende innlastede dokumentet og returnerer SVG-dokumentet som en AnsiString:
var
Pdf: THotPDF;
I: Integer;
Svg: AnsiString;
Output: TFileStream;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('statements.pdf', '') <= 0 then
Exit; // LoadFromFile returnerer sideantallet
for I := 0 to Pdf.LoadedPageCount - 1 do
begin
Svg := Pdf.BuildLoadedPageSVG(I);
if Length(Svg) = 0 then
Continue;
Output := TFileStream.Create(Format('page-%d.svg', [I + 1]), fmCreate);
try
Output.WriteBuffer(Svg[1], Length(Svg));
finally
Output.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Den samme eksporten er tilgjengelig gjennom HotPDFs kommandolinjeverktøy som kommandoen export-svg, som er nyttig i byggepipeliner og regresjonsskript der du ønsker en tekst-diffbar representasjon av en side uten å skrive noe Pascal-kode. Siden SVG er tekst, er det en naturlig følgesvenn til rasterbanen beskrevet i rendering av en PDF-side til et bitmap: bitmapet viser deg hvordan siden ser ut, SVG-en viser deg hva den er bygget opp av
Hvordan blir PDF-tekst kartlagt til SVG-tekstelementer?
HotPDF setter sammen tekstmatrisekjeden som prefiks multiplisert med CTM multiplisert med tekstmatrise multiplisert med glyfvending, der glyfvendingen er en høyremultiplikasjon med matrix(1,0,0,-1,0,0). Denne høyrefaktoren finnes utelukkende for å oppheve den sideomfattende vertikale vendingen for glyfformene, siden SVG-tekst tegnet i en vendt lokal ramme ellers ville vist seg opp ned. Ved å legge korreksjonen inn i matrisen i stedet for i spesialtilpasset kode, kommer rotert, speilvendt og skjevstilt tekst automatisk ut riktig uten ekstra forgreininger
Horisontal plassering bruker flerverdisyntaksen for x i SVG-text-elementet, én koordinat per tegn, akkumulert fra hver glyfforflytning pluss tegnavstanden Tc og ordavstanden Tw som gjaldt på det tidspunktet. Horisontal skalering Tz blir felt inn i a- og c-kolonnene i tekstmatrisen i stedet for å skrives ut separat, slik at en visningsklient som ignorerer eksotiske tekstattributter, fremdeles plasserer hver glyf der PDF-en satte den. Tekst produsert gjennom kompleks forming, dekket i kompleks skriftforming for skript, følger samme vei, fordi formingsmotoren allerede har løst klynger til posisjonerte glyfer innen innholdsstrømmen tolkes
Rotasjon og bilder: to vendinger det er lett å snu feil vei
En side med en /Rotate-verdi ulik null trenger en for-transformasjon satt sammen av en vending mot den roterte lerrethøyden og en rotasjon uttrykt i y-opp visningsrom. De tre rotasjonsmatrisene er (0,-1,1,0,0,W) for 90 grader, (-1,0,0,-1,W,H) for 180 grader og (0,1,-1,0,H,0) for 270 grader, der W og H er sidedimensjonene før rotasjon. Å utlede disse for hånd inviterer til fortegnsfeil på nøyaktig tre steder, så eksportøren setter dem sammen gjennom den samme matrisemultiplikasjonsrutinen som håndterer alle andre transformasjoner
Innebygde bilder trenger sin egen vending, fordi PDF-bilderommet plasserer den første samplingsraden ved øvre kant av enhetskvadratet, mens SVG-image-elementet har en y-ned lokal ramme. Den utskrevne transformasjonen er derfor CTM høyremultiplisert med matrix(1,0,0,-1,0,1). Å få dette galt gir vertikalt speilvendte fotografier på en ellers perfekt side, noe som er den typen feil en korrekturleser oppdager umiddelbart, mens en automatisert test ofte ikke gjør det
Hva bevarer grafikktilstandsenheten egentlig?
HotPDF sender strekstilstandsoperatorene w, J, j, M og d gjennom et separat, valgfritt enhetsgrensesnitt, slik at nøyaktig strekgjengivelse ble lagt til uten å endre vtabellen til det eksisterende innholdsenhetsgrensesnittet og uten å bryte binær kompatibilitet for kode bygget mot tidligere versjoner. Konkret mottar den eksporterte SVG-en oversatte nøkkelord i stedet for rå PDF-heltall:
// PDF-heltallsenumereringer blir til SVG-nøkkelordattributter
// endestrek 0, 1, 2 -> butt, round, square
// hjørne 0, 1, 2 -> miter, round, bevel
//
// Null linjebredde betyr en hårfin strek i enhetsrommet i PDF, så
// eksportøren skriver ut vector-effect="non-scaling-stroke" for å
// holde streken synlig og nær én enhetspiksel bred etter CTM
//
// f* B* b* velger paritetsregelen (even-odd) og skriver ut
// fill-rule="evenodd", mens f B b beholder SVG-standarden nonzero winding
Gjenoppretting av tilstand ved en Q dekker opasitet, linjebredde, endestrek, hjørneutforming, gjæringsgrense, strekmønster og strekfase samlet. Nøstede Form XObjects tar øyeblikksbilde av og gjenoppretter det samme fulle settet ved sine grenser, slik at en stiplet kantlinje definert inni et stempel ikke kan lekke mønsteret sitt inn i sideinnholdet som følger etter. Hvis du allerede følger med på klipping og CTM-oppførsel av andre grunner, er dette den samme tilstandsmodellen som opptrer i EMF- og WMF-vektorimport, bare i motsatt retning
Begrensninger verdt å kjenne til før du sender det ut
Eksportøren er ærlig om sitt omfang, og å bli kjent med grensene på forhånd er billigere enn å oppdage dem i produksjon. Farge når SVG-enheten gjennom operatorene rg, RG, g og G. Fyll etablert gjennom et fargerom pluss scn, som er slik Separation-, DeviceN- og ICCBased-farger males, ankommer ikke enheten som en oppløst RGB-triplett, så sider som bruker spotfarger på denne måten, eksporterer geometrien sin, men ikke disse fargene. For trykkorienterte kilder bør du rastrere i stedet eller flate ut spotfargene først; selve malemodellen er dekket i rendering av Separation- og DeviceN-spotfarger
To mindre detaljer sparer feilsøkingstid. Heksadesimale fargeverdier skrives ut med store bokstaver, så en test som forventer #ff0000, feiler mot en helt korrekt #FF0000. Og SVG-enheten er referansetalt gjennom grensesnittet sitt, noe som betyr at frigjøring skjer ved å la grensesnittet gå ut av scope, i stedet for å kalle Free på objektet, et skille som betyr noe hvis du utvider enheten til å skrive ut din egen markup ved siden av sideinnholdet
SVG-eksport passer naturlig sammen med strukturell sammenligning når du trenger å vite om et generert dokument faktisk endret seg mellom to bygg. Det bredere verktøysettet rundt innlastede dokumenter, fra rendering til redigering til eksport, er dokumentert på HotPDF Delphi PDF-komponentsiden