git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1778869 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_16_BETA2
@@ -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(); | |||
} | |||
} |