<changes>
<release version="3.8-beta4" date="2011-??-??">
+ <action dev="poi-developers" type="add">Support for appending images to existing drawings in HSSF</action>
<action dev="poi-developers" type="fix">Added initial support for bookmarks in HWFP</action>
<action dev="poi-developers" type="fix">46250 - Fixed cloning worksheets with images</action>
<action dev="poi-developers" type="fix">51524 - PapBinTable constructor is slow (regression)</action>
/**
* Finds the primary drawing group, if one already exists
*/
- public void findDrawingGroup() {
+ public DrawingManager2 findDrawingGroup() {
if(drawingManager != null) {
// We already have it!
- return;
+ return drawingManager;
}
// Need to find a DrawingGroupRecord that
if(bs instanceof EscherBSERecord) escherBSERecords.add((EscherBSERecord)bs);
}
}
- return;
+ return drawingManager;
}
}
}
}
}
}
+ return drawingManager;
}
/**
}
private void convertToEscherRecords( int offset, int size, byte[] data )
{
+ escherRecords.clear();
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
int pos = offset;
while ( pos < offset + size )
import org.apache.poi.hssf.usermodel.HSSFShapeContainer;
import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
import org.apache.poi.hssf.usermodel.HSSFTextbox;
+import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
case ST_TEXTBOX:
HSSFTextbox box = new HSSFTextbox( null,
new HSSFClientAnchor() );
- patriarch.getChildren().add( box );
+ patriarch.addShape( box );
convertRecordsToUserModel( shapeContainer, box );
break;
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() );
+ HSSFClientAnchor anchor = toClientAnchor(anchorRecord);
HSSFPicture picture = new HSSFPicture( null, anchor );
picture.setPictureIndex( pictureIndex );
- patriarch.getChildren().add( picture );
+ patriarch.addShape( picture );
}
break;
default:
// log.log(POILogger.WARN, "Not processing objects into Patriarch!");
}
+ private HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord){
+ HSSFClientAnchor anchor = new HSSFClientAnchor();
+ anchor.setAnchorType(anchorRecord.getFlag());
+ 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() );
+ return anchor;
+ }
+
private void convertRecordsToUserModel(EscherContainerRecord shapeContainer, Object model) {
for(Iterator<EscherRecord> it = shapeContainer.getChildIterator(); it.hasNext();) {
EscherRecord r = it.next();
import org.apache.poi.ddf.EscherComplexProperty;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperty;
+import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.ss.usermodel.Chart;
import org.apache.poi.util.StringUtil;
+import org.apache.poi.util.Internal;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.ClientAnchor;
{
HSSFShapeGroup group = new HSSFShapeGroup(null, anchor);
group.anchor = anchor;
- _shapes.add(group);
+ addShape(group);
return group;
}
{
HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
shape.anchor = anchor;
- _shapes.add(shape);
+ addShape(shape);
return shape;
}
HSSFPicture shape = new HSSFPicture(null, anchor);
shape.setPictureIndex( pictureIndex );
shape.anchor = anchor;
- shape._patriarch = this;
- _shapes.add(shape);
+ addShape(shape);
+
+ EscherBSERecord bse = _sheet.getWorkbook().getWorkbook().getBSERecord(pictureIndex);
+ bse.setRef(bse.getRef() + 1);
return shape;
}
+
public HSSFPicture createPicture(ClientAnchor anchor, int pictureIndex)
{
return createPicture((HSSFClientAnchor)anchor, pictureIndex);
{
HSSFPolygon shape = new HSSFPolygon(null, anchor);
shape.anchor = anchor;
- _shapes.add(shape);
+ addShape(shape);
return shape;
}
{
HSSFTextbox shape = new HSSFTextbox(null, anchor);
shape.anchor = anchor;
- _shapes.add(shape);
+ addShape(shape);
return shape;
}
{
HSSFComment shape = new HSSFComment(null, anchor);
shape.anchor = anchor;
- _shapes.add(shape);
+ addShape(shape);
return shape;
}
HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_COMBO_BOX);
shape.anchor = anchor;
- _shapes.add(shape);
+ addShape(shape);
return shape;
}
return _shapes;
}
+ /**
+ * add a shape to this drawing
+ */
+ @Internal
+ public void addShape(HSSFShape shape){
+ shape._patriarch = this;
+ _shapes.add(shape);
+ }
+
/**
* Total count of all children and their children's children.
*/
import java.io.ByteArrayInputStream;
import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherBlipRecord;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.util.ImageUtils;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.poi.hssf.model.InternalWorkbook;
/**
* Represents a escher picture. Eg. A GIF, JPEG etc...
private static final int PX_ROW = 15;
private int _pictureIndex;
- HSSFPatriarch _patriarch; // TODO make private
/**
* Constructs a picture object.
int type = bse.getBlipTypeWin32();
return ImageUtils.getImageDimension(new ByteArrayInputStream(data), type);
}
+
+ /**
+ * Return picture data for this shape
+ *
+ * @return picture data for this shape
+ */
+ public HSSFPictureData getPictureData(){
+ InternalWorkbook iwb = _patriarch._sheet.getWorkbook().getWorkbook();
+ EscherBlipRecord blipRecord = iwb.getBSERecord(_pictureIndex).getBlipRecord();
+ return new HSSFPictureData(blipRecord);
+ }
}
// TODO - make all these fields private
final HSSFShape parent;
HSSFAnchor anchor;
+ HSSFPatriarch _patriarch;
private int _lineStyleColor = 0x08000040;
int _fillColor = 0x08000009;
private int _lineWidth = LINEWIDTH_DEFAULT; // 12700 = 1pt
public HSSFPatriarch createDrawingPatriarch() {
if(_patriarch == null){
// Create the drawing group if it doesn't already exist.
- _book.createDrawingGroup();
-
- _sheet.aggregateDrawingRecords(_book.getDrawingManager(), true);
- EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
- _patriarch = new HSSFPatriarch(this, agg);
- agg.clear(); // Initially the behaviour will be to clear out any existing shapes in the sheet when
- // creating a new patriarch.
- agg.setPatriarch(_patriarch);
+ _workbook.initDrawings();
+
+ if(_patriarch == null){
+ _sheet.aggregateDrawingRecords(_book.getDrawingManager(), true);
+ EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
+ _patriarch = new HSSFPatriarch(this, agg);
+ agg.setPatriarch(_patriarch);
+ }
}
return _patriarch;
}
int shapeType = OBJECT_TYPE_LINE;
- HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
+ public HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
{
super( parent, anchor );
}
import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.model.DrawingManager2;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.record.common.UnicodeString;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.commons.codec.digest.DigestUtils;
/**
/**
* Set the sheet name.
*
- * @param sheet number (0 based)
+ * @param sheetIx number (0 based)
* @throws IllegalArgumentException if the name is null or invalid
* or workbook already contains a sheet with this name
* @see {@link #createSheet(String)}
w.flush();
}
+ void initDrawings(){
+ DrawingManager2 mgr = workbook.findDrawingGroup();
+ if(mgr != null) {
+ for(int i=0; i < getNumberOfSheets(); i++) {
+ getSheetAt(i).getDrawingPatriarch();
+ }
+ } else {
+ workbook.createDrawingGroup();
+ }
+ }
+
/**
* Adds a picture to the workbook.
*
*/
public int addPicture(byte[] pictureData, int format)
{
- byte[] uid = newUID();
+ initDrawings();
+
+ byte[] uid = DigestUtils.md5(pictureData);
EscherBitmapBlip blipRecord = new EscherBitmapBlip();
blipRecord.setRecordId( (short) ( EscherBitmapBlip.RECORD_ID_START + format ) );
switch (format)
return new HSSFCreationHelper(this);
}
- private static byte[] newUID() {
- return new byte[16];
- }
-
/**
*
* Returns the locator of user-defined functions.
void resize(double scale);
ClientAnchor getPreferredSize();
+
+ /**
+ * Return picture data for this picture
+ *
+ * @return picture data for this picture
+ */
+ PictureData getPictureData();
}
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.ss.usermodel.BaseTestPicture;
+import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.ss.usermodel.Workbook;
+
+import java.util.Arrays;
+import java.util.List;
/**
* Test <code>HSSFPicture</code>.
HSSFPicture pic = p1.createPicture(new HSSFClientAnchor(), idx1);
pic.resize();
}
+
+
+ public void testAddPictures(){
+ HSSFWorkbook wb = new HSSFWorkbook();
+
+ HSSFSheet sh = wb.createSheet("Pictures");
+ HSSFPatriarch dr = sh.createDrawingPatriarch();
+ assertEquals(0, dr.getChildren().size());
+ HSSFClientAnchor anchor = wb.getCreationHelper().createClientAnchor();
+
+ //register a picture
+ byte[] data1 = new byte[]{1, 2, 3};
+ int idx1 = wb.addPicture(data1, Workbook.PICTURE_TYPE_JPEG);
+ assertEquals(1, idx1);
+ HSSFPicture p1 = dr.createPicture(anchor, idx1);
+ assertTrue(Arrays.equals(data1, p1.getPictureData().getData()));
+
+ // register another one
+ byte[] data2 = new byte[]{4, 5, 6};
+ int idx2 = wb.addPicture(data2, Workbook.PICTURE_TYPE_JPEG);
+ assertEquals(2, idx2);
+ HSSFPicture p2 = dr.createPicture(anchor, idx2);
+ assertEquals(2, dr.getChildren().size());
+ assertTrue(Arrays.equals(data2, p2.getPictureData().getData()));
+
+ // confirm that HSSFPatriarch.getChildren() returns two picture shapes
+ assertTrue(Arrays.equals(data1, ((HSSFPicture)dr.getChildren().get(0)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data2, ((HSSFPicture)dr.getChildren().get(1)).getPictureData().getData()));
+
+ // write, read back and verify that our pictures are there
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
+ List<? extends PictureData> lst2 = wb.getAllPictures();
+ assertEquals(2, lst2.size());
+ assertTrue(Arrays.equals(data1, lst2.get(0).getData()));
+ assertTrue(Arrays.equals(data2, lst2.get(1).getData()));
+
+ // confirm that the pictures are in the Sheet's drawing
+ sh = wb.getSheet("Pictures");
+ dr = sh.createDrawingPatriarch();
+ assertEquals(2, dr.getChildren().size());
+ assertTrue(Arrays.equals(data1, ((HSSFPicture)dr.getChildren().get(0)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data2, ((HSSFPicture)dr.getChildren().get(1)).getPictureData().getData()));
+
+ // add a third picture
+ byte[] data3 = new byte[]{7, 8, 9};
+ // picture index must increment across write-read
+ int idx3 = wb.addPicture(data3, Workbook.PICTURE_TYPE_JPEG);
+ assertEquals(3, idx3);
+ HSSFPicture p3 = dr.createPicture(anchor, idx3);
+ assertTrue(Arrays.equals(data3, p3.getPictureData().getData()));
+ assertEquals(3, dr.getChildren().size());
+ assertTrue(Arrays.equals(data1, ((HSSFPicture)dr.getChildren().get(0)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data2, ((HSSFPicture)dr.getChildren().get(1)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data3, ((HSSFPicture)dr.getChildren().get(2)).getPictureData().getData()));
+
+ // write and read again
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
+ List<? extends PictureData> lst3 = wb.getAllPictures();
+ // all three should be there
+ assertEquals(3, lst3.size());
+ assertTrue(Arrays.equals(data1, lst3.get(0).getData()));
+ assertTrue(Arrays.equals(data2, lst3.get(1).getData()));
+ assertTrue(Arrays.equals(data3, lst3.get(2).getData()));
+
+ sh = wb.getSheet("Pictures");
+ dr = sh.createDrawingPatriarch();
+ assertEquals(3, dr.getChildren().size());
+
+ // forth picture
+ byte[] data4 = new byte[]{10, 11, 12};
+ int idx4 = wb.addPicture(data4, Workbook.PICTURE_TYPE_JPEG);
+ assertEquals(4, idx4);
+ dr.createPicture(anchor, idx4);
+ assertEquals(4, dr.getChildren().size());
+ assertTrue(Arrays.equals(data1, ((HSSFPicture)dr.getChildren().get(0)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data2, ((HSSFPicture)dr.getChildren().get(1)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data3, ((HSSFPicture)dr.getChildren().get(2)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data4, ((HSSFPicture)dr.getChildren().get(3)).getPictureData().getData()));
+
+ wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
+ List<? extends PictureData> lst4 = wb.getAllPictures();
+ assertEquals(4, lst4.size());
+ assertTrue(Arrays.equals(data1, lst4.get(0).getData()));
+ assertTrue(Arrays.equals(data2, lst4.get(1).getData()));
+ assertTrue(Arrays.equals(data3, lst4.get(2).getData()));
+ assertTrue(Arrays.equals(data4, lst4.get(3).getData()));
+ sh = wb.getSheet("Pictures");
+ dr = sh.createDrawingPatriarch();
+ assertEquals(4, dr.getChildren().size());
+ assertTrue(Arrays.equals(data1, ((HSSFPicture)dr.getChildren().get(0)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data2, ((HSSFPicture)dr.getChildren().get(1)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data3, ((HSSFPicture)dr.getChildren().get(2)).getPictureData().getData()));
+ assertTrue(Arrays.equals(data4, ((HSSFPicture)dr.getChildren().get(3)).getPictureData().getData()));
+ }
+
}