Tekninen artikkeli

PDF-sivujen vienti SVG-muotoon Delphissä HotPDF:llä

HotPDF vie minkä tahansa ladatun PDF-dokumentin sivun itsenäiseksi SVG-merkinnäksi yhdellä kutsulla, BuildLoadedPageSVG, joka palauttaa koko SVG-dokumentin merkkijonona. Viety merkintä sisältää sivun geometrian, tekstin oikeina SVG:n text-elementteinä, upotetut rasterikuvat sekä piirtotilan, jonka PDF-operaattorit olivat asettaneet kussakin piirtotoiminnossa

Juuri tämä viimeinen osa on kohta, jossa useimmat itse tehdyt muuntimet hiljaa pettävät. PDF-sivun muuttaminen SVG:ksi näyttää koordinaattiongelmalta, mutta osoittautuu tilaongelmaksi. PDF on pinokone, jonka piirtotila muuttuu sisältövirtaa tulkittaessa; SVG puolestaan on deklaratiivinen puu, jonka jokainen elementti kantaa omat esitysattribuuttinsa. Kaikki, mitä tulkki ei onnistu tallentamaan hetkellä, jolloin elementti tuotetaan, katoaa tulosteesta jäljettömiin, ja virhe on äänetön: tuloksena on kelvollinen SVG, joka piirtää hienovaraisesti väärän sivun

Miksi PDF-sivu ei vain muunnu suoraan SVG:ksi?

Kolme yhteensopimattomuutta tekevät muunnoksesta ei-triviaalin, ja kaikki kolme tuottavat tulosteen, joka näyttää uskottavalta, kunnes sitä vertaa rinnakkain alkuperäiseen. Ensimmäinen on y-akseli. PDF:n käyttäjätila kasvaa ylöspäin sivun vasemmasta alakulmasta; SVG kasvaa alaspäin vasemmasta yläkulmasta. Yksittäinen sivutason peilaus korjaa piirtokoordinaatit ja rikkoo sitten jokaisen glyyfin, koska koko piirtoalueen peilaaminen peilaa myös kirjainmuodot

Toinen yhteensopimattomuus on periytyminen. PDF:ssä q ja Q työntävät ja palauttavat piirtotilan pinosta, mikä kattaa viivan leveyden, viivan päätteen, viivan liitoksen, kulmarajan, viivakuvion, viivakuvion vaiheen ja alfa-arvon. SVG:ssä elementti, joka ei nimeä attribuuttia, perii sen esi-isäryhmältä, mikä on täysin eri näkyvyyssääntö. Vientityökalu, joka seuraa vain nykyistä muunnosmatriisia ja unohtaa piirtotilan, päästää Q:n jälkeen palautetun tilan vuotamaan seuraaviin elementteihin

Kolmas on se, että PDF ilmaisee useita asioita sopimuksenvaraisesti, ei arvon kautta. Viivan päätteet ja liitokset ovat kokonaislukuja, nollaviivanleveys tarkoittaa laitetilan hiusviivaa eikä näkymätöntä viivaa, ja piirto-operaattorien tähtimuunnokset muuttavat kiertosääntöä värin sijaan. Jokainen näistä vaatii käännöksen, ei kopiointia

Yksi kutsu tavalliseen tapaukseen

Tavalliseen tehtävään, jossa sivuja viedään verkkokatseluohjelmaa, diff-työkalua tai suunnittelun luovutusta varten, API-pinta on yksi funktio. BuildLoadedPageSVG ottaa nollapohjaisen sivuindeksin nykyisin ladattua dokumenttia vastaan ja palauttaa SVG-dokumentin AnsiString-tyyppisenä:

var
  Pdf: THotPDF;
  I: Integer;
  Svg: AnsiString;
  Output: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('statements.pdf', '') <= 0 then
      Exit;                     // LoadFromFile palauttaa sivujen määrän
    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;

Sama vienti on käytettävissä myös HotPDF:n komentorivityökalun export-svg-komentona, mikä on hyödyllistä koontiputkissa ja regressioskripteissä, joissa halutaan tekstinä diffattava esitys sivusta kirjoittamatta Pascal-koodia. Koska SVG on tekstiä, se toimii luontevana parina rasteripolulle, joka kuvataan artikkelissa PDF-sivun renderöinti bittikartaksi: bittikartta kertoo, miltä sivu näyttää, SVG kertoo, mistä se koostuu

Miten PDF-teksti kuvataan SVG:n text-elementeiksi?

HotPDF muodostaa tekstimatriisiketjun järjestyksessä etuliite kertaa CTM kertaa tekstimatriisi kertaa glyyfipeilaus, jossa glyyfipeilaus on oikealta kertominen matriisilla matrix(1,0,0,-1,0,0). Tämä oikeanpuoleinen tekijä on olemassa ainoastaan kumotakseen sivutason pystysuuntaisen peilauksen glyyfimuodoille, sillä muuten peilatussa paikallisessa kehyksessä piirretty SVG-teksti näkyisi ylösalaisin. Kun korjaus tehdään matriisissa erikoistapauskoodin sijaan, kierretty, peilattu ja vinoutettu teksti tulee kaikki oikein ilman ylimääräisiä haaroja

Vaakasuora sijoittelu käyttää SVG:n text-elementin monilukuista x-syntaksia, yksi koordinaatti merkkiä kohden, kertyneenä jokaisesta glyyfin etenemästä sekä kulloinkin voimassa olevasta merkkivälistyksestä Tc ja sanavälistyksestä Tw. Vaakasuora skaalaus Tz on taitettu tekstimatriisin a- ja c-sarakkeisiin erillisen tuottamisen sijaan, joten katseluohjelma, joka jättää huomiotta eksoottiset tekstiattribuutit, silti sijoittaa jokaisen glyyfin sinne, minne PDF sen asetti. Monimutkaisen muotoilun kautta tuotettu teksti, josta kerrotaan artikkelissa monimutkaisten kirjoitusjärjestelmien tekstin muotoilu, kulkee saman polun, koska muotoilija on jo ratkaissut klusterit sijoitetuiksi glyyfeiksi siihen mennessä, kun sisältövirtaa tulkitaan

Kierto ja kuvat: kaksi peilausta, jotka on helppo tehdä väärinpäin

Sivu, jolla on nollasta poikkeava /Rotate-arvo, tarvitsee esimuunnoksen, joka koostuu peilauksesta kierretyn piirtoalueen korkeutta vasten sekä kierrosta ilmaistuna y-ylös-näyttötilassa. Kolme kiertomatriisia ovat (0,-1,1,0,0,W) 90 asteelle, (-1,0,0,-1,W,H) 180 asteelle ja (0,1,-1,0,H,0) 270 asteelle, missä W ja H ovat sivun mitat ennen kiertoa. Näiden johtaminen käsin altistaa merkkivirheille juuri kolmessa kohdassa, joten vientityökalu muodostaa ne saman matriisikertolaskurutiinin kautta, joka käsittelee kaikki muutkin muunnokset

Upotetut kuvat tarvitsevat oman peilauksensa, koska PDF:n kuvatila sijoittaa ensimmäisen näyterivin yksikköneliön yläreunaan, kun taas SVG:n image-elementillä on y-alas-paikallinen kehys. Tuotettu muunnos on siis CTM oikealta kerrottuna matriisilla matrix(1,0,0,-1,0,1). Tämän tekeminen väärin tuottaa pystysuunnassa peilattuja valokuvia muuten täydellisellä sivulla, ja tällaisen virheen arvioija huomaa välittömästi, mutta automaattinen testi usein ei

Mitä piirtotilalaite todella säilyttää?

HotPDF ohjaa piirtotilan operaattorit w, J, j, M ja d erillisen valinnaisen laiterajapinnan kautta, joten viivan piirtotarkkuus lisättiin muuttamatta olemassa olevan sisältölaitteen vtable-taulua ja rikkomatta binaarista yhteensopivuutta aiempia versioita vasten käännetylle koodille. Käytännössä viety SVG saa käännettyjä avainsanoja raakojen PDF-kokonaislukujen sijaan:

// PDF:n kokonaislukuenumeraatioista tulee SVG:n avainsana-attribuutteja
//   line cap  0, 1, 2  ->  butt, round, square
//   line join 0, 1, 2  ->  miter, round, bevel
//
// Nollaviivanleveys tarkoittaa PDF:ssä laitetilan hiusviivaa, joten
// vientityökalu tuottaa vector-effect="non-scaling-stroke", jotta
// viiva pysyy näkyvänä ja lähes yhden laitepikselin levyisenä CTM:n jälkeen
//
// f* B* b* valitsevat parillinen-pariton-säännön ja tuottavat fill-rule="evenodd",
// kun taas f B b säilyttävät SVG:n oletuksena olevan nonzero-kiertosäännön

Tilan palautus Q:ssa kattaa läpinäkyvyyden, viivan leveyden, päätteen, liitoksen, kulmarajan, viivakuvion ja viivakuvion vaiheen yhdessä. Sisäkkäiset Form XObject -objektit tallentavat ja palauttavat saman täyden joukon rajoillaan, joten leimauksen sisällä määritelty katkoviivainen reuna ei voi vuotaa kuviotaan seuraavaan sivusisältöön. Jos seuraat jo leikkausta ja CTM-käyttäytymistä muista syistä, tämä on sama tilamalli, joka esiintyy artikkelissa EMF- ja WMF-vektorituonti, vain vastakkaiseen suuntaan käytettynä

Rajat, jotka kannattaa tuntea ennen käyttöönottoa

Vientityökalu on rehellinen kattavuudestaan, ja rajojen tunteminen etukäteen on halvempaa kuin niiden löytäminen tuotannossa. Väri saapuu SVG-laitteelle operaattoreiden rg, RG, g ja G kautta. Väriavaruuden ja scn:n kautta määritetyt täytöt, joilla Separation-, DeviceN- ja ICCBased-värit maalataan, eivät saavu laitteelle ratkaistuna RGB-kolmikkona, joten sivut, jotka käyttävät spottivärejä tällä tavoin, vievät geometriansa mutta eivät näitä värejä. Painotarkoituksiin suunnatuille lähteille rasteroi sen sijaan tai litistä spottivärit ensin; itse maalausmalli käydään läpi artikkelissa Separation- ja DeviceN-spottivärien renderöinti

Kaksi pienempää huomiota säästää vianetsintäaikaa. Heksadesimaaliset värikirjaimet tuotetaan isoin kirjaimin, joten testi, joka väittää arvoa #ff0000, epäonnistuu täysin oikeaa arvoa #FF0000 vastaan. Ja SVG-laite on viiteytetty rajapintansa kautta, mikä tarkoittaa, että sen vapauttaminen tapahtuu antamalla rajapinnan pudota käytöstä Free-kutsun sijaan objektille, ja tällä erolla on merkitystä, jos laajennat laitetta tuottamaan omaa merkintääsi sivusisällön rinnalle

SVG-vienti sopii luontevasti yhteen rakenteellisen vertailun kanssa, kun on tarpeen tietää, muuttuiko tuotettu dokumentti todella kahden koonnoksen välillä. Laajempi ladattujen dokumenttien ympärillä oleva työkalupakki, renderöinnistä muokkaukseen ja vientiin, on dokumentoitu sivulla HotPDF Delphi PDF -komponentin sivulla