首页 文章

Java - PDFBox - ReplaceString - 解析的令牌问题(可能编码?)

提问于
浏览
0

我一直在努力解决与PDFBox和PDF编辑相关的问题 . 我被分配了一个任务,即在给定PDF文件的情况下编辑几个字符串,并将带有编辑过的字符串的文件的镜像版本输出到其中 . 我被告知过去使用这个工具已经解决了这个问题,所以我被告知要做同样的事情 . 我正在使用的功能是这样的:

public void doIt( String inputFile, String outputFile, String strToFind, String message)
    throws IOException, COSVisitorException
{
    // the document
    PDDocument doc = null;
    try
    {
        doc = PDDocument.load( inputFile );
        List pages = doc.getDocumentCatalog().getAllPages();
        for( int i=0; i<pages.size(); i++ )
        {
            PDPage page = (PDPage)pages.get( i );
            PDStream contents = page.getContents();
            PDFStreamParser parser = new PDFStreamParser(contents.getStream() );
            parser.parse();
            List tokens = parser.getTokens();
            for( int j=0; j<tokens.size(); j++ )
            {
                Object next = tokens.get( j );
                if( next instanceof PDFOperator )
                {
                    PDFOperator op = (PDFOperator)next;
                    //Tj and TJ are the two operators that display
                    //strings in a PDF
                    if( op.getOperation().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( strToFind, message );
                        previous.reset();
                        previous.append( string.getBytes("ISO-8859-1") );
                    }
                    else if( op.getOperation().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 = string.replaceFirst( strToFind, message );
                                cosString.reset();
                                cosString.append( string.getBytes("ISO-8859-1") );
                            }
                        }
                    }
                }
            }
            //now that the tokens are updated we will replace the
            //page content stream.
            PDStream updatedStream = new PDStream(doc);
            OutputStream out = updatedStream.createOutputStream();
            ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
            tokenWriter.writeTokens( tokens );
            page.setContents( updatedStream );
        }
        doc.save( outputFile );
    }
    finally
    {
        if( doc != null )
        {
            doc.close();
        }
    }
}

哪个是包含在PDFBox示例(https://svn.apache.org/repos/asf/pdfbox/tags/1.5.0/pdfbox/src/main/java/org/apache/pdfbox/examples/pdmodel/ReplaceString.java)中的文件中使用的代码 .

但是,我给出的文件根本没有被修改过 . 什么都没发生 . 经过进一步检查,我决定分析解析器生成的令牌的顺序 . 正在COSString元素以外的所有内容中正确解析该文件,其中包含看起来像是错误编码的乱码字符(随机符号和数字串) . 我尝试解析其他文档,并且该函数可以与其中一些文档一起使用,但不是我作为输入传递的所有内容(乳胶输出文件已正确修改并且已正确编码COSStrings,而其他自动生成的pdfs没有产生带有乱码COSString内容的结果) . 我也很确定正在正确读取结构的其余部分,因为我在不同的文件上重建输出,并且输出文件看起来与输入完全相同,这似乎意味着正在正确分析文件结构 . 该文件包含Identity-H编码字体 .

我尝试使用PDFTextStripper(从PDF中提取文本)解析同一个文件,并从那里解析输出返回正确的文本输出,使用:

PDFTextStripper pdfStripper = new PDFTextStripper("UTF-8");
            String result = pdfStripper.getText(doc);
            System.out.println(result);

这可能是编码问题吗?我可以告诉PDFStreamParser(或负责任的人)强制读取编码吗?它甚至是编码问题,因为文本提取工作正常吗?

在此先感谢您的帮助 .

2 回答

  • 0

    某些文件使用字体子集 . 假设子集仅使用字符E,G,L和O.因此GOOGLE将在文件中显示为十六进制字节值2,4,4,2,3和1 .

    现在,如果您想将GOOGLE更改为APPLE,您将遇到三个问题:

    1)您的子集不包含字符A,L和P.

    2)尺寸会有所不同

    3)你正在搜索的字符串很可能分成几个部分 .

    顺便说一下当前版本是1.8.10 . 在即将发布的2.0版本中已删除ReplaceString实用程序,以避免产生可轻松替换字符的错觉 .

    这个答案有点推测,因为你还没有链接到PDF .

  • 0

    PDF文本内部可以存储在两个地方:

    • 内容流

    • X资源内的对象

    内容流内部主要是文本与TJ或Tj运算符相关联 . 但是与Tj或TJ相关的文本并不总是ASCII格式,它可能是一些字节值 . 在使用适当的编码和映射将字符代码映射到unicode值之后,我们可以从这些字节值中提取文本 . 在提取文本时,我们使用映射和编码,但是我们没有反向映射来检查字形是否属于哪个字符代码 . 所以基本上我们应该用新字符串的字符代码替换字符串的字符代码 .

    例:

    1. (Text) Tj
    2. (12 45 5 3)Tj
    

    我们还应该替换内容流中的字符串以及资源内的X Object(如果存在) .

    所以我认为这可能会有所帮助 .

    祝好运!

相关问题