#60996 - XSSF: Multiple embedded objects on same sheet are ignored
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1791644 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3d53258942
commit
bd237e2483
@ -263,4 +263,9 @@ public class HSSFSimpleShape extends HSSFShape implements SimpleShape
|
|||||||
}
|
}
|
||||||
return _textObjectRecord;
|
return _textObjectRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getShapeId(){
|
||||||
|
return super.getShapeId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,14 @@ package org.apache.poi.ss.usermodel;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A common interface for simple shapes.
|
* A common interface for simple shapes.
|
||||||
* (Currently the HSSF and XSSF classes don't share common method signatures ...)
|
|
||||||
*
|
*
|
||||||
* @since POI 3.16-beta2
|
* @since POI 3.16-beta2
|
||||||
*/
|
*/
|
||||||
public interface SimpleShape extends Shape {
|
public interface SimpleShape extends Shape {
|
||||||
|
/**
|
||||||
|
* @return the shape id, which is unique within the sheet
|
||||||
|
*
|
||||||
|
* @since POI 3.17-beta1
|
||||||
|
*/
|
||||||
|
int getShapeId();
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,24 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
|||||||
public XSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
|
public XSSFObjectData createObjectData(ClientAnchor anchor, int storageId, int pictureIndex) {
|
||||||
XSSFSheet sh = getSheet();
|
XSSFSheet sh = getSheet();
|
||||||
PackagePart sheetPart = sh.getPackagePart();
|
PackagePart sheetPart = sh.getPackagePart();
|
||||||
long shapeId = newShapeId();
|
|
||||||
|
/*
|
||||||
|
* 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
|
// add reference to OLE part
|
||||||
PackagePartName olePN;
|
PackagePartName olePN;
|
||||||
@ -446,6 +463,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
|||||||
|
|
||||||
CTNonVisualDrawingProps cNvPr = ctShape.getNvSpPr().getCNvPr();
|
CTNonVisualDrawingProps cNvPr = ctShape.getNvSpPr().getCNvPr();
|
||||||
cNvPr.setId(shapeId);
|
cNvPr.setId(shapeId);
|
||||||
|
cNvPr.setName("Object "+shapeId);
|
||||||
|
|
||||||
XmlCursor extCur = cNvPr.getExtLst().getExtArray(0).newCursor();
|
XmlCursor extCur = cNvPr.getExtLst().getExtArray(0).newCursor();
|
||||||
extCur.toFirstChild();
|
extCur.toFirstChild();
|
||||||
@ -520,7 +538,10 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing<XSS
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long newShapeId(){
|
private long newShapeId(){
|
||||||
return drawing.sizeOfTwoCellAnchorArray() + 1;
|
return 1+
|
||||||
|
drawing.sizeOfAbsoluteAnchorArray()+
|
||||||
|
drawing.sizeOfOneCellAnchorArray()+
|
||||||
|
drawing.sizeOfTwoCellAnchorArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,7 +210,7 @@ public class XSSFObjectData extends XSSFSimpleShape implements ObjectData {
|
|||||||
try {
|
try {
|
||||||
if (cur.toChild(XSSFRelation.NS_SPREADSHEETML, "objectPr")) {
|
if (cur.toChild(XSSFRelation.NS_SPREADSHEETML, "objectPr")) {
|
||||||
String blipId = cur.getAttributeText(new QName(PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS, "id"));
|
String blipId = cur.getAttributeText(new QName(PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS, "id"));
|
||||||
return (XSSFPictureData)getDrawing().getRelationById(blipId);
|
return (XSSFPictureData)getSheet().getRelationById(blipId);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -869,4 +869,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
|
|||||||
public String getShapeName() {
|
public String getShapeName() {
|
||||||
return ctShape.getNvSpPr().getCNvPr().getName();
|
return ctShape.getNvSpPr().getCNvPr().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getShapeId() {
|
||||||
|
return (int)ctShape.getNvSpPr().getCNvPr().getId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,20 @@
|
|||||||
package org.apache.poi.ss.usermodel;
|
package org.apache.poi.ss.usermodel;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||||
import org.apache.poi.sl.usermodel.AutoShape;
|
import org.apache.poi.sl.usermodel.AutoShape;
|
||||||
import org.apache.poi.sl.usermodel.ShapeType;
|
import org.apache.poi.sl.usermodel.ShapeType;
|
||||||
import org.apache.poi.sl.usermodel.Slide;
|
import org.apache.poi.sl.usermodel.Slide;
|
||||||
@ -36,29 +41,26 @@ import org.apache.poi.ss.extractor.EmbeddedExtractor;
|
|||||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TestEmbedOLEPackage {
|
public class TestEmbedOLEPackage {
|
||||||
|
private static byte[] samplePPT, samplePPTX, samplePNG;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void init() throws IOException {
|
||||||
|
samplePPT = getSamplePPT(false);
|
||||||
|
samplePPTX = getSamplePPT(true);
|
||||||
|
samplePNG = POIDataSamples.getSpreadSheetInstance().readFile("logoKarmokar4.png");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void embedXSSF() throws IOException {
|
public void embedXSSF() throws IOException {
|
||||||
Workbook wb1 = new XSSFWorkbook();
|
Workbook wb1 = new XSSFWorkbook();
|
||||||
Sheet sh = wb1.createSheet();
|
addEmbeddedObjects(wb1);
|
||||||
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);
|
Workbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb1);
|
||||||
|
validateEmbeddedObjects(wb2);
|
||||||
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();
|
wb2.close();
|
||||||
wb1.close();
|
wb1.close();
|
||||||
@ -73,30 +75,53 @@ public class TestEmbedOLEPackage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Workbook wb1 = new HSSFWorkbook();
|
Workbook wb1 = new HSSFWorkbook();
|
||||||
Sheet sh = wb1.createSheet();
|
addEmbeddedObjects(wb1);
|
||||||
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);
|
Workbook wb2 = HSSFTestDataSamples.writeOutAndReadBack((HSSFWorkbook)wb1);
|
||||||
|
validateEmbeddedObjects(wb2);
|
||||||
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();
|
wb2.close();
|
||||||
wb1.close();
|
wb1.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] getSamplePng() {
|
static void validateEmbeddedObjects(Workbook wb) throws IOException {
|
||||||
return POIDataSamples.getSpreadSheetInstance().readFile("logoKarmokar4.png");
|
boolean ooxml = wb.getClass().getName().toLowerCase().contains("xssf");
|
||||||
|
byte data[] = (ooxml) ? samplePPTX : samplePPT;
|
||||||
|
Iterator<Integer> shapeIds = Arrays.asList(1025,1026,2049).iterator();
|
||||||
|
EmbeddedExtractor ee = new EmbeddedExtractor();
|
||||||
|
for (Sheet sheet : wb) {
|
||||||
|
Drawing<? extends Shape> pat = sheet.getDrawingPatriarch();
|
||||||
|
for (Shape shape : pat) {
|
||||||
|
assertTrue(shape instanceof ObjectData);
|
||||||
|
ObjectData od = (ObjectData)shape;
|
||||||
|
EmbeddedData ed = ee.extractOne((DirectoryNode)od.getDirectory());
|
||||||
|
assertArrayEquals(data, ed.getEmbeddedData());
|
||||||
|
assertArrayEquals(samplePNG, od.getPictureData().getData());
|
||||||
|
assertEquals((int)shapeIds.next(), od.getShapeId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addEmbeddedObjects(Workbook wb) throws IOException {
|
||||||
|
boolean ooxml = wb.getClass().getName().toLowerCase().contains("xssf");
|
||||||
|
int picIdx = wb.addPicture(samplePNG, Workbook.PICTURE_TYPE_PNG);
|
||||||
|
byte data[] = (ooxml) ? samplePPTX : samplePPT;
|
||||||
|
String ext = (ooxml) ? ".pptx" : ".ppt";
|
||||||
|
|
||||||
|
int oleIdx1a = wb.addOlePackage(data, "dummy1a"+ext, "dummy1a"+ext, "dummy1a"+ext);
|
||||||
|
int oleIdx1b = wb.addOlePackage(data, "dummy1b"+ext, "dummy1b"+ext, "dummy1b"+ext);
|
||||||
|
int oleIdx2 = wb.addOlePackage(data, "dummy2"+ext, "dummy2"+ext, "dummy2"+ext);
|
||||||
|
|
||||||
|
Sheet sh1 = wb.createSheet();
|
||||||
|
Drawing<?> pat1 = sh1.createDrawingPatriarch();
|
||||||
|
ClientAnchor anchor1a = pat1.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
|
||||||
|
pat1.createObjectData(anchor1a, oleIdx1a, picIdx);
|
||||||
|
ClientAnchor anchor1b = pat1.createAnchor(0, 0, 0, 0, 1, 1+7, 3, 6+7);
|
||||||
|
pat1.createObjectData(anchor1b, oleIdx1b, picIdx);
|
||||||
|
|
||||||
|
Sheet sh2 = wb.createSheet();
|
||||||
|
Drawing<?> pat2 = sh2.createDrawingPatriarch();
|
||||||
|
ClientAnchor anchor2 = pat2.createAnchor(0, 0, 0, 0, 1, 1, 3, 6);
|
||||||
|
pat2.createObjectData(anchor2, oleIdx2, picIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] getSamplePPT(boolean ooxml) throws IOException {
|
static byte[] getSamplePPT(boolean ooxml) throws IOException {
|
||||||
|
Loading…
Reference in New Issue
Block a user