使用ApachePOI创建带图片的Excel

  最近一个项目中使用到了列表数据导出为Excel表格的功能,项目中是使用了Apache的POI来生成Excel文件。

  由于使用到的技术有一定的复杂度,我在此特别列出一些实现上的细节作为记录和备忘。

  首先我们要用到的jar包是POI,我使用的是项目框架中的,版本可能有一些老,不过功能还算完整。

  

  我先把代码贴一些出来,并解释一下:

 1 package test;
 2 
 3 import java.awt.image.BufferedImage;
 4 import java.io.ByteArrayOutputStream;
 5 import java.io.File;
 6 import java.io.FileOutputStream;
 7 import java.net.URL;
 8 
 9 import javax.imageio.ImageIO;
10 import javax.swing.filechooser.FileSystemView;
11 
12 import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
13 import org.apache.poi.hssf.usermodel.HSSFPatriarch;
14 import org.apache.poi.hssf.usermodel.HSSFSheet;
15 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
16 
17 // 测试Apache POI
18 public class Main{
19     public static void main(String[] args){
20         // 第一步:拿到图片资源
21         BufferedImage bi = null; // 声明图片
22         // 1.从网络获取图片资源(下面的图片为百度首页图片)
23         //URL url = new URL("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif");
24         //bi = ImageIO.read(url);
25         // 2.从物理存储设备获取图片资源(以下示例为从笔者桌面获取图片)
26         File f = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/baidu.gif");
27         bi = ImageIO.read(f);
28         
29         // 第二步:处理图片(很多时候失败原因就是没有处理图片)
30         ByteArrayOutputStream bos = new ByteArrayOutputStream();
31         ImageIO.write(bi, "jpg", bos);
32         
33         // 第三步:创建Excel并插入图片(这里就要使用POI了)
34         HSSFWorkbook wb = new HSSFWorkbook(); // 创建一个工作簿
35         HSSFSheet sheet = wb.createSheet("Sample"); // 创建一个床单-_-
36         HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); // 创建一个用于画图的对象
37         // 以上部分为共用,表单Sample中所有图片的操作都应该有patriarch负责
38         HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, (short)0, 0, (short)1, 1); // 创建一个图片停靠信息对象
39         // anchor.setAnchorType(2); 设置这个属性是为哪个图片设置的,第一张图片不需要设置
40         patriarch.createPicture(anchor, wb.addPicture(bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG)); // 这一步就是按照上面的属性将图片插入到床单Sample中去
41         
42         // 第四步:我们保存(或下载)生成的Excel(笔者保存到桌面)
43         File fo = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/sample.xls");
44         FileOutputStream fos = null;
45         fos = new FileOutputStream(fo);
46         wb.write(fos);
47         fos.flush();
48         fos.close();
49     }
50 }

  

  (上图异常未处理,因为最终我们需要将代码写得更规范,异常的处理也要更加好,上图只做参考)

  我稍微解释一下,首先图片的获得一般为两种途径,网络和磁盘。我们拿到图片后的处理是必须的,因为大家可以看到,POI对图片的支持和解析并不是那么强大,我们需要使用ImageIO来提取图片的内容,并使用jpg格式写入缓冲来交给POI使用。

  其次就是图片在Excel中的放置,顺便提一下Anchor的各个参数,为了方便大家理解,我先将代码运行结果贴出来给大家: 

  

  可以看到,在坐上角为0,0 右下角为1,1的网格中出现了图片,这解释了anchor的后四个参数,即图片左上角和右下角的坐标,至于为什么x坐标为short,不会不知道吧?

  (所以我们没有在sheet里创建row和column来放置图片,因为在office套件里图片和文字并不是放置在一个平面的,可以这么理解:文字是放置在行、列中的格子里,而图片是沉浮在网格中的)

  那么anchor的前四个参数是什么呢?其实Excel为了图片停靠地更加精细,将一个格子分成了1024x256个小格子,我们可以为图片设置它相对于左上角、右下角的横向和纵向偏移量(0-1023或0-255),看了下图大家就明白了:

  

  (上图为anchor前四个参数设置为512,126,0,0)

  

  (上图为anchor前四个参数设置为0,0,512,126)

  

  (毋庸置疑,上图为anchor四个参数设置为512,126,512,126)

  可以通过sheet.setColumWidth和row.setHeight设置列宽和行高。

  贴上我的代码:

 1 package test;
 2 
 3 import java.awt.image.BufferedImage;
 4 import java.io.ByteArrayOutputStream;
 5 import java.io.File;
 6 import java.io.FileNotFoundException;
 7 import java.io.FileOutputStream;
 8 import java.io.IOException;
 9 import java.net.MalformedURLException;
10 import java.net.URL;
11 
12 import javax.imageio.ImageIO;
13 import javax.swing.filechooser.FileSystemView;
14 
15 import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
16 import org.apache.poi.hssf.usermodel.HSSFPatriarch;
17 import org.apache.poi.hssf.usermodel.HSSFSheet;
18 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
19 
20 // 测试Apache POI
21 public class Main {
22     public static void main(String[] args) {
23         BufferedImage bi = null; 
24         ByteArrayOutputStream bos = new ByteArrayOutputStream();
25         HSSFWorkbook wb = new HSSFWorkbook();
26         HSSFSheet sheet = wb.createSheet("Sample");
27         HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
28         FileOutputStream fos = null;
29         
30         try {
31             URL url = new URL("http://www.baidu.com/img/shouye_b5486898c692066bd2cbaeda86d74448.gif");
32             bi = ImageIO.read(url);
33 
34             //File f = new File(FileSystemView.getFileSystemView().getHomeDirectory() + "/baidu.gif");
35             //bi = ImageIO.read(f);
36             
37             ImageIO.write(bi, "jpg", bos);
38             HSSFClientAnchor anchor = new HSSFClientAnchor(512, 126, 512, 126, (short) 0,
39                     0, (short) 1, 1);
40             // anchor.setAnchorType(2);
41             patriarch.createPicture(anchor,wb.addPicture(bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG));
42             
43             File fo = new File(FileSystemView.getFileSystemView()
44                     .getHomeDirectory() + "/sample.xls");
45             fos = new FileOutputStream(fo);
46             wb.write(fos);
47             fos.flush();
48             fos.close();
49             
50             
51         } catch (MalformedURLException e) {
52             // TODO Auto-generated catch block
53             e.printStackTrace();
54         } catch (FileNotFoundException e) {
55             // TODO Auto-generated catch block
56             e.printStackTrace();
57         } catch (IOException e) {
58             // TODO Auto-generated catch block
59             e.printStackTrace();
60         }
61     }
62 }

  注意:ByteArrayOutputStream与HSSFClientAnchor是一次性用品,需要在真正使用前声明,后释放(上图是一个不正规的示范,很明显,在多个图片后bos会溢出)。

    anchorType从2开始,1不需要设置。

    有关生成的xls从服务器下载到客户端,以后再讨论。

 

 欢迎您移步我们的交流群,无聊的时候大家一起打发时间:Programmer Union

 或者通过QQ与我联系:点击这里给我发消息

 (最后编辑时间2013-03-27 13:46:00)

 

posted @ 2013-03-26 22:29  云中双月  阅读(1141)  评论(0编辑  收藏  举报