123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- /* ====================================================================
- 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.xssf.usermodel;
-
- import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.util.ArrayList;
- import java.util.Iterator;
- 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;
- import org.apache.poi.ss.util.ImageUtils;
- import org.apache.poi.util.Internal;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.util.POILogger;
- import org.apache.poi.util.Units;
- import org.apache.poi.xssf.model.CommentsTable;
- import org.apache.xmlbeans.XmlCursor;
- 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;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTAbsoluteAnchor;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTConnector;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrame;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGroupShape;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
- import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor;
- 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;
-
- protected static final String NAMESPACE_A = XSSFRelation.NS_DRAWINGML;
- protected static final String NAMESPACE_C = XSSFRelation.NS_CHART;
-
- /**
- * Create a new SpreadsheetML drawing
- *
- * @see org.apache.poi.xssf.usermodel.XSSFSheet#createDrawingPatriarch()
- */
- protected XSSFDrawing() {
- super();
- drawing = newDrawing();
- }
-
- /**
- * Construct a SpreadsheetML drawing from a package part
- *
- * @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 {
- super(part);
- XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
- //Removing root element
- options.setLoadReplaceDocumentElement(null);
- InputStream is = part.getInputStream();
- try {
- drawing = CTDrawing.Factory.parse(is,options);
- } finally {
- is.close();
- }
- }
-
- /**
- * Construct a new CTDrawing bean. By default, it's just an empty placeholder for drawing objects
- *
- * @return a new CTDrawing bean
- */
- private static CTDrawing newDrawing(){
- return CTDrawing.Factory.newInstance();
- }
-
- /**
- * Return the underlying CTDrawing bean, the root element of the SpreadsheetML Drawing part.
- *
- * @return the underlying CTDrawing bean
- */
- @Internal
- public CTDrawing getCTDrawing(){
- return drawing;
- }
-
- @Override
- protected void commit() throws IOException {
- XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
-
- /*
- Saved drawings must have the following namespaces set:
- <xdr:wsDr
- xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
- xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">
- */
- xmlOptions.setSaveSyntheticDocumentElement(
- new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr")
- );
-
- PackagePart part = getPackagePart();
- OutputStream out = part.getOutputStream();
- drawing.save(out, xmlOptions);
- out.close();
- }
-
- @Override
- public XSSFClientAnchor createAnchor(int dx1, int dy1, int dx2, int dy2,
- int col1, int row1, int col2, int row2) {
- return new XSSFClientAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2);
- }
-
- /**
- * Constructs a textbox under the drawing.
- *
- * @param anchor the client anchor describes how this group is attached
- * to the sheet.
- * @return the newly created textbox.
- */
- public XSSFTextBox createTextbox(XSSFClientAnchor anchor){
- long shapeId = newShapeId();
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTShape ctShape = ctAnchor.addNewSp();
- ctShape.set(XSSFSimpleShape.prototype());
- ctShape.getNvSpPr().getCNvPr().setId(shapeId);
- XSSFTextBox shape = new XSSFTextBox(this, ctShape);
- shape.anchor = anchor;
- return shape;
-
- }
-
- /**
- * Creates a picture.
- *
- * @param anchor the client anchor describes how this picture is attached to the sheet.
- * @param pictureIndex the index of the picture in the workbook collection of pictures,
- * {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()} .
- *
- * @return the newly created picture shape.
- */
- public XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex)
- {
- PackageRelationship rel = addPictureReference(pictureIndex);
-
- long shapeId = newShapeId();
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTPicture ctShape = ctAnchor.addNewPic();
- ctShape.set(XSSFPicture.prototype());
-
- ctShape.getNvPicPr().getCNvPr().setId(shapeId);
-
- XSSFPicture shape = new XSSFPicture(this, ctShape);
- shape.anchor = anchor;
- shape.setPictureReference(rel);
- ctShape.getSpPr().setXfrm(createXfrm(anchor));
-
- return shape;
- }
-
- @Override
- public XSSFPicture createPicture(ClientAnchor anchor, int pictureIndex){
- return createPicture((XSSFClientAnchor)anchor, pictureIndex);
- }
-
- /**
- * Creates a chart.
- * @param anchor the client anchor describes how this chart is attached to
- * the sheet.
- * @return the newly created chart
- * @see org.apache.poi.xssf.usermodel.XSSFDrawing#createChart(ClientAnchor)
- */
- public XSSFChart createChart(XSSFClientAnchor anchor) {
- int chartNumber = getPackagePart().getPackage().
- getPartsByContentType(XSSFRelation.CHART.getContentType()).size() + 1;
-
- RelationPart rp = createRelationship(
- XSSFRelation.CHART, XSSFFactory.getInstance(), chartNumber, false);
- XSSFChart chart = rp.getDocumentPart();
- String chartRelId = rp.getRelationship().getId();
-
- XSSFGraphicFrame frame = createGraphicFrame(anchor);
- frame.setChart(chart, chartRelId);
- frame.getCTGraphicalObjectFrame().setXfrm(createXfrm(anchor));
-
- return chart;
- }
-
- /**
- * Creates a chart.
- * @param anchor the client anchor describes how this chart is attached to
- * the sheet.
- * @return the newly created chart
- */
- public XSSFChart createChart(ClientAnchor anchor) {
- return createChart((XSSFClientAnchor)anchor);
- }
-
- /**
- * Add the indexed picture to this drawing relations
- *
- * @param pictureIndex the index of the picture in the workbook collection of pictures,
- * {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()} .
- */
- @SuppressWarnings("resource")
- protected PackageRelationship addPictureReference(int pictureIndex){
- XSSFWorkbook wb = (XSSFWorkbook)getParent().getParent();
- XSSFPictureData data = wb.getAllPictures().get(pictureIndex);
- XSSFPictureData pic = new XSSFPictureData(data.getPackagePart());
- RelationPart rp = addRelation(null, XSSFRelation.IMAGES, pic);
- return rp.getRelationship();
- }
-
- /**
- * Creates a simple shape. This includes such shapes as lines, rectangles,
- * and ovals.
- *
- * @param anchor the client anchor describes how this group is attached
- * to the sheet.
- * @return the newly created shape.
- */
- public XSSFSimpleShape createSimpleShape(XSSFClientAnchor anchor)
- {
- long shapeId = newShapeId();
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTShape ctShape = ctAnchor.addNewSp();
- ctShape.set(XSSFSimpleShape.prototype());
- ctShape.getNvSpPr().getCNvPr().setId(shapeId);
- ctShape.getSpPr().setXfrm(createXfrm(anchor));
- XSSFSimpleShape shape = new XSSFSimpleShape(this, ctShape);
- shape.anchor = anchor;
- return shape;
- }
-
- /**
- * Creates a simple shape. This includes such shapes as lines, rectangles,
- * and ovals.
- *
- * @param anchor the client anchor describes how this group is attached
- * to the sheet.
- * @return the newly created shape.
- */
- public XSSFConnector createConnector(XSSFClientAnchor anchor)
- {
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTConnector ctShape = ctAnchor.addNewCxnSp();
- ctShape.set(XSSFConnector.prototype());
-
- XSSFConnector shape = new XSSFConnector(this, ctShape);
- shape.anchor = anchor;
- return shape;
- }
-
- /**
- * Creates a simple shape. This includes such shapes as lines, rectangles,
- * and ovals.
- *
- * @param anchor the client anchor describes how this group is attached
- * to the sheet.
- * @return the newly created shape.
- */
- public XSSFShapeGroup createGroup(XSSFClientAnchor anchor)
- {
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTGroupShape ctGroup = ctAnchor.addNewGrpSp();
- ctGroup.set(XSSFShapeGroup.prototype());
- CTTransform2D xfrm = createXfrm(anchor);
- CTGroupTransform2D grpXfrm =ctGroup.getGrpSpPr().getXfrm();
- grpXfrm.setOff(xfrm.getOff());
- grpXfrm.setExt(xfrm.getExt());
- grpXfrm.setChExt(xfrm.getExt());
-
- XSSFShapeGroup shape = new XSSFShapeGroup(this, ctGroup);
- shape.anchor = anchor;
- return shape;
- }
-
- /**
- * Creates a comment.
- * @param anchor the client anchor describes how this comment is attached
- * to the sheet.
- * @return the newly created comment.
- */
- @Override
- public XSSFComment createCellComment(ClientAnchor anchor) {
- XSSFClientAnchor ca = (XSSFClientAnchor)anchor;
- XSSFSheet sheet = getSheet();
-
- //create comments and vmlDrawing parts if they don't exist
- CommentsTable comments = sheet.getCommentsTable(true);
- XSSFVMLDrawing vml = sheet.getVMLDrawing(true);
- com.microsoft.schemas.vml.CTShape vmlShape = vml.newCommentShape();
- if(ca.isSet()){
- // convert offsets from emus to pixels since we get a DrawingML-anchor
- // but create a VML Drawing
- int dx1Pixels = ca.getDx1()/Units.EMU_PER_PIXEL;
- int dy1Pixels = ca.getDy1()/Units.EMU_PER_PIXEL;
- int dx2Pixels = ca.getDx2()/Units.EMU_PER_PIXEL;
- int dy2Pixels = ca.getDy2()/Units.EMU_PER_PIXEL;
- String position =
- ca.getCol1() + ", " + dx1Pixels + ", " +
- ca.getRow1() + ", " + dy1Pixels + ", " +
- ca.getCol2() + ", " + dx2Pixels + ", " +
- ca.getRow2() + ", " + dy2Pixels;
- vmlShape.getClientDataArray(0).setAnchorArray(0, position);
- }
- CellAddress ref = new CellAddress(ca.getRow1(), ca.getCol1());
-
- 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);
- }
-
- /**
- * Creates a new graphic frame.
- *
- * @param anchor the client anchor describes how this frame is attached
- * to the sheet
- * @return the newly created graphic frame
- */
- private XSSFGraphicFrame createGraphicFrame(XSSFClientAnchor anchor) {
- CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);
- CTGraphicalObjectFrame ctGraphicFrame = ctAnchor.addNewGraphicFrame();
- ctGraphicFrame.set(XSSFGraphicFrame.prototype());
- ctGraphicFrame.setXfrm(createXfrm(anchor));
-
- long frameId = numOfGraphicFrames++;
- XSSFGraphicFrame graphicFrame = new XSSFGraphicFrame(this, ctGraphicFrame);
- graphicFrame.setAnchor(anchor);
- graphicFrame.setId(frameId);
- graphicFrame.setName("Diagramm" + frameId);
- return graphicFrame;
- }
-
- @Override
- public XSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
- XSSFSheet sh = getSheet();
- PackagePart sheetPart = sh.getPackagePart();
-
- /*
- * The shape id of the ole object seems to be a legacy shape id.
- *
- * see 5.3.2.1 legacyDrawing (Legacy Drawing Object):
- * Legacy Shape ID that is unique throughout the entire document.
- * Legacy shape IDs should be assigned based on which portion of the document the
- * drawing resides on. The assignment of these ids is broken down into clusters of
- * 1024 values. The first cluster is 1-1024, the second 1025-2048 and so on.
- *
- * Ole shapes seem to start with 1025 on the first sheet ...
- * and not sure, if the ids need to be reindexed when sheets are removed
- * or more than 1024 shapes are on a given sheet (see #51332 for a similar issue)
- */
- XSSFSheet sheet = getSheet();
- XSSFWorkbook wb = sheet.getWorkbook();
- int sheetIndex = wb.getSheetIndex(sheet);
- long shapeId = (sheetIndex+1)*1024 + 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);
- cNvPr.setName("Object "+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.
- */
- public List<XSSFChart> getCharts() {
- List<XSSFChart> charts = new ArrayList<>();
- for(POIXMLDocumentPart part : getRelations()) {
- if(part instanceof XSSFChart) {
- charts.add((XSSFChart)part);
- }
- }
- return charts;
- }
-
- /**
- * Create and initialize a CTTwoCellAnchor that anchors a shape against top-left and bottom-right cells.
- *
- * @return a new CTTwoCellAnchor
- */
- private CTTwoCellAnchor createTwoCellAnchor(XSSFClientAnchor anchor) {
- CTTwoCellAnchor ctAnchor = drawing.addNewTwoCellAnchor();
- ctAnchor.setFrom(anchor.getFrom());
- ctAnchor.setTo(anchor.getTo());
- ctAnchor.addNewClientData();
- anchor.setTo(ctAnchor.getTo());
- anchor.setFrom(ctAnchor.getFrom());
- STEditAs.Enum aditAs;
- switch(anchor.getAnchorType()) {
- case DONT_MOVE_AND_RESIZE: aditAs = STEditAs.ABSOLUTE; break;
- case MOVE_AND_RESIZE: aditAs = STEditAs.TWO_CELL; break;
- case MOVE_DONT_RESIZE: aditAs = STEditAs.ONE_CELL; break;
- default: aditAs = STEditAs.ONE_CELL;
- }
- ctAnchor.setEditAs(aditAs);
- return ctAnchor;
- }
-
- private CTTransform2D createXfrm(XSSFClientAnchor anchor) {
- CTTransform2D xfrm = CTTransform2D.Factory.newInstance();
- CTPoint2D off = xfrm.addNewOff();
- off.setX(anchor.getDx1());
- off.setY(anchor.getDy1());
- XSSFSheet sheet = getSheet();
- double widthPx = 0;
- for (int col=anchor.getCol1(); col<anchor.getCol2(); col++) {
- widthPx += sheet.getColumnWidthInPixels(col);
- }
- double heightPx = 0;
- for (int row=anchor.getRow1(); row<anchor.getRow2(); row++) {
- heightPx += ImageUtils.getRowHeightInPixels(sheet, row);
- }
- long width = Units.pixelToEMU((int)widthPx);
- long height = Units.pixelToEMU((int)heightPx);
- 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 1+
- drawing.sizeOfAbsoluteAnchorArray()+
- drawing.sizeOfOneCellAnchorArray()+
- drawing.sizeOfTwoCellAnchorArray();
- }
-
- /**
- * @return list of shapes in this drawing
- */
- public List<XSSFShape> getShapes(){
- List<XSSFShape> lst = new ArrayList<>();
- XmlCursor cur = drawing.newCursor();
- try {
- if (cur.toFirstChild()) {
- addShapes(cur, lst);
- }
- } finally {
- cur.dispose();
- }
- return lst;
- }
-
- /**
- * @return list of shapes in this shape group
- */
- public List<XSSFShape> getShapes(XSSFShapeGroup groupshape){
- List<XSSFShape> lst = new ArrayList<>();
- XmlCursor cur = groupshape.getCTGroupShape().newCursor();
- try {
- addShapes(cur, lst);
- } finally {
- cur.dispose();
- }
- return lst;
- }
-
- private void addShapes(XmlCursor cur, List<XSSFShape> lst) {
- try {
- do {
- cur.push();
- if (cur.toFirstChild()) {
- do {
- XmlObject obj = cur.getObject();
-
- XSSFShape shape;
- if (obj instanceof CTMarker) {
- // ignore anchor elements
- continue;
- } else if (obj instanceof CTPicture) {
- shape = new XSSFPicture(this, (CTPicture)obj) ;
- } else if(obj instanceof CTConnector) {
- shape = new XSSFConnector(this, (CTConnector)obj) ;
- } else if(obj instanceof CTShape) {
- shape = hasOleLink(obj)
- ? new XSSFObjectData(this, (CTShape)obj)
- : new XSSFSimpleShape(this, (CTShape)obj) ;
- } else if(obj instanceof CTGraphicalObjectFrame) {
- shape = new XSSFGraphicFrame(this, (CTGraphicalObjectFrame)obj) ;
- } else if(obj instanceof CTGroupShape) {
- shape = new XSSFShapeGroup(this, (CTGroupShape)obj) ;
- } else if(obj instanceof XmlAnyTypeImpl) {
- LOG.log(POILogger.WARN, "trying to parse AlternateContent, "
- + "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();
- XmlCursor cur2 = null;
- try {
- // need to parse AlternateContent again, otherwise the child elements aren't typed,
- // but also XmlAnyTypes
- CTDrawing alterWS = CTDrawing.Factory.parse(cur.newXMLStreamReader());
- cur2 = alterWS.newCursor();
- if (cur2.toFirstChild()) {
- addShapes(cur2, lst);
- }
- } catch (XmlException e) {
- LOG.log(POILogger.WARN, "unable to parse CTDrawing in alternate content.", e);
- } finally {
- if (cur2 != null) {
- cur2.dispose();
- }
- cur.pop();
- }
- continue;
- } else {
- // ignore anything else
- continue;
- }
-
- assert(shape != null);
- shape.anchor = getAnchorFromParent(obj);
- lst.add(shape);
-
- } while (cur.toNextSibling());
- }
- cur.pop();
- } while (cur.toNextSibling());
- } finally {
- cur.dispose();
- }
- }
-
- private boolean hasOleLink(XmlObject shape) {
- QName uriName = new QName(null, "uri");
- String xquery = "declare namespace a='"+XSSFRelation.NS_DRAWINGML+"' .//a:extLst/a:ext";
- XmlCursor cur = shape.newCursor();
- cur.selectPath(xquery);
- try {
- while (cur.toNextSelection()) {
- String uri = cur.getAttributeText(uriName);
- if ("{63B3BB69-23CF-44E3-9099-C40C66FF867C}".equals(uri)) {
- return true;
- }
- }
- } finally {
- cur.dispose();
- }
- return false;
- }
-
- private XSSFAnchor getAnchorFromParent(XmlObject obj){
- XSSFAnchor anchor = null;
-
- XmlObject parentXbean = null;
- XmlCursor cursor = obj.newCursor();
- if(cursor.toParent()) {
- parentXbean = cursor.getObject();
- }
- cursor.dispose();
- if(parentXbean != null){
- if (parentXbean instanceof CTTwoCellAnchor) {
- CTTwoCellAnchor ct = (CTTwoCellAnchor)parentXbean;
- anchor = new XSSFClientAnchor(ct.getFrom(), ct.getTo());
- } else if (parentXbean instanceof CTOneCellAnchor) {
- CTOneCellAnchor ct = (CTOneCellAnchor)parentXbean;
- anchor = new XSSFClientAnchor(getSheet(), ct.getFrom(), ct.getExt());
- } else if (parentXbean instanceof CTAbsoluteAnchor) {
- CTAbsoluteAnchor ct = (CTAbsoluteAnchor) parentXbean;
- anchor = new XSSFClientAnchor(getSheet(), ct.getPos(), ct.getExt());
- }
- }
- return anchor;
- }
-
- @Override
- public Iterator<XSSFShape> iterator() {
- return getShapes().iterator();
- }
-
- /**
- * @return the sheet associated with the drawing
- */
- public XSSFSheet getSheet() {
- return (XSSFSheet)getParent();
- }
-
- }
|