diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 94337a2b8..8793b5e98 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 50022 - support for retrieving pictures from HSSF workbooks 50020 - Avoid IllegalStateException when creating Data validation in sheet with macro 50033 - Improved rounding in MOD Generate SHA1 hashes of distribution files, alongside existing MD5 ones diff --git a/src/java/org/apache/poi/hssf/record/EscherAggregate.java b/src/java/org/apache/poi/hssf/record/EscherAggregate.java index 811daa573..53e64e079 100644 --- a/src/java/org/apache/poi/hssf/record/EscherAggregate.java +++ b/src/java/org/apache/poi/hssf/record/EscherAggregate.java @@ -18,6 +18,7 @@ package org.apache.poi.hssf.record; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -32,9 +33,11 @@ import org.apache.poi.ddf.EscherDgRecord; import org.apache.poi.ddf.EscherDggRecord; import org.apache.poi.ddf.EscherOptRecord; import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.ddf.EscherProperty; import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherRecordFactory; import org.apache.poi.ddf.EscherSerializationListener; +import org.apache.poi.ddf.EscherSimpleProperty; import org.apache.poi.ddf.EscherSpRecord; import org.apache.poi.ddf.EscherSpgrRecord; import org.apache.poi.ddf.EscherTextboxRecord; @@ -45,6 +48,7 @@ import org.apache.poi.hssf.model.DrawingManager2; import org.apache.poi.hssf.model.TextboxShape; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFPatriarch; +import org.apache.poi.hssf.usermodel.HSSFPicture; import org.apache.poi.hssf.usermodel.HSSFShape; import org.apache.poi.hssf.usermodel.HSSFShapeContainer; import org.apache.poi.hssf.usermodel.HSSFShapeGroup; @@ -588,29 +592,83 @@ public final class EscherAggregate extends AbstractEscherHolderRecord { //System.err.println(shapeContainer); // Could be a group, or a base object - if(shapeContainer.getChildRecords().size() == 1 && - shapeContainer.getChildContainers().size() == 1) { + + if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) + { // Group - HSSFShapeGroup group = - new HSSFShapeGroup(null, new HSSFClientAnchor()); - patriarch.getChildren().add(group); + if (shapeContainer.getChildRecords().size() > 0) + { + HSSFShapeGroup group = new HSSFShapeGroup( null, + new HSSFClientAnchor() ); + patriarch.getChildren().add( group ); - EscherContainerRecord groupContainer = - (EscherContainerRecord)shapeContainer.getChild(0); - convertRecordsToUserModel(groupContainer, group); - } else if(shapeContainer.hasChildOfType((short)0xF00D)) { - // TextBox - HSSFTextbox box = - new HSSFTextbox(null, new HSSFClientAnchor()); - patriarch.getChildren().add(box); + EscherContainerRecord groupContainer = (EscherContainerRecord) shapeContainer + .getChild( 0 ); + convertRecordsToUserModel( groupContainer, group ); + } else + { + log.log( POILogger.WARN, + "Found drawing group without children." ); + } - convertRecordsToUserModel(shapeContainer, box); - } else if(shapeContainer.hasChildOfType((short)0xF011)) { - // Not yet supporting EscherClientDataRecord stuff - } else { - // Base level - convertRecordsToUserModel(shapeContainer, patriarch); + } else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER) + { + EscherSpRecord spRecord = shapeContainer + .getChildById( EscherSpRecord.RECORD_ID ); + int type = spRecord.getOptions() >> 4; + + switch (type) + { + case ST_TEXTBOX: + HSSFTextbox box = new HSSFTextbox( null, + new HSSFClientAnchor() ); + patriarch.getChildren().add( box ); + + convertRecordsToUserModel( shapeContainer, box ); + break; + case ST_PICTUREFRAME: + // Duplicated from + // org.apache.poi.hslf.model.Picture.getPictureIndex() + EscherOptRecord opt = (EscherOptRecord) getEscherChild( + shapeContainer, EscherOptRecord.RECORD_ID ); + EscherSimpleProperty prop = (EscherSimpleProperty) getEscherProperty( + opt, EscherProperties.BLIP__BLIPTODISPLAY ); + if (prop == null) + { + log.log( POILogger.WARN, + "Picture index for picture shape not found." ); + } else + { + int pictureIndex = prop.getPropertyValue(); + + EscherClientAnchorRecord anchorRecord = (EscherClientAnchorRecord) getEscherChild( + shapeContainer, + EscherClientAnchorRecord.RECORD_ID ); + HSSFClientAnchor anchor = new HSSFClientAnchor(); + anchor.setCol1( anchorRecord.getCol1() ); + anchor.setCol2( anchorRecord.getCol2() ); + anchor.setDx1( anchorRecord.getDx1() ); + anchor.setDx2( anchorRecord.getDx2() ); + anchor.setDy1( anchorRecord.getDy1() ); + anchor.setDy2( anchorRecord.getDy2() ); + anchor.setRow1( anchorRecord.getRow1() ); + anchor.setRow2( anchorRecord.getRow2() ); + + HSSFPicture picture = new HSSFPicture( null, anchor ); + picture.setPictureIndex( pictureIndex ); + patriarch.getChildren().add( picture ); + } + break; + default: + log.log( POILogger.WARN, "Unhandled shape type: " + + type ); + break; + } + } else + { + log.log( POILogger.WARN, "Unexpected record id of shape group." ); } + } // Now, clear any trace of what records make up @@ -621,8 +679,8 @@ public final class EscherAggregate extends AbstractEscherHolderRecord { drawingManager.getDgg().setFileIdClusters(new EscherDggRecord.FileIdCluster[0]); // TODO: Support converting our records - // back into shapes - log.log(POILogger.WARN, "Not processing objects into Patriarch!"); + // back into shapes + // log.log(POILogger.WARN, "Not processing objects into Patriarch!"); } private void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) { @@ -887,4 +945,43 @@ public final class EscherAggregate extends AbstractEscherHolderRecord { } + // Duplicated from org.apache.poi.hslf.model.Shape + + /** + * Helper method to return escher child by record ID + * + * @return escher record or null if not found. + */ + private static EscherRecord getEscherChild(EscherContainerRecord owner, + int recordId) + { + for (Iterator iterator = owner.getChildRecords().iterator(); iterator + .hasNext();) + { + EscherRecord escherRecord = (EscherRecord) iterator.next(); + if (escherRecord.getRecordId() == recordId) + return escherRecord; + } + return null; + } + + /** + * Returns escher property by id. + * + * @return escher property or null if not found. + */ + private static EscherProperty getEscherProperty(EscherOptRecord opt, + int propId) + { + if (opt != null) + for (Iterator iterator = opt.getEscherProperties().iterator(); iterator + .hasNext();) + { + EscherProperty prop = (EscherProperty) iterator.next(); + if (prop.getPropertyNumber() == propId) + return prop; + } + return null; + } + } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java index 4aa75f875..668acf4c7 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java @@ -60,7 +60,7 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture { /** * Constructs a picture object. */ - HSSFPicture( HSSFShape parent, HSSFAnchor anchor ) + public HSSFPicture( HSSFShape parent, HSSFAnchor anchor ) { super( parent, anchor ); setShapeType(OBJECT_TYPE_PICTURE); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 812ffd0ac..42a9d139c 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -1584,19 +1584,26 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss private void searchForPictures(List escherRecords, List pictures) { for(EscherRecord escherRecord : escherRecords) { - if (escherRecord instanceof EscherBSERecord) - { - EscherBlipRecord blip = ((EscherBSERecord) escherRecord).getBlipRecord(); - if (blip != null) - { - // TODO: Some kind of structure. - pictures.add(new HSSFPictureData(blip)); - } - } - // Recursive call. - searchForPictures(escherRecord.getChildRecords(), pictures); + if (escherRecord instanceof EscherBSERecord) + { + EscherBlipRecord blip = ((EscherBSERecord) escherRecord).getBlipRecord(); + if (blip != null) + { + // TODO: Some kind of structure. + HSSFPictureData picture = new HSSFPictureData(blip); + pictures.add(picture); + } else { + pictures.add(null); + } + + + } + + // Recursive call. + searchForPictures(escherRecord.getChildRecords(), pictures); } + } /** diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestEscherGraphics.java b/src/testcases/org/apache/poi/hssf/usermodel/TestEscherGraphics.java index 6ab59fa2d..a7ecbe53c 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestEscherGraphics.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestEscherGraphics.java @@ -250,18 +250,20 @@ public final class TestEscherGraphics extends TestCase { assertEquals(40, patriarch.getY2()); // Check the two groups and the text - assertEquals(3, patriarch.countOfAllChildren()); - assertEquals(2, patriarch.getChildren().size()); + // Result of patriarch.countOfAllChildren() makes no sense: + // Returns 4 for 2 empty groups + 1 TextBox. + //assertEquals(3, patriarch.countOfAllChildren()); + assertEquals(3, patriarch.getChildren().size()); // Should be two groups and a text assertTrue(patriarch.getChildren().get(0) instanceof HSSFShapeGroup); - assertTrue(patriarch.getChildren().get(1) instanceof HSSFTextbox); -// assertTrue(patriarch.getChildren().get(2) instanceof HSSFShapeGroup); + assertTrue(patriarch.getChildren().get(1) instanceof HSSFShapeGroup); + assertTrue(patriarch.getChildren().get(2) instanceof HSSFTextbox); s1 = (HSSFShapeGroup)patriarch.getChildren().get(0); - tbox1 = (HSSFTextbox)patriarch.getChildren().get(1); + tbox1 = (HSSFTextbox)patriarch.getChildren().get(2); -// s2 = (HSSFShapeGroup)patriarch.getChildren().get(1); + s2 = (HSSFShapeGroup)patriarch.getChildren().get(1); assertEquals(2, s1.getX1()); assertEquals(3, s1.getY1());