You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PDFBox渲染SVG时如何修改图标颜色?

如何在使用PDFBox将SVG渲染到PDF时修改颜色?

我尝试用PDFBox和SVG Salamander将SVG渲染到PDF,想把图标改成绿色,但不管怎么设置颜色,最终显示都是黑色。我的代码如下:

File svgFile = new File("roots.svg");

SVGUniverse svgUniverse = new SVGUniverse();
SVGDiagram diagram = svgUniverse.getDiagram(svgUniverse.loadSVG(svgFile.toURL()));

PdfBoxGraphics2D graphics = new PdfBoxGraphics2D(document, 32, 32);
graphics.setColor(Color.green);

try {
    diagram.render(graphics);
} catch (SVGException e) {
    e.printStackTrace();
} finally {
    graphics.dispose();
}

PDFormXObject xform = graphics.getXFormObject();

try (PDPageContentStream contentWriter = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, false)) {
    AffineTransform transform = AffineTransform.getTranslateInstance(0, 0);
    transform.scale(2,2);
    xform.setMatrix(transform);
    contentWriter.setNonStrokingColor(Color.green);
    contentWriter.setStrokingColor(Color.green);
    contentWriter.drawForm(xform);
}

依赖配置:

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.25</version>
</dependency>

<dependency>
    <groupId>com.weblookandfeel</groupId>
    <artifactId>svg-salamander</artifactId>
    <version>1.1.2.2</version>
</dependency>

调整contentWriter.setNonStrokingColor和setStrokingColor也没有效果,请问该怎么解决?


问题原因

  1. SVG文件内部的元素可能已经定义了明确的fill或stroke颜色,渲染时会优先使用这些属性,覆盖你通过Graphics2D.setColor设置的全局颜色。
  2. 绘制XForm对象时设置的颜色不会生效,因为XForm是独立的内容流,内部已经包含了完整的绘图指令(包括颜色),外部设置的颜色无法穿透到XForm内部。

解决方案

方案1:渲染前修改SVG元素的颜色(推荐)

直接通过SVG Salamander的API遍历SVG的DOM结构,修改所有元素的填充和描边颜色。

示例代码:

File svgFile = new File("roots.svg");
SVGUniverse svgUniverse = new SVGUniverse();
URI svgURI = svgFile.toURI();
SVGDiagram diagram = svgUniverse.getDiagram(svgUniverse.loadSVG(svgURI));

// 获取SVG根元素,遍历所有子元素修改颜色
Element root = diagram.getRoot();
changeElementColor(root, Color.green);

// 后续渲染逻辑不变
PdfBoxGraphics2D graphics = new PdfBoxGraphics2D(document, diagram.getWidth(), diagram.getHeight());
try {
    diagram.render(graphics);
} catch (SVGException e) {
    e.printStackTrace();
} finally {
    graphics.dispose();
}

// ... 剩余绘制XForm的代码不变

添加颜色修改的工具方法:

private static void changeElementColor(Element element, Color targetColor) {
    // 修改当前元素的填充和描边颜色
    element.setAttributeNS(null, "fill", String.format("#%02x%02x%02x", targetColor.getRed(), targetColor.getGreen(), targetColor.getBlue()));
    element.setAttributeNS(null, "stroke", String.format("#%02x%02x%02x", targetColor.getRed(), targetColor.getGreen(), targetColor.getBlue()));
    
    // 递归处理子元素
    NodeList children = element.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        if (node instanceof Element) {
            changeElementColor((Element) node, targetColor);
        }
    }
}

方案2:自定义Graphics2D拦截颜色设置

继承PdfBoxGraphics2D,重写颜色相关的方法,强制使用目标颜色。

示例代码:

class ColorOverrideGraphics2D extends PdfBoxGraphics2D {
    private final Color targetColor;

    public ColorOverrideGraphics2D(PDDocument document, float width, float height, Color targetColor) {
        super(document, width, height);
        this.targetColor = targetColor;
    }

    @Override
    public void setColor(Color c) {
        // 忽略传入的颜色,强制使用目标颜色
        super.setColor(targetColor);
    }

    @Override
    public void setPaint(Paint paint) {
        // 如果是Color类型,强制替换;否则保留原Paint(渐变/图案等)
        if (paint instanceof Color) {
            super.setPaint(targetColor);
        } else {
            super.setPaint(paint);
        }
    }

    @Override
    public void setStroke(Stroke s) {
        super.setStroke(s);
        // 同时设置描边颜色
        super.setColor(targetColor);
    }
}

使用这个自定义Graphics2D:

PdfBoxGraphics2D graphics = new ColorOverrideGraphics2D(document, 32, 32, Color.green);
try {
    diagram.render(graphics);
} catch (SVGException e) {
    e.printStackTrace();
} finally {
    graphics.dispose();
}

方案3:修改SVG文件内容

如果允许修改原始SVG文件,可以直接在SVG中把所有fill和stroke属性改成目标颜色,或者删除这些属性让渲染时继承全局颜色。

注意事项

  • 方案1需要确保SVG的元素都使用了fill/stroke属性,如果有使用CSS类定义颜色,需要额外处理CSS样式。
  • 方案2对复杂SVG(如包含渐变、图案填充)可能不适用,因为这类填充不是简单的Color类型。

内容的提问来源于stack exchange,提问作者Christoph Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:28