360SDN.COM

首页/Java/列表

java利用POI的XWPFParagraph向word添加图片,表格

来源:  2017-10-24 14:12:49    评论:0点击:

    package com.xxx.yyy.commons;  
       
    import java.io.IOException;  
    import java.io.InputStream;  
      
    import org.apache.poi.openxml4j.opc.OPCPackage;  
    import org.apache.poi.xwpf.usermodel.XWPFDocument;  
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;  
    import org.apache.xmlbeans.XmlException;  
    import org.apache.xmlbeans.XmlToken;  
    import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;  
    import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;  
    import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;  
        
    /**  
     * @author POI 导出图片bug修复 
     *   
     */    
    public class CustomXWPFDocument extends XWPFDocument {    
        public CustomXWPFDocument(InputStream in) throws IOException {    
            super(in);    
        }    
        
        /**  
         *   
         */    
        public CustomXWPFDocument() {    
            super();    
            // TODO Auto-generated constructor stub     
        }    
        
        /**  
         * @param pkg  
         * @throws IOException  
         */    
        public CustomXWPFDocument(OPCPackage pkg) throws IOException {    
            super(pkg);    
            // TODO Auto-generated constructor stub     
        }  // picAttch 图片后面追加的字符串 可以是空格  
        public void createPicture(XWPFParagraph paragraph,int id, int width, int height,String picAttch) {    
            final int EMU = 9525;    
            width *= EMU;    
            height *= EMU;    
            String blipId = getAllPictures().get(id).getPackageRelationship()    
                    .getId();    
        
            CTInline inline = paragraph.createRun().getCTR()    
                    .addNewDrawing().addNewInline();    
            paragraph.createRun().setText(picAttch);  
            String picXml = ""    
                    + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"    
                    + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                    + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"    
                    + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\""    
                    + id    
                    + "\" name=\"Generated\"/>"    
                    + "            <pic:cNvPicPr/>"    
                    + "         </pic:nvPicPr>"    
                    + "         <pic:blipFill>"    
                    + "            <a:blip r:embed=\""    
                    + blipId    
                    + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"    
                    + "            <a:stretch>"    
                    + "               <a:fillRect/>"    
                    + "            </a:stretch>"    
                    + "         </pic:blipFill>"    
                    + "         <pic:spPr>"    
                    + "            <a:xfrm>"    
                    + "               <a:off x=\"0\" y=\"0\"/>"    
                    + "               <a:ext cx=\""    
                    + width    
                    + "\" cy=\""    
                    + height    
                    + "\"/>"    
                    + "            </a:xfrm>"    
                    + "            <a:prstGeom prst=\"rect\">"    
                    + "               <a:avLst/>"    
                    + "            </a:prstGeom>"    
                    + "         </pic:spPr>"    
                    + "      </pic:pic>"    
                    + "   </a:graphicData>" + "</a:graphic>";    
        
            // CTGraphicalObjectData graphicData =     
            inline.addNewGraphic().addNewGraphicData();    
            XmlToken xmlToken = null;    
            try {    
                xmlToken = XmlToken.Factory.parse(picXml);    
            } catch (XmlException xe) {    
                xe.printStackTrace();    
            }    
            inline.set(xmlToken);    
            // graphicData.set(xmlToken);     
        
            inline.setDistT(0);    
            inline.setDistB(0);    
            inline.setDistL(0);    
            inline.setDistR(0);    
        
            CTPositiveSize2D extent = inline.addNewExtent();    
            extent.setCx(width);    
            extent.setCy(height);    
        
            CTNonVisualDrawingProps docPr = inline.addNewDocPr();    
            docPr.setId(id);    
            docPr.setName("图片" + id);    
            docPr.setDescr("");    
        }    
    }    
 
POI或者JXL、docx4j,都是基于公开的标准做的。Office自2007版本开始使用ooxml,压缩的xml文档,2007之前都是二进制的B+树。但是2007+版本也只是把文件通用性结构部分公开了,微软的半开放导致一残废则都残废。所以设计到真正的图表,Flash 都没法子了。上面的类是代替POI中的XWPFDocument。因为继承了XWPFDocument,所以addPictureData不用重写了,图片显示的方法新增一下。这是因为POI 在拼装xml的时候把图片数据放入了,但是没有给提供显示的方法。用了OOXML就要用2007+版本,之所以选择它是因为2007+已经成为了世界标准。2007更是一个里程碑(不谈对微软情感看法)。(忘记说了POI 对word处理相当不给力,上面的代码是添加图片的bug处理,即使因为官方少了一段显示图片的xml)
 
 action:
 
  
Java代码  收藏代码
 
    public void exportToWord2(){  
        try {  
            int picWidth = 240;  
            int picHeight = 150;  
            int picType = XWPFDocument.PICTURE_TYPE_JPEG;  
            String filePath = "简报.docx";  
            response.reset(); // 清空buffer  
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");  
            filePath = java.net.URLEncoder.encode(filePath, "UTF-8");  
            response.setHeader("Content-Disposition", "attachment; filename="+ new String(filePath.getBytes("UTF-8"), "GBK"));// 定义文件名  
            response.setHeader("Pragma", "no-cache");  
            response.setHeader("Expires", " 0");  
            ServletOutputStream fOut = response.getOutputStream();  
            XWPFParagraph paragraph = null;  
            XWPFTable table = null;  
            CustomXWPFDocument doc = new CustomXWPFDocument();  
            paragraph = doc.createParagraph();  
            doc.addPictureData(picInputStream,picType);  
            doc.createPicture(paragraph,doc.getAllPictures().size()-1, picWidth, picHeight,"");  
            doc.write(fOut);  
            fOut.flush();  
            fOut.close();  
            response.getOutputStream().flush();  
            response.getOutputStream().close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
 
 其中picInputStream 省略,这个图可以是又Jfreechart得到。
 
  
Java代码  收藏代码
 
    JFreeChart chart = null;   
    //.......省略  
    ByteArrayOutputStream out = new ByteArrayOutputStream();  
                ChartUtilities.writeChartAsPNG(out, chart, 400, 300);  
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());  
    return in;  
 
  
 
这样通过Jfreechart就可以得到ByteArrayInputStream.
 
因为addPictureData方法接收的参数是InputStream 看到网上很多人喜欢先写入操作系统,然后读取到流,我不喜。在生成图片的时候直接放到ByteArrayInputStream(继承了抽象类InputStream),直接获取就少了存储相关的操作。JFreechart获取inputStream也就这2行代码。
 
createPicture方法的picAttch是图片之间放的东西 可以是N个空格做间隔,也可以是文字
 
弄一个word文件写入磁盘中测试例子,包含POI生成表格到word,jfreechart和POI生成图插入到word.需要jfreechart和poi ooxml的jar
Java代码  收藏代码
 
    import java.awt.Color;  
    import java.awt.Font;  
    import java.io.ByteArrayInputStream;  
    import java.io.ByteArrayOutputStream;  
    import java.io.FileOutputStream;  
    import java.text.DecimalFormat;  
    import java.text.NumberFormat;  
    import org.apache.poi.xwpf.usermodel.XWPFDocument;  
    import org.apache.poi.xwpf.usermodel.XWPFTable;  
    import org.apache.poi.xwpf.usermodel.XWPFTableRow;  
    import org.jfree.chart.ChartFactory;  
    import org.jfree.chart.ChartUtilities;  
    import org.jfree.chart.JFreeChart;  
    import org.jfree.chart.labels.StandardPieSectionLabelGenerator;  
    import org.jfree.chart.plot.PiePlot;  
    import org.jfree.chart.plot.PlotOrientation;  
    import org.jfree.data.category.DefaultCategoryDataset;  
    import org.jfree.data.general.DefaultPieDataset;  
       
      
    public class CreateTablesWithPOI {  
        public static void main(String[] args) {  
            String outputFile = "D:\\test.docx";  
            CustomXWPFDocument document = new CustomXWPFDocument();  
            XWPFTable tableOne = document.createTable();  
            XWPFTableRow tableOneRowOne = tableOne.getRow(0);  
            tableOneRowOne.getCell(0).setText("第1行第1列");  
            tableOneRowOne.addNewTableCell().setText("第1行第2列");  
            tableOneRowOne.addNewTableCell().setText("第1行第3列");  
            tableOneRowOne.addNewTableCell().setText("第1行第4列");  
            XWPFTableRow tableOneRowTwo = tableOne.createRow();  
            tableOneRowTwo.getCell(0).setText("第2行第1列");  
            tableOneRowTwo.getCell(1).setText("第2行第2列");  
            tableOneRowTwo.getCell(2).setText("第2行第3列");  
            FileOutputStream fOut;  
            try {  
                fOut = new FileOutputStream(outputFile);  
                ByteArrayInputStream  in = getPieChartImage();  
                String ind = document.addPictureData(in, XWPFDocument.PICTURE_TYPE_JPEG);   
                System.out.println("pic ID=" + ind);  
                document.createPicture(document.getAllPictures().size()-1, 200, 200,"    ");   
                // 放第二张图  
                ind = document.addPictureData(getBarChartImage(), XWPFDocument.PICTURE_TYPE_JPEG);   
                System.out.println("pic ID=" + ind);  
                document.createPicture(document.getAllPictures().size()-1, 200, 200,"    ");   
                document.write(fOut);   
                fOut.flush();  
                // 操作结束,关闭文件  
                fOut.close();  
            } catch (Exception e) {  
                e.printStackTrace();  
            }   
        }  
        public static ByteArrayInputStream getPieChartImage() {  
            ByteArrayInputStream in = null;  
            DefaultPieDataset pieDataset = new DefaultPieDataset();  
            pieDataset.setValue(" 北京局 ", 20);  
            pieDataset.setValue(" 上海局 ", 18);  
            pieDataset.setValue(" 天津局 ", 16);  
            pieDataset.setValue(" 重庆局 ", 15);  
            pieDataset.setValue(" 山东局 ", 45);  
            JFreeChart chart = ChartFactory.createPieChart3D(" 企业备案图 ", pieDataset,  
                    true, false, false);  
            // 设置标题字体样式  
            chart.getTitle().setFont(new Font(" 黑体 ", Font.BOLD, 20));  
            // 设置饼状图里描述字体样式  
            PiePlot piePlot = (PiePlot) chart.getPlot();  
            piePlot.setLabelFont(new Font(" 黑体 ", Font.BOLD, 10));  
            // 设置显示百分比样式  
            piePlot.setLabelGenerator(new StandardPieSectionLabelGenerator(  
                    (" {0}({2}) "), NumberFormat.getNumberInstance(),  
                    new DecimalFormat(" 0.00% ")));  
            // 设置统计图背景  
            piePlot.setBackgroundPaint(Color.white);  
            // 设置图片最底部字体样式  
            chart.getLegend().setItemFont(new Font(" 黑体 ", Font.BOLD, 10));  
            try {  
                ByteArrayOutputStream out = new ByteArrayOutputStream();  
                ChartUtilities.writeChartAsPNG(out, chart, 400, 300);  
                in  = new ByteArrayInputStream(out.toByteArray());  
            } catch (Exception e) {  
                e.printStackTrace();  
            }   
            return in;  
        }  
          
        public static ByteArrayInputStream getBarChartImage() {  
            ByteArrayInputStream in = null;  
            DefaultCategoryDataset dataset =new DefaultCategoryDataset();   
            dataset.addValue(100,"Spring Security","Jan");  
            dataset.addValue(200,"jBPM 4","Jan");  
            dataset.addValue(300,"Ext JS","Jan");  
            dataset.addValue(400,"JFreeChart","Jan");  
            JFreeChart chart = ChartFactory.createBarChart("chart","num","type",dataset, PlotOrientation.VERTICAL, true, false, false);   
            // 设置标题字体样式  
            chart.getTitle().setFont(new Font(" 黑体 ", Font.BOLD, 20));  
            // 设置饼状图里描述字体样式  
            // 设置图片最底部字体样式  
            chart.getLegend().setItemFont(new Font(" 黑体 ", Font.BOLD, 10));  
            try {  
                ByteArrayOutputStream out = new ByteArrayOutputStream();  
                ChartUtilities.writeChartAsPNG(out, chart, 400, 300);  
                in  = new ByteArrayInputStream(out.toByteArray());  
            } catch (Exception e) {  
                e.printStackTrace();  
            }   
            return in;  
        }  
    }  
 
 
 
 POI中设置一段文字我们可以写一个静态通用方法createParagraphContent,大致内容如下POI.java
 
 
 
    public static void createParagraphContent(CustomXWPFDocument doc,String content) {  
        XWPFRun title= doc.createParagraph().createRun();// 设置一个新的段落  
        title.setText(content);   
        title.setFontFamily("宋体");   
        title.setBold(true);   
    }  
 
 itext的例子请参考  http://oneinit.iteye.com/blog/1529917
 
图表  http://www.dotblogs.com.tw/angus/archive/2010/05/19/15332.aspx



来源:http://maclab.iteye.com/blog/1749049
为您推荐

友情链接 |九搜汽车网 |手机ok生活信息网|ok生活信息网|ok微生活
 Powered by www.360SDN.COM   京ICP备11022651号-4 © 2012-2016 版权