Bir PDF'teki görünür her karakter, kendisini çizen yazı tipine (font) bir referans taşır ve PDFium Component, bu referansı yazı tipi nesnesine kadar izlemenize ve bildiklerini okumanıza olanak tanır. Erişim birimi belge değil karakterdir: sayfa metnindeki indeksine göre bir karakter seçer ve aile adını, temel adını, ağırlığını, italik açısını ve temel yazı tipinin (face) dosya içinde gerçekten taşınıp taşınmadığını sorarsınız. Son özellik, çoğu analizin asıl peşinde olduğu özelliktir, çünkü gömülü bir yazı tipi belgeyle birlikte seyahat ederken, gömülü olmayan bir yazı tipi okuyucunun makinesinde aynı yazı tipinin kurulu olduğuna dair bir varsayımdan ibarettir
Bileşen bunları, işleme (rendering) ve metin çıkarma için kullandığınız aynı TPdf ve TPdfView nesneleri aracılığıyla sunar. Açılacak ayrı bir "yazı tipi tablosu" nesnesi yoktur. Bir sayfanın metni ayrıştırıldıktan sonra, yazı tipi özellikleri karakter indeksine asılır ve bunları her seferinde bir glif (glyph) olmak üzere okursunuz. Bu tasarım, PDF'in bilgiyi en başta nasıl sakladığına uyar: tek bir sayfa onlarca kez yazı tipi değiştirebilir ve "bu belge hangi yazı tipinde" sorusunun tek dürüst cevabı "hangi karakteri kastettiğinize bağlıdır" olur
Bir karakterin arkasındaki yazı tipini okuma
En küçük yararlı işlem, bir karakter indeksi almak ve PDFium'un yazı tipi hakkında size söyleyebileceği her şeyi dökmektir. TPdf ve TPdfView üzerindeki her yazı tipi özelliği karakter konumuna göre indekslenir, bu nedenle indeks hepsinin içinden geçer. Ayrıca indeksin doğru metne karşı çözümlenmesi için sayfanın mevcut sayfa olması gerekir; bu durum birinci sayfayı geçtiğinizde önem kazanır
procedure DescribeFontAt(Pdf: TPdf; CharIndex: Integer);
var
Report: TStringList;
PtSize: Single;
begin
Report := TStringList.Create;
try
PtSize := Pdf.FontSize[CharIndex];
Report.Add('Character : ' + Pdf.Character[CharIndex]);
Report.Add('Family : ' + Pdf.FontFamilyName[CharIndex]);
Report.Add('Base name : ' + Pdf.FontBaseName[CharIndex]);
Report.Add('Weight : ' + IntToStr(Pdf.FontWeight[CharIndex]));
Report.Add('Italic : ' + IntToStr(Pdf.FontItalicAngle[CharIndex]) + ' deg');
Report.Add('Size : ' + FormatFloat('0.0', PtSize) + ' pt');
Report.Add('Ascent : ' + FormatFloat('0.0', Pdf.FontAscent[CharIndex, PtSize]));
Report.Add('Descent : ' + FormatFloat('0.0', Pdf.FontDescent[CharIndex, PtSize]));
Report.Add('Embedded : ' + BoolToStr(Pdf.FontIsEmbedded[CharIndex], True));
ShowMessage(Report.Text);
finally
Report.Free;
end;
end;
Diğer kütüphanelerden gelenler için imzalardan (signatures) birkaçı şaşırtıcı olabilir. FontAscent ve FontDescent iki argüman alır: karakter indeksi ve punto (point) boyutu; çünkü PDFium bu metrikleri yalnızca metnin ayarlandığı boyuta göre ölçeklendirdiğinizde piksel haline gelen glif uzayı birimlerinde raporlar. FontSize[CharIndex] üzerinden zaten okuduğunuz değeri ilettiğinizde, düzenin (layout) geri kalanıyla aynı punto cinsinden üst (ascent) ve alt (descent) çıkıntı değerlerini alırsınız. Alt çıkıntı, taban çizgisinin altını ölçtüğü için negatif olarak döner. Aile adı ve temel ad bilerek ayrı dizelerdir (strings): temel ad PDF'teki ham /BaseFont girdisidir ve genellikle ABCDEF+ gibi bir alt küme ön eki taşırken, aile adı işleyicinin çözümlediği temizlenmiş addır
Bir tıklamayı karakter indeksine dönüştürme
Bir görüntüleyicide (viewer) indeksi önceden nadiren bilirsiniz. Kullanıcı bir glife tıklar ve piksel koordinatını altındaki karaktere çevirmeniz gerekir. CharacterIndexAtPos tam olarak bunu yapar; fare konumunu ve bir tolerans değerini alarak en yakın karakterin indeksini veya tıklama boşluğa ya da boş bir sayfaya denk geldiğinde negatif bir değer döndürür
procedure TfrmMain.PdfViewMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Index: Integer;
begin
if not PdfView.Active then
Exit;
// 4 px of slack in each direction so a near-miss still hits the glyph.
Index := PdfView.CharacterIndexAtPos(X, Y, 4.0, 4.0);
if Index < 0 then
Exit; // clicked between glyphs; leave the panel alone
PdfView.CurrentCharIndex := Index;
DescribeFontAt(PdfView.Pdf, Index);
end;
Toleransı ayarlamaya değer. Çok sıkı olursa kullanıcılar harfin tam sapına (stem) denk getirmek zorundaymış gibi hissederler; çok gevşek olursa kenar boşluğuna yapılan bir tıklama, kastedilenle hiç ilgisi olmayan uzak bir karaktere yapışır. Ekran görüntülemesi için üç ila beş cihaz pikseli makul bir başlangıç noktasıdır. Döndürülen indeks, mevcut sayfanın ayrıştırılmış metnine aittir; yani her yazı tipi özelliğinin beklediğiyle aynı indeks alanıdır, bu nedenle yukarıdaki rutine doğrudan iletebilirsiniz. Bunu CurrentCharIndex içinde saklamak isteğe bağlıdır ancak kullanışlıdır: görünüm (view) bunu odaklanılan glif kavramı olarak tutar ve bu da kullanıcı arayüzünün diğer kısımları seçimi yeniden türetmeden okumak isterse elverişlidir
Önemli olan özellik gömülü olmasıdır
Çoğu gerçek iş için cevaplanmaya değer tek soru, her bir yazı tipinin gömülü (embedded) olup olmadığıdır. Tüm yazı tiplerini içinde barındıran bir belge; bir baskı bürosunun RIP'inde, bir iş arkadaşının dizüstü bilgisayarında ve hiçbir GUI'si olmayan bir sunucuda aynı şekilde işlenir (renders). Gömülü olmayan bir Helvetica'ya dayanan bir belge, bu makinelerin her birinin eşleşen bir yazı tipine sahip olduğu üzerine kumar oynar ve kumar başarısız olduğunda okuyucu yakın bir şeyle değiştirir, metrikler kayar ve özenle düzenlenmiş bir form kırılacak kadar yeniden şekillenir (reflows). Sayfa metnini gezinmek ve yazı tiplerini gömülme durumlarına göre gruplamak (bucketing) size bu cevabı ucuz bir şekilde verir
procedure ReportNonEmbeddedFonts(Pdf: TPdf);
var
Embedded, External: TStringList;
I: Integer;
Name: string;
begin
Embedded := TStringList.Create;
External := TStringList.Create;
try
Embedded.Sorted := True;
Embedded.Duplicates := dupIgnore;
External.Sorted := True;
External.Duplicates := dupIgnore;
for I := 0 to Pdf.CharacterCount - 1 do
begin
Name := Pdf.FontBaseName[I];
if Name = '' then
Continue; // generated spaces and the like have no font
if Pdf.FontIsEmbedded[I] then
Embedded.Add(Name)
else
External.Add(Name);
end;
if External.Count > 0 then
ShowMessage(IntToStr(External.Count) +
' non-embedded font(s):' + sLineBreak + External.Text)
else
ShowMessage('All ' + IntToStr(Embedded.Count) +
' font(s) on this page are embedded.');
finally
Embedded.Free;
External.Free;
end;
end;
İki ayrıntı bunu dürüst tutar. İlk olarak, CharacterCount sayfa başınadır, bu nedenle tüm belgenin denetimi, Pdf.PageNumber'ı sırayla her sayfaya ayarlamak ve döngüyü yeniden çalıştırıp sonuçları birleştirmek anlamına gelir. İkinci olarak, metin katmanı okuyucunun kelimeler arasında çıkarsadığı boşluklar gibi oluşturulmuş karakterler içerir ve bunların arkasında hiçbir yazı tipi nesnesi yoktur; boş temel ad (empty-base-name) kontrolü, hayalet bir girdi oluşturmak yerine bunları atlar. Taşıdığı alt küme (subset) ön eki, genellikle bilmek isteyeceğiniz aynı ailenin iki farklı alt kümesini ayırdığı için, burada tekilleştirme (de-duplication) için doğru anahtar temel addır
Gömülü yazı tipini dışarı çıkarma
Bir yazı tipi gömüldüğünde baytlarını doğrudan okuyabilirsiniz. FontData, ham yazı tipi programını, yani PDF'in taşıdığı aynı TrueType veya CFF verilerini döndürür; bu, bağımsız bir yazı tipi dosyası yazmak veya yazı tipinin bilinen bir kütüphaneye karşı parmak izini çıkarmak (fingerprint) için yeterlidir. Yazı tipi gömülü olmadığında boş bir dizi döndürür, bu nedenle gömülme kontrolü ve uzunluk kontrolü birlikte yazma işlemini korur
procedure SaveEmbeddedFont(Pdf: TPdf; CharIndex: Integer;
const OutputFile: string);
var
Data: TBytes;
Stream: TFileStream;
begin
if not Pdf.FontIsEmbedded[CharIndex] then
begin
ShowMessage('That glyph''s font is not embedded; nothing to extract.');
Exit;
end;
Data := Pdf.FontData[CharIndex];
if Length(Data) = 0 then
Exit;
Stream := TFileStream.Create(OutputFile, fmCreate);
try
Stream.WriteBuffer(Data[0], Length(Data));
finally
Stream.Free;
end;
ShowMessage('Wrote ' + IntToStr(Length(Data)) + ' bytes.');
end;
Baytlar, orijinal perakende yazı tipi değil gömülü alt kümedir, bu nedenle geri aldığınız şey genellikle yalnızca belgenin gerçekte kullandığı glifleri kapsar. Bu, adli tıp ve doğrulama için tam olarak doğrudur, ancak yeniden kullanım için zayıf bir uyumdur; otuz glif içeren bir Times New Roman alt kümesi, yükleyip yazabileceğiniz bir yazı tipi değildir. Çıkarmayı (extraction), bir yazı tipi kurtarma aracı olarak değil, neyin gönderildiğini incelemenin bir yolu olarak ele alın. Çıktıyı etiketlemek için eşleşen temel ada ihtiyacınız varsa, veriyle birlikte FontBaseName[CharIndex] değerini okuyun ve salt aileyi (bare family) istiyorsanız baştaki alt küme etiketini (subset tag) çıkarın
Ağırlık sayısını anlamlandırma
FontWeight, CSS'in kullandığı aynı 100'den 900'e kadar olan ölçekte (400'ün normal, 700'ün kalın/bold olduğu) sayısal ağırlık sınıfını döndürür. PDFium yazı tipi ne beyan ediyorsa onu raporlar, bu her zaman yuvarlak bir yüzlük dilim değildir; bir yazı tipi 350 veya 650 bildirebilir ve 600 veya üzerindeki herhangi bir değeri "önemli olacak kadar kalın" olarak değerlendirmek, tam olarak 700'ü test etmekten daha iyi dayanır. İtalik açısı eşlik eden bir sinyaldir: genellikle negatif olan sıfır dışı bir değer, yazı tipinin eğik (oblique) veya gerçek italik bir tasarım olduğu anlamına gelir ve sıfır dik olduğu anlamına gelir. Birlikte, hiçbir şeyi işlemeden (rendering) kalın-italik (bold-italic) bir diziyi normal bir diziden ayırt etmenizi sağlarlar; bu, bir baskı öncesi (preflight) geçişinin veya bir erişilebilirlik denetiminin toplu olarak yapmak isteyeceği türden bir kontroldür
Bu okumaların hiçbiri işlenmiş bir bitmap gerektirmez. Ayrıştırılmış metin katmanından gelirler, bu nedenle doğru sayfada açık bir belge ihtiyacınız olan tüm kurulumdur; bu da yazı tipi incelemesini tüm bir arşiv boyunca çalıştırmayı ucuz hale getirir. Bunu metin çıkarma işlemiyle eşleştiriyorsanız, aynı karakter indeksleri çıkardığınız metinle hizalanır, böylece bir glifin yazı tipi ve Unicode değeri tek bir indekse karşı yapılan iki okumadır. PDFium Component ile PDF belgelerinden metin çıkarma hakkındaki eşlik eden makale, metin katmanının o yönünü daha derinlemesine ele almaktadır
Burada gösterilen yazı tipi özellikleri PDFium Delphi VCL Component'in bir parçasıdır