Teknik Makale

Delphi'de PDF Formlarını Birleştirme: Yinelenen Alan Kuralları

PDF Library for Delphi, aynı adı paylaşan alanlar için açık bir ilkeyle iki AcroForm belgesini birleştirir. MergeDocumentEx, kaynak belge tanımlayıcısını ve üç stratejiden birini alır: dfsReject birleştirmeyi reddeder, dfsMerge paylaşılan adı korur ve değerleri eşitler, dfsAutoNumber ise gelen alanları belirlenimci bir şekilde yeniden adlandırır. Ad taraması, herhangi bir nesne numarası kaymadan önce gerçekleşir, bu yüzden reddedilen bir birleştirme her iki belgeyi de tam olarak kullanılabilir bırakır

Bir PDF başvuru paketi bir araya getirmiş herkes bununla karşılaşmıştır. Her biri Signature, Date veya Total adlı bir alana sahip üç form, tek bir dosyada birleştirilir. Bir AcroForm'da, tam nitelikli alan adı alanın kimliğidir, bu yüzden aynı ada sahip iki alan hiç de iki alan değildir: birini doldurmak diğerini de doldurur ve birine uygulanan bir imza, kimsenin amaçlamadığı bir kapsamı kapsar

Ad çakışmasına neden birleştirmeden önce karar veriliyor?

Daha eski MergeDocument, iki AcroForm kök alan dizisini birleştirir ve hiçbir seçim sunmaz. Daha kötüsü, sonuç kullanılamaz olduğunda, keşif nesne numaraları yeniden numaralandırılıp sayfa ağaçları dikildikten sonra gerçekleşir; bu, çağıranı, hiçbir orijinalin bulunmadığı bir durumdaki bir belgeyle baş başa bırakır

MergeDocumentEx sırayı tersine çevirir. Her iki belgeden üst düzey alan adlarını toplar, bunları karşılaştırır ve herhangi bir şey hareket etmeden önce stratejiyi uygular. Bu yüzden bir ret, temiz bir hiçbir-şey-yapmama (no-op) işlemidir: hedef belge dokunulmamıştır, kaynak belge dokunulmamıştır ve ikisi de açık ve kullanılabilir kalır; birleştirme testi de reddedilen bir birleştirmeden sonra kaynaktan bir alan değerini geri okuyarak bunu doğrular

Karşılaştırma, sıralı, büyük/küçük harfe duyarlı bir ad kümesi kullanır, bu yüzden maliyet, iki sayının çarpımına değil, birleşik alan sayısı çarpı logaritmik bir çarpana orantılıdır. Büyük/küçük harf duyarlılığı burada doğru seçimdir, çünkü PDF alan adları büyük/küçük harfe duyarlıdır; onları katlamak, spesifikasyonun ayrı saydığı alanları birleştirirdi

Üç strateji ve her birinin ne zaman doğru olduğu

dfsReject, belirsiz belgeler üretmemesi gereken otomatik işlem hatları için stratejidir. Birleştirme sıfır döndürür ve LastErrorCode 705'i bildirir; bu, yinelenen adların diğer her birleştirme hatasından ayırt edilebilmesi ve belirli bir çözüme — genellikle kaynağında alanları yeniden adlandırmaya — yönlendirilebilmesi için ayrılmış bir koddur

dfsMerge, paylaşılan adı kasıtlı olarak korur ve hedef değeri ile varsayılan değeri kaynak alana eşitler, bu yüzden uyumlu bir görüntüleyici birden çok widget'ı mantıksal olarak adlandırılmış tek bir alan olarak ele alır; bu, birden çok widget açıklamasına (annotation) sahip bir alan için standart AcroForm davranışıdır. Yapmadığı şey ise farklı alan sözlüklerini tek bir nesneye katlamaktır. Her alan kendi sayfa ilişkisini, görünümünü ve eylemlerini korur, çünkü bunları çökertmek, gelen belgeye ait biçimlendirmeyi ve davranışı sessizce atardı

dfsAutoNumber, gelen yinelenenleri _2'den başlayan bir sayısal sonek ekleyerek ve ilk boş olanı alarak yeniden adlandırır. Sonuç yeniden üretilebilir: yalnızca mevcut adlara bağlıdır, hiçbir zaman alan nesne numaralarına bağlı değildir, bu yüzden aynı belge çiftini iki kez birleştirmek her iki seferde de aynı adları verir. Bu özellik, sonraki bir kod, bir FDF içe aktarması veya bir veritabanı eşlemesi alanlara ada göre başvurduğunda önemlidir

uses
  PDFlibrary;

var
  Lib: TPDFlib;
  TargetDoc, SourceDoc: Integer;
begin
  Lib := TPDFlib.Create;
  try
    TargetDoc := Lib.SelectedDocument;
    Lib.LoadFromFile('application-part1.pdf', '');

    SourceDoc := Lib.NewDocument;
    Lib.LoadFromFile('application-part2.pdf', '');

    Lib.SelectDocument(TargetDoc);
    if Lib.MergeDocumentEx(SourceDoc, dfsReject) = 0 then
    begin
      if Lib.LastErrorCode = 705 then
      begin
        // Her iki belge de hâlâ bozulmamış - bir ilkeyle yeniden dene
        Log('duplicate field names; retrying with auto-numbering');
        Lib.MergeDocumentEx(SourceDoc, dfsAutoNumber);
      end;
    end;

    Lib.SaveToFile('application-complete.pdf');
  finally
    Lib.Free;
  end;
end;

O koddaki iki adımlı deseni not edin; bu, yalnızca reddin yıkıcı olmamasından ötürü mümkündür. Önce katı ilkeyi deneyin, hatayı inceleyin, ardından karar verin. Yarı yolda başarısız olan bir birleştirmeyle, geri düşüş her iki dosyayı da yeniden yükleyerek baştan başlamak zorunda kalırdı

Birleştirilmiş form sonrasında nasıl görünür?

dfsMerge altında, "Target value" taşıyan Shared adlı bir hedef alan ile aynı ada sahip bir kaynak alan, ikisi de Shared adında, ikisi de hedef değeri bildiren iki alan üretir, çünkü hedef değer ve varsayılan değer gelen alana eşitlenir. Bu, paylaşılan bir ad için amaçlanan anlambilimdir: tek mantıksal alan, birkaç widget, tek değer

dfsAutoNumber altında, aynı girdi Shared ve Shared_2'yi bağımsız değerlere sahip ayrı alanlar olarak üretir. İkisi arasında tek bir soru sorarak seçim yapın: bir denetimi doldurmak diğerini de doldurmalı mı? Bir paketin her parçasında tekrarlanan bir imzalayan adı için, evet, ve dfsMerge doğrudur. Her formda farklı bir şey ifade eden bir toplam için, hayır, ve otomatik numaralandırma doğrudur

// Bir birleştirmeden sonra, gerçekte neyi aldığınızı numaralandırın
for I := 1 to Lib.FormFieldCount do
  Log(Format('%d: %s = %s',
    [I, Lib.GetFormFieldTitle(I), Lib.GetFormFieldValue(I)]));

Form paketlerini bir araya getirmek için pratik notlar

Başarılı bir birleştirme kaynak belgeyi tüketir: kütüphanenin belge listesinden kaldırılır; DocumentCount'un ikiden bire düşmesinin nedeni budur. Sonrasında kaynak tanımlayıcısını kullanmaya devam etmeyin. Belge sürümü ikisinden yüksek olana yükseltilir, bu yüzden bir PDF 2.0 formunu bir 1.7 belgesine birleştirmek 2.0 bir dosya verir

Adlar için sıra önemlidir. A'yı B'ye birleştirmek ile B'yi A'ya birleştirmek, farklı otomatik numaralandırılmış sonuçlar üretir, çünkü birleştirmeyi yapan belge kendi adlarını değişmeden korur. Bir paketin kurallı bir birincil formu olduğunda, o formu hedef yapın

İmza alanları kendi düşüncelerini hak eder. Bir birleştirmeden önce uygulanmış bir imza, yalnızca imzaladığı revizyonu kapsar, bu yüzden birleştirme, dosyanın imzalanmasından bu yana değiştiği pratik anlamda onu geçersiz kılar. İmzalı parçaları birleştirmek yerine önce bir araya getirin ve birleştirilmiş belgeyi imzalayın. Birleştirme formlar yerine sayfa içeriğiyle ilgiliyse, bayt referansı kaydırmayla hızlı PDF birleştirme yazısında anlatılan daha hızlı yol daha iyi bir araçtır

Son olarak, paketin veri tarafını birleştirmeyle birlikte planlayın. Alan değerleri harici bir sistemden geliyorsa, otomatik numaralandırmayı seçmeden önce o sistemin alanlara ada göre başvurup başvurmadığına karar verin, çünkü Shared_2, Shared bekleyen bir eşlemeyle eşleşmeyecektir. İçe ve dışa aktarma biçimleri FDF, XFDF ve XFA form veri değişimi yazısında ele alınmıştır ve yeniden adlandırmadan da etkilenebilecek alan düzeyi betikleme davranışı etkileşimli form eylemleri ve JavaScript yazısında ele alınmıştır

Form birleştirme, veri değişimi ve imzalama, Delphi, C++Builder ve Free Pascal için aynı kütüphanede çalışır; eksiksiz özellik listesi Delphi için PDF Library sayfasındadır