【问题标题】:Traverse whole PDF and Remove underlines of hyperlinks (annotations) only + iText仅遍历整个 PDF 并删除超链接(注释)的下划线 + iText
【发布时间】:2019-09-20 13:39:35
【问题描述】:

我已使用以下链接代码成功更改了下划线的颜色。任何人都可以帮助我如何从 PDF 中删除下划线,我使用下面的链接代码找到了下划线。

Traverse whole PDF and change blue color to black ( Change color of underlines as well) + iText

以下是我查找超链接并将其颜色更改为黑色的代码。我必须修改此代码以删除这些下划线。

PdfCanvasEditor editor = new PdfCanvasEditor() {
    @Override
    protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
    {
        String operatorString = operator.toString();

        if (SET_FILL_RGB.equals(operatorString) && operands.size() == 4) {
            if (isApproximatelyEqual(operands.get(0), 0) &&
                    isApproximatelyEqual(operands.get(1), 0) &&
                    isApproximatelyEqual(operands.get(2), 1)) {
                super.write(processor, new PdfLiteral("g"), Arrays.asList(new PdfNumber(0), new PdfLiteral("g")));
                return;
            }
        }

        if (SET_STROKE_RGB.equals(operatorString) && operands.size() == 4) {
            if (isApproximatelyEqual(operands.get(0), 0) &&
                    isApproximatelyEqual(operands.get(1), 0) &&
                    isApproximatelyEqual(operands.get(2), 1)) {
                super.write(processor, new PdfLiteral("G"), Arrays.asList(new PdfNumber(0), new PdfLiteral("G")));
                return;
            }
        }

        super.write(processor, operator, operands);
    }

    boolean isApproximatelyEqual(PdfObject number, float reference) {
        return number instanceof PdfNumber && Math.abs(reference - ((PdfNumber)number).floatValue()) < 0.01f;
    }

    final String SET_FILL_RGB = "rg";
    final String SET_STROKE_RGB = "RG";
};
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
    editor.editPage(pdfDocument, i);
}

已编辑:

接受的答案不适用于以下文件:

https://raad-dev-test.s3.ap-south-1.amazonaws.com/36/2019-08-30/021549Orig1s025_aprepitant_clinpharm_prea_Mac.pdf(第41页)

https://raad-dev-test.s3.ap-south-1.amazonaws.com/36/2019-08-30/400_206494S5_avibactam_and_ceftazidine_unireview_prea_Mac.pdf(第 60 页)。

请帮忙。

【问题讨论】:

    标签: pdf itext itext7


    【解决方案1】:

    如引用问题上下文中的评论所述

    通过将填充或描边指令替换为删除当前路径而不绘制它的指令,可以很容易地使上面的编辑器类删除矢量图形。如果仅在适用的当前颜色为蓝色的情况下这样做,那么在您的示例 PDF 的情况下可能会完成这项工作。但请注意,在带有其他带有蓝色元素(例如徽标)的图形的文档中,这些也会被破坏。

    这是以下内容编辑器的作用:

    class PdfGraphicsRemoverByColor extends PdfCanvasEditor {
        public PdfGraphicsRemoverByColor(Color color) {
            this.color = color;
        }
    
        @Override
        protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
        {
            String operatorString = operator.toString();
    
            if (color.equals(getGraphicsState().getFillColor())) {
                switch (operatorString) {
                case "f":
                case "f*":
                case "F":
                    operatorString = "n";
                    break;
                case "b":
                case "b*":
                    operatorString = "s";
                    break;
                case "B":
                case "B*":
                    operatorString = "S";
                    break;
                }
            }
    
            if (color.equals(getGraphicsState().getStrokeColor())) {
                switch (operatorString) {
                case "s":
                case "S":
                    operatorString = "n";
                    break;
                case "b":
                case "B":
                    operatorString = "f";
                    break;
                case "b*":
                case "B*":
                    operatorString = "f*";
                    break;
                }
            }
    
            operator = new PdfLiteral(operatorString);
            operands.set(operands.size() - 1, operator);
            super.write(processor, operator, operands);
        }
    
        final Color color;
    }
    

    (RemoveGraphicsByColor 助手类)

    这样应用:

    try (   PdfReader pdfReader = new PdfReader(INPUT);
            PdfWriter pdfWriter = new PdfWriter(OUTPUT);
            PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) )
    {
        PdfCanvasEditor editor = new PdfGraphicsRemoverByColor(ColorConstants.BLUE);
        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
        {
            editor.editPage(pdfDocument, i);
        }
    }
    

    (RemoveGraphicsByColor 测试)

    到引用问题中的示例文件Control_of_nitrosamine_impurities_in_sartans__rev.pdfEDQM_reports_issues_of_non-compliance_with_tooth__Mac.pdforiginalFile.pdf,得到:

    请注意,这只是概念验证,而不是最终和完整的解决方案。特别是:

    • 仅考虑 RGB 蓝色。这可能是一个问题,尤其是在明确设计用于打印的文档(可能使用 CMYK 颜色)的情况下。

    • 只要是蓝色的,所有路径填充和描边都会被丢弃。根据您的文档,这可能需要过滤。

    • PdfCanvasEditor只检查和编辑页面本身的内容流,而不是显示的表单XObjects或patterns的内容流;因此,可能找不到某些内容。它可以很容易地概括。

    与其他 RGB 色彩空间不同的蓝色深浅

    测试上面的代码,您发现文档中的蓝线没有被删除。事实证明,这些蓝色不是来自 DeviceRGB 标准 RGB,而是来自 ICCBased 颜色空间,更准确地说是配置 RGB 颜色空间。此外,在一个文档中,使用的不是纯蓝色 0 0 1,而是 .17255 .3098 .63529 蓝色。

    为了也能够处理这些文件,上述方法必须是通用的;例如我们可以使用Predicate&lt;Color&gt; 而不是单个特定的Color,例如像这样:

    class PdfGraphicsRemoverByColorPredicate extends PdfCanvasEditor {
        public PdfGraphicsRemoverByColorPredicate(Predicate<Color> colorPredicate) {
            this.colorPredicate = colorPredicate;
        }
    
        @Override
        protected void write(PdfCanvasProcessor processor, PdfLiteral operator, List<PdfObject> operands)
        {
            String operatorString = operator.toString();
    
            if (colorPredicate.test(getGraphicsState().getFillColor())) {
                switch (operatorString) {
                case "f":
                case "f*":
                case "F":
                    operatorString = "n";
                    break;
                case "b":
                case "b*":
                    operatorString = "s";
                    break;
                case "B":
                case "B*":
                    operatorString = "S";
                    break;
                }
            }
    
            if (colorPredicate.test(getGraphicsState().getStrokeColor())) {
                switch (operatorString) {
                case "s":
                case "S":
                    operatorString = "n";
                    break;
                case "b":
                case "B":
                    operatorString = "f";
                    break;
                case "b*":
                case "B*":
                    operatorString = "f*";
                    break;
                }
            }
    
            operator = new PdfLiteral(operatorString);
            operands.set(operands.size() - 1, operator);
            super.write(processor, operator, operands);
        }
    
        final Predicate<Color> colorPredicate;
    }
    

    (RemoveGraphicsByColor 助手类)

    这样应用:

    try (   PdfReader pdfReader = new PdfReader(INPUT);
            PdfWriter pdfWriter = new PdfWriter(OUTPUT);
            PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) )
    {
        PdfCanvasEditor editor = new PdfGraphicsRemoverByColorPredicate(RemoveGraphicsByColor::isRgbBlue);
        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++)
        {
            editor.editPage(pdfDocument, i);
        }
    }
    

    RemoveGraphicsByColortestRemoveAllBlueLinesFrom* 测试)

    到使用这个谓词方法的新示例文件

    public static boolean isRgbBlue(Color color) {
        if (color instanceof CalRgb || color instanceof DeviceRgb || (color instanceof IccBased && color.getNumberOfComponents() == 3)) {
            float[] components = color.getColorValue();
            float r = components[0];
            float g = components[1];
            float b = components[2];
            return b > .5f && r < .9f*b && g < .9f*b;
        }
        return false;
    }
    

    (RemoveGraphicsByColor 辅助方法)

    一个得到

    请注意,上面的警告仍然适用。

    【讨论】:

    • @AsadRao 太好了!在这种情况下,您可能应该将答案标记为“已接受”(单击左上角的勾号,在投票箭头的正下方)。
    • 我在问题描述中添加了两个新文件。代码不起作用,请您帮我解决一下。
    • @AsadRao 正如 cmets 在引用问题的上下文中所解释的,这两个新文件不使用 DeviceRGB 而是使用一些基于 ICC 的颜色空间。此外,第二个文档没有使用纯蓝色,而是使用.17255 .3098 .63529。因此,测试color.equals(getGraphicsState().getFillColor()) 需要相当泛化(以便能够跨色彩空间进行比较)和软化(也可以识别脏蓝色)。
    • 好的。明天我会调查的。
    • “我们可以只提到蓝色的阴影吗” - 你可以尝试更加严格,例如将r &lt; .9f*b &amp;&amp; g &lt; .9f*b 替换为r &lt; .75f*b &amp;&amp; g &lt; .75f*b,但RGB 蓝色几乎没有任何固定限制,请参阅this answer,它基本上切换到HSV 颜色,即使那里也只能给出近似范围;最后,答案回到 RGB 并提出 if( max( red, green, blue) == blue),它甚至比上面的 b &gt; .5f &amp;&amp; r &lt; .9f*b &amp;&amp; g &lt; .9f*b 更不严格,因此将更多颜色归类为蓝色......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 2016-04-30
    • 2013-09-19
    相关资源
    最近更新 更多