从SVG到PNG与Batik:多行文字的问题

时间:2018-03-02 09:52:46

标签: java svg batik

我正在使用Batik将SVG转换为PNG图像,但是多行上的文本无法正确呈现。它可以以非确定的方式发生,文本本身不再在最终图像上居中。

举个例子,考虑一下起始SVG的这一部分:

enter image description here

这是正确的渲染,我希望在PNG中获得。顺便说一下,生成的PNG看起来像这样:

enter image description here

如您所见,顶部绿框中的文字不再居中。

这是定义它的SVG(怀疑字体问题,我也尝试删除所有font-family="",但没有效果):

  <g transform="translate(184.68 -0.600364)">
     <text fill="rgb(255, 255, 255)" fill-opacity="1" font-family="Kievit Pro" font-size="10px" font-style="normal" font-weight="normal" text-anchor="middle" transform="translate(48 0.429996)">
        <tspan dy="1em" x="0">A simple activity, with</tspan>
        <tspan dy="1.5em" x="0">a text that goes on t</tspan>
     </text>
  </g>

如果有帮助,这就是我用于转换的代码:

static byte[] convertToPng(byte[] byteSvgSmall) throws TranscoderException, IOException {
    if (byteSvgSmall != null) {

        byte[] byteImagePng = null;
        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        InputStream targetStream = null;

        try {
            targetStream = new ByteArrayInputStream(byteSvgSmall);
            TranscoderInput input = new TranscoderInput(targetStream);

            PNGTranscoder transcoder = new PNGTranscoder();
            transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, new Float(diagramWidthInPixelsForPdf));

            TranscoderOutput output = new TranscoderOutput(baos);
            transcoder.transcode(input, output);

            byte[] byteOutput = baos.toByteArray();
            byteImagePng = new byte[byteOutput.length];
            bais = new ByteArrayInputStream(baos.toByteArray());
            bais.read(byteImagePng);
            targetStream.close();
            baos.flush();
            return byteImagePng;
        } catch (Exception e) {
            BeanFactory
                    .getLogger()
                    .error(SVGTransformer.class,
                            "An error occurred. A null byte[] will be returned",
                            e);
            return null;
        } finally {
            if (bais != null) bais.close();
            if (baos != null) baos.close();
            if (targetStream != null) targetStream.close();
        }
    }
    return null;
}

然后,返回的字节为[]:

if (pngBytes != null) {
   BufferedImage final_img = ImageIO.read(new ByteArrayInputStream(pngBytes));
   File output_file = new File(imagepath);
   ImageIO.write(final_img, "png", output_file);
}

非常感谢您的任何见解。

2 个答案:

答案 0 :(得分:1)

我下载了你的svg并且文件(至少在我的电脑上)不太适合绿色框的边界内的文本(有一些溢出,被剪裁)。我不确定这是否是一个平台问题,因为你的屏幕截图显示带有一点边距的文本(而在我的情况下,用GIMP打开,文本超出了)。

因此,我修改了你的svg,使所有10px字体大小减少到9px(为了适应方块中的所有内容)。

然后我用java-8-openjdk-amd64,提供的svg和以下依赖项运行你的代码:

compile group: 'org.apache.xmlgraphics', name: 'batik-transcoder', version: '1.9.1'
compile group: 'org.apache.xmlgraphics', name: 'xmlgraphics-commons', version: '2.2'
compile group: 'org.apache.xmlgraphics', name: 'batik-codec', version: '1.9.1'

我的png中TEST1框呈现的类似但不完全相同:

A simple activity, with
  a text that goes on t

然后我修改了xml节点,将第二行从“一个t上的文本”改为“一个文本”。这次第二行是居中的。

A simple activity, with
     a text that

然后我将原始文本放回节点,并将框的字体系列更改为Lucida Sans,并将大小更改为7px(我在下面修改过的节点)。

<text fill="rgb(255, 255, 255)" fill-opacity="1" font-family="Lucida Sans" font-size="7px" font-style="normal" font-weight="normal" text-anchor="middle" transform="translate(48 0.429996)">
    <tspan dy="1em" x="0">A simple activity, with</tspan>
    <tspan dy="1.5em" x="0">a text that goes on t</tspan>
</text>

这一次是集中的。你有什么尝试?如果您尝试上述操作会得到什么结果(更改字体大小和/或字体系列)?我还使用了1000px作为KEY_WIDTH转码提示,如果这可能会改变您的情况。

答案 1 :(得分:0)

经过一段时间后,我终于找到了真正的问题,感谢帖子this Jira。尾部和结尾的空格进入tspans'文本,导致Batik光栅化器误解内容。

通过扫描tspan元素,并设置文本的剪裁版本:

for (int tspanCounter = 0; tspanCounter < tspanList.getLength(); tspanCounter++) {
   Node tspan = tspanList.item(tspanCounter);
   tspan.setTextContent(actParts[tspanCounter].trim());
}

我获得了正确的结果。在下面的图片中,您可以使用和不使用简单的trim()调用来查看结果!

错误的版本(tspan内容中的空格)

enter image description here

“正确”版本(在tspan内容中修剪的空格)

enter image description here