我想使用apache poi将excel表单嵌入到演示文稿(PPT)中。我们应该怎么做?如果有人知道,请帮助我。使用apache poi将HSSF(excel)嵌入HSLF(ppt)
6
A
回答
5
这花了我一段时间才能找出各部分是如何属于一起...
嵌入可以通过两种方式来完成:
- by updating an already embedded worksheet
- 临:只需要调用
ObjectData.get/setData()
和您的工作已完成 - Con:如果您想要嵌入多个OLE对象,该怎么办?
- 临:只需要调用
- 或者你可以嵌入从头元素(见下文)
像往常一样,当我揣摩,如何实现某种功能的POI,我比较自由报Office文件的结果在这种情况下几部分必须创建/修改:
-
在PowerPoint对象
- ...
- 的emebedded对象的二进制数据被存储为一个根级记录。大部分根记录是position dependent,所以当新记录(例如,记录)被重新计算时,您需要重新计算它们的所有偏移量。幻灯片,创建
- 二进制数据记录是由嵌入记录引用的
Document
记录 - 里面......和混淆多一点,这个文件引用由实际形状对象引用一次
在嵌入的工作表的POIFS
- ...
- 的Ole Stream条目需要创建
- 和根节点有嵌入的文件类型的类ID
- 除此之外,还有在嵌入工作簿对象neccessary和数据本身并没有改变,是一个自包含的excel文件
而且我用两个实用信息类:BiffViewer
和POIFSLister
。
由于这仅仅是一个概念证明,它远非完整。 有关嵌入元素表示的进一步修改,您需要咨询the spec。
为嵌入式对象创建预览图像仍有一个未解决的问题。您可能希望使用中性图像,只要用户激活(双击)该ole对象,就会被替换。另一种方法是使用jodconverter,但比POI方法有点没有意义。
(测试POI3.9/Libre Office 4。0/MS Excel查看/ MS Office 2003)中
import java.awt.geom.Rectangle2D;
import java.io.*;
import java.lang.reflect.Field;
import org.apache.poi.POIDocument;
import org.apache.poi.ddf.*;
import org.apache.poi.hpsf.ClassID;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.util.*;
public class PoiOleXlsInPpt {
static final OleType EXCEL97 = new OleType("{00020820-0000-0000-C000-000000000046}");
static final OleType EXCEL95 = new OleType("{00020810-0000-0000-C000-000000000046}");
static final OleType WORD97 = new OleType("{00020906-0000-0000-C000-000000000046}");
static final OleType WORD95 = new OleType("{00020900-0000-0000-C000-000000000046}");
static final OleType POWERPOINT97 = new OleType("{64818D10-4F9B-11CF-86EA-00AA00B929E8}");
static final OleType POWERPOINT95 = new OleType("{EA7BAE70-FB3B-11CD-A903-00AA00510EA3}");
static class OleType {
final String classId;
OleType(String classId) {
this.classId = classId;
}
ClassID getClassID() {
ClassID cls = new ClassID();
byte clsBytes[] = cls.getBytes();
String clsStr = classId.replaceAll("[{}-]", "");
for (int i=0; i<clsStr.length(); i+=2) {
clsBytes[i/2] = (byte)Integer.parseInt(clsStr.substring(i, i+2), 16);
}
return cls;
}
}
public static void main(String[] args) throws Exception {
HSLFSlideShow _hslfSlideShow = HSLFSlideShow.create();
SlideShow ppt = new SlideShow(_hslfSlideShow);
OLEShape oleShape1 = createOLEShape(getSampleWorkbook1(), ppt, _hslfSlideShow, EXCEL97);
oleShape1.setAnchor(new Rectangle2D.Double(100,100,100,100));
OLEShape oleShape2 = createOLEShape(getSampleWorkbook2(), ppt, _hslfSlideShow, EXCEL97);
oleShape2.setAnchor(new Rectangle2D.Double(300,300,100,100));
OLEShape oleShape3 = createOLEShape(getSampleDocument(), ppt, _hslfSlideShow, WORD97);
oleShape3.setAnchor(new Rectangle2D.Double(300,100,100,100));
// create and link visuals to the ole data
Slide slide = ppt.createSlide();
slide.addShape(oleShape1);
slide.addShape(oleShape2);
slide.addShape(oleShape3);
FileOutputStream fos = new FileOutputStream("ole_xls_in_ppt_out2.ppt");
ppt.write(fos);
fos.close();
}
static OLEShape createOLEShape(
POIDocument sample
, SlideShow ppt
, HSLFSlideShow _hslfSlideShow
, OleType oleType
) throws IOException {
// generate a preview image
int prevIdx = generatePreview(ppt, sample);
// add the data to the SlideShow
ExEmbed eeEmbed = addOleDataToDocumentRecord(ppt);
ExOleObjStg exOleObjStg = addOleDataToRootRecords(_hslfSlideShow, sample, oleType);
eeEmbed.getExOleObjAtom().setObjStgDataRef(exOleObjStg.getPersistId());
OLEShape oleShape = new OLEShape(prevIdx);
linkOleDataToShape(oleShape, eeEmbed);
return oleShape;
}
static POIDocument getSampleWorkbook1() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
sheet.createRow(1).createCell(1).setCellValue("First Workbook");
return wb;
}
static POIDocument getSampleWorkbook2() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
sheet.createRow(1).createCell(1).setCellValue("Second Workbook");
return wb;
}
// the sample document has apparently a problem,
// i.e. word inside ms powerpoint crashed, and libre office doesn't display the text
// it was just a test, if embedding elements != Excel works
// in case HWPF is interesting to you, you probably know anyway, where the error below is ...
static POIDocument getSampleDocument() throws IOException {
FileInputStream fis = new FileInputStream("src/test/resources/empty.doc");
HWPFDocument doc = new HWPFDocument(fis);
fis.close();
Range range = doc.getRange();
CharacterRun run1 = range.insertAfter("Sample text");
run1.setFontSize(11);
return doc;
}
/**
* Generates a modified version of the sample element, which
* contains embedding informations
*/
static byte[] wrapOleData(POIDocument oleData, OleType oleType) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
oleData.write(bos);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
bos.reset();
POIFSFileSystem poifs = new POIFSFileSystem(bis);
final String OLESTREAM_NAME = "\u0001Ole";
DirectoryNode root = poifs.getRoot();
if (!root.hasEntry(OLESTREAM_NAME)) {
// the following data was taken from an example libre office document
// beside this "\u0001Ole" record there were several other records, e.g. CompObj,
// OlePresXXX, but it seems, that they aren't neccessary
byte oleBytes[] = { 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
poifs.createDocument(new ByteArrayInputStream(oleBytes), OLESTREAM_NAME);
}
// need to set storage clsid, otherwise embedded object is not recognized
root.setStorageClsid(oleType.getClassID());
poifs.writeFilesystem(bos);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException("wth?!", e);
}
}
/**
* to be defined, how to create a preview image
* for a start, I've taken just a dummy image, which will be
* replaced, when the user activates the ole object
*
* not really an alternativ:
* http://stackoverflow.com/questions/16704624/how-to-print-a-workbook-file-made-using-apache-poi-and-java
*
* @return image index of the preview image
*/
static int generatePreview(SlideShow ppt, POIDocument oleData) {
try {
FileInputStream fis = new FileInputStream("src/test/resources/dilbert-2011-09-28-powerpoint.jpg");
byte previewImg[] = IOUtils.toByteArray(fis);
fis.close();
return ppt.addPicture(previewImg, Picture.JPEG);
} catch (IOException e) {
throw new RuntimeException("not really?", e);
}
}
static ExEmbed addOleDataToDocumentRecord(SlideShow ppt) {
// taken from SlideShow.addControl()
Document _documentRecord = ppt.getDocumentRecord();
ExObjList lst = _documentRecord.getExObjList();
if (lst == null) {
lst = new ExObjList();
_documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
try {
Field f = Document.class.getDeclaredField("exObjList");
f.setAccessible(true);
f.set(_documentRecord, lst);
} catch (Exception e) {
throw new RuntimeException("not here", e);
}
}
ExObjListAtom objAtom = lst.getExObjListAtom();
// increment the object ID seed
int objectId = (int) objAtom.getObjectIDSeed() + 1;
objAtom.setObjectIDSeed(objectId);
ExEmbed exEmbed = new ExEmbed();
// remove unneccessary infos, so we don't need to specify the type
// of the ole object multiple times
Record children[] = exEmbed.getChildRecords();
exEmbed.removeChild(children[2]);
exEmbed.removeChild(children[3]);
exEmbed.removeChild(children[4]);
ExEmbedAtom eeEmbed = exEmbed.getExEmbedAtom();
try {
Field f = ExEmbedAtom.class.getDeclaredField("_data");
f.setAccessible(true);
f.set(eeEmbed, new byte[]{0,0,0,0,1/*CantLockServerB*/,0,0,0});
// oops, there seems to be an error in the default constructor ...
// should be 8 and not 7 bytes
setRecordLength(eeEmbed, 8);
} catch (Exception e) {
throw new RuntimeException("trust me ;)", e);
}
ExOleObjAtom eeAtom = exEmbed.getExOleObjAtom();
eeAtom.setObjID(objectId);
eeAtom.setDrawAspect(ExOleObjAtom.DRAW_ASPECT_VISIBLE);
eeAtom.setType(ExOleObjAtom.TYPE_EMBEDDED);
// eeAtom.setSubType(ExOleObjAtom.SUBTYPE_EXCEL);
// should be ignored?!?, see MS-PPT ExOleObjAtom, but Libre Office sets it ...
eeAtom.setOptions(1226240);
lst.addChildAfter(exEmbed, objAtom);
return exEmbed;
}
static ExOleObjStg addOleDataToRootRecords(
HSLFSlideShow _hslfSlideShow
, POIDocument oleData
, OleType oleType
) throws IOException {
ExOleObjStg exOleObjStg = new ExOleObjStg();
int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(exOleObjStg);
exOleObjStg.setPersistId(slideRecordPos);
exOleObjStg.setData(wrapOleData(oleData, oleType));
// taken from SlideShow.createSlide
Record _records[] = _hslfSlideShow.getRecords();
// Add the new OLE record into the PersistPtr stuff
int offset = 0;
int slideOffset = 0;
PersistPtrHolder ptr = null;
UserEditAtom usr = null;
for (int i = 0; i < _records.length; i++) {
Record record = _records[i];
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
record.writeOut(out);
} catch (IOException e) {
throw new HSLFException(e);
}
// Grab interesting records as they come past
if (_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID) {
ptr = (PersistPtrHolder) _records[i];
}
if (_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
usr = (UserEditAtom) _records[i];
}
if (i == slideRecordPos) {
slideOffset = offset;
}
offset += out.size();
}
// the ole objects needs to know its position within
// the root records, because it will be later accessed
// via its index from the shape
int psrId = usr.getMaxPersistWritten() + 1;
exOleObjStg.setPersistId(psrId);
// Last view is now of the slide
usr.setLastViewType((short) UserEditAtom.LAST_VIEW_SLIDE_VIEW);
usr.setMaxPersistWritten(psrId); // increment the number of persit objects
// Add the new slide into the last PersistPtr
// (Also need to tell it where it is)
exOleObjStg.setLastOnDiskOffset(slideOffset);
ptr.addSlideLookup(psrId, slideOffset);
return exOleObjStg;
}
static void linkOleDataToShape(OLEShape oleShape, ExEmbed exEmbed) {
oleShape.setEscherProperty(EscherProperties.BLIP__PICTUREID, exEmbed.getExOleObjAtom().getObjID());
EscherSpRecord spRecord = oleShape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
spRecord.setFlags(spRecord.getFlags()|EscherSpRecord.FLAG_OLESHAPE);
// ExObjRefAtom is not set in OLEShape
UnknownEscherRecord uer = new UnknownEscherRecord();
byte uerData[] = new byte[12];
LittleEndian.putShort(uerData, 0, (short)0); // options = 0
LittleEndian.putShort(uerData, 2, (short)RecordTypes.ExObjRefAtom.typeID); // recordId
LittleEndian.putInt(uerData, 4, 4); // remaining bytes
LittleEndian.putInt(uerData, 8, exEmbed.getExOleObjAtom().getObjID()); // the data
uer.fillFields(uerData, 0, null);
EscherContainerRecord uerCont = new EscherContainerRecord();
uerCont.setRecordId((short)RecordTypes.EscherClientData);
uerCont.setVersion((short)0x000F); // yes, we are still a container ...
uerCont.addChildRecord(uer);
oleShape.getSpContainer().addChildRecord(uerCont);
}
static void setRecordLength(Record record, int len) throws NoSuchFieldException, IllegalAccessException {
Field f = record.getClass().getDeclaredField("_header");
f.setAccessible(true);
byte _header[] = (byte[])f.get(record);
LittleEndian.putInt(_header, 4, len);
f.set(record, _header);
}
}
+1
修补程序可以在错误报告[#55579](https://issues.apache .ORG/bugzilla的/ show_bug.cgi?ID = 55579) – kiwiwings 2013-09-21 23:58:40
相关问题
- 1. 如何使用Apache POI HSLF在Powerpoint ppt文件中嵌入avi视频?
- 2. 使用apache poi hslf在ppt中添加子弹和非子弹
- 3. apache poi不更新HSLF组件的ppt文件
- 4. 使用POI HSSF
- 5. Apache POI,同时使用XSSF和HSSF
- 6. java.lang.NoSuchMethodError:org.apache.poi.hssf.usermodel.HSSFWorkbook.createDataFormat()Lorg/apache/poi/hssf/usermodel/HSSFDataFormat;
- 7. java.lang.NoSuchMethodError:org.apache.poi.hssf.usermodel.HSSFWorkbook.getCreationHelper()Lorg/apache/poi/hssf/usermodel/HSSFCreationHelper;
- 8. 使用Apache POI从Excel工作表中删除行HSSF
- 9. 转换的PPT与Apache POI
- 10. 去除PPT的Apache POI
- 11. apache poi ppt to png emf
- 12. 使用Apache POI hslf调整/压缩图片 - PowerPoint
- 13. 使用apache poi写入xlsm(Excel 2007)
- 14. Vaadin 7.4.9错误 - java.lang.NoClassDefFoundError:org/apache/poi/hssf/usermodel/HSSFWorkbook
- 15. Apache POI HSSF。获取总页数
- 16. 的Apache POI HSSF XLS读数误差
- 17. Apache Poi:从HSSF转换为SS?
- 18. 获取画面位置的Apache POI从Excel XLS HSSF
- 19. 使用apache poi下载excel
- 20. 读取Excel使用Apache POI
- 21. 尝试使用Apache POI-HSSF读取MS Excel文件时发生IndexOutOfBoundsException
- 22. 如何在HSSF(Apache POI)的现有Excel中的两行之间插入一行
- 23. Apache poi excel
- 24. excel java apache poi
- 25. 使用Apache POI和TestNG框架将数据写入excel
- 26. 使用Apache POI将数据写入java中的excel文件
- 27. 使用Apache POI将excel文件导入到postgreSQL表中
- 28. 如何将广告串匹配仅在Apache的POI HSSF
- 29. 使用POI或HSSF从Excel文档中提取图表?
- 30. 转换的PPT PNG的Apache POI
目前我只管理像它在该[链接](HTTP真实描述修改一个已经嵌入excel工作表://apache-poi.1045710.n5.nabble。 COM /变通的解决方案对嵌入-工作表到幻灯片-使用-POI-td2300252.html)。还有一个类似的[POI错误](https://issues.apache.org/bugzilla/show_bug.cgi?id=44939)指出,ole嵌入是不完整的支持。另一方面自由办公室似乎支持它 - 不确定,如果他们使用POI写作和他们定制了多少... – kiwiwings 2013-05-04 20:04:43