Teknik Makale

Delphi'de PDFium Bileşeni ile Taranan Görüntüleri Tek Bir PDF'de Birleştirin

Bir hasar (claims-processing) işleme ekibinin yaprak beslemeli (sheet-fed) bir tarayıcıdan geçen otuz yıllık kağıt dosyaları vardı. Tarayıcı her sayfa için bir klasöre 0001.jpg, 0002.jpg ve benzeri isimlerde bir JPEG tükürdü (spat out). Arşivin aslında ihtiyaç duyduğu şey, bir inceleyicinin (reviewer) yüzlerce küçük resme (thumbnails) tıklamak yerine tek bir belge açabilmesi için sayfaların sırayla (in order) olduğu vaka dosyası (case file) başına tek bir PDF'di. Numaralandırılmış bir tarama yığınını (pile) tek bir sıralı (ordered) PDF'ye dönüştüren bu son adım, buradaki iştir

PDFium Bileşeni (Component) bunu doğrudan (directly) halleder. Oluşturma (rendering) ve metin çıkarmanın (extraction) ötesinde, bileşen sıfırdan bir PDF oluşturabilir: boş bir belge oluşturun, istediğiniz boyutta (sized however you like) boş bir sayfa ekleyin, kullanıcı uzayı (user-space) koordinatlarında o sayfaya bir görüntü bırakın (drop), ardından kaydedin. Tüm boru hattı (pipeline) TPdf bileşeni üzerinde yaşar, bu nedenle bir toplu (batch) dönüştürücü dosya adları üzerinde bir döngü artı (plus) bir avuç çağrıdır (calls)

Bir Delphi toplu iş hattı, numaralı taramalardan oluşan bir klasörü tek sıralı bir PDF'ye çevirmek için PDFium Component AddPage, PageNumber, AddImage ve SaveAs çağrılarını kullanır
Her tarama, AddPage'in kurduğu ve AddImage çizmeden önce PageNumber'ın hedeflediği bir sayfa olur; SaveAs biten belgeyi bir kez yazar

Dönüşümün (conversion) şekli

Her tarama (scan) için üç şeyin gerçekleşmesi gerekir. Sayfa boyutuna (size) karar (decide) verirsiniz, bir kenar boşluğu (margin) bırakarak görüntüyü (image) sayfanın içine (inside) yerleştirirsiniz ve bir sonraki sayfaya (page) ilerlersiniz (advance). PDFium Bileşeni (Component) her biri (each) için size bir yöntem (method) sunar (gives): AddPage verilen (given) bir boyutta boş (blank) bir sayfa oluşturur (creates), AddImage (veya zaten (already) bir TPicture tutuyorsanız (hold) AddPicture) bit eşlemi (bitmap) geçerli (current) sayfaya (page) çizer (draws) ve PageNumber bileşene daha (subsequent) sonraki çizim çağrılarının (calls) hangi (which) sayfayı hedeflediğini (target) söyler

İnsanları çelmeleyen (trips up) tek (one) detay koordinat (coordinate) sistemidir (system). PDF kullanıcı (user) alanı (space), Delphi geliştiricilerinin refleks olarak uzandığı (reach for) ekran (screen) koordinatlarının aksine (opposite), orijini (origin) sayfanın sol (lower-left) alt (lower-left) köşesine (corner) koyar ve Y yukarı doğru (upward) artar (increasing). AddImage'a geçirdiğiniz (pass) X, Y görüntü dikdörtgeninin (rectangle) sol (lower-left) alt köşesidir ve Width, Height kaynak dosyanın (file) piksel boyutu değil, nokta (points) cinsinden (in) yerleşim (placement) boyutudur. Bunu geriye (backwards) alın ve taramalarınız sayfanın (page) dışına iner (land) veya (or) onları beklediğiniz yere (where) göre ters (upside down) döner

Belgeyi (document) ve (and) tarama (scan) başına bir (a) sayfa oluşturma

Boş (empty) bir belge (document) ile (with) başlayın (Start). CreateDocument taze (fresh) bir PDF ayırır (allocates) ve (and) bileşeni (component) aktif (active) bırakır (leaves), bu nedenle ayrı (separate) bir (no) açık (open) adım (step) yoktur (no). Oradan taranmış dosyaların listesinde yürürsünüz (walk) ve her biri için (for each one) bir sayfa ekler (add), onu geçerli (current) yapar (make) ve görüntüyü yerleştirirsiniz (place). Buradaki sayfa (Page) boyutları (dimensions), arşivlenmiş (archived) yazışmalar (correspondence) için standart sayfa (sheet) boyutu (size) olan nokta (points) cinsinden (in) A4'tür (595 × 842 dikey (portrait))

procedure TArchiveForm.ScansToPdf(const Files: TStrings; const OutputPath: string);
const
  PageW = 595.0;   // nokta cinsinden A4 genişliği
  PageH = 842.0;   // nokta cinsinden A4 yüksekliği
  Margin = 36.0;   // her tarama çevresinde yarım inçlik kenar boşluğu
var
  I: Integer;
  Pdf: TPdf;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.CreateDocument;                       // new, empty, already active
    for I := 0 to Files.Count - 1 do
    begin
      Pdf.AddPage(I + 1, PageW, PageH);       // 1 tabanlı sayfa dizini
      Pdf.PageNumber := I + 1;                // yeni sayfayı geçerli yap
      PlaceScan(Pdf, Files[I], PageW, PageH, Margin);
    end;
    Pdf.SaveAs(OutputPath);
  finally
    Pdf.Free;
  end;
end;

Her yineleme (iteration) bir sayfa (page) oluşturur (creates) ve (and) hemen (immediately) ona PageNumber'ı ayarlar (sets). Bu (That) ikinci (second) satır (line) önemlidir (matters): AddPage sayfayı ekler (inserts) ancak (but) çizim (draw) yöntemleri (methods) hangi (whichever) sayfa (page) geçerliyse (current) onda (on) hareket eder (act), bu nedenle (so) PageNumber'ı ayarlamak (setting), AddImage'ı yeni (just) yaptığınız sayfaya yönelten (aims) şeydir (what). Onu atlayın (Skip it) ve resimleriniz daha (before) önce (before) yüklü (loaded) olan hangi sayfa (page) tesadüfen (happened to) geldiyse (happened to) onun üzerine istiflenir (stack)

Bu döngüde bir varsayım (assumption) saklanıyor (hides): Files sırası (order). Bir tarayıcı (scanner) sayfaları (pages) 0001.jpg'den 0100.jpg'ye kadar (through) isimlendirir (names), ancak (but) bir dizin (directory) numaralandırması (enumeration) bunları her zaman sıralanmış (sorted) olarak (always) döndürmez (does not) ve (and) page10.jpg'nin (page10.jpg) yanındaki (next to) page9.jpg'ye bastığınız an (moment) düz (plain) bir dize (string) sıralaması (sort) sayfa 10'u sayfa 9'un önüne koyar (puts). Döngüden (loop) önce listeyi (list) açıkça (explicitly) sıralayın (Sort) ve (and) tarama (scan) zamanında (time) sözlüksel (lexical) sıranın (order) sayfa (page) sırasıyla eşleşmesi (matches) için sıfırla desteklenmiş (zero-padded) isimleri (names) tercih (prefer) edin. Sayfa (Page) dizisi (sequence), bir inceleyicinin (reviewer) anında (immediately) fark ettiği (notices) tek (one) şeydir (thing) ve (and) önlenmesi (prevent) en (cheapest) ucuz hatadır (mistake)

Bir taramayı (scan) yerleştirmek ve en (aspect) boy oranını korumak (keeping)

Bir tarama (scan) nadiren sayfa (page) ile aynı (same) şekildedir (shape). Yaprağı (sheet) doldurmak (fill) için gererseniz (stretch) metni (text) bozarsınız (distort); tam piksel (pixel) boyutunda (size) yerleştirirseniz (place) taşar (overflows). Çözüm (fix), iki orandan (ratios) daha (smaller) küçük olanına, genişliğe (width-fit) sığdırma (width-fit) veya yüksekliğe (height-fit) sığdırma (height-fit), göre ölçeklendirmek (scale) ve (and) geriye kalanı (left over) ortalamaktır (center). Orijin (origin) sol altta (lower-left) oturduğundan (sits), ortalamak (centering), kalan boşluğu (space) eşit olarak (evenly) bölmek (splitting) ve hem X hem de Y'ye eklemek (adding) anlamına gelir (means)

Bir A4 sayfa şeması, PDFium Component AddImage'nin Delphi kodu ve sol-alt başlangıç noktası kullanarak ölçeklenmiş bir taramayı kenar boşluklarının içine nasıl yerleştirdiğini gösterir
AddImage yerleştirme dikdörtgeninin sol alt köşesini alır; böylece sığdırma ve ortalama, başlangıç noktasından sayfa punto cinsinden hesaplanır
procedure TArchiveForm.PlaceScan(Pdf: TPdf; const FileName: string;
  PageW, PageH, Margin: Double);
var
  Pic: TPicture;
  AvailW, AvailH, Scale, DrawW, DrawH, X, Y: Double;
begin
  Pic := TPicture.Create;
  try
    Pic.LoadFromFile(FileName);              // VCL grafik birimleri aracılığıyla BMP, JPG, PNG vb.

    AvailW := PageW - 2 * Margin;
    AvailH := PageH - 2 * Margin;

    // Taramanın biçimini bozmadan kenar boşluklarının içine sığdırın.
    Scale := Min(AvailW / Pic.Width, AvailH / Pic.Height);
    DrawW := Pic.Width * Scale;
    DrawH := Pic.Height * Scale;

    // Ortala: kalan alan eşit şekilde bölünür. Y, sayfanın altından ölçülür.
    X := (PageW - DrawW) / 2;
    Y := (PageH - DrawH) / 2;

    Pdf.AddImage(FileName, X, Y, DrawW, DrawH);
  finally
    Pic.Free;
  end;
end;

Bu, piksel (pixel) boyutlarını (dimensions) okumak için dosyayı bir kez yükler, tek bir (single) tek tip (uniform) ölçek hesaplar ve yerleşim (placement) dikdörtgenini (rectangle) AddImage'a iletir (passes). AddImage doğrudan (directly) bir dosya yolu (path) kabul eder (accepts) ve onu AddPicture ile aynı görüntü ardışık düzeninden (pipeline) yönlendirir (routes), böylece (so) VCL grafik (graphics) birimlerinin (units) tanıdığı herhangi bir (any) format (format), özel durum (special-casing) gerektirmeden çalışır (works). Resmi önizleme bölmesinden (preview pane) bir TPicture'da zaten deşifre ettiyseniz (decoded), aynı (same) dikdörtgen (rectangle) ile AddPicture(Pic, X, Y, DrawW, DrawH)'yi çağırın ve ikinci dosya okumayı atlayın (skip)

JPEG taramaları (scans) için deşifrelemeyi (decode) atlama (Skipping)

Tarayıcılar (Scanners) neredeyse her zaman JPEG çıkarır (emit). Bir JPEG'i bir TPicture'a yüklemek onu bir bitmap'e (bitmap) çözer (decodes) ve daha sonra PDFium kaydederken (save) onu yeniden (re-encodes) kodlar, ihtiyacınız olmayan (do not need) iki kayıplı (lossy) gidiş-dönüş (round trips). AddJpegImage orijinal sıkıştırılmış (compressed) baytları (bytes) bir (a) akıştan (stream) doğrudan (straight) sayfaya (page) gömer (embeds), ki bu (which) yüksek (high-volume) hacimli (high-volume) bir (a) toplu iş (batch) için (for) hem (both) daha hızlı (faster) hem de görsel olarak (visually) daha (cleaner) temizdir

AddJpegImage özgün JPEG baytlarını bir PDFium Component sayfasına gömerken AddImage çözümler ve SaveAs, Delphi'de pikselleri yeniden kodlar
AddJpegImage tarayıcının sıkıştırılmış baytlarını olduğu gibi gömer; AddImage ile SaveAs'in yaptığı çözme ve yeniden kodlama geçişlerini önler
var
  Stream: TFileStream;
begin
  // ... geçerli sayfa için AddPage + PageNumber'dan sonra ...
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    // JPEG baytlarını olduğu gibi gömer; kod çözme/yeniden kodlama döngüsü yoktur.
    Pdf.AddJpegImage(Stream, X, Y, DrawW, DrawH);
  finally
    Stream.Free;
  end;
end;

Piksel boyutlarına (dimensions) ölçeklemek (scale) için (since) hala X, Y, DrawW ve (and) DrawH'yi aynı (same) şekilde (way) hesaplıyorsunuz (compute). Onları (those) dosyadan (file) veya hızlı (quick) bir (a) başlık (header) ayrıştırmasından (parse) okuyun (Read), ardından (then) ham (raw) akışı (stream) AddJpegImage'a elden (hand) verin. PNG veya (or) TIFF taramaları (scans) için (For) AddImage yolu (path) doğru (right) olandır (one); JPEG kısayolunu (shortcut) gerçekten (actually) geçerli olduğu format (format) için ayırın (reserve)

Her (each) sayfayı (page) etiketleme (Labeling)

Her (each) sayfa (page) kaynak (source) dosya adını taşıdığında (carries) arşivlenmiş (Archived) taramaların denetlenmesi (audit) daha (easier) kolaydır. AddText kullanıcı alanı (user-space) koordinatında (coordinate) bir (a) dize (string) çizer (draws), böylece (so) bir altyazı (caption) görüntünün hemen (just) altında (under) oturur (sits). Ters çevrilmiş (inverted) Y eksenini unutmayın (Remember): taramanın (scan) altına (below) bir (a) etiket (label) koymak (put) için (to), ona (it) eklemek (add to) yerine (rather than) görüntünün alt (bottom) kenarından çıkarırsınız (subtract)

// Taramanın altındaki başlık: Y, sayfanın altına doğru azalır.
Pdf.AddText('File: ' + ExtractFileName(FileName), 'Helvetica', 9,
  X, Y - 14, clGray);

Kaydetme ile ilgili (about) son (last) bir (One) nokta (point). SaveAs, Boole (Boolean) döndüren (returns) bir işlevdir, bu nedenle üretim (production) kodunda yazmanın başarılı (succeeded) olduğunu varsaymak (assuming) yerine (rather than) sonucunu (result) kontrol edin; (check) aksi takdirde tam (full) bir disk veya (or) kilitli (locked) bir çıktı (output) yolu (path) sessizce (quietly) başarısız olur. Döngü bittiğinde (finishes) ve (and) dosya yazıldığında, tam olarak (exactly) arşivin ihtiyacı olan (needed) şeye sahipsiniz: durum (case) dosyası (file) başına (per) sıralanmış bir (one) PDF, sığacak (fit) şekilde (to) ölçeklenmiş sayfalar, herhangi bir (any) görüntüleyicide (viewer) okumaya hazır (ready)

Aynı yapı taşları (building blocks) ilgili işleri kapsar. Sayfa (per-page) başına (per) boyutlandırma (sizing) kuralını değiştirin ve yaprak başına bir görüntü (image) içeren (with) bir fotoğraf kitabı elde edersiniz; döngüyü tutun (keep) ancak çok (multi-page) sayfalı (multi-page) bir TIFF kaynağından (source) okuyun (read) ve (and) bir faks arşivi (fax-archive) dönüştürücüsüne sahip olun. Programlı (programmatically) olarak PDF'ler (PDFs) oluşturmanın (building) daha (wider) geniş (wider) bir resmini istiyorsanız, PDFium Bileşeni (Component) ile sıfırdan PDF belgeleri oluşturma konusuna (see) bakın (see); sonucu daha (later) sonra (later) tekrar ekrana oluşturmak (render) için (to), PDFium Bileşeni ile PDF sayfalarını JPEG resimlerine dönüştürme konusuna bakın

loslab.com'dan PDFium Bileşeni, bu (this) seri (series) boyunca (throughout) kullanılan belge-oluşturma, oluşturma ve metin API'lerini (APIs) bir araya getirir (bundles)