使用freemarker生成word、html时,在图片显示这儿碰了个大钉子,最后总算弄出来了,这里总结一下。
1、生成word:
a、使用freemarker生成word文档图片显示需要特殊处理,若是按照常理(使用占位符的形式)替换完成之后显示图片的区域只会出现一堆内容(即你给它赋值的内容)而不是一张图片。
b、如何处理:直接从某处复制一张图片放到word中需要显示的区域,然后另存为xml。打开xml文件可以发现这张图片是以base64编码存在的,且这些编码放在<w:binData>标签之中。将这些base64编码使用占位符代替然后进行常规处理就能正常显示了。
c、word中添加图片之后,xml里边就会多出一个<w:pict>标签,内容如下(以我本地的为例):
<w:pict> <v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype> <w:binData w:name="wordml://03000001.png" xml:space="preserve">${field30}</w:binData> <v:shape id="_x0000_i1025" type="#_x0000_t75" alt="" style="width:90.35pt;height:112.75pt"> <v:imagedata src="wordml://03000001.png" o:href="http://127.0.0.1:8080/bfp/2016/12/30/00000000001.png"/> </v:shape> </w:pict>我们 需要用到的是<w:binData>,这个标签中间用来显示图片内容(通常都是base64编码),也就是要使用占位符的地方,我这里用的是${field30}。
若需要调整别的可以直接修改其他标签内容。
d、使用java代码将图片生成base64编码:/** * 该方法用来将指定的文件转换成base64编码 * @param path:图片路径 * **/ private String getImageStr(String path){ //1、校验是否为空 if(path==null || path.trim().length()<=0){return "";} //2、校验文件是否为目录或者是否存在 File picFile = new File(path); if(picFile.isDirectory() || (!picFile.exists())) return ""; //3、校验是否为图片 try { BufferedImage image =ImageIO.read(picFile); if (image == null) { return ""; } } catch(IOException ex) { ex.printStackTrace(); return ""; } //4、转换成base64编码 String imageStr = ""; try { byte[] data = null; InputStream in = new FileInputStream(path); data = new byte[in.available()]; in.read(data); BASE64Encoder encoder = new BASE64Encoder(); imageStr = encoder.encode(data); } catch (Exception e) { imageStr=""; e.printStackTrace(); } return imageStr; }
2、生成html:
a、模板文件中直接使用img标签显示即可,如:<img width="120" height="150" src="${field30}" />。
b、src中可以直接放图片的路径,也可以放base64编码。若是使用绝对路径,需要添加前缀:file:///。如图片路径为:D:/temp/1.png,那么src="file:///D:/temp/1.png"。这样子才能显示出来。缺点:因为图片通常都存在服务器端,在服务器端显示图片自然没有问题,若是放到客户端因为指定目录下没有文件那么页面中的图片自然就显示不出来了。
c、使用base64编码显示图片。若是在src属性中直接加载base64编码的图片,形如:src="base64编码",这样的图片也显示不出来,还需要添加形如data:image/图片格式;base64,的前缀。如显示png格式的图片,src="data:image/png;base64,base64编码“,如此才能显示出来。(测试了一下,火狐、360、谷歌、IE11、IE8都能很好的支持,其他浏览器没测过)
3、生成pdf:
a、生成pdf我分成了两步:先使用freemarker生成html文件,然后使用flying saucer将html转成pdf文件。 b、 直接使用“base64编码显示图片”生成的HTML文件,转成pdf时,图片会显示不出来(html文件自然是能正常显示的),具体原因未知。解决办法是 采用绝对路径。先使用绝对路径的方法生成html文件中的图片,此时图片和html文件都在服务器端,图片自然能正常显示,然后将该文件转成pdf。在客户端下载下来之后,图片也能正常显示。