#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 и удалить все недопустимые ссылки на маски, как это:
- найдите все действительные идентификаторы масок:
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")); } }
- удалите все недопустимые ссылки на маски:
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?