web-dev-qa-db-ja.com

PDFからコピーするか、ドキュメントを印刷すると、テキスト `fi`が切り取られるのはなぜですか?

Adobe Readerからコピーする場合PDFを含むファイル

Define an operation

むしろ見る

Dene an operation

テキストを貼り付けると、どうしてですか?

この厄介な問題を解決するにはどうすればよいですか?

これは、Microsoft Office Wordファイルをプリンターに印刷したときにも発生します。

16
Tamara Wijsman

これはフォントの問題のようです。 PDFはおそらくOpenType filigature をWordで使用しているdefineであり、宛先アプリケーションの現在のフォントが欠落しているそのグリフ。

Acrobatで合字をコピーで分解する簡単な方法があるかどうかはわかりません。

印刷に関する問題もおそらくフォントに関連しています。何かが原因で、プリンタがドキュメントのフォントを独自の組み込みフォントに置き換えている可能性があり、プリンタのフォントのバージョンにもその特定のグリフがありません。この問題を回避するには、常にフォントをプリンターにダウンロードするようにWindowsに指示する必要があります。

印刷時の別の可能性:UniScribeが有効になっていない可能性があります。 MS KB 264202 これと考えられる回避策について説明します(つまり、EMFタイプ印刷ではなくRAWタイプ印刷を使用します)。コンテキストは特定のタイプと少し異なりますが問題、原因は同じであり、同じ回避策が適用される場合があります。

14
afrazier

これらの「壊れた」単語のほとんどをオリジナルに置き換えることができます。次の場合、Wordを安全に置き換えることができます。

  • denereyのように、実際のWordではありません
  • defineまたはfireflyのように、合字シーケンス(fffiflffi、またはffl)を再追加して実際の単語を作成する方法は1つあります

ほとんどの合字問題はこれらの基準に適合します。ただし、次のものを置き換えることはできません。

  • usは、本来fluffs [.____でしたが、実際のWordであるためです。]
    • また、affirmbutterflyfieldersfortifiesflimflammisfits...
  • cusは、cuffsまたはficus になる可能性があるためです。
    • また、stiffed/stifledrifle/riffleflung/fluffing...

この496千語の英語の辞書 には、少なくとも1つのfffiflffi、またはfflを含む16055単語があります。合字が削除されると15879の単語に変わります。 cuffsficusのように衝突した欠落単語の173、および最後の3は、その辞書にfffi、およびfl

これらの「合字が削除された」単語の790は、usのような実際の単語ですが、15089は壊れた単語です。 14960の壊れた単語は元の単語で安全に置き換えることができます。つまり、壊れた単語の99.1%は修正可能であり、合字を含む元の単語の93.2%は、PDFのコピーアンドペースト後に復元できます。 合字シーケンスを含む単語の6.8%は、衝突(cus)およびサブワード(us)によって失われます。置換が保証されていない単語のそれぞれに最適な置換。

以下は、上記の統計を生成したmy Pythonスクリプトです。1行に1ワードの辞書テキストファイルが必要です。最後に、修正可能な壊れた単語を元の単語にマップするCSVファイルを書き込みます。

CSVをダウンロードするためのリンクは次のとおりです。 http://www.filedropper.com/brokenligaturewordfixes 壊れた単語のほとんどを置き換えるために、このマッピングを正規表現置換スクリプトのようなものと組み合わせます。

import csv
import itertools
import operator
import re


dictionary_file_path = 'dictionary.txt'
broken_Word_fixes_file_path = 'broken_Word_fixes.csv'
ligatures = 'ffi', 'ffl', 'ff', 'fi', 'fl'


with open(dictionary_file_path, 'r') as dictionary_file:
    dictionary_words = list(set(line.strip()
                                for line in dictionary_file.readlines()))


broken_Word_fixes = {}
ligature_words = set()
ligature_removed_words = set()
broken_words = set()
multi_ligature_words = set()


# Find broken Word fixes for words with one ligature sequence
# Example: "dene" --> "define"
words_and_ligatures = list(itertools.product(dictionary_words, ligatures))
for i, (Word, ligature) in enumerate(words_and_ligatures):
    if i % 50000 == 0:
        print('1-ligature words {percent:.3g}% complete'
              .format(percent=100 * i / len(words_and_ligatures)))
    for ligature_match in re.finditer(ligature, Word):
        if Word in ligature_words:
            multi_ligature_words.add(Word)
        ligature_words.add(Word)
        if Word == ligature:
            break
        # Skip words that contain a larger ligature
        if (('ffi' in Word and ligature != 'ffi') or
                ('ffl' in Word and ligature != 'ffl')):
            break
        # Replace ligatures with dots to avoid creating new ligatures
        # Example: "offline" --> "of.ine" to avoid creating "fi"
        ligature_removed_Word = (Word[:ligature_match.start()] +
                                 '.' +
                                 Word[ligature_match.end():])
        # Skip words that contain another ligature
        if any(ligature in ligature_removed_Word for ligature in ligatures):
            continue
        ligature_removed_Word = ligature_removed_Word.replace('.', '')
        ligature_removed_words.add(ligature_removed_Word)
        if ligature_removed_Word not in dictionary_words:
            broken_Word = ligature_removed_Word
            broken_words.add(broken_Word)
            if broken_Word not in broken_Word_fixes:
                broken_Word_fixes[broken_Word] = Word
            else:
                # Ignore broken words with multiple possible fixes
                # Example: "cus" --> "cuffs" or "ficus"
                broken_Word_fixes[broken_Word] = None


# Find broken Word fixes for Word with multiple ligature sequences
# Example: "rey" --> "firefly"
multi_ligature_words = sorted(multi_ligature_words)
numbers_of_ligatures_in_Word = 2, 3
for number_of_ligatures_in_Word in numbers_of_ligatures_in_Word:
    ligature_lists = itertools.combinations_with_replacement(
        ligatures, r=number_of_ligatures_in_Word
    )
    words_and_ligature_lists = list(itertools.product(
        multi_ligature_words, ligature_lists
    ))
    for i, (Word, ligature_list) in enumerate(words_and_ligature_lists):
        if i % 1000 == 0:
            print('{n}-ligature words {percent:.3g}% complete'
                  .format(n=number_of_ligatures_in_Word,
                          percent=100 * i / len(words_and_ligature_lists)))
        # Skip words that contain a larger ligature
        if (('ffi' in Word and 'ffi' not in ligature_list) or
                ('ffl' in Word and 'ffl' not in ligature_list)):
            continue
        ligature_removed_Word = Word
        for ligature in ligature_list:
            ligature_matches = list(re.finditer(ligature, ligature_removed_Word))
            if not ligature_matches:
                break
            ligature_match = ligature_matches[0]
            # Replace ligatures with dots to avoid creating new ligatures
            # Example: "offline" --> "of.ine" to avoid creating "fi"
            ligature_removed_Word = (
                ligature_removed_Word[:ligature_match.start()] +
                '.' +
                ligature_removed_Word[ligature_match.end():]
            )
        else:
            # Skip words that contain another ligature
            if any(ligature in ligature_removed_Word for ligature in ligatures):
                continue
            ligature_removed_Word = ligature_removed_Word.replace('.', '')
            ligature_removed_words.add(ligature_removed_Word)
            if ligature_removed_Word not in dictionary_words:
                broken_Word = ligature_removed_Word
                broken_words.add(broken_Word)
                if broken_Word not in broken_Word_fixes:
                    broken_Word_fixes[broken_Word] = Word
                else:
                    # Ignore broken words with multiple possible fixes
                    # Example: "ung" --> "flung" or "fluffing"
                    broken_Word_fixes[broken_Word] = None


# Remove broken words with multiple possible fixes
for broken_Word, fixed_Word in broken_Word_fixes.copy().items():
    if not fixed_Word:
        broken_Word_fixes.pop(broken_Word)


number_of_ligature_words = len(ligature_words)
number_of_ligature_removed_words = len(ligature_removed_words)
number_of_broken_words = len(broken_words)
number_of_fixable_broken_words = len(
    [Word for Word in set(broken_Word_fixes.keys())
     if Word and broken_Word_fixes[Word]]
)
number_of_recoverable_ligature_words = len(
    [Word for Word in set(broken_Word_fixes.values())
     if Word]
)
print(number_of_ligature_words, 'ligature words')
print(number_of_ligature_removed_words, 'ligature-removed words')
print(number_of_broken_words, 'broken words')
print(number_of_fixable_broken_words,
      'fixable broken words ({percent:.3g}% fixable)'
      .format(percent=(
      100 * number_of_fixable_broken_words / number_of_broken_words
  )))
print(number_of_recoverable_ligature_words,
      'recoverable ligature words ({percent:.3g}% recoverable)'
      '(for at least one broken Word)'
      .format(percent=(
          100 * number_of_recoverable_ligature_words / number_of_ligature_words
      )))


with open(broken_Word_fixes_file_path, 'w+', newline='') as broken_Word_fixes_file:
    csv_writer = csv.writer(broken_Word_fixes_file)
    sorted_broken_Word_fixes = sorted(broken_Word_fixes.items(),
                                      key=operator.itemgetter(0))
    for broken_Word, fixed_Word in sorted_broken_Word_fixes:
        csv_writer.writerow([broken_Word, fixed_Word])
9
Jan Van Bruggen

ここでの問題は other answer 注記のように合字です。ただし、OpenTypeとは何の関係もありません。基本的な問題は、PDFが印刷前のフォーマットであり、コンテンツとセマンティクスにはほとんど関係しないが、印刷されるページを忠実に表現することに向けられていることです。

テキストはテキストとしてではなく、特定の位置にあるフォントのglyphsのランとしてレイアウトされます。したがって、「グリフ番号72をそこに配置し、グリフ番号101をそこに配置し、グリフ番号108をそこに配置する」などのようになります。そのレベルでは、基本的にテキストの概念はまったくありません。これは、の外観の説明にすぎません。一連のグリフから意味を抽出するには、2つの問題があります。

  1. 空間レイアウト。 PDFには、各グリフを配置する特定の情報が既に含まれているため、通常のようにその下に実際のテキストはありません。もう1つの副作用は、スペースがないことです。確かに、テキストはありますが、PDFにはありません。何も出力しないだけで空白のグリフを出力するのはなぜですか?結果は結局同じです。したがって、PDF読者は注意深くつなぐ必要がありますテキストを再度、グリフ間のギャップが大きくなるたびにスペースを挿入します。

  2. PDFはテキストではなくグリフをレンダリングします。ほとんどの場合、グリフIDはUnicodeコードポイントまたは少なくとも埋め込みフォントのASCIIコードに対応しています。つまり、ASCIIまたはラテン語を取得できることがよくあります。最初の場所でPDFを作成した人に応じて、1つのテキストは十分に戻ってきます(プロセスで一部の文字化けすべて) )しかし、多くの場合、PDFでさえも、ASCIIテキストをうまく表示できるようにしても、ASCIIではないASCII) 。アラビア語などの複雑なスクリプトでは特に恐ろしいです。レイアウト段階の後にonly合字と代替字形が含まれているため、アラビア語PDFには実際のテキストはほとんど含まれません。

2番目の問題は、あなたが直面している問題のようなものです。ここでの一般的な原因はLaTeXで、推定数238982375の異なるフォント(それぞれ256グリフに制限されています)を使用して出力を実現しています。通常のテキスト、数学(複数使用)などのフォントが異なると、特にMetafontがほぼ20年前にUnicodeを使用するようになり、Unicodeマッピングがなかったため、状況が非常に難しくなっています。ウムラウトは、文字に重ねられた分音記号によってもレンダリングされます。 PDFからコピーすると、"ä"ではなく"¨a"が表示されます(もちろん、検索もできません)。

PDFを生成するアプリケーションは、実際のテキストをメタデータとして含めることを選択できます。そうでない場合、埋め込まれたフォントの処理方法、およびPDFリーダーが元のテキストを再びつなぎ合わせることができるかどうかに依存することになります。しかし"fi"は空白であるか、まったくない場合は、通常LaTeX PDFの兆候です。Unicode文字を石にペイントしてプロデューサーに投げ、XeLaTeXに切り替えて、最終的に1990年代の文字エンコーディングとフォント標準に到達することを期待します。

8
Joey