关于svg:蜡染无法呈现正确的字体颜色?

Batik not rendering the correct font color?

我正在使用Apache Batik Java库将.svg矢量图像文件转换为.png文件。问题在于所生成的.png图像的字体颜色全部变为黑色。这是我用来进行转换的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;

public class SVGHelperDesktop extends SVGHelper {
    @Override
    public byte[] convertSvgToPng(String svgXml, float png_width)
            throws SVGConversionException {
        byte[] resultPngBytes = null;

        try {
            ByteArrayInputStream inputSvgBytes = new
                    ByteArrayInputStream(svgXml.getBytes());
            TranscoderInput input_svg_image = new
                    TranscoderInput(inputSvgBytes);

            ByteArrayOutputStream outputPngBytes = new ByteArrayOutputStream();
            TranscoderOutput output_png_image = new TranscoderOutput(outputPngBytes);

            PNGTranscoder svgToPngConverter = new PNGTranscoder();
            svgToPngConverter.addTranscodingHint(PNGTranscoder.KEY_WIDTH, png_width);
            svgToPngConverter.transcode(input_svg_image, output_png_image);

            resultPngBytes = outputPngBytes.toByteArray();

            outputPngBytes.flush();
            outputPngBytes.close();
        } catch (Exception e) {
            throw new SVGConversionException("Error converting SVG to PNG", e);
        }

        return resultPngBytes;
    }
}

在同一.svg文件上使用AndroidSVG库会生成具有正确颜色的正确.png图像。

另一个音符;使用默认字体inkscape(我用来创建矢量图形的程序)解决了此问题。使用其他字体会使蜡染将其颜色更改为黑色。

这是指向我的SVG文件的链接。


Inkscape将自定义CSS属性-inkscape-font-specification添加到与自定义字体文本关联的style属性。以下是摘录:

1
style="...;-inkscape-font-specification:'Aharoni, Bold';..."

一个已知的蜡染错误阻止呈现以连字符(-)开头的CSS属性。

一个简单的解决方法是编辑文件,然后删除"-inkscape-font-specification "属性。

或者,您可以使用Batik \\的API创建新的CSS样式解析器,以删除有问题的CSS样式类。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /**
   * Bug fix
   */
  public static final class InkscapeCssParser extends Parser {
    public void parseStyleDeclaration( final String source )
      throws CSSException, IOException {
      super.parseStyleDeclaration(
        source.replaceAll("-inkscape-font-specification:[^;"]*;","" )
      );
    }
  }

  static {
    XMLResourceDescriptor.setCSSParserClassName(
      InkscapeCssParser.class.getName()
    );
  }

所接受的答案非常有帮助地指向蜡染错误1112,表明" -inkscape-font-specification "未正确解析。该错误报告提供了一种变通方法,该方法可以通过重新实现Batik中的CSS解析器的一部分来实现。要对此进行扩展并使其在此处可用,这是我的变通方法的简化和天真的版本。

首先需要一个CSS解析器类来覆盖Batik中的类:

1
2
3
4
5
6
7
8
9
10
11
12
import org.apache.batik.css.parser.ExtendedParser;
import org.apache.batik.css.parser.Parser;
import org.w3c.css.sac.CSSException;
import java.io.IOException;

public class InkscapeCssParser extends Parser {
    public void parseStyleDeclaration(String source)
            throws CSSException, IOException {
        source = source.replaceAll(";-inkscape",";inkscape");
        super.parseStyleDeclaration(source);
    }
}

请注意,source参数是特定SVG元素的CSS样式,而不是完整的SVG源。每个具有style属性的元素都会调用parseStyleDeclaration

蜡染错误中提供的解决方法重新实现了很大一部分parseStyleDeclaration,但我只是简单地执行了一个天真的字符串替换,以消除"; "之后令人反感的"-",因为是问题的核心。

要使用此功能,请在加载文档之前设置CSS解析器类名称:

1
2
3
JSVGCanvas mSvgCanvas;
XMLResourceDescriptor.setCSSParserClassName(InkscapeCssParser.class.getName());
mSvgCanvas.setURI(svgUrl.toString());