PDFium, Chrome'un PDF sekmesinin arkasındaki oluşturucu olan bir görüntüleme motoru olarak üne sahiptir, bu nedenle açıklığa kavuşturulması gereken ilk şey, PDFium Bileşeni'nin daha önce hiç var olmayan bir belgeyi de oluşturabileceğidir. Yazarlık tarafı PDFium'un sayfa-nesnesi API'sini sarar: boş bir belge oluşturursunuz, açık boyutlara sahip sayfalar eklersiniz ve her bir sayfaya seçtiğiniz koordinatlarda metin, vektör yolları ve resimler bırakırsınız. Öğrenilecek hiçbir sayfa tanımlama dili yoktur ve döngüde yazıcı sürücüsü yoktur. Yöntemleri çağırırsınız, kütüphane PDF nesnelerini bir araya getirir ve SaveAs sonucu seri hale getirir
Elde edemeyeceğiniz şey bir düzen motorudur. Bu, en başından söylenecek kadar önemlidir, çünkü aşağıdaki her örneği şekillendirir. PDFium Bileşeni içeriği yalnızca söylediğiniz yere, mutlak koordinatlarda yerleştirir ve başka hiçbir yere yerleştirmez. Bir paragrafı kaydırmaz, bir sayfa sonu boyunca metni akıtmaz veya satır ve sütunlardan bir tablo hesaplamaz. Bunlar sizin işiniz. Düzyazıyı bir kelime işlemcinin yaptığı gibi yeniden düzenleyen bir şey bekleyerek geldiyseniz, şimdi beklentinizi ayarlayın: bu, bir belgeyi dizmekten çok bir tuval üzerine çizim yapmaya daha yakın, hassas ve düşük seviyeli bir yerleştirme API'sidir. Üretilen faturalar, sertifikalar, etiketler ve her bir öğenin nereye ait olduğunu zaten bildiğiniz rapor sayfaları için, bu hassasiyet tam olarak istediğiniz şeydir
Bir dosya üreten minimum değer
Boş bir TPdf ile kaydedilmiş bir PDF arasında üç çağrı bulunur: belgeyi oluşturun, bir sayfa ekleyin, yazın. Geri kalan her şey, araya katmanladığınız içeriktir
uses
Vcl.Graphics, // for clBlack and TColor
PDFium; // TPdf lives here
procedure CreateBlankPdf(const FileName: string);
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument; // empty in-memory document
Pdf.AddPage(0, 595, 842); // A4 portrait, in points
Pdf.AddText('First page', 'Arial', 18, 50, 780);
Pdf.SaveAs(FileName); // serialize to disk
finally
Pdf.Active := False;
Pdf.Free;
end;
end;
Daha eski kod parçacıklarını görenleri bir detay yanıltabilir: CreateDocument işleminden sonra Pdf.Active := True ataması yapmazsınız. Active özelliği, bir belge tutucusunun var olup olmadığını bildirir ve CreateDocument zaten bir tane oluşturmuştur, bu nedenle özellik çağrı döndüğü anda True olur. Yeniden ayarlamak en iyi ihtimalle hiçbir işe yaramaz ve en kötü ihtimalle sonraki okuyucuyu yanıltır. Active çıkışta görevini yapar: False atamak, Free işleminden önce temel belgeyi serbest bırakır; bu da temiz bir sökme sırasıdır. CreateDocument ve dosya yükleme açılışına birbirini dışlayan işlemler olarak davranın. Kütüphane, zaten bir belgenin açık olduğu bir TPdf üzerinde yeni bir belge oluşturmayı reddeder, bu nedenle yeniden kullanmak mevcut belgeyi önce kapatmak anlamına gelir
Koordinatlar sol alttan başlar
AddText ve her yerleştirme çağrısı için ikinci argüman çifti, PDF kullanıcı alanındaki bir noktadır. Orijin, sayfanın sol alt köşesinde bulunur, X sağa doğru ilerler ve Y yukarı doğru ilerler. Bir birim bir noktadır, bir inçin 1/72'si, yani bir A4 sayfası 595'e 842 birim ve US Letter 612'ye 792 birimdir. Yukarı doğru olan Y, "metnim sayfanın dışında" karışıklığının en yaygın kaynağıdır, çünkü ekran ve bit eşlem koordinatları orijini en üste yerleştirir ve Y aşağı doğru büyür. 842 puan yüksekliğinde bir sayfada, en üste yakın bir başlık Y 60'ta değil, Y 780 civarında oturur. Bir çalışma beklenmedik bir yere düştüğünde, sayfa yüksekliği eksi Y değeriniz neredeyse her zaman aslında kastettiğiniz sayıdır
AddPage ilk argümanı olarak, 1 tabanlı ifade edilen ve 0'ın uygun bir "belge başlangıcı" kısayolu olduğu bir ekleme konumu alır. İlk sayfa için 0 veya 1 geçin ve sayfa en başa eklenir; sona eklemek için ekleme yaptığınız sayı ile eşleşen değeri geçin. Yeni eklenen sayfa aynı zamanda geçerli sayfa haline gelir, sonraki çizim çağrılarının hedeflediği sayfa, bu nedenle eklendikten sonra ayrı bir "bu sayfayı seç" adımı yoktur. Birkaç sayfa eklerseniz ve daha sonra önceki sayfalardan birine geri çizim yapmanız gerekirse, imleci taşımak için PageNumber değerini ayarlayın; sayfaları oluşturdukça sırayla doldururken, onu olduğu gibi bırakabilirsiniz
Metin yazma ve sessizce ısıran yazı tipi kuralı
AddText imzası, tek bir çalıştırmanın ihtiyaç duyduğu her şeyi taşır: dize, yazı tipi adı, nokta cinsinden boyut, X ve Y bağlantısı, ardından isteğe bağlı renk, şeffaflık için bir alfa baytı ve derece cinsinden dönüş açısı
procedure WriteHeader(Pdf: TPdf; const Title, Author: string);
begin
// Title in black, default opacity, no rotation
Pdf.AddText(Title, 'Arial', 20, 50, 780);
// A lighter byline 24 points below it
Pdf.AddText('By ' + Author, 'Arial', 11, 50, 756, clGray);
// A faint diagonal draft stamp across the page
Pdf.AddText('DRAFT', 'Arial', 64, 180, 380, clGray, $30, 45.0);
end;
Alfa baytı $00 (görünmez) ile $FF (opak) arasında değişir ve taslak damgasını sağlam bir bloktan ziyade bir filigran yapan şey budur: $30, yaklaşık olarak yüzde on dokuzluk bir opaklıktır, bu da içini okuyabilmek için yeterlidir. Açı, çalışmayı bağlantı noktasının etrafında saat yönünün tersine döndürür, bu nedenle 45 derece klasik köşeden köşeye damgayı verir. Bunların hiçbirinin ayrı bir filigran özelliğine ihtiyacı yoktur. Filigran, yalnızca büyük, yarı saydam, döndürülmüş bir AddText çağrısıdır ve onu gövdeden önce veya sonra çizmek, içeriğin arkasında mı yoksa üstünde mi oturacağına karar verir
Yazı tipleri dikkatli bir cümleyi hak ediyor, çünkü hata modu sessiz. Bir yazı tipi adı geçtiğinizde, PDFium Bileşeni işletim sisteminden o yazı tipinin TrueType verilerini ister ve belgeye gömer; makinenizde oluşturulan bir dosyanın yazı tipinin hiç yüklenmediği bir dosyada tamamen aynı şekilde işlenmesinin nedeni budur. İşin püf noktası, ad çözümlenmediğinde ne olduğudur: bir yazım hatası veya yapı makinesinde basitçe bulunmayan bir yüz. Hiçbir istisna yoktur. Kütüphane, hiçbir şey gömülmeden yalnızca etiket olarak adı taşıyan bir metin nesnesi oluşturmaya geri döner ve görüntüleyicinin yakın bulduğu herhangi bir şeyi yerine koymasına izin verir. Metin testlerinizde belirir, makul görünür ve dosya farklı yazı tiplerinin yüklü olduğu bir yerde açıldığı anda ölçümleri veya glifleri kaydırır. Üretici makinede bulunduğunu bildiğiniz isimleri kullanın, yazı tipi listesine bir dağıtım bağımlılığı olarak davranın ve çıktıya güvenmeden önce temiz bir sistemdeki bir görüntüleyicide örnek açın
Vektör şekilleri: bir yol oluşturun, sonra onu işleyin
Çizgiler, dikdörtgenler ve dolu bölgeler bir yoldan geçer. Birini, başlangıç noktasını ve tüm stili aynı anda, doldurma modunu, kendi alfa baytlarıyla dolgu ve kontur renklerini, kontur genişliğini, satır başlıklarını ve birleşimlerini ayarlayan CreatePath ile açarsınız. Ardından LineTo, BezierTo ve ClosePath ile uzatırsınız ve son olarak AddPath bitmiş yolu sayfaya işler. İşleme adımını unutmak kolaydır ve atlarsanız hiçbir şey üretmez
procedure DrawDivider(Pdf: TPdf; X, Y, Width: Single);
begin
// A thin horizontal rule. The rectangle overload sets a box directly:
// X, Y, Width, Height, then fill mode and colors.
Pdf.CreatePath(X, Y, Width, 0.5, fmNone, clBlack, $FF,
True, clBlack, $FF, 1.0);
Pdf.AddPath;
end;
procedure DrawTriangle(Pdf: TPdf);
begin
// Point overload: start at the first vertex, line to the rest, close.
Pdf.CreatePath(200, 300, fmWinding, clBlue, $80, True, clNavy, $FF, 2.0);
Pdf.LineTo(300, 300);
Pdf.LineTo(250, 400);
Pdf.ClosePath;
Pdf.AddPath; // nothing is drawn until this runs
end;
İki aşırı yükleme, yaygın durumları kapsar. Dört koordinatlı form X, Y, genişlik ve yüksekliği alır ve tek bir çağrıda size eksenle hizalı bir dikdörtgen verir; bir kural, hücre sınırı veya dolu bir arka plan paneli çizmek için ulaştığınız şey budur. İki koordinatlı form yalnızca bir başlangıç noktası belirler ve taslağın geri kalanını LineTo ve BezierTo ile kendiniz izlersiniz. Dolgu modu, örtüşen bölgelerin nasıl boyandığını kontrol eder: fmWinding (sıfır olmayan sargı) çoğu katı şekle uyar, fmAlternate (çift-tek) kesikleri ve kendi kendine kesişen anahatları yönetir ve fmNone, yalnızca konturlu, dolgusu olmayan bir yol bırakır, yukarıdaki bölücünün kullandığı da budur
Tablolar, elle birleştirilen yollar ve metinlerdir
Bir tablo ilkeli (primitive) olmadığı için tablo bir döngüdür. Sütun X ofsetlerine ve satır yüksekliğine karar verirsiniz, her hücreyi AddText ile yazarsınız ve dikdörtgen yollarla kuralları çizersiniz. Aritmetik size aittir, ancak basittir ve bir kez yazıldığında ihtiyacınız olan herhangi bir ızgaraya genelleşir
procedure DrawTable(Pdf: TPdf; Left, Top: Double);
const
ColX: array[0..2] of Double = (0, 110, 210); // column offsets
RowH = 20;
var
Y: Double;
Row: Integer;
begin
// Header row
Pdf.AddText('Item', 'Arial', 10, Left + ColX[0], Top);
Pdf.AddText('Qty', 'Arial', 10, Left + ColX[1], Top);
Pdf.AddText('Price', 'Arial', 10, Left + ColX[2], Top);
// Rule under the header
Pdf.CreatePath(Left, Top - 5, 260, 0.5, fmNone, clBlack, $FF);
Pdf.AddPath;
// Data rows, stepping Y downward each iteration
Y := Top;
for Row := 1 to 3 do
begin
Y := Y - RowH;
Pdf.AddText('Item ' + IntToStr(Row), 'Arial', 9, Left + ColX[0], Y);
Pdf.AddText(IntToStr(Row * 2), 'Arial', 9, Left + ColX[1], Y);
Pdf.AddText('$' + IntToStr(Row * 10) + '.00', 'Arial', 9, Left + ColX[2], Y);
end;
end;
Yukarı yönün pozitif olmasından dolayı, Y'nin her geçişte satır yüksekliği kadar aşağı inmesine dikkat edin. Bu aynı zamanda metin ölçümünün olmamasının da görüldüğü yerdir: uzun bir öğe adının sonraki sütuna taşmasını hiçbir şey durduramaz, çünkü kütüphane dizenizin ne kadar geniş oluşturulduğunu bilmez. Verileri kontrol ettiğiniz sabit biçimli çıktılar için, sütunları cömertçe boyutlandırır ve devam edersiniz. Gerçekten değişken içerik için, ya girdileri kısıtlarsınız ya da yerleştirmeden önce glif genişliklerini kendiniz ölçersiniz; bu, özel bir kompozisyon kütüphanesinin masrafını çıkarmaya başladığı noktadır
Resimler ve çoklu sayfalar
Tarama (raster) içeriği, görüntü yardımcıları aracılığıyla gelir. AddPicture, yüklenmiş bir TPicture alır ve onu ölçeklendirmek için isteğe bağlı bir genişlik ve yükseklikle bir noktaya yerleştirir; AddImage doğrudan bir dosya yolu veya TBitmap kabul eder ve AddJpegImage bir bit eşlem aracılığıyla gidiş-dönüş yapmadan JPEG baytlarını aktarır. Diğer her şeyde olduğu gibi, yerleştirme koordinatları kullanıcı alanındaki görüntünün sol alt köşesidir ve genişlik ve yükseklik kaynağın piksel boyutları değil, nokta cinsinden sayfa içi boyuttur
procedure CreateMultiPageReport(const FileName: string; PageCount: Integer);
var
Pdf: TPdf;
P: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.CreateDocument;
for P := 1 to PageCount do
begin
Pdf.AddPage(P, 595, 842); // append; the new page becomes current
Pdf.AddText('Page ' + IntToStr(P) + ' of ' + IntToStr(PageCount),
'Arial', 10, 50, 30); // footer near the bottom edge
// ... draw this page's body here ...
end;
Pdf.SaveAs(FileName);
finally
Pdf.Active := False;
Pdf.Free;
end;
end;
Çok sayfalı bir belge, döngüdeki tek sayfalık kalıptır. Her AddPage, bir sayfa ekler ve onu geçerli hale getirir, böylece bir sonra çizeceğiniz gövde ve altbilgi, az önce eklediğiniz sayfaya düşer. Bu döngü içinde PageNumber değerini yeniden atamazsınız, çünkü sayfa eklemek imleci zaten oraya taşımıştır; yalnızca oluşturma sırası dışındaki bir sayfaya geri döndüğünüzde PageNumber'a ihtiyacınız olur. Son sayfa doldurulduktan sonra, en sonda SaveAs işlevini bir kez çağırın. Düz bir dosya yerine bir arşiv profiline ihtiyacınız varsa, aynı belge nesnesi SaveAsPdfA ve diğer uyumluluk türevlerini sunar, bu nedenle çıktı standardı seçimi farklı bir oluşturma yolu değil, farklı bir kaydetme çağrısıdır
Bu nereye uyuyor
Dürüst çerçeveleme, PDFium Bileşeni'nin yazar API'sinin, PDFium'un sayfa nesne modeli üzerinde sadık, ince bir katman olduğudur: gerçek belge oluşturma, gerçek gömülü yazı tipleri, gerçek vektör ve tarama (raster) içeriği, standartlara uygun bir dosyaya seri hale getirilmiştir. Metni yeniden düzenleyen bir belge motoru değildir ve öyleymiş gibi de davranmaz. Ayırıcı çizgi metin düzenidir. Çıktınız şablonlanmışsa, faturalar, sertifikalar, etiketler, sabit bir ızgarada oluşturulan gösterge tabloları ise, mutlak koordinat modeli doğrudan ve hızlıdır ve kod okunabilir kalır. Çıktınız kendi kendine kayması (wrap) ve sayfalandırılması (paginate) gereken uzun biçimli bir düz yazıysa, bu çağrıların üzerine bir düzen motorunu yeniden inşa edersiniz ve bu, iş için yanlış araçtır. Bu çizginin hangi tarafında olduğunuzu bilmek, kararın büyük kısmıdır
Burada açıklanan oluşturma yöntemleri, bu yazarlık yolunu PDFium'un daha iyi bilindiği oluşturma ve metin çıkarma özellikleriyle eşleştiren Delphi için PDFium Bileşeni'nin bir parçasıdır