java - 如何在 JasperReport 中将 svg 字节数组显示为图像?

标签 java arrays svg jasper-reports

我有一张保存为 byte[] 的图像,我想在 JasperReport 中将其显示为图像。我尝试从 Java 方法获取数据:

public InputStream getImage(){
  return new ByteArrayInputStream(getImageByteArray());
}

public Image getImage() throws IOException{
    return ImageIO.read(new ByteArrayInputStream(getImageByteArray()));
}

public String getImage(){
  return new String((new org.apache.commons.codec.binary.Base64()).encode(getImageByteArray()));
}

但它们似乎都不起作用。

jrxml 看起来像这样:

<image hAlign="Center" vAlign="Middle" isUsingCache="true" isLazy="true">
   <reportElement positionType="Float" x="0" y="0" width="164" height="32" isRemoveLineWhenBlank="true" isPrintWhenDetailOverflows="true" uuid="c63c84a8-41c7-4ca3-8451-751d43fa8a9e"/>
   <imageExpression><![CDATA[$P{paramObject}.getImage()]]></imageExpression>
</image>

我尝试的一些事情会出现异常,一些会打印 JasperReport,但图像应该位于的区域是空白的。 我知道图像数据在那里,因为我可以在 JSF 页面中显示它。 图片数据为SVG数据。

最佳答案

自定义图像转码器

编写一个可以读取 SVG 文件并将该资源转换为 PNG 或 SVG 文件的自定义图像转码器。导出为 PDF 时,直接使用 SVG 文件是可以的。考虑:

import java.awt.Color;
import java.io.*;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.util.JRLoader;
import org.apache.batik.transcoder.*;
import static org.apache.batik.transcoder.image.ImageTranscoder.*;
import org.apache.batik.transcoder.image.PNGTranscoder;

public class ImageTranscoder {
    public static InputStream asSVG(final String file) throws JRException {
        return new ByteArrayInputStream(load(file));
    }

    public static InputStream asPNG(final String file)
            throws TranscoderException, JRException {
        return asPNG(load(file));
    }

    public static InputStream asPNG(final byte[] svg)
            throws TranscoderException {
        final ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
        final ByteArrayInputStream inBytes = new ByteArrayInputStream(svg);

        final TranscoderInput input = new TranscoderInput(inBytes);
        final TranscoderOutput output = new TranscoderOutput(outBytes);
        final PNGTranscoder transcoder = new PNGTranscoder();

        transcoder.addTranscodingHint(KEY_BACKGROUND_COLOR, Color.white);
        transcoder.addTranscodingHint(KEY_FORCE_TRANSPARENT_WHITE, true);
        transcoder.transcode(input, output);

        final byte[] bytes = outBytes.toByteArray();
        return new ByteArrayInputStream(bytes);
    }

    private static byte[] load(final String file) throws JRException {
        return JRLoader.loadBytesFromResource(file);
    }
}

导入转码器

在 JRXML 文件中,导入完全限定的类:

<import value="com.company.jasper.ImageTranscoder"/>

应用图像转码器

像往常一样,将图像从调色板拖放到报告中。将其 Expression 设置为:

ImageTranscoder.asSVG($P{IMAGES_PATH} + $P{IMAGE_FILENAME} + ".svg")

如果您确实需要 PNG 版本,请即时对其进行转码:

ImageTranscoder.asPNG($P{IMAGES_PATH} + $P{IMAGE_FILENAME} + ".svg")

HTML 与 PDF

对于 HTML,通常首选 PNG 图像。您可以采用多种方法来区分 HTML (PNG) 和 PDF (SVG)。一种简单的方法是将两个不同的键值分配给两个不同的图像元素。例如:

<image scaleImage="RetainShape" onErrorType="Blank">
    <reportElement key="IMAGE_PNG"/>
    <imageExpression><![CDATA[ImageTranscoder.asPNG(...)]]></imageExpression>
</image>
<image scaleImage="RetainShape" onErrorType="Blank">
    <reportElement key="IMAGE_SVG"/>
    <imageExpression><![CDATA[ImageTranscoder.asSVG(...)]]></imageExpression>
</image>

然后您可以根据导出类型排除一个或另一个:

<property name="net.sf.jasperreports.export.html.exclude.key.IMAGE_SVG"/>
<property name="net.sf.jasperreports.export.pdf.exclude.key.IMAGE_PNG"/>

总结

虽然包含 PNG 图像更简单,但从 SVG 转换 PNG 图像是一个可以避免的额外步骤。由于 JasperReports 库使用 Batik 引擎渲染图像,因此在生成报告时利用它来将 SVG 文件转换为 PNG。

这样,无论报告中使用的是 PNG 还是 SVG 文件,SVG 都可以作为所有格式的单一来源。

一定要适本地设置 IMAGES_PATHIMAGE_FILENAME 参数。

HTML 和 Base64

使用以下方法强制嵌入图像:

<property name="net.sf.jasperreports.export.html.embed.image" value="true"/>

PNG 图像变成 Base64 编码的字符串:

<img src="data:image/png;base64,..."/>

这将使报告加载速度更快(没有额外的 HTTP 图像请求)并简化架构,因为它消除了外部依赖性。也就是说,不再需要 Web 服务器来提供图像,因为它是完全嵌入式的。

关于java - 如何在 JasperReport 中将 svg 字节数组显示为图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33547588/

相关文章:

python - 如何在 python 中从 3 个数组创建颜色映射

html - 使边框夹住其他元素并显示背景内容

css - 如何增加刻度线动画的大小

javascript - D3 Javascript map 比例分散数据

java - 无限递归,霍夫曼树中的 StackOverflowError

java - 在字符串中移动字符

java - android 在 TextWatcher 中更改 autocompletetextview 适配器

java - ArrayList 的数组?

java - 真正年轻的软件架构师

java - 为什么使用静态记录器比不使用它花费更多时间