【问题标题】:Remove underlines from text in PDF file从 PDF 文件中的文本中删除下划线
【发布时间】:2016-04-15 17:21:36
【问题描述】:

我有一堆链接损坏的 PDF 文件。 我需要删除这些链接,现在我可以执行以下操作:

  1. 删除链接操作
  2. 将文本颜色从蓝色更改为黑色

我不能做的是删除之前作为链接的文本下方的蓝色下划线。

我尝试了几个用于 .NET 的 PDF 库(因为这是我的主要平台)

  • Aspost.PDF
  • PDFSharp
  • ceTe 动态PDF
  • PDFBox

欢迎您推荐任何编程语言、平台和库的解决方案。我只需要这样做。

【问题讨论】:

  • 请注意,PDF 中的文本下划线只是页面某处的图形线,而不是文本的某些属性。因此,您必须使用相关的 PDF 库来访问矢量图形,而不是文本属性。话虽如此,任何体面的通用 PDF 库都应该可以做到这一点。
  • 你能链接到这样的PDF文件吗?
  • @mkl 是的,我知道下划线的存储方式与 PDF 文件中的文本不同。我不确定矢量图像,但许多库都具有从 PDF 文件中提取位图图像的功能。 Aspose.PDF 和 PDFBox 没有捕获下划线,但有 2 个位图图像。 (请参阅之前评论中的链接)
  • 下划线不是位图图像而是矢量图形矩形(长而细的)。

标签: pdf pdfbox pdfsharp underline aspose


【解决方案1】:

在示例文档的情况下,下划线绘制为蓝色 (RGB 0,0,1) 填充矢量图形矩形(长而细的矩形)。由于链接仅使用蓝色,因此我们可以使用该标准来查找有问题的矩形。

这里是使用 PDFBox 1.8.10 的示例实现:

void removeBlueRectangles(PDDocument document) throws IOException
{
    List<?> pages = document.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<Object> tokens = parser.getTokens();  

        Stack<Boolean> blueState = new Stack<Boolean>();
        blueState.push(false);

        for (int j = 0; j < tokens.size(); j++)  
        {  
            Object next = tokens.get(j);
            if (next instanceof PDFOperator)
            {
                PDFOperator op = (PDFOperator) next;  
                if (op.getOperation().equals("q"))
                {
                    blueState.push(blueState.peek());
                }
                else if (op.getOperation().equals("Q"))
                {
                    blueState.pop();
                }
                else if (op.getOperation().equals("rg"))
                {
                    if (j > 2)
                    {
                        Object r = tokens.get(j-3);
                        Object g = tokens.get(j-2);
                        Object b = tokens.get(j-1);
                        if (r instanceof COSNumber && g instanceof COSNumber && b instanceof COSNumber)
                        {
                            blueState.pop();
                            blueState.push((
                                    Math.abs(((COSNumber)r).floatValue() - 0) < 0.001 &&
                                    Math.abs(((COSNumber)g).floatValue() - 0) < 0.001 &&
                                    Math.abs(((COSNumber)b).floatValue() - 1) < 0.001));
                        }
                    }
                }
                else if (op.getOperation().equals("f"))
                {
                    if (blueState.peek() && j > 0)
                    {
                        Object re = tokens.get(j-1);
                        if (re instanceof PDFOperator && ((PDFOperator)re).getOperation().equals("re"))
                        {
                            tokens.set(j, PDFOperator.getOperator("n"));
                        }
                    }
                }
            }
        }

        PDStream updatedStream = new PDStream(document);  
        OutputStream out = updatedStream.createOutputStream();  
        ContentStreamWriter tokenWriter = new ContentStreamWriter(out);  
        tokenWriter.writeTokens(tokens);  
        page.setContents(updatedStream);
    }
}

(RemoveUnderlines.java)

原始文件.pdf

将此应用于您的第一个示例文件original.pdf

public void testOriginal() throws IOException, COSVisitorException
{
    try (   InputStream resourceStream = getClass().getResourceAsStream("original.pdf")   )
    {
        PDDocument document = PDDocument.loadNonSeq(resourceStream, null);

        removeBlueRectangles(document);
        document.save("original-noBlueRectangles.pdf");

        document.close();
    }
}

(RemoveUnderlines.java)

结果

1178.pdf

你评论了

在对许多文件进行了测试之后,我不得不说这个解决方案在某些情况下无法正常工作。例如,对于此文件 (dropbox.com/s/23g54bvt781lb93/1178.pdf?dl=0),它会删除页面的全部内容。继续搜索..

所以我将代码应用到您的新示例文件1178.pdf

public void test1178() throws IOException, COSVisitorException
{
    try (   InputStream resourceStream = getClass().getResourceAsStream("1178.pdf")   )
    {
        PDDocument document = PDDocument.loadNonSeq(resourceStream, null);

        removeBlueRectangles(document);
        document.save(new File(RESULT_FOLDER, "1178-noBlueRectangles.pdf"));

        document.close();
    }
}

(RemoveUnderlines.java)

导致

因此,我无法确认您声称 该解决方案无法正常工作;特别是我看到 它不会删除页面的全部内容。

由于我无法重现您的观察结果,我假设您的设置中还有其他您尚未提及的问题。

【讨论】:

  • 在对许多文件进行了测试之后,我不得不说这个解决方案在某些情况下无法正常工作。例如,对于这个文件 (dropbox.com/s/23g54bvt781lb93/1178.pdf?dl=0),它会删除页面的全部内容。继续搜索...
  • 我检索了您的新文件,将代码应用到它,它工作正常。因此,您的设置似乎还有其他问题。
  • 你是对的。我的错。我为 PDFBox 使用了 .NET 端口。
  • 啊,好的。我不得不承认,我不知道那个端口是哪个版本的,也不知道是否存在实质性差异。
猜你喜欢
  • 2013-03-12
  • 2016-03-12
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-19
  • 2014-10-26
相关资源
最近更新 更多