Bir mimari CAD paketinin dışa aktardığı kat planı, tipik olarak ilk sayfasında iki viewport taşıyan bir /VP dizisine sahiptir ve her viewport, bir görüntüleyicinin metreleri doğrudan çizimden okuyabilmesi için bir /Measure girdisi taşır. Bir GeoPDF harita yaprağı aynı /VP dizisine ve aynı /Measure anahtarına sahiptir. Kat planı sıradan bir PDF 1.6'dır. Harita yaprağı ise PDF 1.7 artı Adobe Extension Level 3 ister. Anahtar adında duran bir sürüm denetimi her ikisi için de eklentiyi ister ve kat planı, hiç taşımadığı jeo-uzaysal içerikten bahseden bir mesajla kaydetme anında reddedilir
Tek bir /Measure anahtarı, iki farklı sözlük
Anahtar adı, viewport'un ölçülebilir olduğunu söyler; nasıl ölçülebildiğini yalnızca ardındaki sözlük söyler. Ölçüm sözlükleri PDF 1.6'da geldi ve ISO 32000-1 §12.9 doğrusal (rectilinear) türü tanımlar: /R içinde bir ölçek oranı dizgesi, /X ve /Y içinde sayı biçimi dizileri, uzaklık (/D) ve alan (/A) için öteki diziler. Jeo-uzaysal ölçüm sonra geldi; PDF 1.7 üzerine Adobe Extension Level 3'ün parçası olarak. /Subtype /GEO ile işaretlenir ve /GCS içinde coğrafi bir koordinat sistemi, isteğe bağlı bir görüntüleme koordinat sistemi için /DCS, /GPTS ve /LPTS içinde eşleşen nokta dizileri ve tercih edilen görüntüleme birimleri için /PDU taşır — yapılar Delphi'de GeoPDF viewport'larını, GPTS ve LPTS dizilerini okumak başlığında geziliyor
İnsanları tökezleten ayrıntı varsayılandır. §12.9, /Subtype girdisine varsayılan RL değerini verir ve pek çok CAD dışa aktarıcı bunun avantajını kullanıp girdiyi yazmaz. Eksik bir alt türü "bilinmiyor, kötüsünü varsay" diye okuyan bir denetleyici, o çizimlerin hepsini jeo-uzaysal bir belgeye çevirir. /Measure anahtarı üzerinde eşleşen bir denetleyici ise alt tür sorusuna hiç varmaz; çünkü anahtarı taşıyan viewport sözlüğü, cevabı veren ölçüm sözlüğünün bir üst düzeyindedir
PDF Library for Delphi kaydetme preflight'ı karara nasıl varıyor?
PDF Library for Delphi (PDFlibPas), hiçbir çıktı yazılmadan önce SaveToFile içinde bir sürüm preflight'ı koşar. Her dolaylı nesneyi ziyaret eder, iç içe sözlüklere ve dizilere iner ve her düğümü bir özellik kuralı tablosuna karşı sınar. Her kural bir minimum PDF sürümü ve eklenti özellikleri için bir Adobe eklenti düzeyi adlandırır; bir eklenti kuralı, yalnızca PDF 1.7 ile katalogdaki eşleşen bir /Extensions /ADBE girdisi birlikte olduğunda karşılanabilir. Karşılaştırdığı hedef, belge sürümüdür — ya da LockSaveVersion ile sabitlediğiniz sürüm — artı katalogun bildirdiği eklenti düzeyi. Hem eşleşen hem hedefi aşan ilk kural kaydı bitirir: SaveToFile 0 döndürür ve LastErrorCode, PDFLIB_ERROR_VERSION_COMPLIANCE sabitinin değeri olan 602 olur
Tek bir hata kodu neyi düzelteceğinizi söylemez. Üç GetInformation anahtarı gerisini taşır: 311, suçlu özelliğin gerektirdiği sürümdür (örneğin 1.7 ExtensionLevel 3); 312, özelliğin adıdır; 313 ise save hedefinin kilitli olduğu sürümdür ve hiçbir şey kilitli değilken boştur
var
Pdf: TPDFlib;
begin
Pdf := TPDFlib.Create;
try
if Pdf.LoadFromFile('floor-plan.pdf', '') <> 1 then
raise Exception.Create('load failed');
if Pdf.SaveToFile('floor-plan-out.pdf') <> 1 then
if Pdf.LastErrorCode = PDFLIB_ERROR_VERSION_COMPLIANCE then
// 311: gereken sürüm, 312: tetikleyen özellik,
// 313: save hedefinin kilitli olduğu sürüm (kilit yoksa '')
Writeln('Needs ', Pdf.GetInformation(311),
' for ', Pdf.GetInformation(312),
', locked at [', Pdf.GetInformation(313), ']');
finally
Pdf.Free;
end;
end;
Ölçüm içeriği için tabloda üç kural vardır ve çıplak /Measure anahtarı üzerinde bilinçli olarak hiçbir kural yoktur. /VP ya da /UserUnit taşıyan bir sayfa PDF 1.6 ister. Bir /PtData sözlüğü eklenti düzeyi 3 ister. Bir ölçüm sözlüğü, /Subtype /GEO dediğinde ya da /GCS, /DCS, /GPTS, /LPTS ya da /PDUdan herhangi birini taşıdığında eklenti düzeyi 3 ister. Böylece /Subtype girdisini atlayan bir viewport ölçüm sözlüğü ile /RLyi açıkça yazan aynı düzeyde 1.6'da geçer; aynı sayfa 1.5'teyken /VP nedeniyle reddedilir. Bir /GPTS dizisi ekleyin, cevap 1.7 ExtensionLevel 3 olur
İçerik testi bilinçli olarak muhafazakârdır. Başıboş bir /GCS ya da /PDU da taşıyan doğrusal bir sözlük jeo-uzaysal sayılır. O dosyayı geçirmektense reddetmeyi tercih ederiz: o anahtarlar doğrusal modelde hiçbir şey ifade etmez; yazan ya bir jeo-uzaysal araçtır ya da dosyayı bozmuş bir şeydir ve GEO farkındalıklı bir görüntüleyici onları yorumlamayı deneyebilir. Yükleyici öbür yönde de aynı derecede titizdir. Özellik taraması belgenin sürüm numarasını 1.7'ye çıkarabilir ama bir girdi dosyası adına asla /Extensions bildirimi yazmaz — eklenti bildirmek içerik hakkında bir iddiadır ve onu yalnızca sizin kodunuz ya da yazma çağrıları yapmalıdır
Kaydetmeden önce bir çizimin viewport'larını denetlemek
312 bir jeo-uzaysal özellik adlandırıyordu ve dosyanın düz bir çizim olduğundan eminseniz, ölçüm sözlüklerine kendiniz bakın. Herkese açık viewport çağrıları yeterlidir. GetMeasureDictCoordinateSystem /Subtype girdisini okur ve RL için 1, GEO için 2 döndürür; girdi yokken 0 döner — ki §12.9'a göre bu da doğrusal demektir. Nokta dizisi sayıları, jeo-referans verisinin bulunup bulunmadığını söyler
// Yüklü belgedeki her ölçüm sözlüğünü raporla.
// Buradaki çağrıların hepsi yalnızca okur; hiçbiri dosyaya anahtar eklemez.
procedure ReportMeasureDicts(Pdf: TPDFlib);
var
Page, VP, VPID, MD, Kind: Integer;
begin
for Page := 1 to Pdf.PageCount do
begin
Pdf.SelectPage(Page);
for VP := 1 to Pdf.GetPageViewPortCount do
begin
VPID := Pdf.GetPageViewPortID(VP);
MD := Pdf.GetViewPortMeasureDict(VPID);
if MD = 0 then
Continue;
Kind := Pdf.GetMeasureDictCoordinateSystem(MD); // 0 = atlanmış (RL), 1 = RL, 2 = GEO
Writeln(Format('page %d viewport "%s": subtype %d, GPTS %d, LPTS %d',
[Page, string(Pdf.GetViewPortName(VPID)), Kind,
Pdf.GetMeasureDictGPTSCount(MD), Pdf.GetMeasureDictLPTSCount(MD)]));
end;
end;
end;
O döngüde iki çağrı bilinçli olarak eksiktir: GetMeasureDictGCSDict ve GetMeasureDictDCSDict. O ikisi, yazma için kurulmuş al-ya-da-oluştur erişimcileridir. /GCS girdisi olmayan bir ölçüm sözlüğünde GetMeasureDictGCSDict boş bir tane ekler ve belge için eklenti düzeyi 3 bildirir. Doğrusal bir kat planında sonda gibi çağırın ve sözlük artık gerçekten /GCS içerir; 1.6'da kilitli bir sonraki kayıt, tanınızın yeni yazdığı içerik nedeniyle doğru biçimde reddedilir. Bir koordinat sisteminin var olup olmadığını bilmeniz gerekiyorsa alt tür ve nokta dizisi sayıları bunu yan etkisiz cevaplar
Çıktıyı PDF 1.6'da kilitlemek
Sabitlenmiş bir sürüm, tüketicilerinizin bir tavanı olduğunda çıktıyı dürüst tutar. TPDFlib.LockSaveVersion '1.0' ile '1.7' arasındaki dizeleri kabul eder ve başkaları için 0 döndürür. Belge sürümünü sabitler ve yazıcı tarafındaki çağrıların onu kendi başına yükseltmesini durdurur; ama kaydetme preflight'ı yine kilitli değere karşı koşar. 1.6'da kilitli bir CAD çizimi tertemiz kaydedilir. 1.6'da kilitli gerçek bir GeoPDF 602 alır ve istediğiniz cevap tam olarak budur; çünkü öteki seçenek, başlığı içeriğinin ihtiyacından az söz veren bir dosyadır
if Pdf.LockSaveVersion('1.6') <> 1 then
raise Exception.Create('unsupported version string');
try
if Pdf.SaveToFile('floor-plan-16.pdf') <> 1 then
if Pdf.LastErrorCode = PDFLIB_ERROR_VERSION_COMPLIANCE then
// 1.6 üstü gerçek içerik, örneğin bir GEO ölçüm sözlüğü
raise Exception.CreateFmt('Locked at 1.6 but %s needs %s',
[string(Pdf.GetInformation(312)), string(Pdf.GetInformation(311))]);
finally
Pdf.UnlockSaveVersion;
end;
Sürüme dokunmadan önce 311 ve 312'yi okuyun. Özellik gerçek bir jeo-uzaysal içerikse iki dürüst seçeneğiniz vardır: belgeyi eklenti bildirimiyle 1.7'de kilitlenmemiş bırakmak ya da yalnızca 1.6 tüketenine göndereceğiniz kopyadan jeo-uzaysal veriyi düşürmek. Hatayı susturmak için kilidi yükseltmek kaçınılacak seçenektir; gerçek soruyu gizler — aşağı akıştaki okuyucu gönderdiğinizi kaldırabilir mi? Jeo-uzaysal içeriği API üzerinden kurarken SetMeasureDictCoordinateSystem ve SetMeasureDictGPTSCount gibi SetMeasureDict* yazıcıları eklenti düzeyi 3'ü kendileri bildirir; böylece yazılan dosyalar preflight'a çoktan etiketlenmiş olarak gelir. Sınırlı ve kanıta dayalı denetim alışkanlığı mühendislik belgeleri için PDF/E-1 yazar modu preflight'ı başlığında da görülür; orada CAD çizimleri bir sürüm numarasıyla değil bir uyumluluk standardıyla karşılaşır
Kural taraması tabloyu neden yerinde okuyor?
Preflight'ın maliyeti kabaca nesne düğümü çarpı kuraldır ve düğüm sayısı, her dizinin içindeki her sayıyı ve adı kapsar. Bu, kural başına ek yükün göründüğünden daha önemli olduğunu gösterir. Tablodaki her kural iki AnsiString alanlı bir kayıttır: eşleşme dizgesi ve özellik adı. Böyle bir kaydı yerel bir değişkene kopyalamak, Delphi ya da FPC'nin iki referans sayımını artırmasını ve yerelin önceden tuttuğunu salıvermesini sağlar. Kural başına düğüm başına bir kez yapıldığında, hedef sürüme uygulanmayan ve bir sonraki satırda çöpe giden kurallar için bile dizge defter tutma bedeli ödenmiş olur
Kural tablosu birim başlatılırken bir kez doldurulur ve sonra hiç değiştirilmez; tarama, tablo girdilerini eşleme koduna const kayıt parametreleriyle verir ve onları yaşadıkları yerde okur. const bir kayıt parametresi referansla geçirilir; bir kuralı sınamak iki dizge alanına da dokunmaz ve referans sayıları eski halinde kalır. Etki kural eşleme yolunda yoğunlaşır. Gerçek bir kaydetme ayrıca nesneleri çözer, ertelenmiş özellik algılamayı koşar ve çıktıyı serileştirir; o aşamalar kuralların nasıl geçirildiğinden etkilenmez. Kural sırası, eşikler ve 311 ile 312'deki ilk başarısızlık tanısı buna bağlı değildir ve hiçbir kural sonucu kaydetmeler arasında önbelleklenmez; yani iki kez düzenleyip kaydettiğiniz bir belge her iki kez de eksiksiz denetlenir
Aynı desen, dizge, arayüz ya da dinamik dizi içeren kayıtlardan oluşan bir tabloyu gezen her döngüde kendi Delphi kodunuzda da denetlemeye değer:
type
TMyRule = record
Name: string; // yönetilen alan: kopyalar referans sayımı işine mal olur
Threshold: Integer;
end;
// Okuyucunun kendi kodu, bir desen olarak gösteriliyor
function Applies(const Rule: TMyRule; Value: Integer): Boolean;
begin
Result := Value >= Rule.Threshold; // const: kopya yok, refcount trafiği yok
end;
// Sıcak döngüde tablo girdisini doğrudan geçirin;
// önce yerel bir kayda atamayın
for I := 0 to High(Rules) do
if Applies(Rules[I], V) then
Inc(Hits);
Ölçüm viewport'ları, jeo-uzaysal sözlükler, sürüm kilitleme ve kaydetme anı uyumluluk denetimi, Delphi, C++Builder ve Lazarus projeleri için sunulan PDF Library for Delphi içinde gelir