HotPDF Delphi Component, THotPDF.ExtractLoadedPageTextte kelime boşluklarını ve satır sonlarını glyph geometrisinden yeniden kurar; space karakterlerinden değil. Bir glyphin kendi genişliğinden sonraki boşluk, text heightin 0.15ini aşınca bir space girer ve yeni satır, yalnızca text origin yazma yönü boyunca text heightin yarısından fazlasını katettiğinde başlar. v2.768.3ten beri sayfa metni Form XObjectler üzerinden boyanan metni de içerir ve görünür crop alanının dışındaki glyphleri bırakır. Bu yazının gerisi, her kuralın neden bu şekilde göründüğünü anlatır; çünkü her biri, gerçek belgelerde inandırıcı ama yanlış çıktı üreten daha basit bir kuralın yerini aldı
Belirtiler, PDF metnini bir arama indeksine yedirmiş herkese tanıdıktır. Bir kapak sayfası PDFReferenceManualNovember4,1998 olarak çıkar, bir vergi formu 156 satıra bölünür, çapraz bir filigran satır başına bir karakter gelir ve kırpılmış bir prova, hiçbir görüntüleyicinin göstermediği yazıcının slug satırıyla başlar. Bu dosyaların hiçbiri bozuk değildir. Her biri, naif bir extractorın yanlış okuduğu, tamamen meşru bir metin yerleştirme yolu kullanır
Çıkarılan PDF metni kelime boşluklarını neden kaybeder?
Çıkarılan metin kelime boşluklarını kaybeder, çünkü bir PDFin onları içermesi asla zorunlu değildir. Bir üretici kelimeleri space karakteri göstererek ayırabilir; ama aynı işi TJ dizisi içindeki bir sayıyla (ISO 32000-1 §9.4.3) ya da taze bir Tdyle (§9.4.2) kalemi oynatarak da yapabilir; TeX çıktısı, pek çok Distiller dosyası ve çoğu iki yana yaslanmış düzen tam olarak bunu yapar. v2.766.76dan önce HPDFAssemblePageText yalnızca dikey harekete bakıyordu; konumlandırmayla yapılan kelime ayrımı bu yüzden sessizce kayboluyordu. Assembler artık, önceki glyphin yazma yönü boyunca, o glyphin kendi genişliğinin sonundan mevcut glyphin başlangıcına olan mesafeyi ölçer ve mesafe, user spacete ascentten descente ölçülen mevcut glyphin kutu yüksekliğinin 0.15ini aştığında bir space ekler. İki taraftan biri hâlihazırda boşken space eklenmez; iki CJK karakteri arasında da eklenmez, çünkü iki yana yaslanma ideografları, o açıklık kelime sınırı demeden açar. Glyph kayıtları aynı geometriyi açığa verir; yani belirli bir dosya şaşırttığında kararı yeniden üretebilirsiniz
uses
SysUtils, HPDFDoc, HPDFContentStream;
procedure DumpWordGaps(Pdf: THotPDF; PageIndex: Integer);
var
Glyphs: THPDFGlyphArray;
I: Integer;
Height, Gap: Double;
begin
if not Pdf.ExtractLoadedPageGlyphs(PageIndex, Glyphs) then
Exit;
for I := 1 to High(Glyphs) do
begin
// glyph kutusunun ascent-descent yüksekliği, user spacete
Height := Sqrt(Sqr(Glyphs[I].QuadX[3] - Glyphs[I].QuadX[0]) +
Sqr(Glyphs[I].QuadY[3] - Glyphs[I].QuadY[0]));
// yatay metin: önceki glyphin kendi genişliği sonundan boşluk
Gap := Glyphs[I].BaselineStartX - Glyphs[I - 1].GlyphEndX;
if (Height > 0) and (Gap > 0.15 * Height) then
Writeln(Format('U+%.4x gap %.2f height %.2f: space',
[Glyphs[I].Unicode, Gap, Height]));
end;
end;
Neden kalem konumundan değil glyphin kendi genişliğinden ölçülür?
HotPDF kelime boşluklarını GlyphEndX / GlyphEndYden ölçer, çünkü bir glyphden sonraki kalem konumu, boşluk olmayan aralıkları çoktan taşır. ISO 32000-1 §9.4.4 yatay yer değiştirmeyi, glyph genişliği çarpı font boyutu artı karakter aralığı Tc artı kelime aralığı Tw olarak tanımlar; hepsi Tzyle ölçeklenir. BaselineEndX / BaselineEndY o tam yer değiştirmeyi tutar; GlyphEndX / GlyphEndY ise yalnızca font advanceini ve Tzyi tutar. Fark, negatif bir Tcyle trackingi sıkılaştırıp her glyphden sonra o alanı bir TJ ayarıyla geri veren üreticiler için önem taşır: kalem konumundan ölçüldüğünde geri verilen alan boşluk gibi görünür ve Çince "95后" terimi "9 5 后" olarak çıkardı. Eşik benzer bir sebeple Tf boyutu yerine glyph kutusu yüksekliğine bağlıdır. Word exportları sık sık 1 Tf yazıp gerçek boyutu ölçeklenmiş bir Tmde taşır; Tfs 1 derken metin 10 punto boyundadır ve Tfse bağlanan bir kural aynı sayfanın iki yazımını farklı işlerdi
Kuralın dürüst sınırları vardır. Çok gevşek trackingle set edilmiş bir başlık, Tcnin tek başına harfler arasında text heightin 0.15inden fazlasını açtığı durumlarda her harfin arasına bir space girerek çıkar; sayfanın göründüğü de budur ama muhtemelen indekslemek istediğiniz de değil. Aynı baseline üzerinde sıra dışı çizilen parçalar negatif boşluk üretir ve spacesiz birleşir. İki durum da gövde metninde nadirdir ve test korpusunda değişiklik, hiçbirini düşürmeden bir referans extractora karşı 28 sayfada kelime eşleşmelerini yükseltti
HotPDF çıkarılan metinde yeni satıra ne zaman başlar?
v2.766.79dan beri yeni satır, önceki glyphin başlangıcından mevcut glyphin başlangıcına olan hareketin, önceki yazma yönünün normaline izdüşümü, iki glyphin daha büyük kutu yüksekliğinin yarısını aştığında başlar. Daha eski kural, ham Y hareketini Tfsin yarısıyla karşılaştırıyordu ve iki yönde başarısız oluyordu. 1 Tf ve ölçeklenmiş bir Tm ile eşik yarım birime indi; 0.4lik bir text rise ile yükseltilmiş bir üst simge ya da sıradan baseline titremesi satırı kırıyordu. Kural ayrıca Xiyi tamamen yok sayıyordu; döndürülmüş bir Tm altındaki metin her glyphle sayfada aşağı adımlıyor ve satır başına bir glyph çıkıyordu. Yön normaline izdüşüm, döndürülmüş koşuları yataylar gibi davranıştırır; iki yükseklikten büyüğünü almak ise baseline paylaştıklarında büyük bir örnek kelimeyle küçük altyazısını aynı satırda tutar. Yukarıda sözü edilen vergi formunda satır sayısı 156dan 97ye indi. Yazma modu 1deki (§9.7.4.3) dikey metin ayrı bir yol izler: o glyphler kolonlara gruplanır, sağdan sola ve yukarıdan aşağı okunur, her kolon değişiminde satır sonu gelir
ExtractLoadedPageText hangi metni alır, hangisini bırakır?
ExtractLoadedPageText, bir görüntüleyicinin gösterdiği metni döndürür. v2.766.80den beri yalnızca görünür glyphlerden çalışır; kutu merkezi GetLoadedPageVisibleBoxın — MediaBoxa kırpılmış CropBoxın (§14.11.2) — dışına düşen her glyphi düşürür. Bu, trim alanının dışında metin olarak set edilmiş slug satırlarını ve diğer yazıcı işaretlerini kaldırır. ExtractLoadedPageGlyphs ise bilinçli olarak sayfa content streaminin her glyphini döndürmeye devam eder; o malzemeye ihtiyacınız olduğunda hâlâ bulabilirsiniz. Filtre kutu testidir, görünürlük testi değil: clipping yoluyla gizlenmiş, beyaz boyanmış ya da bir image altında kalmış metin yine de çıkar
var
Pdf: THotPDF;
Glyphs: THPDFGlyphArray;
PageText: UnicodeString;
L, B, R, T: Single;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('trimmed-proof.pdf');
if Pdf.GetLoadedPageVisibleBox(0, L, B, R, T) then
Writeln(Format('Visible box: %.1f %.1f %.1f %.1f', [L, B, R, T]));
// sayfa content streaminin her glyphi, slug satırı dahil
if Pdf.ExtractLoadedPageGlyphs(0, Glyphs) then
Writeln(Length(Glyphs), ' glyphs in the page content stream');
// yalnızca sayfanın gösterdiği, Form XObject metni araya eklenmiş hâlde
if Pdf.ExtractLoadedPageText(0, PageText) then
Writeln(PageText);
finally
Pdf.Free;
end;
end;
Form XObjectler üzerinden boyanan metin, v2.768.3ten beri sayfa metninin parçasıdır. Başlıklar, damgalar ve filigranlar çoğu zaman formlarda yaşar ve bazı standart belgelerinde değişiklikten önce karakterlerin yüzde 30 ila 35i kayboluyordu. THotPDF.InterpretContentWithForms, her Doyu etkilenen CTMle birlikte kaydeder, formu /Matrixi çarpı o CTMde (§8.10.1) yorumlar ve formun glyphlerini Dounun konumuna ekleyerek iç içe formlara iner. Kendi /Resourcesu olmayan bir form, onu boyayan streaminkileri ödünç alır; §7.8.3 buna izin verir. Form glyphleri TokenIndex = -1 taşır ve ExtractLoadedPageGlyphs hâlâ yalnızca page-stream glyphleri döndürür, çünkü arama, değiştirme ve redaction değişiklikleri TokenIndex üzerinden geri yazar ve bir form glyphi sızarsa yanlış baytları düzenlerdi. Bilinmesi gereken iki sadeleştirme vardır: form metni formun /BBoxına kırplmaz ve döngü tespiti yerine özyineleme 12. seviyede durur; yani kendini boyayan bozuk bir form, tavana ulaşana dek metnini tekrar eder
Q operatöründen sonraki metin neden çöp olarak çözülüyordu?
Qdan sonraki metin v2.766.73ten önce yanlış çözülebiliyordu, çünkü extractor q üzerinde yalnızca CTMyi kaydediyordu. Font, boyut, Tc, Tw, Tz, TL, render modu ve rise gibi text state parameterleri grafik durumuna aittir (§9.3.1); dolayısıyla Q onları yığındaki her şeyin geri kalanıyla birlikte geri yüklemek zorundadır (§8.4.2). Bir sektör raporu, q … Q içinde iki baytlık bir Identity-H fontu seçiyor ve ardından kendi Tfsi olmayan tek baytlık WinAnsi metin gösteriyordu. Extractor iç fontu tutuyor, içindekiler tablosundaki leaderları ve "Adobe" kelimesini iki baytlık kodlar olarak okuyor ve sayfanın karakterlerinin yüzde 15ini düşürüyordu. Interpreterın q/Q yığını artık tam text durumunu tutar. Buradaki çıkarma kuralları her sayfa için geçerlidir; yani bütün bir belge tek çağrıda bir dosyaya gider
var
Output: TFileStream;
Pages: Integer;
begin
Output := TFileStream.Create('report.txt', fmCreate);
try
// boş aralık = bütün sayfalar; sayfalar arası form feed; UTF-8 BOM
Pages := Pdf.ExtractLoadedPagesTextToStream(Output, '', #12, True);
Writeln(Pages, ' pages extracted');
finally
Output.Free;
end;
end;
Hangi HotPDF text APIsinı kullanmalısınız?
ExtractLoadedPageText content-stream sırasında kalır; arama ve indeksleme için doğru varsayılan budur ve altındaki decoding zinciri HotPDF ile yüklenmiş PDFlerden metin çıkarmada kapsanır. Yazım sırasının önemli olduğu etiketli belgeler için yapı sıralı metin çıkarma geometriden tahmin etmek yerine yapı ağacında yürür; tablolara kilitlenmiş veriler için sayfa kesmelerinde tipli tablo çıkarma satır yerine hücre döndürür. Tam API referansı ve deneme indirmesi HotPDF Delphi PDF Component ürün sayfasındadır