PDF dosya ekleri, çoğu görüntüleyicinin bir ataş paneli veya ekler kenar çubuğu olarak yüzeye çıkardığı bir yapı olan belgenin gömülü dosya ağacında (embedded-file tree) saklanır. Delphi kodundan PDFium Bileşeni, bu ağacı TPdf üzerindeki küçük bir dizinli özellikler kümesi aracılığıyla sunar: Tamsayı dizinine göre yineler, adları ve bayt yüklerini okur, yeni yuvalar (slots) oluşturur ve mevcut olanları silersiniz. API yüzeyi dardır; etrafında üretim kodu yazmadan önce bilinmesi gereken yalnızca birkaç sıralama kısıtlaması ve bir temizleme (sanitization) kuralı vardır
Açık bir belgeden ekleri okuma
AttachmentCount, belgenin beyan ettiği gömülü dosyaların sayısını verir. Doğrudan PDFium'un alttaki çağrısından okur, bu nedenle yalnızca PDF'in gerçekte ne içerdiğini yansıtır. Oradan, AttachmentName[Index] görüntü adını bir WString olarak döndürür ve Attachment[Index] ham baytları bir TBytes dizisi olarak sunar. Her ikisi de sıfır tabanlıdır. Her iki özelliği de sorgulamadan önce belgenin açık olması gerekir (Pdf.Active = True); bunları kapalı bir belgede çağırmak, istisna olmaksızın size sıfır veya boş bir sonuç verir
Akılda tutulması gereken bir şey: Attachment[Index] her okumada dosya yükünün tamamını tahsis eder ve döndürür. Büyük bir gömülü varlık taşıyan bir belge için, bir görüntüleme listesi oluşturmak üzere tüm ekleri yinelemek, her çağrıda bu tahsis maliyetini ödemek anlamına gelir. Yalnızca görüntüleme amacıyla adlara ihtiyacınız varsa, önce AttachmentName özelliğini okuyun ve bayt alımını kullanıcı dosyayı gerçekten talep edene kadar erteleyin
procedure ListAttachments(Pdf: TPdf);
var
I: Integer;
Data: TBytes;
begin
if not Pdf.Active then
Exit;
for I := 0 to Pdf.AttachmentCount - 1 do
begin
Data := Pdf.Attachment[I];
Writeln(Format('%d: %s (%d bayt)',
[I, Pdf.AttachmentName[I], Length(Data)]));
end;
end;
Bir eki diske çıkarma
SaveAttachment yardımcısı yoktur. Baytları okur ve ihtiyacınız olan her yere yazarsınız; bu da yol oluşturmayı ve temizlemeyi tamamen sizin kodunuza bırakır. Bu durum, ek adları güvenilmeyen belgelerden geldiğinde önem taşır. PDF ek adları dosya içinde saklanan dizelerdir; doğrudan TFileStream.Create'e iletirseniz beklenmeyen sonuçlar üretecek yol ayırıcıları, Unicode benzerleri ve diğer karakterleri içerebilirler. Herhangi bir çıktı yolu oluşturmadan önce adı her zaman ExtractFileName'den geçirin ve nokta ile başlayan veya sisteminizin beklediğinin dışındaki karakterleri içeren adları reddetmeyi düşünün
Attachment[Index] tarafından döndürülen bayt dizisi çağırana aittir. Normal bir TFileStream ile yazın; beyan edilen ada güvenmek yerine gerçek dosya biçimini doğrulamak için ilk birkaç baytı incelemek de dahil olmak üzere dilediğinizi yapmak size kalmıştır
procedure ExtractAttachment(Pdf: TPdf; Index: Integer; const OutputDir: string);
var
SafeName: string;
OutPath: string;
Data: TBytes;
FS: TFileStream;
begin
SafeName := ExtractFileName(Pdf.AttachmentName[Index]);
if SafeName = '' then
SafeName := Format('attachment_%d', [Index]);
OutPath := IncludeTrailingPathDelimiter(OutputDir) + SafeName;
Data := Pdf.Attachment[Index];
FS := TFileStream.Create(OutPath, fmCreate);
try
if Length(Data) > 0 then
FS.WriteBuffer(Data[0], Length(Data));
finally
FS.Free;
end;
end;
Ek ekleme ve iki adımlı yazma
Bir ek oluşturmak tek değil, iki çağrı gerektirir. CreateAttachment(Name) gömülü dosya ağacında yeni bir yuva (slot) kaydeder ve başarı durumunda True döndürür. Bu yuva boş başlar. Daha sonra en son oluşturulan girişi hedefleyerek Attachment[AttachmentCount - 1]'e yazarak yükü atarsınız. CreateAttachment False döndürürse yuva oluşturulmamış demektir ve atama işlemi son sırada hangi dizin varsa oradaki eki bozacaktır
Ek listesini değiştirdikten sonra, değişiklikler yalnızca bellekte yaşar. Güncellenmiş gömülü dosya ağacıyla yeni bir dosya yazmak için SaveAs işlevini çağırın. PDFium Bileşeni, motor kaynak üzerinde bir okuma tanıtıcısı (read handle) tuttuğundan, şu anda açık olan aynı dosyaya geri kaydetmeyi desteklemez. Yerinde güncelleme için standart kalıp, geçici bir yola kaydetmek, belgeyi kapatmak, orijinali silmek veya yeniden adlandırmak, ardından geçici dosyayı yerine yeniden adlandırmak ve yeniden açmaktır
procedure AddFileAttachment(Pdf: TPdf; const FilePath: string);
var
FS: TFileStream;
Data: TBytes;
AttachName: string;
begin
if not Pdf.Active then
Exit;
FS := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);
try
SetLength(Data, FS.Size);
if FS.Size > 0 then
FS.ReadBuffer(Data[0], FS.Size);
finally
FS.Free;
end;
AttachName := ExtractFileName(FilePath);
if Pdf.CreateAttachment(AttachName) then
Pdf.Attachment[Pdf.AttachmentCount - 1] := Data;
end;
Ek türü bilgisi
Ad ve bayt yükünün ötesinde, dosya ilk eklendiğinde kaydedilmişse AttachmentType[Index] PDF'in gömülü dosya sözlüğünde saklanan MIME türü dizesini döndürür. Birçok üretici bu alanı boş bırakır veya application/octet-stream gibi genel bir değere ayarlar, bu nedenle bir üretim hattında biçim algılama için buna güvenemezsiniz. Güvenilir tanımlama için, yükün ilk birkaç baytını okuyun ve bilinen dosya imzalarını kontrol edin: İç içe geçmiş bir PDF için %PDF, Office Open XML belgeleri için ZIP yerel dosya başlığı PK\x03\x04, eski bileşik dosya ikilileri için \xD0\xCF\x11\xE0. Sözlükten gelen tür bilgisi bir kullanıcı arayüzü etiketinde gösterilmek için uygundur, ancak gerçek baytlar elinizdeyken işleme kararlarını yönlendirmemelidir
Ekleri silme
DeleteAttachment(Index) o konumdaki girişi kaldırır ve başarı durumunda True döndürür. Silme işleminden sonra, kalan girişler aşağı kayar; bu nedenle bir döngüde birden fazla eki siliyorsanız, her kaydırmadan sonra girişlerin atlanmasını önlemek için ileri doğru değil, son dizinden geriye doğru yinelemelisiniz. Değişiklik, siz SaveAs çağırana kadar bellek içindedir
Belge işleme hatlarında yaygın bir senaryo, güvenlik veya boyut nedenleriyle gelen bir PDF'teki tüm ekleri sonraki aşamalara aktarmadan önce temizlemektir. Döngüden önce bir kez sayın ve tersine yineleyin:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
PDF eklerinin pratikte göründüğü yerler
Ek API'si PDFium'un açabileceği her PDF'te çalışır, ancak gerçekte gömülü dosyalarla karşılaştığınız belgeler birkaç özel durumda kümelenir. PDF/A-3 (ISO 19005-3), arşiv sunumunun yanı sıra kaynak verileri de paketlemek için bir mekanizma olarak kurallara uygun gömülü dosyalara açıkça izin verir; ZUGFeRD ve Factur-X elektronik faturaları, insan tarafından okunabilen PDF düzeninin içine yapılandırılmış bir XML yükü yerleştirmek için tam olarak buna dayanır. E-postadan türetilen PDF'ler bazen gömülü dosya ağacına iletilen orijinal mesaj eklerini taşır. Yapılandırılmış yazma sistemlerinden kaynaklanan teknik belgeler bazen destekleyici varlıkları aynı şekilde paketler
Uygulamanız kuruluşunuz dışından gelen PDF'leri işlediğinde, belge alımının bir parçası olarak AttachmentCount değerini kontrol etmek iki bağımsız nedenden dolayı değerlidir. İlk olarak, gömülü dosyalar, fatura PDF'inin içindeki XML gibi ayıklamak ve işlemek istediğiniz verileri taşıyabilir. İkinci olarak, gömülü dosyalar rastgele yürütülebilir içerik taşıyabilir, bu nedenle neyin mevcut olduğunu bilmek, onu ayıklamayı asla düşünmeseniz bile önemlidir. Her iki neden de karmaşık bir şey yapmanızı gerektirmez: Sayıyı okuyun, adları kontrol edin ve baytlarla ne yapacağınıza karar verin
Burada gösterilen ek özellikleri Delphi ve C++Builder için PDFium Bileşeni'nin bir parçasıdır