我正在使用Batik将SVG转换为PNG图像,但是多行上的文本无法正确呈现。它可以以非确定的方式发生,文本本身不再在最终图像上居中。
举个例子,考虑一下起始SVG的这一部分:
这是正确的渲染,我希望在PNG中获得。顺便说一下,生成的PNG看起来像这样:
如您所见,顶部绿框中的文字不再居中。
这是定义它的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);
}
非常感谢您的任何见解。
答案 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内容中的空格)
“正确”版本(在tspan内容中修剪的空格)