İçeriğe geç
getnextpdf.com

Bir PDF'deki metnin neden gerçekte metin olmadığı

Bir PDF okuduğunuzda sözcükler görürsünüz. Dosya sözcükler içermez. Koordinatlara şekiller boyamaya yönelik yönergeler içerir ve bu şekiller tesadüfen harfler gibi görünür. Bir PDF’in çizdiği ile kastettiği arasındaki uçurum, bir sayfanın kusursuz görünüp yine de saçma sapan kopyalanmasının nedenidir. Bu sayfa, işte o uçurumu ve onu kapatan o küçük, ayrı eşlemeyi konu alır.

Bir PDF’e metin olarak yaptığınız her şey — onu seçmek, kopyalamak, aramak, geri getirme için dizinlemek, bir ekran okuyucuyla sesli okumak — dosyanın hiçbir zaman doğrudan saklamadığı karakterleri kurtarmaya dayanır. Bu kurtarma başarısız olursa, başarısızlık görünmezdir. Sayfa yine de işlenir. Biri bir paragrafı bir e-postaya kopyalayıp □□□□ alana ya da 400 sayfalık bir sözleşmede apaçık orada duran bir maddeyi arayıp hiçbir şey bulamayana dek kimse fark etmez.

Bu, tam da her görsel incelemeden sağ çıktığı için pahalı bir hata sınıfıdır. Görülecek hiçbir şey yoktur. Belge yetkili görünür ve makine açısından suskundur.

  • Bir PDF, Unicode karakterlerini değil, bir yazı tipindeki sayısal kodlarla seçilen görsel şekilleri — glifleri — çizer.
  • Aynı şekil farklı karakterler anlamına gelebilir ve aynı karakter farklı gliflerle çizilebilir. Görünüm ile anlam, tasarım gereği ayrıştırılmıştır.
  • Metni geri almak için bir okuyucu, gösterme yolunu tersine çalıştırır: koddan karaktere. Yazı tipinin /ToUnicode CMap’i, bu ters adım için arama tablosudur (Spec: ISO 32000-2, §9.10).
  • /ToUnicode’un olmaması ya da yanlış olması, sayfa hâlâ piksel kusursuz dururken, bozuk kopyala-yapıştır ve başarısız arama demektir.
  • Bu, anlam sorunudur. Glifin doğru görünüp görünmediği, Yazı tipleri: en zor kısım bölümünde ele alınan ayrı görünüm sorunudur. NextPDF, gidiş-dönüş sadık olsun diye doğru bir /ToUnicode yayar.

Metnin sayfaya nasıl geldiğiyle başlayın. Bir içerik akışı “dosya sözcüğünü yaz” demez. Bir yazı tipi seçer, sonra bir metin gösterme işlecine bir kodlar dizesi verir (Spec: ISO 32000-2, §9). Her kod bir dizindir — bir yazı tipi programındaki bir konum — ve yazı tipi o dizini bir glif anahattına çevirip boyar. 70 kodu, F karakteri değildir. “Bu yazı tipindeki 70 numaralı yuva”dır ve 70 numaralı yuva tesadüfen F biçiminde bir eğri tutar. Farklı bir yazı tipi seçin, 70 numaralı yuva bir kar tanesi olabilir.

Yani bir kod ancak yazı tipinin kodlamasına göre bir şey ifade eder. Basit bir yazı tipi için bu kodlama kabaca glif başına bir bayttır. Binlerce glif gerektiren betikler için — CJK ya da herhangi bir tam Unicode belgesi — bu kadar yer yeterli değildir ve PDF, birleşik (Type 0) bir yazı tipine uzanır (Spec: ISO 32000-2, §9.7). Bir birleşik yazı tipi, çok baytlı kodları bir CMap aracılığıyla okur, bunları CID’lere (karakter tanımlayıcılarına) çevirir ve CID’leri gliflere eşler. Bu, tek bir yazı tipinin muazzam bir glif kümesini adresleyebilmesini sağlayan zarif bir dolaylamadır. Aynı zamanda “gösterilen” ile “kastedilen” arasındaki izin soğuyabileceği bir yer daha demektir.

Şimdi onu tersine çalıştırın. Metni çıkarmak için bir okuyucu, içerik akışında bulduğu kodları alır ve karakterleri kurtarmak zorundadır (Spec: ISO 32000-2, §9.10). Glifi çizen kodlama karakterden glife gitti; çıkarmaysa glif kodundan karaktere ihtiyaç duyar ve bu yön tersine çevrilebilir olmak zorunda değildir. Bir alt küme yazı tipi gliflerini yeniden numaralandırmış olabilir. Bir birleşik yazı tipinin CID’leri özel olabilir. Sayfadaki şekil, kendinde hiçbir Unicode anlamı taşımaz.

Çözüm, ters eşlemeyi yazı tipiyle birlikte göndermektir. O eşleme, /ToUnicode CMap’idir: belgenin kullandığı her kod için, o kodun temsil ettiği Unicode değerini (ya da değerlerini) kaydeder. Onunla birlikte çıkarma, temiz bir aramadır. Onsuz bir okuyucu, yazı tipi kodlamalarından ve sezgisel yöntemlerden tahmin etmeye kalır — ve fi’nin bir soru işaretine dönüştüğü yer tam da tahmin etmektir.

  1. Your charactersThe Unicode text you set, for example the word 'file'.
  2. Encoding → codesThe font's encoding turns characters into numeric codes; a composite font routes them through a CMap to CIDs.
  3. Codes → glyphsEach code selects a glyph outline, which is painted to the page. This is the part you see.
  4. Extraction reverses itA reader reads the codes back and looks each one up in /ToUnicode to recover Unicode.
  5. Text againWith a correct /ToUnicode, copy, search, indexing, and screen readers all get the original characters back.
PDF metninin iki yönü. İşleme, karakter → glif yönünde gider ve gördüğünüz şeydir. Çıkarma ise kod → karakter yönünde gider ve kopyalayabileceğiniz, arayabileceğiniz ve sesli okutabileceğiniz şeydir — ve yalnızca /ToUnicode eşlemesi döngüyü kapattığında çalışır.

NextPDF, ters eşlemeyi rutin olarak yazar. Bir birleşik yazı tipi gömdüğünde, CIDFontType2 torununu, Type0 ebeveynini ve kodların Unicode’a geri çözülmesi için bir /ToUnicode CMap’ini yayar — bu, Yazı tipleri: en zor kısım bölümünde anlatılan kodlama işidir. Burada ayrı tutmaya değer nokta, nedendir: /ToUnicode akışı, sayfanın doğru görünmesini sağlamakla ilgili değildir. Glifler onsuz da zaten doğru görünür. Metni çıkarılabilir tutan tek yapı odur.

Bunun en ünlü ortaya çıktığı yer, fi bitişik harfidir. Birçok yazı tipi, i’nin noktası f’nin kancasıyla çakıştığı için f ile i’yi tek bir birleşik glif olarak çizer. Sayfada bu, tek bir kodla çizilen tek bir şekildir. Asıl soru, onu kopyaladığınızda ne olduğudur.

% A /ToUnicode entry that maps the single ligature code to TWO characters,
% so selecting the 'fi' glyph copies out as 'f' then 'i' — not one mystery box.
1 beginbfchar
<0085> <00660069> % code 0x85 -> U+0066 'f' U+0069 'i'
endbfchar

İşte o tek girdi, “file” araması eşleşmesiyle, bitişik harfle işlenmiş her geçişin sessizce ıskalandığı bir “file” araması arasındaki farktır. Bitişik harf kodunu iki karakterli f + i dizisine eşleyin, sözcük aranabilir ve kopyalanabilir olur. Onu eşlenmemiş bırakın, sayfa hâlâ file’ı kusursuz gösterirken metin sessizce bir makinenin okuyabileceği hiçbir şey söylemez.

“fi”nin neden bir karakter ya da iki karakter olarak çıkarılabildiği ve farkın neden rastgele olmadığı işte budur — bu, /ToUnicode eşlemesine ne söylemesi söylendiyse odur. Doğru bir eşleme, bitişik harfi karakterlerine ayrıştırır. NextPDF tam olarak bu türden bir girdi yayar; böylece sayfadaki bir bitişik harf, panodaki iki sıradan harftir.

Tuzak, adıyla: “metin işleniyor, demek ki metin yolunda.” İşleme ve çıkarma, farklı verileri okuyan farklı mekanizmalardır. İşleme, koddan glife yolunu izler ve gözlerinizin denetlediği şeydir. Çıkarma, /ToUnicode aracılığıyla koddan karaktere yolunu izler ve her makine tüketicisinin denetlediği şeydir. Bir belge birincisinde mükemmel olup ikincisinde tamamen başarısız olabilir; çünkü yapısı gereği bunu açığa çıkaracak görsel hiçbir şey yoktur.

İkinci, daha incelikli bir tuzak: bir glifin hangi karakter olduğunu “besbelli” bildiğini varsaymak. Bilmez. Bir glif, bir dizine sahip bir şekildir. Bir karaktere geri eşleme, üreticinin sağlaması gereken ek bilgidir. Üretici onu hiç yazmadıysa, hiçbir okuyucu onu sadık biçimde kurtaramaz — yalnızca tahmin edebilir.

Faithful text extraction from documents NextPDF writes — edition availability
EditionAvailability
CoreNextPDF, gömdüğü yazı tipleri için, bitişik harf ve birleşik yazı tipi durumları dâhil, doğru bir /ToUnicode CMap’i yayar; böylece ürettiği belgeler aranabilir ve kopyalanabilir.
ProNot in this edition
EnterpriseNot in this edition

Bir /ToUnicode eşlemesi yalnızca kaynak yazı tipinin gerçekten ortaya koyduğu bilgiyi taşıyabilir. Bir glifin belirlenebilir bir karakteri olmadığı yerde — salt süsleme amaçlı bir işaret, Unicode ataması olmayan özel kullanımlı bir simge — hiçbir eşleme, hiç var olmamış bir anlamı icat edemez. NextPDF, türetebildiği doğru eşlemeyi yayar; bir boşluğu doldurmak için karakter uydurmaz.

Bu sayfa, NextPDF’in yazdığı belgelerle ilgilidir. /ToUnicode’u zaten eksik ya da yanlış olan keyfi gelen PDF’ler için bir onarım aracı değildir; bunlardan metin kurtarmak ayrı, sezgisel bir sorundur. Ve sadık çıkarma, erişilebilirlik için gereklidir ama onun tamamı değildir — okuma sırası, etiketler ve alternatif metin, Bir PDF’i erişilebilir kılan nedir bölümünde ele alınır.

Aynı PDF neden bir okuyucuda iyi, başka bir okuyucuda kötü kopyalanır? Farklı okuyucular, /ToUnicode eksik olduğunda farklı geri çekilir. Bazıları yazı tipinin yerleşik kodlamasından tahmin eder ve yaygın Latin metinde şansı yaver gider; bazıları gitmez. Doğru bir /ToUnicode, piyangoyu ortadan kaldırır — uyumlu her okuyucu aynı karakterleri alır.

Bu, yazı tipinin gömülü olmamasıyla aynı şey mi? Hayır. Gömme, görünümle ilgilidir — glif, yazı tipi kurulu olmadan boyanır mı. /ToUnicode ise anlamla ilgilidir — kod bir karaktere geri eşlenir mi. Bir yazı tipi kusursuz gömülü olup yine de kullanılabilir bir /ToUnicode’a sahip olmayabilir; aranamaz-ama-güzel başarısızlığı budur.

Çıkarma hiç kod başına birden fazla karaktere ihtiyaç duyar mı? Evet — bitişik harf durumu tam olarak budur: bir kod, iki karaktere eşlenir. Bir /ToUnicode girdisi, tek bir kodu kısa bir diziye eşleyebilir; bitişik harfler ve bazı bileşik biçimler bu sayede kendi bileşen harfleri olarak geri gelir.

  • Yazı tipleri: en zor kısımgörünüm tarafındaki tamamlayıcı parça: gömme, alt kümeleme ve kodlamanın nasıl oluşturulduğu. Bu sayfa, aynı madalyonun anlam tarafıdır.
  • Bir PDF’i erişilebilir kılan nedir — sadık metin bileşenlerden biridir; okuma sırası, etiketler ve alternatif metin geri kalanıdır.
  • Bir PDF gerçekte nedir — yazı tiplerinin, kodlamaların ve /ToUnicode akışlarının içinde yaşadığı nesne modeli.
  • Glif — bir yazı tipindeki görsel bir şekil (bir anahat). Bir PDF’in gerçekte boyadığı şey. Bir glifin bir dizini vardır ama kendinde bir karakter anlamı yoktur.
  • Karakter — bir Unicode kod noktasıyla tanımlanan bir yazı dili birimi. Kastettiğiniz şey ve çıkarmanın kurtarmaya çalıştığı şey.
  • Kod — bir içerik akışında, geçerli yazı tipinden bir glif seçen sayısal değer. Bir Unicode karakteri değildir; yalnızca yazı tipine göre anlamlıdır.
  • CID — büyük bir küme içinde bir glifi adreslemek için bir birleşik yazı tipinin kullandığı bir karakter tanımlayıcı; kod ile glif arasındaki bir ara adım.
  • Birleşik (Type 0) yazı tipi — bir yazı tipinin binlerce glifi adreslemesi gerektiğinde kullanılan, çok baytlı kodları bir CMap aracılığıyla okuyup CID’lere ve gliflere ulaşan bir yazı tipi.
  • /ToUnicode — bir belgenin kullandığı kodları Unicode değerlerine geri eşleyen CMap akışı; PDF metnini aranabilir, kopyalanabilir ve erişilebilir kılan şey.
  • Bitişik harf — iki veya daha fazla harfi tek bir şekil olarak çizen tek bir glif (örneğin fi); /ToUnicode girdisi onu karakterlerine geri ayrıştırır.