2017-08-04 1 views
1

Essayer d'utiliser Apache PDFBox version 2.0.2 pour un remplacement de texte (avec le code ci-dessous) produit une sortie où peu de caractères ne seraient pas affichés, principalement le majuscule. Par exemple un remplacement par "ABCDEFGHIJKLMNOPQRSTUVWXYZ" la sortie apparaît en pdf comme "ABCDEF HIJKLM OP RST W Y". Est-ce un bug? ou nous avons une solution de contournement pour gérer ces caractères.Apache PDFBox remplace les résultats de texte dans peu de caractères manqués

public static PDDocument replaceText(PDDocument document, String searchString, String replacement) throws IOException { 
    if (StringUtils.isEmpty(searchString) || StringUtils.isEmpty(replacement)) { 
     return document; 
    } 
    PDPageTree pages = document.getDocumentCatalog().getPages(); 
    for (PDPage page : pages) { 
     PDFStreamParser parser = new PDFStreamParser(page); 
     parser.parse(); 
     List tokens = parser.getTokens(); 
     for (int j = 0; j < tokens.size(); j++) { 
      Object next = tokens.get(j); 
      if (next instanceof Operator) { 
       Operator op = (Operator) next; 
       //Tj and TJ are the two operators that display strings in a PDF 
       if (op.getName().equals("Tj")) { 
        // Tj takes one operator and that is the string to display so lets update that operator 
        COSString previous = (COSString) tokens.get(j - 1); 
        String string = previous.getString(); 
        string = string.replaceFirst(searchString, replacement); 
        previous.setValue(string.getBytes()); 
       } else if (op.getName().equals("TJ")) { 
        COSArray previous = (COSArray) tokens.get(j - 1); 
        for (int k = 0; k < previous.size(); k++) { 
         Object arrElement = previous.getObject(k); 
         if (arrElement instanceof COSString) { 
          COSString cosString = (COSString) arrElement; 
          String string = cosString.getString(); 
          string = StringUtils.replaceOnce(string, searchString, replacement); 
          cosString.setValue(string.getBytes()); 
         } 
        } 
       } 
      } 
     } 
     // now that the tokens are updated we will replace the page content stream. 
     PDStream updatedStream = new PDStream(document); 
     OutputStream out = updatedStream.createOutputStream(); 
     ContentStreamWriter tokenWriter = new ContentStreamWriter(out); 
     tokenWriter.writeTokens(tokens); 
     page.setContents(updatedStream); 
     out.close(); 
    } 
    return document; 
} 
+1

Votre question est parallèle à [cette question] (https://stackoverflow.com/q/34239106/1729265) avec la petite différence que la bibliothèque PDF utilisée était iText. Une grande partie de [ma réponse] (https://stackoverflow.com/a/34315962/1729265) s'applique également ici. – mkl

+0

Merci @mkl, gentil et élaboré .. j'essaie de travailler sur votre suggestion, voudrais toujours aller avec la solution PDFbox si possible. –

+0

Je ne voulais pas vous faire remplacer PDFBox par iText. Ce que je voulais dire par "Une grande partie de ma réponse s'applique ici aussi." étaient les explications pourquoi le problème se produit, et ces explications sont indépendantes de la bibliothèque, ils sont basés sur le fonctionnement de PDF en général. – mkl

Répondre

1

Je cite https://pdfbox.apache.org/2.0/migration.html

Pourquoi at-on l'exemple ReplaceText enlevé?

L'exemple ReplaceText a été supprimé car il donnait l'illusion incorrecte que le texte pouvait être remplacé facilement. Les mots sont souvent divisés, comme on le voit par cet extrait d'un flux de contenu:

[(Do) -29 (c) -1 (umen) 30 (mise en)] TJ

D'autres problèmes apparaissent avec des sous-ensembles de polices : par exemple, si seulement les glyphes pour a, b et c sont utilisés, ceux-ci seront codés comme hex 0, 1 et 2, donc vous ne trouverez pas "abc". De plus, vous ne pouvez pas remplacer "c" par "d" car cela ne fait pas partie du sous-ensemble.

Vous pourriez également avoir des problèmes avec les ligatures, par ex. "Ff", "fl", "fi", "ffi", "ffl", qui peut être représenté par un seul code dans de nombreuses polices. Pour le comprendre vous-même, affichez n'importe quel fichier avec PDFDebugger et regardez l'entrée "Contents" d'une page.

============================================== ========================

Votre description suggère que le fichier initial utilise un sous-ensemble de polices, c'est-à-dire qu'il manque les caractères G, N , Q, V et Y.

Et non, il n'y a pas de solution de contournement facile. Vous devez supprimer le texte que vous ne voulez pas du flux de contenu, puis ajouter un nouveau flux de contenu avec le texte que vous souhaitez avec une nouvelle police au bon endroit.

P.S. la version actuelle de PDFBox est 2.0.7, pas 2.0.2.

+0

Merci @Tilman, j'ai essayé d'utiliser la dernière version 2.0.7 mais le problème persiste encore.Comme suggéré, pourriez-vous m'aider avec des exemples de code pour supprimer un texte particulier du flux de contenu et ajouter également ajouter du texte au nouveau flux de contenu. soyez d'une grande aide .. –

+0

Je n'ai pas prétendu que cela fonctionnerait en 2.0.7. J'ai seulement mentionné 2.0.7 parce que c'est une mauvaise pratique d'utiliser un logiciel obsolète. Pour supprimer un texte particulier, jetez un oeil à l'exemple RemoveAllText.java, vous devez le modifier afin qu'il fonctionne pour votre fichier. (le texte est dans 'newTokens.get (newTokens.size() - 1)', donc vérifiez qu'il correspond, peut être difficile en raison de l'encodage). Ajouter du texte dans le nouveau flux de contenu, voir l'exemple AddMessageToEachPage.java dans le téléchargement du code source. –

+0

Merci pour l'exemple de code, l'approche de jeton de suppression est réalisable mais pour l'écriture, mon cas nécessite une insertion de texte à un emplacement particulier (avec une certaine coordonnée x, y). La lecture au-dessus d'une zone rectangle a bien fonctionné avec une coordonnée x, y et largeur, hauteur, donc j'aimerais savoir si quelque chose de similaire est possible pour l'écriture aussi. –