【问题标题】:How to display a svg byte array as an image in a JasperReport?如何在 JasperReport 中将 svg 字节数组显示为图像?
【发布时间】:2016-02-06 11:11:47
【问题描述】:

我有一个保存为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数据。

【问题讨论】:

    标签: java arrays svg jasper-reports


    【解决方案1】:

    自定义图像转码器

    编写一个可以读取 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"/>
    

    应用图像转码器

    照常将图像从调色板拖放到报表上。将其表达式设置为:

    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 元素。例如:

    <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。

    这样,SVG 可作为所有格式的单一来源,无论报告中使用的是 PNG 还是 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 请求)并简化架构,因为它消除了外部依赖。也就是说,不再需要网络服务器来提供图像,因为它是完全嵌入的。

    【讨论】:

      【解决方案2】:

      假设你有base64编码的图像字节,你可以使用以下

      <image>
          <reportElement/>
          <imageExpression>
              <![CDATA[javax.imageio.ImageIO.read(new java.io.ByteArrayInputStream(new sun.misc.BASE64Decoder().decodeBuffer("/9j/4AAQ .... "))) ]]>
          </imageExpression>
      </image>
      

      【讨论】:

        【解决方案3】:

        你可以试试这个:

        将您的图像参数(这里是 img)设置为 InputStream

        <parameter name="img" class="java.io.InputStream">
                <parameterDescription><![CDATA[]]></parameterDescription>
            </parameter>
        

        然后将 onErrorType="Blank" 设置为您的图像元素(实际上不知道这样做的原因:))

        <image onErrorType="Blank">
            <reportElement x="2" y="4" width="119" height="62" uuid="66857471-6aa2-4ff0-be59-e2e1b0214bfc"/>
            <imageExpression><![CDATA[$P{img}]]></imageExpression>
        </image>
        

        【讨论】:

        • 对不起,图像必须来自参数映射中对象中的getter,项目以某种方式设置。但是无论哪种方式使图像成为自己的参数而不是从参数对象访问它都不应该有所作为。 onErrorType="Blank" 只是使得当将图像放入报告中而不是抛出异常时出错时,它只会将图像空间留空。这无助于显示图像。
        • 对我来说,这是比其他解决方案最简单的解决方案。谢谢。
        【解决方案4】:

        我提出一个简单的解决方案。它有效,我正在使用它。这样我们就可以避免中间代码和修改我们的应用程序。

        我们必须建立以下导入:

        <import value="javax.swing.ImageIcon"/>
        

        我们为图像定义的字段必须是 Objet 类型:

        <field name="myImage" class="java.lang.Object"/>
        

        然后在报告正文中,我们必须将图像放置在下面的表达式中:

        <image>
          <reportElement x="10" y="10" width="100" height="100" uuid="a791129e-a20d-4be3-bdcd-27528bf2edc4"/>
          <imageExpression><![CDATA[(new ImageIcon((byte[])$F{foto})).getImage()]]></imageExpression>
        </image>
        

        就是这样。解决方案如何工作?我们导入javax.swing.ImageIcon 库,它允许我们从byte[] 创建一个新的ImageIcon,然后我们可以使用getImage()ImageIcon 转换为Image

        【讨论】:

          【解决方案5】:

          getImage() 应该返回 byte[]

          我在你的 jasperreports 模板中看不到 paramObject 是什么类型,但它应该是 String

          在没有任何不可用的 oracle 库的情况下反序列化 pic 的最简单方法是:

          <imageExpression><![CDATA[javax.imageio.ImageIO.read(new java.io.ByteArrayInputStream(java.util.Base64.getDecoder().decode($F{paramObject})))]]></imageExpression>
          

          【讨论】:

            【解决方案6】:

            我们为图像定义的字段必须是 Objet 类型:

            然后在报告的正文中,我们必须将图像放置在下面的表达式中:

            这段代码对我有用....

            【讨论】:

            • 您好,请提供上述表达方式。另外,请避免“此代码对我有用”。尝试解释为什么代码有效或无效。
            猜你喜欢
            • 2013-05-18
            • 2012-08-04
            • 1970-01-01
            • 2019-09-21
            • 2023-02-22
            • 1970-01-01
            • 2021-10-09
            • 2010-12-18
            • 2021-11-17
            相关资源
            最近更新 更多