2016-08-05 34 views
4

Ich habe Probleme mit pdfbox 2.0.2 beim Schreiben eines PDF-Dokuments aus Elementen eines zuvor gelesenen Dokuments (https://www.dropbox.com/s/ttxiv0dq3abh5kj/Test.pdf?dl=0). Alles funktioniert gut, außer wenn ich showText auf einem PDPageContentStream anrufe, wo ich vorher die Schrift mit out.setFont(textState.getFont(), textState.getFontSize()) eingestellt habe (siehe das INFORMATION-Log) und die Schriftart ist ComicSansMS oder ArialBlack. textState ist (ein Klon von) der Zustand aus dem zuvor gelesenen Dokument. Schreiben von Text mit Helvetica oder Times-Roman funktioniert gut.pdfbox: ... ist nicht in der Codierung dieser Schrift verfügbar

INFORMATION: set font PDTrueTypeFont RXNQOL+ComicSansMS,Bold/18.0 embedded  
SEVERE: error writing <w>U+0077 is not available in this font's encoding: built-in (TTF) 

Ich nehme an, das Problem durch einen fehlenden Bindestrich oder Leerzeichen in dem Schriftnamen verursacht werden kann, habe aber keine Ahnung, wie dies zu beheben.

Dies ist die komplette Code

import java.awt.Point; 
import java.awt.geom.Point2D; 
import java.io.File; 
import java.io.IOException; 
import org.apache.pdfbox.contentstream.PDFGraphicsStreamEngine; 
import org.apache.pdfbox.cos.COSName; 
import org.apache.pdfbox.pdmodel.PDDocument; 
import org.apache.pdfbox.pdmodel.PDPage; 
import org.apache.pdfbox.pdmodel.PDPageContentStream; 
import org.apache.pdfbox.pdmodel.font.PDFont; 
import org.apache.pdfbox.pdmodel.graphics.image.PDImage; 
import org.apache.pdfbox.pdmodel.graphics.state.PDTextState; 
import org.apache.pdfbox.util.Matrix; 
import org.apache.pdfbox.util.Vector; 

public class Test extends PDFGraphicsStreamEngine { 

public static void main(String[] args) throws IOException { 
    test(); 
} 

public static void test() throws IOException { 
    PDDocument document = PDDocument.load(new File("Test.pdf")); 
    PDPage pageIn = document.getPage(0); 
    PDDocument saveDoc = new PDDocument(); 
    PDPage savePage = new PDPage(pageIn.getMediaBox()); 
    saveDoc.addPage(savePage); 
    try (PDPageContentStream out = new PDPageContentStream(saveDoc, savePage)) { 
     Test test = new Test(pageIn, out); 
     test.processPage(pageIn); 
    } 
} 

private final PDPageContentStream out; 

public Test(PDPage pageIn, PDPageContentStream out) { 
    super(pageIn); 
    this.out = out; 
} 

@Override 
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException { 
} 

@Override 
public void clip(int windingRule) throws IOException { 
} 

@Override 
public void closePath() throws IOException { 
} 

@Override 
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException { 
} 

@Override 
public void drawImage(PDImage pdImage) throws IOException { 
} 

@Override 
public void endPath() throws IOException { 
} 

@Override 
public void fillAndStrokePath(int windingRule) throws IOException { 
} 

@Override 
public void fillPath(int windingRule) throws IOException { 
} 

@Override 
public Point2D getCurrentPoint() { 
    return new Point(0, 0); 
} 

@Override 
public void lineTo(float x, float y) throws IOException { 
} 

@Override 
public void moveTo(float x, float y) throws IOException { 
} 

@Override 
public void shadingFill(COSName shadingName) throws IOException { 
} 

@Override 
protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, String unicode, Vector displacement) throws IOException { 
    super.showGlyph(textRenderingMatrix, font, code, unicode, displacement); 
    PDTextState textState = getGraphicsState().getTextState(); 
    out.beginText(); 
    out.setTextMatrix(getTextMatrix()); 
    out.setFont(textState.getFont(), textState.getFontSize()); 
    out.showText(unicode); 
    out.endText(); 
} 

@Override 
public void strokePath() throws IOException { 
} 

} 

Irgendwelche Vorschläge?

Danke, Juergen

+0

Bitte zeigen Sie Ihren zentralen Code und einen Link zu einer Beispiel-PDF-Quelle an, um die Reproduktion Ihres Problems zu ermöglichen. – mkl

Antwort

4

tl; dr: Das Schrift nicht Codierung unterstützt.

Die Ursache des Problems ist, dass Ihre Comic Sans-Untergruppe Schriftart eine "Post" (Postscript) -Tabelle hat, aber dass seine GlyphNames-Tabelle Null ist. I.e. Ihre Schriftart hat keine Glyphnamen. Für A-Z, a-z sind die Namen wie diese Zeichen; für "(" der Glyphename ist "parenleft". Da diese Namen fehlen, erzeugt PDFBox Pseudonyme aus der Glyphen-ID wie "90" (statt "w") für "w" im zweiten Teil von PDTrueType.readEncodingFromFont ().

enter image description here

jedoch, wenn Codierung PDFBox den Adobe Glyphlist verwendet, da die Schriftart nicht eine Codierung Eintrag hat. Wenn Sie mit PDFDebugger an den anderen Schriftarten suchen, zB R18, finden Sie „Encoding : WinAnsiEncoding ":

enter image description here

Was macht ihr offenbar ist creat e eine neue Seite mit nur Text. Eine andere Möglichkeit besteht darin, die Inhaltsströme zu analysieren und einfach alle Token zu entfernen, die etwas anderes als Text malen. Sehen Sie sich zunächst das RemoveAllText-Beispiel im Quellcode-Download an und laden Sie die PDF 32000-Spezifikation herunter. Sehen Sie sich den Teil "Operators Summary" an, und achten Sie darauf, was Sie löschen. Zum Beispiel wird "Do" sowohl zum Zeichnen von Bildern als auch zum Zeichnen von XObject-Formularen verwendet, bei denen es sich ebenfalls um Inhalts-Streams handelt.

Siehe hier: How can I remove all images/drawings from a PDF file and leave text only in Java?

Beide Lösungen sind falsch, die erste zieht nur alle Bilder unter den Füßen, ist der zweite ein guter Anfang, aber nicht kümmern uns um zu überprüfen, ob der Parameter ein Bild oder nicht.

+0

1. Nein, das tue ich nicht; Dies war nur eine abgespeckte Probe, um das Problem zu reproduzieren. 2. Sie sagen also, es gibt keine Möglichkeit, eine (neue) PDF-Seite mit PDFBox mit dieser Schriftart zu erstellen - obwohl sie zumindest im Quelldokument verfügbar/eingebettet ist, um die Glyphen für die enthaltenen Zeichen anzuzeigen? 3. Wenn ja, können Sie auf programmatische Weise feststellen, ob eine in einem Quelldokument verwendete Schriftart für die Kodierung und/oder eine Möglichkeit zum (erneuten) Laden und dann zum Verwenden solcher Fonts (sowohl Arial Black als auch Comis Sans MS) verwendet werden kann wäre zumindest in den meisten Windows-Installationen verfügbar)? – Juergen

+0

2. Nicht leicht. Ich dachte darüber nach, PDFBox zu ändern und probierte es sogar ein wenig aus, aber das entwickelte sich zu viel mehr Arbeit als gedacht.Und selbst das würde in einigen Fällen fehlschlagen, z. mit Ligaturen, wo ein Code in einem PDF mehrere Unicodes bedeuten würde. Und Sie können nicht sicher sein, dass es überhaupt einen "Unicode" gibt, einige PDF-Dateien haben es nicht. Eine andere Lösung wäre, rohe Befehle zu verwenden, aber auch das würde schwierig werden, einige Codes haben 2 Bytes und nicht eins. –

+0

3. Sie könnten versuchen, getEncoding() für die Schriftart aufzurufen (falls für diesen Typ verfügbar) und dann mit contains (code) oder getName (int code) überprüfen. Sie können Truetype-Schriftarten mit 'PDType0Font.load()' verwenden, aber das würde natürlich nur funktionieren (in Ihrer Lösung), wenn Unicode verfügbar ist. –