PDFiumPas ile bir PDF sayfasına bir satır damgalamak için AddText'i çağırırsınız, ardından damganın indiğini doğrulamak için hemen FindFirst'ı çağırırsınız ve arama boş döner. Metin sayfadadır -Acrobat onu gösterir- ama PDFiumPas'ın TPdf bileşeni, sayfanın içerik akışından bir kez ayrıştırılmış ayrı bir önbelleğe alınmış FPDF_TEXTPAGE yapısı tutar ve bir düzenleme o yapıyı kendiliğinden geriye dönük olarak güncellemez. Yenilenmeden önce sorgularsanız, sayfayı değişikliğinizden sonra değil önce göründüğü tam haliyle okursunuz
PDFium bir düzenlemeden hemen sonra neden bayat metin döndürür?
PDFiumPas, Delphi ve C++Builder için Google'ın PDFium render motorunu sarmalar ve metin ile düzenleme çağrıları o motorun içindeki iki farklı alt sisteme ulaşır. FPDF_TEXTPAGE okuma tarafına aittir: FPDFText_LoadPage, sayfanın içerik akışını bir kez dolaşır ve metin sayfasını -karakter kodları, konumlar, yazı tipi ölçütleri, kelime sınırları- kurar ve PDFiumPas o yapıyı sayfa yüklü kaldığı sürece önbelleğe alır. FPDFPage_InsertObject veya FPDFPage_GenerateContent gibi düzenleme çağrıları tamamen farklı bir temsil üzerinde çalışır, sayfanın nesne ve içerik akışı grafiği, ve PDFium bu değişiklikleri kendiliğinden zaten açık olan bir metin sayfasına itmez. Her düzenlemede yeniden kurmak toplu düzenlemeyi kabul edilemez şekilde yavaşlatırdı; bu yüzden tasarım o maliyeti bir kural karşılığında takas eder -tutamacı elinde tutan her kimse, içerik değiştiren bir düzenlemeden sonra onu kapatır ve bir sonraki okuma taze bir tane kurar
TPdf'in metin önbelleğinin içinde: FTextPage, LoadTextPage ve UnloadTextPage
TPdf, önbelleğe alınmış tutamacı tek bir özel alanda, FTextPage'de takip eder ve yaşam döngüsünü iki metotta sarmalar. LoadTextPage, FTextPage'in nil olup olmadığını kontrol eder ve yalnızca o durumda, mevcut sayfaya karşı FPDFText_LoadPage'i çağırır; bir tutamaç zaten varsa, LoadTextPage sayfa onu kurduğundan beri değişip değişmediğini sormadan onu yeniden kullanır. UnloadTextPage diğer yarısıdır: yerel tutamacı FPDFText_ClosePage ile kapatır, FTextPage'i geri nil'e ayarlar ve ayrıca önbelleğe alınmış web bağlantısı listesini ve devam eden herhangi bir bulma oturumunu da düşürür, çünkü ikisi de aynı metin sayfasından türetilmiştir ve aynı nedenle bayatlarlar
LoadTextPage'in kontrolsüz yeniden kullanma davranışı, sıralamanın neden önemli olduğunun tam nedenidir. TPdf üzerindeki her metin sorgusu -Text, FindFirst, GetWebLinks- önce LoadTextPage'den geçer; bu yüzden FTextPage hâlâ düzenleme öncesi tutamacı tutuyor olduğu sürece, bu çağrıların hiçbirinin bir değişikliğin gerçekleştiğini bilmesinin bir yolu yoktur. Sayfa gezinmesi burada hiçbir zaman risk değildi: sayfa geçişlerinde, yeniden yüklemelerde ve belge kapanışında çalışan UnloadPage, her zaman metin sayfasını sayfanın kendisiyle birlikte kapattı. Açık soru her zaman hâlâ üzerinde oturduğunuz sayfaya uygulanan düzenlemeler hakkındaydı
Hangi PDFiumPas metotları önbelleği otomatik olarak yeniler?
TPdf'in kendi sayfa düzenleme metotları -AddText, SetText, SetTextPositions, AddPath, RemoveObject ve InsertFormObjectFromXObject- değişikliği içerik akışına serileştirmek için UpdatePage'i (PDFium'un FPDFPage_GenerateContent'i) çağırmadan önce her biri UnloadTextPage'i çağırır. Bunlardan herhangi birini çağırın ve bir sonraki Text, FindFirst veya GetWebLinks çağrısı, sizin tarafınızdan gereken hiçbir ekstra çağrı olmadan, içeriği şu anda durduğu haliyle metin sayfasını yeniden kurar
var
Pdf: TPdf;
Index: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'invoice.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
Pdf.AddText('Reviewed by J. Alvarez', 'Helvetica', 10, 72, 40, clBlack, 255, 0);
// AddText already closed the cached text page, so this FindFirst
// call rebuilds it fresh before it searches
Index := Pdf.FindFirst('Reviewed by J. Alvarez');
if Index >= 0 then
ShowMessage('Stamp confirmed at character ' + IntToStr(Index));
finally
Pdf.Free;
end;
end;
Hâlâ bozulan örüntü: ham TextPage tutamacını önbelleğe almak
TPdf, PDFiumPas'ın sarmalamadığı bir FPDFText_* fonksiyonunu çağırmanız gereken nadir durum için, canlı tutamacı salt okunur bir TextPage özelliği üzerinden sunar. Bu çıkış kapağı, otomatik geçersizleştirmenin yardımcı olamadığı tek yerdir de: FPDF_TEXTPAGE değerini özellikten yerel bir değişkene bir kez kopyaladığınızda, PDFiumPas'ın onu hâlâ tuttuğunuzu bilmesinin hiçbir yolu yoktur ve kodunuzda başka bir yerde UnloadTextPage çalıştığında kopyanızı güncellemesinin de hiçbir yolu yoktur
var
Pdf: TPdf;
RawHandle: FPDF_TEXTPAGE;
StaleCount: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'contract.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
RawHandle := Pdf.TextPage; // FPDFText_LoadPage handle, cached in FTextPage
Pdf.SetText(0, 'Amended Clause 4.2');
// SetText already closed RawHandle and set Pdf.TextPage back to nil.
// Calling any FPDFText_* function against the old value now touches a
// handle PDFium has already freed — undefined behavior, not a bug you
// can catch with a nil check
StaleCount := FPDFText_CountChars(RawHandle);
finally
Pdf.Free;
end;
end;
FPDFText_ClosePage onun üzerinde çalıştıktan sonra bir tutamacı kullanmak, göz ardı etmeyi seçebileceğiniz bir PDFiumPas kuralı değil, PDFium'un kendisinde tanımsız davranıştır -son bilinen veriyi döndürebilir, hiçbir şey döndürmeyebilir veya süreci çökertebilir ve belirli bir derlemede bunlardan hangisinin olacağı, uygulama kodunun bağımlı olması gereken bir şey değildir. Güvenli kural dardır: Pdf.TextPage'i, ihtiyaç duyan FPDFText_* çağrısından hemen önce taze okuyun ve sayfayı düzenleyebilecek bir ifadenin ötesinde asla bir kopyasını tutmayın
Düzenlemelerinizi toplulaştırın, sonra bir kez sorgulayın
Bunların hiçbiri her AddText veya RemoveObject çağrısının sonucu kontrol etmek için hemen ardından savunmacı bir metin sorgusuna ihtiyaç duyduğu anlamına gelmez. Her düzenleme metodu metin sayfasını bir kez kapatmanın maliyetini zaten öder; bir döngü içindeki her tek düzenlemeden sonra sorgulamak, FPDFText_LoadPage her çalıştığında tüm içerik akışını yeniden dolaştığından, hiçbir fayda için o maliyeti tekrar öder
var
Pdf: TPdf;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'watermarked.pdf';
Pdf.Active := True;
Pdf.PageNumber := 1;
// Strip every text object that looks like a draft watermark. Each
// RemoveObject call already invalidates the cache on its own, so
// nothing needs refreshing by hand between iterations
for I := Pdf.ObjectCount - 1 downto 0 do
if (Pdf.ObjectType[I] = otText) and (Pdf.ObjectBounds[I].Top > 700) then
Pdf.RemoveObject(I, True);
// Query once, after the whole batch is done, not once per removal
if Pdf.FindFirst('DRAFT') < 0 then
ShowMessage('Watermark cleared');
finally
Pdf.Free;
end;
end;
Aynı toplulaştırma mantığı özellikle arama durumu için de geçerlidir. FindNext ve FindPrevious, FindFirst tarafından başlatılan bir oturuma devam eder ve o oturum, her şeyle birlikte UnloadTextPage tarafından yıkılır; bu yüzden bir düzenlemeden sonra tekrar FindFirst'ı çağırmak yerine tekrar FindNext'i çağırmak, artık var olmayan içeriğe karşı sessizce bir aramaya devam etmek yerine bir istisna fırlatır. Herhangi bir düzenlemeyi hem metin içeriği hem de arama konumu için sert bir sınır olarak ele alın ve düzenlemelerinizin öte tarafında taze bir FindFirst'ın aramayı yeniden almasına izin verin
Bu, çıkarma ve açıklama işiyle nereye oturuyor?
Düz metin çıkarma -hiçbir şeyi değiştirmeden bir sayfanın metnini okumak- bunların hiçbirine hiç çarpmaz, çünkü hiçbir düzenlemenin dokunmadığı bir tutamacı hiçbir şey geçersiz kılmaz. Text, karakter dikdörtgenleri ve kelime sınırlarının değiştirilmemiş bir sayfada nasıl çalıştığı için, PDFiumPas ile metin çıkarma üzerine tamamlayıcı makale, bu makalenin üzerine eklediği metin sayfası önbelleği yaşam döngüsü olmadan o zemini kapsar
Önbellek yaşam döngüsü en çok düzenleyip sonucu hemen üzerinde işlem yapan iş akışlarında önemlidir: bir düzeltmeyi damgalayıp onu aramak, bir paragrafı karartıp gittiğini doğrulamak veya yakınına metin eklendikten hemen sonra bir işaretleme açıklamasını çapalamak için bir ifadeyi bulmak. Bu son durum kendi başına işaretlenmeye değer -dörtgen-nokta işaretleme açıklamaları metin sayfasından okunan karakter dikdörtgenlerinden konumlandırılır; bu yüzden bir düzenlemeden önce yakalanan koordinatlardan kurulan bir açıklama, düzenleme indiğinde yanlış noktayı vurgulamış olur
TPdf'in düzenleme ve metin API'leri, Delphi ve C++Builder için PDFium Bileşeni'nin bir parçasıdır ve ürün sayfası, burada ele alınan düzenleme, çıkarma ve arama yüzeyleri için tam metot referansını taşır