简体   繁体   English

使用蜡染从 SVG 到 PNG:多行文本的问题

[英]From SVG to PNG with Batik: an issue with multiline text

I am converting an SVG into a PNG image using Batik, but text that goes on mutiple lines is not rendered correctly.我正在使用蜡染将 SVG 转换为 PNG 图像,但无法正确呈现多行文本。 It can occur, in a non-deterministic way, that the text itself is not centered anymore on the final image.可能会以不确定的方式出现文本本身不再以最终图像为中心的情况。

As an example, consider this part of the starting SVG:例如,考虑起始 SVG 的这一部分:

在此处输入图片说明

This is the correct rendering, that I wish to obtain in the PNG too.这是正确的渲染,我也希望在 PNG 中获得。 The resulting PNG, by the way, looks like this:顺便说一下,生成的 PNG 看起来像这样:

在此处输入图片说明

As you can see, the text into the top green box is not centered anymore.如您所见,顶部绿色框中的文本不再居中。

This is the piece of SVG that define that (suspecting a fonts issue, I have also tried by removing all the font-family="" , with no effect):这是定义它的 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>

If it could help, this is the code I'm using for the conversion:如果有帮助,这是我用于转换的代码:

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;
}

And then, with the returned byte[]:然后,使用返回的字节 []:

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

Thank you so much for any insight.非常感谢您的任何见解。

I downloaded your svg and the file (at least on my computer) doesn't quite fit the text within the bounds of the green boxes (there is a bit of overflow, which is clipped).我下载了你的 svg 并且文件(至少在我的电脑上)不太适合绿色框边界内的文本(有一点溢出,被剪掉了)。 I'm not sure if this is a platform problem since your screen shot shows the text with a bit of margin (whereas in my case, opening with GIMP, the text goes beyond).我不确定这是否是平台问题,因为您的屏幕截图显示的文本带有一点边距(而在我的情况下,用 GIMP 打开,文本超出了)。

As such, I modified your svg such that all the 10px font sizes were reduced to 9px (in order to fit everything in the squares).因此,我修改了您的 svg,以便将所有 10 像素的字体大小减小到 9 像素(以适合正方形中的所有内容)。

I then ran your code with the java-8-openjdk-amd64, the svg provided and the following dependencies:然后我使用 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'

The TEST1 box rendered similar, but not identical, in my png as in yours: TEST1框在我的 png 中与您的相似,但不完全相同:

A simple activity, with
  a text that goes on t

I then modified the xml node, changing the second line from "a text that goes on t" to "a text that".然后我修改了 xml 节点,将第二行从“a text that going on t”更改为“a text that”。 This time the second line was centered.这次第二行居中。

A simple activity, with
     a text that

I then put the original text back in the node and changed the font family for the box to Lucida Sans and size to 7px (my modified node here below).然后我将原始文本放回节点中,并将框的字体系列更改为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>

This time it was centered.这次是居中的。 What have you tried?你尝试过什么? What results do you get if you try the above (changing the font-size and/or font-family)?如果您尝试上述操作(更改字体大小和/或字体系列),您会得到什么结果? I also used 1000px for the KEY_WIDTH transcoding hint if that might change anything in your case.我还使用KEY_WIDTH作为KEY_WIDTH转码提示,如果这可能会改变您的情况。

After some time, I have finally found the real issue, thanks to a post on this Jira .一段时间后,我终于找到了真正的问题,这要感谢关于这个 Jira的帖子。 The trailing and ending whitespaces, into tspans ' text, cause the Batik rasterizer to misinterpret the content. tspans文本中的尾随和结尾空格会导致 Batik 光栅化器误解内容。

By scanning the tspan Elements, and setting a trimmed version of the text:通过扫描 tspan 元素,并设置文本的修剪版本:

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

I obtain the correct result.我得到了正确的结果。 In the images below, you can see the result with and without...the simple trim() call!在下面的图片中,您可以看到有和没有...简单的trim()调用的结果!

Wrong version (whitespaces in the tspan's content)错误的版本(tspan 内容中的空格)

在此处输入图片说明

"Right" version (whitespaces trimmed in the tspan's content) “正确”版本(tspan 内容中的空白被修剪)

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM