首页 > 解决方案 > BridgeException: null:-1 将 SVG 转码为 BufferedImage 并引用不存在的掩码

问题描述

任务:使用 Apache Batik 1.14 ( ) 将 SVG 文件转换为 BufferedImage imageTranscoder.transcode(new TranscoderInput(svgDocument), null)

问题:它抛出这个异常:

Caused by: org.apache.batik.bridge.BridgeException: null:-1
Cannot find the referenced element:
"#mask-2"
specified on the element <path> - may be a problem of 'id'
at org.apache.batik.bridge.BridgeContext.getReferencedNode(BridgeContext.java:762)
at org.apache.batik.bridge.BridgeContext.getReferencedElement(BridgeContext.java:804)
at org.apache.batik.bridge.CSSUtilities.convertMask(CSSUtilities.java:771)
at org.apache.batik.bridge.AbstractGraphicsNodeBridge.buildGraphicsNode(AbstractGraphicsNodeBridge.java:144)
at org.apache.batik.bridge.SVGShapeElementBridge.buildGraphicsNode(SVGShapeElementBridge.java:92)
at org.apache.batik.bridge.GVTBuilder.buildGraphicsNode(GVTBuilder.java:224)
at org.apache.batik.bridge.GVTBuilder.buildComposite(GVTBuilder.java:171)
at org.apache.batik.bridge.GVTBuilder.buildGraphicsNode(GVTBuilder.java:219)
at org.apache.batik.bridge.GVTBuilder.buildComposite(GVTBuilder.java:171)
at org.apache.batik.bridge.GVTBuilder.build(GVTBuilder.java:82)
at org.apache.batik.transcoder.SVGAbstractTranscoder.transcode(SVGAbstractTranscoder.java:210)
... 108 more

原因/原因是 SVG 文档不包含任何mask元素,但包含一些path引用(不存在的)掩码的元素:<path [...] mask="url(#mask-2)" />。有关掩码的更多信息,请参见此处https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mask

我的解决方法是检查 SVG 文档并删除所有无效的掩码引用,如下所示:

  1. 查找所有有效的掩码 ID:

     Set<String> existingMaskIds = new HashSet<>();
     NodeList allMaskNodes = svgDocument.getElementsByTagName("mask");
     int numberOfMaskNodes = allMaskNodes.getLength();
     for (int i = 0; i < numberOfMaskNodes; i++) {
         Element maskElement = (Element) allMaskNodes.item(i);
         if (maskElement.hasAttribute("id")) {
             existingMaskIds.add(maskElement.getAttribute("id"));
         }
     }
    
  2. 删除所有无效的掩码引用:

     private static void removeInvalidMaskReferences(Node svgNode, Set<String> existingMaskIds) {
     short nodeType = svgNode.getNodeType();
     if (nodeType == Node.ELEMENT_NODE || nodeType == Node.DOCUMENT_NODE) {
         if (nodeType == Node.ELEMENT_NODE) {
             Element svgElement = (Element) svgNode;
    
             if (svgElement.hasAttribute("mask")) {
                 String maskValue = svgElement.getAttribute("mask");
                 if (maskValue != null && maskValue.startsWith("url(")) {
                     maskValue = maskValue.replace("url(", "");
                     maskValue = maskValue.replace(")", "");
                     maskValue = maskValue.replace("#", "");
                     maskValue = maskValue.trim();
                     if (!existingMaskIds.contains(maskValue)) {
                         // Remove mask reference
                         svgElement.removeAttribute("mask");
                     }
                 }
             }
         }
    
         if (svgNode.hasChildNodes()) {
             NodeList children = svgNode.getChildNodes();
             if (children != null) {
                 int numberOfChildren = children.getLength();
                 for (int i = 0; i < numberOfChildren; i++) {
                     removeInvalidMaskReferences(children.item(i), bekannteMaskenIds);
                 }
             }
         }
     }
     }
    

我想我不太可能是唯一一个在这件事上绊倒的人。也许有一些 TranscodingHint(或类似的东西)我可以说“请忽略无效的掩码”?不幸的是,我还没有找到类似的 TranscodingHints。

所以我的问题是:我可以将 SVG 文件转码为 BufferedImage 文件,尽管没有我的解决方法代码和(更宽容的)Apache Batik 的无效掩码引用?

标签: javasvgbatik

解决方案


推荐阅读