PDFlibPas (losLab PDF Library), PDF blok şablonlarını Delphi tarafından doldurur: blok, şablon sayfası üzerinde adlandırılmış bir dikdörtgendir; metin, görsel ya da PDF olarak tiplendirilir ve FillTextBlock, FillImageBlock ile FillPDFBlock değişken veriyi içine çizer. Bloklar, PDFlibBlock:Text, PDFlibBlock:Image ve PDFlibBlock:PDF sayfa açıklamaları olarak ya da /PieceInfo altındaki bir page-piece sözlüğünde bulunur
Kullanım senaryosu sıkıcı, yüksek hacimli türdendir. Tasarımcı bir sertifika, bir etkinlik bileti ya da ödeme hatırlatma mektubunu bir kez dizer; program ise on bin kayıt için sabit yuvalara bir ad, bir koltuk numarası, bir imza görseli ya da önceden render edilmiş bir barkod sayfası basar. Form alanları bunun bir kısmını yapabilir ama bir AcroForm alanı, kendi appearance stream'i ve kendi kuralları olan etkileşimli bir nesnedir ve sonuçta genellikle yine de onu düzleştirirsiniz. Blok daha basittir: bir dikdörtgen artı bir avuç stil ipucu; bir kez tüketilir, sonra atılır
PDFlibPas'taki PDF bloğu tam olarak nedir?
Bir PDFlibPas bloğu, /Subtype değeri PDFlibBlock:Text, PDFlibBlock:Image ya da PDFlibBlock:PDF olan, /Rect'i yer tutucu alan olan ve /Contents dizgesi name;key=value;key=value barındıran bir sayfa açıklamasıdır. İlk kesim blok adıdır, sonrasındaki her şey bir özellik listesidir. TPDFlib.AddBlock, açıklamayı /F 4 (Print) ile ve appearance stream olmadan yazar; dolayısıyla doldurulmamış bir blok ekranda ya da kağıtta hiçbir piksel işgal etmez
Okuma tarafının ikinci bir kaynağı vardır. Blok açıklamalarını saydıktan sonra PDFlibPas, sayfa sözlüğü yoluna /PieceInfo << /PDFlib << /Blocks ... >> >> ve onun /PieceInfo << /PDFlib << /Private << /Blocks ... >> >> >> varyantına geri düşer. Page-piece sözlükleri standart PDF'tir ve ISO 32000-1 §14.5'te, bir uygulamanın sayfaya iliştirilmiş özel verileri sakladığı yer olarak tanımlanır; harici şablon hazırlama araçlarının blok tanımları da genellikle tam orada yaşar. /Blocks kapsayıcısı, blok adıyla anahtarlanmış bir sözlük ya da düz bir dizi olabilir; dizi biçiminde PDFlibPas, bloğun kendi /Name'i yoksa girdilere Block1, Block2 ve devamını adlandırır
Bir page-piece bloğunun içinde /Subtype (ya da /Type) değeri Image ise görsel bloğuna, PDF ya da Page ise PDF bloğuna eşlenir; geri kalan her şey metin sayılır. /Type, /Subtype, /Name, /Rect ve /Custom dışındaki her anahtar bir özelliğe dönüşür; iç içe bir /Custom sözlüğünün anahtarları da düzleştirilerek eklenir, böylece /Custom << /department (Finance) >> girdisi GetBlockProperty(Page, Index, 'department') olarak okunur. Blok indeksleri sayfa başına 1 tabanlıdır; önce açıklama blokları, ardından page-piece blokları gelir
AddBlock ile blok şablonu hazırlamak
TPDFlib.AddBlock(BlockType, BlockName, Left, Top, Width, Height, Properties), seçili sayfaya bir blok ekler ve başarı durumunda 1 döndürür. Boş ad, sıfır ya da negatif genişlik/yükseklik ya da 'text', 'image', 'pdf' dışında bir BlockType (büyük/küçük harf duyarsız) durumunda 0 döner. Properties, ada noktalı virgülle eklenir; yani saklanan dizgeyle aynı key=value;key=value söz dizimini kullanır
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
// statik grafikler: çerçeve, logo, sabit metinler ...
Lib.DrawText(72, 200, 'This certifies that');
Lib.AddBlock('text', 'recipient', 72, 230, 450, 44,
'fontname=Times-Bold;fontsize=30;fillcolor={cmyk 0 0.55 1 0.1};alignment=center');
Lib.AddBlock('text', 'course', 72, 290, 450, 24,
'fontname=Helvetica;fontsize=14;alignment=center;fitmethod=word');
Lib.AddBlock('image', 'signature', 360, 600, 160, 60, '');
Lib.AddBlock('pdf', 'seal', 72, 580, 100, 100, '');
if Lib.GetBlockCount(1) <> 4 then
raise Exception.Create('Template blocks missing');
Lib.SaveToFile('certificate-template.pdf');
finally
Lib.Free;
end;
end;
Özellik ayrıştırıcısı bilinçli olarak gevşektir. Anahtarlar büyük/küçük harf duyarsız eşlenir, değerler kenar boşlukları kırpılarak ama aksi hâlde olduğu gibi döndürülür ({top left} olarak yazılmış bir değer süslü parantezleriyle geri gelir) ve eksik anahtar boş bir dizge döndürür. Tek sert sınır ayracıdır: değer noktalı virgül içeremez, çünkü noktalı virgül kesimi bitirir
FillTextBlock fontu, rengi ve hizayı nasıl uygular?
TPDFlib.FillTextBlock(Page, BlockIndex, Text, Options) blok özelliklerini okur, bunları çizim durumuna uygular, metni blok dikdörtgenine FitTextBox ile sığdırır ve ardından çağıranın fontunu, metin boyutunu, metin rengini ve hizasını bir finally bloğunda geri yükler. Bir birleştirme döngüsünde o geri yükleme önemlidir: kırmızı 30 punto başlık bloğu, aynı sayfada yapacağınız bir sonraki DrawText çağrısına stili sızmamalı
fontname(ya dafont): önce belgede o adla zaten yüklü bir fontu yeniden kullanır, sonraHelvetica-Bold,Times-Romanya daCouriergibi Standard 14 adlarını eşler, en sonunda adlaAddTrueTypeFontdenerfontsize(ya dasize): sığdırıcıya verilen metin boyutu; metin sığmazsa onu küçültürfillcolor(ya datextcolor,color):#RRGGBB,{rgb r g b},{cmyk c m y k},{gray g}, çıplak 3 ya da 4 sayılık listeler ya da black, white, red, green, blue ve gray adları; 1'in üzerindeki RGB bileşenleri 0–255 olarak okunuralignment,alignvepositionbirlikte okunur: left, right, center (ya da centre) ve justify yatay hizayı, top ve bottom dikey yerleşimi ayarlar; varsayılan dikeyde ortalanmıştırfitmethod:wordya danofitsplituzun kelimelerin bölünmesini engeller,scaleya daexpandboyutun kutuyu doldurmak için büyümesine izin verir
CMYK yolu, matbaaların önemsemesinin nedenidir. {cmyk 0 0.55 1 0.1} çağrısı SetTextColorCMYK çalıştırır; değişken metin DeviceCMYK olarak yazılır ve baskıda RGB gidiş dönüşü olmadan marka rengine oturur. FillTextBlock, metin çizildiyse 1 döndürür; boş Text, bulunamayan blok ya da metin bloğu olmayan bir blok için 0 döner ve bu durumların hepsinde blok yerinde bırakılır
Görsel ve PDF bloklarını doldurmak ve Options bitleri
FillImageBlock(Page, BlockIndex, ImageID, Options) daha önce eklenmiş bir görseli çizer; FillPDFBlock(Page, BlockIndex, SourceDocumentID, SourcePage, Options) ise yüklü başka bir belgenin sayfasını Form XObject olarak içe aktarıp çizer; kaşe, QR kod sayfası ya da antet gibi vektör içeriği tamamen vektör tutar. İkisi de kaynak en-boy oranını korur ve sonucu blok dikdörtgeninin içinde ortalar. Üç doldurma işlevi de aynı Options bitlerini paylaşır: bit 1 (değer 1) başarılı doldurma sonrası bloğu kaldırır — açıklamayı ya siler ya da girdiyi /Blocks kapsayıcısından çıkarır; bit 2 (değer 2) ise görsel ve PDF içeriğini sığdırmak yerine tam dikdörtgene gerer
function FillCertificate(const TemplateFile, SealFile, SignatureFile,
OutFile: WideString; Values: TStrings): Boolean;
var
Lib: TPDFlib;
SealID, SignatureID, I: Integer;
BlockName, BlockType: WideString;
begin
Result := False;
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile(SealFile, '') <> 1 then Exit;
SealID := Lib.SelectedDocument; // gerçek belge kimliği (ID)
if Lib.LoadFromFile(TemplateFile, '') <> 1 then Exit;
// şablon artık seçili belge
SignatureID := Lib.AddImageFromFile(SignatureFile, 0);
// geriye doğru ilerle: bit 1 her bloğu kaldırır ve sonrakileri yeniden numaralandırır
for I := Lib.GetBlockCount(1) downto 1 do
begin
BlockName := Lib.GetBlockName(1, I);
BlockType := Lib.GetBlockType(1, I);
if BlockType = 'text' then
Lib.FillTextBlock(1, I, Values.Values[BlockName], 1)
else if (BlockType = 'image') and (SignatureID <> 0) then
Lib.FillImageBlock(1, I, SignatureID, 1)
else if BlockType = 'pdf' then
Lib.FillPDFBlock(1, I, SealID, 1, 1);
end;
Result := Lib.SaveToFile(OutFile) = 1;
finally
Lib.Free;
end;
end;
O döngüdeki iki ayrıntıyı kaçırmak kolaydır. Döngü en yüksek indeksten geriye doğru çalışır; çünkü blok 2'yi kaldırmak eski blok 3'ü blok 2 yapar ve bit 1 açıkken yukarı saymak bir blok atlayıp bir blok işler. Ayrıca FillPDFBlock için kaynak belge, şablon yüklenmeden önce yüklenir ve kimliği o sırada yakalanır; çünkü görsel kimlikleri seçili belgeye aittir, dolayısıyla AddImageFromFile şablon seçiliyken çalışmak zorundadır. Kaşenin ya da antetin kayıt başına değiştiği toplu çalıştırmalarda PDFlibPas'ta Form XObject sayfa birleştirme ve birleşik filigran şablonları aynı yakala-ve-çiz mekanizmasını bütün sayfalarda kullanır
Blok koordinatları neden çevrilmiş çıkar?
Kod, PDFlibPas'ın uğraştığı iki koordinat sistemini karıştırınca blok dikdörtgenleri çevrilmiş çıkar. Bir açıklamanın /Rect'i PDF user space'te saklanır ve sayfanın altından ölçülür (ISO 32000-1 §12.5.2); TPDFlib çizim API'si ise üstten ölçer. AddBlock üst tabanlı girdi alır ve alt kenarı PageHeight - Top - Height olarak saklar; GetBlockRect ile üç doldurma işlevi dikdörtgeni geri okur ve PageHeight - URy ile dönüştürür
Pratikte bu şu demektir: yuva geometrisine ihtiyacınız olduğunda — örneğin hata ayıklama çerçevesi çizmek ya da bir bloğun yanına başlık yerleştirmek için — GetBlockRect(Page, BlockIndex, Left, Top, Width, Height) kullanın; /Rect'i genel bir açıklama çağrısıyla okuyup doğrudan DrawText'e vermeyin. 792 pt'lik letter sayfada /Rect [40 700 240 730] değerli bir page-piece bloğu Top = 62 raporlar; 700 değil. Bunun önlediği hata klasiktir: doldurulan her değer alt kenar boşluğuna yakın aynalanmış çıkar ve hiçbir şey hata vermez
Ders çıkarılmaya değer tuzaklar
Blok kodundaki en öğretici hata tek karakterlik bir kaymaydı. Blok açıklamaları, subtype üzerinde bir önek testiyle tanınır ve 'PDFlibBlock:' 12 karakter uzunluğundadır. Erken bir sürüm, Copy(Subtype, 1, 13) sonucunu o 12 karakterlik sabit ile karşılaştırıyordu; bu ikisi asla eşit olamazdı, dolayısıyla GetBlockCount her şablon için 0 döndürüyor ve her doldurma "no such block" raporluyordu. Hiçbir şey çökmüyor, hiçbir şey kayda geçmiyordu. Ders her şablon motoruna genellenir: bilinen bir şablonun blok sayısını bir testte doğrulayın, çünkü sessiz sıfır eşleşmeli sayım boş bir sayfayla birebir aynı görünür
İkinci tuzak belge kimlikleridir. TPDFlib.LoadFromFile, yeni yüklediği belgenin kimliğini değil bir durum kodu döndürür: 1 başarı, 0 başarısızlık. O 1'i FillPDFBlock'a SourceDocumentID olarak vermek başarısız olur, çünkü 1 geçerli bir belge kimliği değildir. Gerçek kimliği almak için başarılı bir yüklemenin hemen ardından SelectedDocument çağırın; kaynağı sonra yüklediyseniz şablona geri dönmek için SelectDocument kullanın
Daha küçüğü: boş dizgeyle FillTextBlock hiçbir şey yapmaz ve bloğu tutar. İkinci adres satırı gibi isteğe bağlı alanların eksik olabildiği bir mail merge'de genellikle istediğiniz de budur, ama doldurulmamış açıklama bu kez çıktı dosyasında kalır. Çıktının temiz olması gerekiyorsa onu DeleteAnnotation ile açıkça silin ya da bit 1 ile tek bir boşluk doldurun. Tüm blok çağrıları seçili sayfayı kaydeder ve geri yükler; 3. sayfada bir doldurma, sonraki çizim çağrınızın gideceği yeri değiştirmez
Blok açıklamalarının birlikte çalışabilirlik sınırları nelerdir?
Blok açıklamaları standart bir PDF özelliği değil, özel bir kuraldır. PDFlibBlock:Text ve kardeşleri, ISO 32000-1 §12.5.6.1'de listelenen açıklama türleri arasında değildir; bir görüntüleyici onları bilinmeyen açıklamalar sayar. Invisible bayrağı temiz olduğu ve appearance stream bulunmadığı için standartlara uygun görüntüleyiciler onlar için hiçbir şey çizmez; yine de bazı görüntüleyiciler bunları bir yorum panelinde listeleyebilir ve diğer PDF araçları anlamlarını ne anlar ne korur
- Sisteminizden çıkacak her şeyi bit 1 açıkken doldurun; böylece nihai dosya yalnızca sıradan sayfa içeriği taşır
- PDF/A, PDF belirtimi dışındaki açıklama türlerine izin vermez (ISO 19005-1 §6.5.2); arşivlenecek bir çıktı bu yüzden doldurulmamış blok açıklamaları taşımamalıdır
- Page-piece blokları şablonda tutulmaya daha uygundur;
/PieceInfostandarttır ve tüketiciler sahibi olmadıkları veriyi yok sayar - Bloklar form alanı değildir: etkileşim yoktur, dosyada alan değeri yoktur ve FDF ya da XFDF dışa aktarımı yoktur; düzenlenebilir kalması gereken veriler için PDFlibPas'ta FDF, XFDF ve XFA form verisi alışverişine bakın
Şablon, değişken alanlarını bir baskı iş akışı için standartlaştırılmış ve doğrulayıcıca denetlenebilir biçimde bildirmek zorundaysa bloklar yanlış araçtır. PDF/VCR-1 tam bunun içindir; PDFlibPas'ta PDF/VCR-1 şablon yer tutucu manifestosu, o yer tutucuların açıklamalar yerine yapı ağacında nasıl yaşadığını anlatır
SSS
PDFlibPas, başka araçlarla üretilmiş blok şablonlarını doldurabilir mi?
Evet; araç blokları /PieceInfo /PDFlib /Blocks ya da /PieceInfo /PDFlib /Private /Blocks altında, sözlük ya da dizi biçiminde ve dört sayılık bir /Rect ile saklıyorsa doldurur. GetBlockCount bunları herhangi bir PDFlibBlock:* açıklamasından sonra sayar ve özel anahtarlar GetBlockProperty üzerinden görünür
FillTextBlock, çağrıdan önce seçtiğim fontu değiştirir mi?
Hayır. FillTextBlock seçili fontu, metin boyutunu, metin rengini ve hizayı saklar, bloğun fontname, fontsize, fillcolor ve alignment özelliklerini uygular ve sığdırma başarısız olsa bile sonrasında özgün durumu geri yükler
Bir bloğa vektör logo ya da barkod sayfasını nasıl yerleştiririm?
Kaynak PDF'i yükleyin, kimliği olarak SelectedDocument değerini saklayın, gerekiyorsa şablon belgesini yeniden seçin ve FillPDFBlock(Page, BlockIndex, SourceID, SourcePage, 1) çağırın. Sayfa Form XObject olarak içe aktarılır; vektör kalır ve bit 2 eklemediğiniz sürece en-boy oranı korunarak bloğa sığdırılır
Blok şablonları, Form XObject sayfa içe aktarımı ve değişken veri araç setinin geri kalanı PDFlibPas, losLab PDF Library for Delphi ile gelir; kütüphane Delphi ve C++Builder projeleri için PDF üretim, düzenleme ve baskıyı kapsar