#60586 - Support embedding OLE1.0 package in XSSF / SS Common
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1778869 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
86eeda4cbd
commit
5899f8884d
@ -48,6 +48,7 @@ import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.ss.usermodel.Chart;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||
import org.apache.poi.ss.usermodel.Drawing;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.NotImplemented;
|
||||
@ -137,6 +138,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
* @param shape to be removed
|
||||
* @return true of shape is removed
|
||||
*/
|
||||
@Override
|
||||
public boolean removeShape(HSSFShape shape) {
|
||||
boolean isRemoved = _mainSpgrContainer.removeChildRecord(shape.getEscherContainer());
|
||||
if (isRemoved){
|
||||
@ -214,22 +216,13 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
*
|
||||
* @return newly created shape
|
||||
*/
|
||||
@Override
|
||||
public HSSFPicture createPicture(ClientAnchor anchor, int pictureIndex) {
|
||||
return createPicture((HSSFClientAnchor) anchor, pictureIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new OLE Package Shape
|
||||
*
|
||||
* @param anchor the client anchor describes how this picture is
|
||||
* attached to the sheet.
|
||||
* @param storageId the storageId returned by {@link HSSFWorkbook#addOlePackage(POIFSFileSystem,String,String,String)}
|
||||
* @param pictureIndex the index of the picture (used as preview image) in the
|
||||
* workbook collection of pictures.
|
||||
*
|
||||
* @return newly created shape
|
||||
*/
|
||||
public HSSFObjectData createObjectData(HSSFClientAnchor anchor, int storageId, int pictureIndex) {
|
||||
@Override
|
||||
public HSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
|
||||
ObjRecord obj = new ObjRecord();
|
||||
|
||||
CommonObjectDataSubRecord ftCmo = new CommonObjectDataSubRecord();
|
||||
@ -248,15 +241,15 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
FtCfSubRecord ftCf = new FtCfSubRecord();
|
||||
HSSFPictureData pictData = getSheet().getWorkbook().getAllPictures().get(pictureIndex-1);
|
||||
switch (pictData.getFormat()) {
|
||||
case HSSFWorkbook.PICTURE_TYPE_WMF:
|
||||
case HSSFWorkbook.PICTURE_TYPE_EMF:
|
||||
case Workbook.PICTURE_TYPE_WMF:
|
||||
case Workbook.PICTURE_TYPE_EMF:
|
||||
// this needs patch #49658 to be applied to actually work
|
||||
ftCf.setFlags(FtCfSubRecord.METAFILE_BIT);
|
||||
break;
|
||||
case HSSFWorkbook.PICTURE_TYPE_DIB:
|
||||
case HSSFWorkbook.PICTURE_TYPE_PNG:
|
||||
case HSSFWorkbook.PICTURE_TYPE_JPEG:
|
||||
case HSSFWorkbook.PICTURE_TYPE_PICT:
|
||||
case Workbook.PICTURE_TYPE_DIB:
|
||||
case Workbook.PICTURE_TYPE_PNG:
|
||||
case Workbook.PICTURE_TYPE_JPEG:
|
||||
case Workbook.PICTURE_TYPE_PICT:
|
||||
ftCf.setFlags(FtCfSubRecord.BITMAP_BIT);
|
||||
break;
|
||||
default:
|
||||
@ -280,14 +273,16 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
DirectoryEntry oleRoot;
|
||||
try {
|
||||
DirectoryNode dn = _sheet.getWorkbook().getDirectory();
|
||||
if (dn == null) throw new FileNotFoundException();
|
||||
if (dn == null) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
oleRoot = (DirectoryEntry)dn.getEntry(entryName);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IllegalStateException("trying to add ole shape without actually adding data first - use HSSFWorkbook.addOlePackage first", e);
|
||||
}
|
||||
|
||||
// create picture shape, which need to be minimal modified for oleshapes
|
||||
HSSFPicture shape = new HSSFPicture(null, anchor);
|
||||
HSSFPicture shape = new HSSFPicture(null, (HSSFClientAnchor)anchor);
|
||||
shape.setPictureIndex(pictureIndex);
|
||||
EscherContainerRecord spContainer = shape.getEscherContainer();
|
||||
EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||||
@ -355,6 +350,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HSSFComment createCellComment(ClientAnchor anchor) {
|
||||
return createComment((HSSFAnchor) anchor);
|
||||
}
|
||||
@ -362,6 +358,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* Returns a unmodifiable list of all shapes contained by the patriarch.
|
||||
*/
|
||||
@Override
|
||||
public List<HSSFShape> getChildren() {
|
||||
return Collections.unmodifiableList(_shapes);
|
||||
}
|
||||
@ -369,6 +366,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* add a shape to this drawing
|
||||
*/
|
||||
@Override
|
||||
@Internal
|
||||
public void addShape(HSSFShape shape) {
|
||||
shape.setPatriarch(this);
|
||||
@ -405,6 +403,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
* Sets the coordinate space of this group. All children are constrained
|
||||
* to these coordinates.
|
||||
*/
|
||||
@Override
|
||||
public void setCoordinates(int x1, int y1, int x2, int y2) {
|
||||
_spgrRecord.setRectY1(y1);
|
||||
_spgrRecord.setRectY2(y2);
|
||||
@ -415,6 +414,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* remove all shapes inside patriarch
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
ArrayList <HSSFShape> copy = new ArrayList<HSSFShape>(_shapes);
|
||||
for (HSSFShape shape: copy){
|
||||
@ -469,6 +469,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* @return x coordinate of the left up corner
|
||||
*/
|
||||
@Override
|
||||
public int getX1() {
|
||||
return _spgrRecord.getRectX1();
|
||||
}
|
||||
@ -476,6 +477,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* @return y coordinate of the left up corner
|
||||
*/
|
||||
@Override
|
||||
public int getY1() {
|
||||
return _spgrRecord.getRectY1();
|
||||
}
|
||||
@ -483,6 +485,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* @return x coordinate of the right down corner
|
||||
*/
|
||||
@Override
|
||||
public int getX2() {
|
||||
return _spgrRecord.getRectX2();
|
||||
}
|
||||
@ -490,6 +493,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
/**
|
||||
* @return y coordinate of the right down corner
|
||||
*/
|
||||
@Override
|
||||
public int getY2() {
|
||||
return _spgrRecord.getRectY2();
|
||||
}
|
||||
@ -517,10 +521,12 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
|
||||
* @param row2 the row (0 based) of the second cell.
|
||||
* @return the newly created client anchor
|
||||
*/
|
||||
@Override
|
||||
public HSSFClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {
|
||||
return new HSSFClientAnchor(dx1, dy1, dx2, dy2, (short) col1, row1, (short) col2, row2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotImplemented
|
||||
public Chart createChart(ClientAnchor anchor) {
|
||||
throw new RuntimeException("NotImplemented");
|
||||
|
@ -2048,6 +2048,16 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
||||
return olemap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an OLE package manager object with the given POIFS to the sheet
|
||||
*
|
||||
* @param poiData an POIFS containing the embedded document, to be added
|
||||
* @param label the label of the payload
|
||||
* @param fileName the original filename
|
||||
* @param command the command to open the payload
|
||||
* @return the index of the added ole object
|
||||
* @throws IOException if the object can't be embedded
|
||||
*/
|
||||
public int addOlePackage(POIFSFileSystem poiData, String label, String fileName, String command)
|
||||
throws IOException {
|
||||
DirectoryNode root = poiData.getRoot();
|
||||
@ -2064,6 +2074,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
||||
return addOlePackage(bos.toByteArray(), label, fileName, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addOlePackage(byte[] oleData, String label, String fileName, String command)
|
||||
throws IOException {
|
||||
// check if we were created by POIFS otherwise create a new dummy POIFS for storing the package data
|
||||
|
@ -62,4 +62,17 @@ public interface Drawing<T extends Shape> extends ShapeContainer<T> {
|
||||
* @return the newly created client anchor
|
||||
*/
|
||||
ClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2);
|
||||
|
||||
/**
|
||||
* Adds a new OLE Package Shape
|
||||
*
|
||||
* @param anchor the client anchor describes how this picture is
|
||||
* attached to the sheet.
|
||||
* @param storageId the storageId returned by {@link Workbook#addOlePackage(byte[], String, String, String)}
|
||||
* @param pictureIndex the index of the picture (used as preview image) in the
|
||||
* workbook collection of pictures.
|
||||
*
|
||||
* @return newly created shape
|
||||
*/
|
||||
ObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex);
|
||||
}
|
||||
|
@ -286,6 +286,7 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
||||
* @return the font with the matched attributes or <code>null</code>
|
||||
* @deprecated POI 3.15 beta 2. Use {@link #findFont(boolean, short, short, String, boolean, boolean, short, byte)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Font findFont(short boldWeight, short color, short fontHeight, String name, boolean italic, boolean strikeout, short typeOffset, byte underline);
|
||||
|
||||
/**
|
||||
@ -635,4 +636,18 @@ public interface Workbook extends Closeable, Iterable<Sheet> {
|
||||
* @since 3.14 beta 2
|
||||
*/
|
||||
SpreadsheetVersion getSpreadsheetVersion();
|
||||
|
||||
/**
|
||||
* Adds an OLE package manager object with the given content to the sheet
|
||||
*
|
||||
* @param oleData the payload
|
||||
* @param label the label of the payload
|
||||
* @param fileName the original filename
|
||||
* @param command the command to open the payload
|
||||
*
|
||||
* @return the index of the added ole object, i.e. the storage id
|
||||
*
|
||||
* @throws IOException if the object can't be embedded
|
||||
*/
|
||||
int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import org.apache.poi.ss.usermodel.Chart;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||
import org.apache.poi.ss.usermodel.Comment;
|
||||
import org.apache.poi.ss.usermodel.Drawing;
|
||||
import org.apache.poi.ss.usermodel.ObjectData;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||
import org.apache.poi.xssf.usermodel.XSSFPicture;
|
||||
import org.apache.poi.xssf.usermodel.XSSFShape;
|
||||
@ -62,9 +63,15 @@ public class SXSSFDrawing implements Drawing<XSSFShape> {
|
||||
return _drawing.createAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
|
||||
return _drawing.createObjectData(anchor, storageId, pictureIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<XSSFShape> iterator() {
|
||||
return _drawing.getShapes().iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1391,5 +1391,10 @@ public class SXSSFWorkbook implements Workbook {
|
||||
return SpreadsheetVersion.EXCEL2007;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException {
|
||||
return _wb.addOlePackage(oleData, label, fileName, command);
|
||||
}
|
||||
|
||||
//end of interface implementation
|
||||
}
|
||||
|
@ -28,9 +28,16 @@ import java.util.List;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.poi.POIXMLDocument;
|
||||
import org.apache.poi.POIXMLDocumentPart;
|
||||
import org.apache.poi.POIXMLException;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.openxml4j.opc.PackagePartName;
|
||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||
import org.apache.poi.ss.usermodel.ClientAnchor;
|
||||
import org.apache.poi.ss.usermodel.Drawing;
|
||||
import org.apache.poi.ss.util.CellAddress;
|
||||
@ -45,7 +52,9 @@ import org.apache.xmlbeans.XmlException;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.apache.xmlbeans.XmlOptions;
|
||||
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
|
||||
@ -59,19 +68,22 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObject;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObjects;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
||||
|
||||
/**
|
||||
* Represents a SpreadsheetML drawing
|
||||
*/
|
||||
public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSSFShape> {
|
||||
private static final POILogger LOG = POILogFactory.getLogger(XSSFDrawing.class);
|
||||
|
||||
|
||||
/**
|
||||
* Root element of the SpreadsheetML Drawing part
|
||||
*/
|
||||
private CTDrawing drawing;
|
||||
private long numOfGraphicFrames = 0L;
|
||||
|
||||
|
||||
protected static final String NAMESPACE_A = XSSFRelation.NS_DRAWINGML;
|
||||
protected static final String NAMESPACE_C = XSSFRelation.NS_CHART;
|
||||
|
||||
@ -90,7 +102,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
*
|
||||
* @param part the package part holding the drawing data,
|
||||
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawing+xml</code>
|
||||
*
|
||||
*
|
||||
* @since POI 3.14-Beta1
|
||||
*/
|
||||
public XSSFDrawing(PackagePart part) throws IOException, XmlException {
|
||||
@ -105,7 +117,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new CTDrawing bean. By default, it's just an empty placeholder for drawing objects
|
||||
*
|
||||
@ -194,7 +206,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
shape.anchor = anchor;
|
||||
shape.setPictureReference(rel);
|
||||
ctShape.getSpPr().setXfrm(createXfrm(anchor));
|
||||
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
@ -319,7 +331,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
@Override
|
||||
public XSSFComment createCellComment(ClientAnchor anchor) {
|
||||
XSSFClientAnchor ca = (XSSFClientAnchor)anchor;
|
||||
XSSFSheet sheet = (XSSFSheet)getParent();
|
||||
XSSFSheet sheet = getSheet();
|
||||
|
||||
//create comments and vmlDrawing parts if they don't exist
|
||||
CommentsTable comments = sheet.getCommentsTable(true);
|
||||
@ -344,7 +356,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
if(comments.findCellComment(ref) != null) {
|
||||
throw new IllegalArgumentException("Multiple cell comments in one cell are not allowed, cell: " + ref);
|
||||
}
|
||||
|
||||
|
||||
return new XSSFComment(comments, comments.newComment(ref), vmlShape);
|
||||
}
|
||||
|
||||
@ -368,7 +380,85 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
graphicFrame.setName("Diagramm" + frameId);
|
||||
return graphicFrame;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public XSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
|
||||
XSSFSheet sh = getSheet();
|
||||
PackagePart sheetPart = sh.getPackagePart();
|
||||
long shapeId = newShapeId();
|
||||
|
||||
// add reference to OLE part
|
||||
PackagePartName olePN;
|
||||
try {
|
||||
olePN = PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+storageId+".bin" );
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIXMLException(e);
|
||||
}
|
||||
PackageRelationship olePR = sheetPart.addRelationship( olePN, TargetMode.INTERNAL, POIXMLDocument.OLE_OBJECT_REL_TYPE );
|
||||
|
||||
// add reference to image part
|
||||
XSSFPictureData imgPD = sh.getWorkbook().getAllPictures().get(pictureIndex);
|
||||
PackagePartName imgPN = imgPD.getPackagePart().getPartName();
|
||||
PackageRelationship imgSheetPR = sheetPart.addRelationship( imgPN, TargetMode.INTERNAL, PackageRelationshipTypes.IMAGE_PART );
|
||||
PackageRelationship imgDrawPR = getPackagePart().addRelationship( imgPN, TargetMode.INTERNAL, PackageRelationshipTypes.IMAGE_PART );
|
||||
|
||||
|
||||
// add OLE part metadata to sheet
|
||||
CTWorksheet cwb = sh.getCTWorksheet();
|
||||
CTOleObjects oo = cwb.isSetOleObjects() ? cwb.getOleObjects() : cwb.addNewOleObjects();
|
||||
|
||||
CTOleObject ole1 = oo.addNewOleObject();
|
||||
ole1.setProgId("Package");
|
||||
ole1.setShapeId(shapeId);
|
||||
ole1.setId(olePR.getId());
|
||||
|
||||
XmlCursor cur1 = ole1.newCursor();
|
||||
cur1.toEndToken();
|
||||
cur1.beginElement("objectPr", XSSFRelation.NS_SPREADSHEETML);
|
||||
cur1.insertAttributeWithValue("id", PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS, imgSheetPR.getId());
|
||||
cur1.insertAttributeWithValue("defaultSize", "0");
|
||||
cur1.beginElement("anchor", XSSFRelation.NS_SPREADSHEETML);
|
||||
cur1.insertAttributeWithValue("moveWithCells", "1");
|
||||
|
||||
CTTwoCellAnchor ctAnchor = createTwoCellAnchor((XSSFClientAnchor)anchor);
|
||||
|
||||
XmlCursor cur2 = ctAnchor.newCursor();
|
||||
cur2.copyXmlContents(cur1);
|
||||
cur2.dispose();
|
||||
|
||||
cur1.toParent();
|
||||
cur1.toFirstChild();
|
||||
cur1.setName(new QName(XSSFRelation.NS_SPREADSHEETML, "from"));
|
||||
cur1.toNextSibling();
|
||||
cur1.setName(new QName(XSSFRelation.NS_SPREADSHEETML, "to"));
|
||||
|
||||
cur1.dispose();
|
||||
|
||||
// add a new shape and link OLE & image part
|
||||
CTShape ctShape = ctAnchor.addNewSp();
|
||||
ctShape.set(XSSFObjectData.prototype());
|
||||
ctShape.getSpPr().setXfrm(createXfrm((XSSFClientAnchor)anchor));
|
||||
|
||||
// workaround for not having the vmlDrawing filled
|
||||
CTBlipFillProperties blipFill = ctShape.getSpPr().addNewBlipFill();
|
||||
blipFill.addNewBlip().setEmbed(imgDrawPR.getId());
|
||||
blipFill.addNewStretch().addNewFillRect();
|
||||
|
||||
CTNonVisualDrawingProps cNvPr = ctShape.getNvSpPr().getCNvPr();
|
||||
cNvPr.setId(shapeId);
|
||||
|
||||
XmlCursor extCur = cNvPr.getExtLst().getExtArray(0).newCursor();
|
||||
extCur.toFirstChild();
|
||||
extCur.setAttributeText(new QName("spid"), "_x0000_s"+shapeId);
|
||||
extCur.dispose();
|
||||
|
||||
XSSFObjectData shape = new XSSFObjectData(this, ctShape);
|
||||
shape.anchor = (XSSFClientAnchor)anchor;
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all charts in this drawing.
|
||||
*/
|
||||
@ -410,7 +500,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
CTPoint2D off = xfrm.addNewOff();
|
||||
off.setX(anchor.getDx1());
|
||||
off.setY(anchor.getDy1());
|
||||
XSSFSheet sheet = (XSSFSheet)getParent();
|
||||
XSSFSheet sheet = getSheet();
|
||||
double widthPx = 0;
|
||||
for (int col=anchor.getCol1(); col<anchor.getCol2(); col++) {
|
||||
widthPx += sheet.getColumnWidthInPixels(col);
|
||||
@ -424,11 +514,11 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
CTPositiveSize2D ext = xfrm.addNewExt();
|
||||
ext.setCx(width - anchor.getDx1() + anchor.getDx2());
|
||||
ext.setCy(height - anchor.getDy1() + anchor.getDy2());
|
||||
|
||||
|
||||
// TODO: handle vflip/hflip
|
||||
return xfrm;
|
||||
}
|
||||
|
||||
|
||||
private long newShapeId(){
|
||||
return drawing.sizeOfTwoCellAnchorArray() + 1;
|
||||
}
|
||||
@ -462,7 +552,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
|
||||
private void addShapes(XmlCursor cur, List<XSSFShape> lst) {
|
||||
try {
|
||||
do {
|
||||
@ -470,7 +560,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
if (cur.toFirstChild()) {
|
||||
do {
|
||||
XmlObject obj = cur.getObject();
|
||||
|
||||
|
||||
XSSFShape shape;
|
||||
if (obj instanceof CTMarker) {
|
||||
// ignore anchor elements
|
||||
@ -480,7 +570,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
} else if(obj instanceof CTConnector) {
|
||||
shape = new XSSFConnector(this, (CTConnector)obj) ;
|
||||
} else if(obj instanceof CTShape) {
|
||||
shape = hasOleLink(obj)
|
||||
shape = hasOleLink(obj)
|
||||
? new XSSFObjectData(this, (CTShape)obj)
|
||||
: new XSSFSimpleShape(this, (CTShape)obj) ;
|
||||
} else if(obj instanceof CTGraphicalObjectFrame) {
|
||||
@ -492,7 +582,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
+ "this unlinks the returned Shapes from the underlying xml content, "
|
||||
+ "so those shapes can't be used to modify the drawing, "
|
||||
+ "i.e. modifications will be ignored!");
|
||||
|
||||
|
||||
// XmlAnyTypeImpl is returned for AlternateContent parts, which might contain a CTDrawing
|
||||
cur.push();
|
||||
cur.toFirstChild();
|
||||
@ -522,7 +612,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
assert(shape != null);
|
||||
shape.anchor = getAnchorFromParent(obj);
|
||||
lst.add(shape);
|
||||
|
||||
|
||||
} while (cur.toNextSibling());
|
||||
}
|
||||
cur.pop();
|
||||
@ -575,4 +665,12 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
||||
public Iterator<XSSFShape> iterator() {
|
||||
return getShapes().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sheet associated with the drawing
|
||||
*/
|
||||
public XSSFSheet getSheet() {
|
||||
return (XSSFSheet)getParent();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,7 +36,17 @@ import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtension;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtensionList;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObject;
|
||||
|
||||
/**
|
||||
@ -56,16 +66,57 @@ public class XSSFObjectData extends XSSFSimpleShape implements ObjectData {
|
||||
super(drawing, ctShape);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prototype with the default structure of a new auto-shape.
|
||||
*/
|
||||
/**
|
||||
* Prototype with the default structure of a new auto-shape.
|
||||
*/
|
||||
protected static CTShape prototype() {
|
||||
final String drawNS = "http://schemas.microsoft.com/office/drawing/2010/main";
|
||||
|
||||
if(prototype == null) {
|
||||
prototype = XSSFSimpleShape.prototype();
|
||||
CTShape shape = CTShape.Factory.newInstance();
|
||||
|
||||
CTShapeNonVisual nv = shape.addNewNvSpPr();
|
||||
CTNonVisualDrawingProps nvp = nv.addNewCNvPr();
|
||||
nvp.setId(1);
|
||||
nvp.setName("Shape 1");
|
||||
// nvp.setHidden(true);
|
||||
CTOfficeArtExtensionList extLst = nvp.addNewExtLst();
|
||||
// https://msdn.microsoft.com/en-us/library/dd911027(v=office.12).aspx
|
||||
CTOfficeArtExtension ext = extLst.addNewExt();
|
||||
ext.setUri("{63B3BB69-23CF-44E3-9099-C40C66FF867C}");
|
||||
XmlCursor cur = ext.newCursor();
|
||||
cur.toEndToken();
|
||||
cur.beginElement(new QName(drawNS, "compatExt", "a14"));
|
||||
cur.insertNamespace("a14", drawNS);
|
||||
cur.insertAttributeWithValue("spid", "_x0000_s1");
|
||||
cur.dispose();
|
||||
|
||||
nv.addNewCNvSpPr();
|
||||
|
||||
CTShapeProperties sp = shape.addNewSpPr();
|
||||
CTTransform2D t2d = sp.addNewXfrm();
|
||||
CTPositiveSize2D p1 = t2d.addNewExt();
|
||||
p1.setCx(0);
|
||||
p1.setCy(0);
|
||||
CTPoint2D p2 = t2d.addNewOff();
|
||||
p2.setX(0);
|
||||
p2.setY(0);
|
||||
|
||||
CTPresetGeometry2D geom = sp.addNewPrstGeom();
|
||||
geom.setPrst(STShapeType.RECT);
|
||||
geom.addNewAvLst();
|
||||
|
||||
prototype = shape;
|
||||
}
|
||||
return prototype;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getOLE2ClassName() {
|
||||
return getOleObject().getProgId();
|
||||
|
@ -47,6 +47,7 @@ import org.apache.poi.POIXMLDocument;
|
||||
import org.apache.poi.POIXMLDocumentPart;
|
||||
import org.apache.poi.POIXMLException;
|
||||
import org.apache.poi.POIXMLProperties;
|
||||
import org.apache.poi.hpsf.ClassID;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
@ -58,6 +59,9 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||
import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.Ole10Native;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.SpreadsheetVersion;
|
||||
import org.apache.poi.ss.formula.SheetNameFormatter;
|
||||
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
|
||||
@ -2437,4 +2441,41 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addOlePackage(byte[] oleData, String label, String fileName, String command)
|
||||
throws IOException {
|
||||
// find an unused part name
|
||||
OPCPackage opc = getPackage();
|
||||
PackagePartName pnOLE;
|
||||
int oleId=0;
|
||||
do {
|
||||
try {
|
||||
pnOLE = PackagingURIHelper.createPartName( "/xl/embeddings/oleObject"+(++oleId)+".bin" );
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new IOException("ole object name not recognized", e);
|
||||
}
|
||||
} while (opc.containPart(pnOLE));
|
||||
|
||||
PackagePart pp = opc.createPart( pnOLE, "application/vnd.openxmlformats-officedocument.oleObject" );
|
||||
|
||||
Ole10Native ole10 = new Ole10Native(label, fileName, command, oleData);
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(oleData.length+500);
|
||||
ole10.writeOut(bos);
|
||||
|
||||
POIFSFileSystem poifs = new POIFSFileSystem();
|
||||
DirectoryNode root = poifs.getRoot();
|
||||
root.createDocument(Ole10Native.OLE10_NATIVE, new ByteArrayInputStream(bos.toByteArray()));
|
||||
root.setStorageClsid(ClassID.OLE10_PACKAGE);
|
||||
|
||||
// TODO: generate CombObj stream
|
||||
|
||||
OutputStream os = pp.getOutputStream();
|
||||
poifs.writeFilesystem(os);
|
||||
os.close();
|
||||
poifs.close();
|
||||
|
||||
return oleId;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,125 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.ss.usermodel;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.sl.usermodel.AutoShape;
|
||||
import org.apache.poi.sl.usermodel.ShapeType;
|
||||
import org.apache.poi.sl.usermodel.Slide;
|
||||
import org.apache.poi.sl.usermodel.SlideShow;
|
||||
import org.apache.poi.ss.extractor.EmbeddedData;
|
||||
import org.apache.poi.ss.extractor.EmbeddedExtractor;
|
||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestEmbedOLEPackage {
|
||||
@Test
|
||||
public void embedXSSF() throws IOException {
|
||||
Workbook wb1 = new XSSFWorkbook();
|
||||
Sheet sh = wb1.createSheet();
|
||||
int picIdx = wb1.addPicture(getSamplePng(), Workbook.PICTURE_TYPE_PNG);
|
||||
byte samplePPTX[] = getSamplePPT(true);
|
||||
int oleIdx = wb1.addOlePackage(samplePPTX, "dummy.pptx", "dummy.pptx", "dummy.pptx");
|
||||
|
||||
Drawing<?> pat = sh.createDrawingPatriarch();
|
||||
ClientAnchor anchor = pat.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
|
||||
pat.createObjectData(anchor, oleIdx, picIdx);
|
||||
|
||||
Workbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
|
||||
|
||||
pat = wb2.getSheetAt(0).getDrawingPatriarch();
|
||||
assertTrue(pat.iterator().next() instanceof ObjectData);
|
||||
|
||||
EmbeddedExtractor ee = new EmbeddedExtractor();
|
||||
EmbeddedData ed = ee.extractAll(wb2.getSheetAt(0)).get(0);
|
||||
assertArrayEquals(samplePPTX, ed.getEmbeddedData());
|
||||
|
||||
wb2.close();
|
||||
wb1.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void embedHSSF() throws IOException {
|
||||
try {
|
||||
Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
|
||||
} catch (Exception e) {
|
||||
assumeTrue(false);
|
||||
}
|
||||
|
||||
Workbook wb1 = new HSSFWorkbook();
|
||||
Sheet sh = wb1.createSheet();
|
||||
int picIdx = wb1.addPicture(getSamplePng(), Workbook.PICTURE_TYPE_PNG);
|
||||
byte samplePPT[] = getSamplePPT(false);
|
||||
int oleIdx = wb1.addOlePackage(samplePPT, "dummy.ppt", "dummy.ppt", "dummy.ppt");
|
||||
|
||||
Drawing<?> pat = sh.createDrawingPatriarch();
|
||||
ClientAnchor anchor = pat.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
|
||||
pat.createObjectData(anchor, oleIdx, picIdx);
|
||||
|
||||
Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)wb1);
|
||||
|
||||
pat = wb2.getSheetAt(0).getDrawingPatriarch();
|
||||
assertTrue(pat.iterator().next() instanceof ObjectData);
|
||||
|
||||
EmbeddedExtractor ee = new EmbeddedExtractor();
|
||||
EmbeddedData ed = ee.extractAll(wb2.getSheetAt(0)).get(0);
|
||||
assertArrayEquals(samplePPT, ed.getEmbeddedData());
|
||||
|
||||
wb2.close();
|
||||
wb1.close();
|
||||
}
|
||||
|
||||
static byte[] getSamplePng() throws IOException {
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
URL imgUrl = cl.getResource("javax/swing/plaf/metal/icons/ocean/directory.gif");
|
||||
BufferedImage img = ImageIO.read(imgUrl);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ImageIO.write(img, "PNG", bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
static byte[] getSamplePPT(boolean ooxml) throws IOException {
|
||||
SlideShow<?,?> ppt = (ooxml) ? new XMLSlideShow() : new org.apache.poi.hslf.usermodel.HSLFSlideShow();
|
||||
Slide<?,?> slide = ppt.createSlide();
|
||||
|
||||
AutoShape<?,?> sh1 = slide.createAutoShape();
|
||||
sh1.setShapeType(ShapeType.STAR_32);
|
||||
sh1.setAnchor(new java.awt.Rectangle(50, 50, 100, 200));
|
||||
sh1.setFillColor(java.awt.Color.red);
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ppt.write(bos);
|
||||
ppt.close();
|
||||
|
||||
return bos.toByteArray();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user