Većina programera posmatra PDF stranicu kao list papira sa tekstom i slikama. Georeferencirani PDF je više od toga. On nosi dovoljno informacija da uzme tačku na stranici, izmerenu u običnim jedinicama stranice, i prijavi geografsku širinu i dužinu iznad koje se nalazi u stvarnom svetu. Ta jedna činjenica pretvara PDF u koristan nosač za topografsku kartu, katastarski plan, prikaz poplavne zone ili bilo koji GIS izvoz koji mora da se odštampa a da i dalje zadrži značenje. Geometrija se nalazi u datoteci; jedino pitanje je da li je vaš učitavač čita.
Razlog zašto se ovo propušta jeste to što se GeoPDF otvara i štampa tačno kao i svaki drugi PDF. Ništa na renderovanoj stranici ne najavljuje da je mapa registrovana na koordinatni sistem. Registracija živi u rečnicima koji vise sa objekta stranice, nikada se ne iscrtava, a pregledač koji ih ignoriše i dalje vam prikazuje mapu. Da biste uradili bilo šta prostorno sa datotekom, očitavanje koordinata premera, reprojekciju, preklapanje sa drugim slojevima, morate sami proći kroz te rečnike.
Dva standarda žive u divljini
Čitač koji želi da obrađuje stvarne datoteke mora da se nosi sa dve šeme georegistracije, jer su obe u opticaju i određena datoteka može koristiti bilo koju. Starija je OGC kodiranje opisano u OGC 08-139r2, koje stranici dodaje LGIDict (rečnik geospatijalne registracije). Ono prethodi bilo kakvom ISO odobrenju i bilo je de facto format za rane GeoPDF izlaze, tako da ga veliki broj starih mapa nosi i ništa drugo.
Moderna šema je ona koju je ISO standardizovao u ISO 32000-1 §8.8.2. Umesto jednog rečnika na nivou stranice, ona modeluje prostorne podatke kao stranicu Viewport sa priloženim Measure rečnikom, a rečnik merenja imenuje geografski koordinatni sistem. Ovo je kodiranje koje pišu Acrobat i trenutni GIS izvoznici. Robustan uvoznik proverava oba: čita viewports za ISO model i vraća se na (ili dodatno proverava) LGIDict za datoteke koje nose samo staru registraciju.
Viewports i njihove granice
U ISO modelu jedinica georegistracije je viewport, a stranica ih može imati nekoliko. Veliki list može postaviti glavnu mapu u jedan pravougaonik, umetak u drugoj razmeri u drugi, i panel legende koji uopšte nije georeferenciran. Svaki viewport nosi BBox, pravougaonik na stranici kojim viewport upravlja, tako da čitač zna na koji deo lista se odnosi dati koordinatni sistem. Testiranje pogotka kliknute tačke u odnosu na te okvire je način na koji pregledač odlučuje koji će rečnik merenja koristiti.
PDFlibPas direktno izlaže viewports izabrane stranice. GetPageViewPortCount vraća koliko ih ima, GetPageViewPortID pretvara indeks zasnovan na jedinici u ViewPortID ručku, a GetViewPortBBox čita granični pravougaonik jednu po jednu dimenziju. Argument Dimension bira koju ivicu ili opseg želite: 0 je Left, 1 je Top, 2 je Width, 3 je Height, 4 je Right, i 5 je Bottom.
var
Pdf: TPDFlib;
vpCount, i, vpID: Integer;
Left, Top, Width, Height: Double;
begin
Pdf := TPDFlib.Create;
try
if Pdf.LoadFromFile('topo_sheet.pdf', '') <> 1 then
raise Exception.Create('load failed');
Pdf.SelectPage(1);
vpCount := Pdf.GetPageViewPortCount;
for i := 1 to vpCount do
begin
vpID := Pdf.GetPageViewPortID(i);
Left := Pdf.GetViewPortBBox(vpID, 0);
Top := Pdf.GetViewPortBBox(vpID, 1);
Width := Pdf.GetViewPortBBox(vpID, 2);
Height := Pdf.GetViewPortBBox(vpID, 3);
// Left/Top/Width/Height describe the map area for this viewport
end;
finally
Pdf.Free;
end;
end;
Vrednost ViewPortID od nula iz GetPageViewPortID znači da viewport na tom indeksu nije mogao biti pronađen, pa ga proverite pre nego što prosledite ručku.
Unutar rečnika merenja
Geometrija koja registruje stranicu za svet živi u rečniku merenja koji je priložen uz viewport. GetViewPortMeasureDict vraća MeasureDictID za dati ViewPortID, ili nulu kada viewport nema rečnik merenja, što je uobičajen slučaj za legendu ili panel naslova. Rečnik merenja drži tri stvari vredne čitanja: koordinatne sisteme na koje se odnosi, nizove koji povezuju tačke stranice sa geografskim tačkama i jedinicu u kojoj su podaci o tačkama izraženi.
Sama registracija je u vidu dva paralelna niza. GPTS je niz geografskih tačaka, parova geografske širine i dužine datih u geografskom koordinatnom sistemu. LPTS je niz tačaka prostora stranice, izraženih kao delovi BBox-a viewport-a kako bi preživeli skaliranje. Stavka n niza LPTS i stavka n niza GPTS označavaju istu fizičku lokaciju, jednom u koordinatama stranice i jednom na globusu. Tri ili više takvih parova definišu afinu, ili u opštem slučaju projektivnu transformaciju koja preslikava bilo koju koordinatu stranice unutar viewport-a u svetsku koordinatu. Čitanje tih vrednosti podrazumeva istovremeni prolazak kroz oba niza.
var
measID, gptsCount, lptsCount, j: Integer;
lat, lon, px, py: Double;
begin
measID := Pdf.GetViewPortMeasureDict(vpID);
if measID <> 0 then
begin
gptsCount := Pdf.GetMeasureDictGPTSCount(measID);
lptsCount := Pdf.GetMeasureDictLPTSCount(measID);
// GPTS holds lat/lon pairs; LPTS holds the matching page fractions.
// Both arrays are read with one-based item indices.
j := 1;
while j < gptsCount do
begin
lat := Pdf.GetMeasureDictGPTSItem(measID, j);
lon := Pdf.GetMeasureDictGPTSItem(measID, j + 1);
px := Pdf.GetMeasureDictLPTSItem(measID, j);
py := Pdf.GetMeasureDictLPTSItem(measID, j + 1);
// (px, py) on the page corresponds to (lat, lon) on the ground
Inc(j, 2);
end;
end;
end;
Rečnik merenja takođe izveštava o svojim jedinicama prikaza kroz GetMeasureDictPDU, koji uzima UnitIndex od 1 za linearne, 2 za površinske ili 3 za ugaone jedinice i vraća kod koji identifikuje specifičnu jedinicu, na primer metar ili međunarodnu stopu za linearnu kategoriju. Niz Bounds, koji se čita pomoću GetMeasureDictBoundsItem, opisuje četvorougao unutar viewport-a koji merenje zapravo pokriva, što nije uvek ceo pravougaonik.
WKT naspram EPSG
Geografska širina i dužina u GPTS nizu su besmislene bez znanja kom geografskom koordinatnom sistemu pripadaju, pošto koordinata 51.5, -0.1 sleće na različito fizičko mesto pod WGS 84 nego pod starijim nacionalnim datumom. Rečnik merenja daje odgovor na ovo kroz rečnik koordinatnog sistema, do kog se dolazi pomoću GetMeasureDictGCSDict za geografski sistem. PDF opisuje taj sistem na jedan od dva zamenljiva načina, a čitač mora da prihvati bilo koji.
Prvi je WKT, Well-Known Text, samostalni string koji u potpunosti navodi datum, elipsoid, početni meridijan i jedinice. Rečit je ali nedvosmislen i ne zahteva spoljnu tabelu pretrage. Drugi je EPSG kod, jedan ceo broj koji indeksira koordinatni sistem u EPSG registru; 4326 is WGS 84, the frame most consumer GPS data uses. EPSG je kompaktan ali pretpostavlja da čitač može da razreši kod u odnosu na bazu podataka. Datoteke se pojavljuju sa jednim, drugim ili oba, zbog čega API izlaže sva tri poziva GetCSDictType, GetCSDictEPSG i GetCSDictWKT. GetCSDictType izveštava da li je sistem geografski (GEOGCS, povratna vrednost 1) ili projektovani (PROJCS, povratna vrednost 2), omogućavajući vam da ispravno interpretirate ostatak pre nego što mu verujete.
var
gcsID, csType, epsg: Integer;
wkt: WideString;
begin
gcsID := Pdf.GetMeasureDictGCSDict(measID);
if gcsID <> 0 then
begin
csType := Pdf.GetCSDictType(gcsID); // 1 = GEOGCS, 2 = PROJCS
epsg := Pdf.GetCSDictEPSG(gcsID); // e.g. 4326 for WGS 84, 0 if absent
wkt := Pdf.GetCSDictWKT(gcsID); // full text description, '' if absent
// Prefer EPSG when present; fall back to parsing WKT otherwise.
end;
end;
Čitanje nasleđenog LGIDict-a
Datoteke koje prethode viewport modelu, ili koje su proizvedene alatima koji i dalje emituju starije kodiranje, nose svoju registraciju u LGIDict-u na stranici, a ne u rečniku merenja. PDFlibPas izveštava koliko takvih rečnika stranica ima kroz GetPageLGIDictCount i vraća sirovi sadržaj svakog od njih pomoću GetPageLGIDictContent, sa indeksiranjem od jedan. Vraćeni tekst je rečnik onakav kakav je napisan, koji drži polja registracije OGC 08-139r2, koja vaš kod zatim analizira kako bi povratio istu vrstu preslikavanja stranice u svet koju pruža rečnik merenja. Na strani upisa, AddLGIDictToPage prilaže LGIDict trenutnoj stranici, tako da konverter može uspešno da učita i sačuva (round-trip) stari oblik kada ga stari korisnik i dalje očekuje.
var
lgiCount, k: Integer;
dictText: WideString;
begin
lgiCount := Pdf.GetPageLGIDictCount;
for k := 1 to lgiCount do
begin
dictText := Pdf.GetPageLGIDictContent(k);
// dictText carries the OGC 08-139r2 registration to parse
end;
end;
Sklapanje čitanja u celinu
Kompletan uvoznik tretira ove dve šeme kao par prolaza preko svake stranice. Izaberite stranicu, zatražite od GetPageViewPortCount ISO viewports, i za svaki viewport koji poseduje rečnik merenja izvucite njegov BBox, njegove GPTS i LPTS nizove, njegovu jedinicu podataka o tačkama i GCS opis kroz rečnik koordinatnog sistema. Zatim proverite GetPageLGIDictCount za bilo koju staru registraciju koju prolaz viewport-a nije pokrio. Mapa koja nosi oba sistema bi trebala da ima njihovo slaganje; mapa koja nosi samo jedan i dalje se razrešava, jer ste pogledali na oba mesta. Ručke vraćene usput, ViewPortID, MeasureDictID, CSDictID, su obični celi brojevi koji ostaju važeći dok je dokument učitan, tako da je ceo prolazak nekoliko ugnežđenih petlji preko liste stranica bez potrebe za upravljanjem alokacijama.
Once you can recover the registration, the page becomes a data source rather than a picture. The companion techniques for reading the rest of a page are covered in the article on text, image, and font extraction, and rendering a georeferenced sheet to a device for on-screen measurement is described in the print and preview device-context walkthrough. The geospatial reader described here ships as part of the losLab PDF Library for Delphi and C++Builder, alongside the loading, extraction, and rendering APIs covered elsewhere on this blog.