Исключение BridgeException: null:-1 при перекодировании SVG в буферизованное изображение со ссылками на несуществующую маску

#java #svg #batik

Вопрос:

Задача: Преобразование SVG-файла в буферизованное изображение с помощью Apache Batik 1.14 ( 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. найдите все действительные идентификаторы масок:
      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 amp;amp; 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);
                 }
             }
         }
     }
     }
     

Я думаю, что маловероятно, что я единственный человек, который спотыкается на этом. Может быть, есть какой-то транскодинг (или что-то в этом роде), с помощью которого я могу сказать: «Пожалуйста, игнорируйте недопустимые маски»? К сожалению, я не нашел таких транскодирующих точек.

Итак, мой вопрос: могу ли я перекодировать SVG-файлы в буферизованные файлы изображений, несмотря на недопустимые ссылки на маски, без моего обходного кода и просто с помощью (более терпимого) Apache Batik?