23 votes

Pourquoi le texte "fi" est-il coupé lorsque je copie depuis un PDF ou que j'imprime un document ?

Lorsque je copie à partir d'un fichier PDF d'Adobe Reader qui contient

Define an operation

Je vois plutôt

Dene an operation

quand je colle le texte, pourquoi ?

Comment puis-je remédier à ce problème ennuyeux ?

J'ai également constaté ce phénomène dans le passé lorsque j'ai imprimé un fichier Microsoft Office Word sur mon imprimante.

16voto

afrazier Points 22479

Cela ressemble à un problème de police. Le PDF utilise probablement la police OpenType fi ligature dans le mot define et la police actuelle de l'application de destination ne contient pas ce glyphe.

Je ne sais pas s'il existe un moyen simple pour qu'Acrobat décompose la ligature à la copie.

Vos problèmes d'impression sont probablement aussi liés à la police. Quelque chose permet probablement à l'imprimante de substituer la police du document par ses propres polices intégrées et la version de l'imprimante de la police est également dépourvue de ce glyphe particulier. Pour contourner ce problème, vous devez demander à Windows de toujours télécharger les polices vers l'imprimante.

Une autre possibilité lors de l'impression : UniScribe n'est peut-être pas activé. MS KB 2642020 traite de ce problème et de certaines solutions de contournement possibles (notamment l'utilisation d'une impression de type RAW plutôt qu'une impression de type EMF). Bien que le contexte soit légèrement différent de votre problème spécifique, la cause peut être la même et les mêmes solutions peuvent s'appliquer.

1 votes

Intéressant pour les ligatures, je me demande si on peut le configurer pour qu'il se comporte correctement. Je pourrais peut-être regarder comment se comportent les autres lecteurs de PDF. Où dois-je le configurer exactement pour que les polices soient envoyées à l'imprimante ?

1 votes

Depuis la boîte de dialogue d'impression d'une application : Cliquez sur Properties (ou Preferences selon la version de la boîte de dialogue) pour l'imprimante, assurez-vous que vous êtes sur la page d'accueil de l'imprimante. Layout o Quality cliquez sur l'onglet Advanced bouton. Dans l'écran Graphic modifiez le TrueType Font option pour Download as Softfont . Cela couvre la plupart des imprimantes PostScript et des imprimantes utilisant les boîtes de dialogue intégrées de Windows (je pense), mais d'autres pilotes peuvent avoir des choses déplacées, ou carrément manquantes.

0 votes

Vous pouvez trouver MS KB 2642020 d'une certaine utilité. J'ai modifié ma réponse avec cette information.

11voto

davidcann Points 1005

Le problème ici est, comme le autre réponse notes, avec ligatures. Cependant, cela n'a absolument rien à voir avec OpenType. Le problème fondamental est que les PDF sont un format de préimpression qui ne se préoccupe guère du contenu et de la sémantique, mais vise plutôt à représenter fidèlement une page telle qu'elle serait imprimée.

Le texte est présenté non pas comme un texte mais comme des séries de glyphes d'une police à certaines positions. Vous obtenez donc quelque chose comme "Placez le glyphe numéro 72 là, le glyphe numéro 101 là, le glyphe numéro 108 là, ...". À ce niveau, il n'y a fondamentalement aucune notion de texte. du tout . C'est juste une description de la façon dont il regarde . Il y a deux problèmes pour extraire une signification d'un ensemble de glyphes :

  1. La disposition spatiale. Comme le PDF contient déjà des informations spécifiques sur l'emplacement de chaque glyphe, il n'y a pas de texte réel sous-jacent, comme cela serait normal. Un autre effet secondaire est qu'il n'y a pas d'espaces. Bien sûr, si vous regardez le texte, il y en a, mais pas dans le PDF. Pourquoi émettre un glyphe vide alors que vous pourriez simplement ne pas en émettre du tout ? Le résultat est le même, après tout. Les lecteurs de PDF doivent donc reconstituer soigneusement le texte, en insérant un espace chaque fois qu'ils rencontrent un grand écart entre les glyphes.

  2. Le PDF rend les glyphes, pas le texte. La plupart du temps, les ID des glyphes correspondent à des points de code Unicode ou au moins à des codes ASCII dans les polices intégrées, ce qui signifie que vous pouvez souvent récupérer du texte ASCII ou Latin 1 de manière satisfaisante, en fonction de la personne qui a créé le PDF en premier lieu (un peu de déformation tout dans le processus). Mais souvent, même les PDF qui vous permettent d'extraire du texte ASCII sans problème gâcheront tout ce qui est en anglais. no ASCII. Particulièrement horrible avec les scripts complexes tels que l'arabe qui contient seulement les ligatures et les glyphes alternatifs après la mise en page, ce qui signifie que les PDF arabes ne contiennent presque jamais de texte réel.

Le deuxième problème est semblable à celui que vous rencontrez. Un coupable commun est LaTeX, qui utilise un nombre estimé à 238982375 polices différentes (chacune d'entre elles étant limitée à 256 glyphes) pour réaliser sa production. Des polices différentes pour le texte normal, les mathématiques (qui en utilisent plusieurs), etc. rendent les choses très difficiles, d'autant plus que Metafont est antérieure à Unicode de près de deux décennies et qu'il n'y a donc jamais eu de correspondance Unicode. Les trémas sont également rendus par un tréma superposé à une lettre, par exemple, vous obtenez "¨a" au lieu de "ä" lorsque vous copiez à partir d'un PDF (et bien sûr, vous ne pouvez pas non plus le rechercher).

Les applications produisant des PDF peuvent choisir d'inclure le texte réel en tant que métadonnées. Si elles ne le font pas, vous êtes laissé à la merci de la façon dont les polices intégrées sont traitées et de la capacité du lecteur PDF à reconstituer le texte original. Mais le fait que "fi" soit copié comme un blanc ou pas du tout est généralement le signe d'un PDF LaTeX. Vous devriez peindre des caractères Unicode sur des pierres et les jeter sur le producteur, en espérant qu'il passera à XeLaTeX et arrivera ainsi enfin dans les années 90 des codages de caractères et des normes de polices.

9voto

Jan Van Bruggen Points 191

Vous pouvez remplacer la plupart de ces mots "cassés" par les originaux. Vous pouvez remplacer un mot en toute sécurité si :

  • comme dene o rey ce n'est pas un vrai mot
  • comme define o firefly il y a un moyen de réajuster les séquences de ligatures ( ff , fi , fl , ffi o ffl ) et faire un vrai mot

La plupart des problèmes de ligature répondent à ces critères. Cependant, vous ne pouvez pas les remplacer :

  • us parce que c'est un mot réel, même si à l'origine il a pu être fluffs
    • également affirm , butterfly , fielders , fortifies , flimflam , misfits ...
  • cus parce qu'il pourrait devenir soit cuffs o ficus
    • également stiffed / stifled , rifle / riffle , flung / fluffing ...

En ce dictionnaire anglais de 496 mille mots il y a 16055 les mots qui contiennent au moins un ff , fi , fl , ffi o ffl qui se transforment en 15879 les mots lorsque leurs ligatures sont supprimées. 173 de ces mots manquants se sont entrechoqués comme cuffs y ficus et le dernier 3 sont parce que ce dictionnaire contient les mots ff , fi y fl .

790 de ces mots "supprimés par la ligature" sont de vrais mots, comme us mais 15089 sont des mots brisés. 14960 des mots brisés peuvent être remplacés sans risque par le mot original, ce qui signifie que 99.1% des mots cassés sont réparables et 93.2% des mots originaux qui contiennent une ligature peuvent être récupérés après avoir copié-collé un PDF. 6.8% des mots contenant des séquences de ligatures sont perdus dans les collisions ( cus ) et des sous-mots ( us ), à moins que vous ne trouviez un moyen (contexte du mot/document ?) de choisir le meilleur remplacement pour chacun des mots qui n'ont pas de remplacement garanti.

Voici mon script Python qui a généré les statistiques ci-dessus. Il s'attend à un fichier texte de type dictionnaire avec un mot par ligne. À la fin, il écrit un fichier CSV qui fait correspondre les mots cassés réparables à leurs mots d'origine.

Voici un lien pour télécharger le CSV : http://www.filedropper.com/brokenligaturewordfixes Combinez ce mappage avec quelque chose comme un remplacement regex script afin de remplacer la plupart des mots cassés.

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])

0 votes

Le lien vers le .csv est cassé. Ce serait génial si vous pouviez le télécharger à nouveau ! Dans tous les cas, merci pour le code.

0 votes

@Enora J'ai retéléchargé le CSV sur le même lien - j'espère que cela vous aidera ! J'ai également remarqué quelques problèmes dans le code/résultats (utilisation de points comme caractères de remplissage alors que le nouveau dictionnaire contient des points dans ses mots, et pas de minuscules dans les mots avant de les comparer). Je pense que tous les remplacements sont corrects, mais prenez-les avec un grain de sel et sachez que d'autres bons remplacements sont possibles. Je recommande d'automatiser les remplacements avec des regex, puis de confirmer chaque remplacement de vos propres yeux.

1voto

compound eye Points 211

Si vous générez ce PDF, vous pouvez éviter que les ligatures soient saisies en premier lieu.

Je génère des pdf à partir de markdown et de css et j'inclus les éléments suivants afin de pouvoir convertir mes documents dans d'autres formats - y compris word - sans perdre les ff, fi, fl etc :

* {
font-variant-ligatures: none;
}

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X