]> source.dussan.org Git - poi.git/commitdiff
Support for appending images to existing drawings in HSSF
authorYegor Kozlov <yegor@apache.org>
Wed, 20 Jul 2011 07:38:01 +0000 (07:38 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 20 Jul 2011 07:38:01 +0000 (07:38 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1148637 13f79535-47bb-0310-9956-ffa450edef68

12 files changed:
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/model/InternalWorkbook.java
src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java
src/java/org/apache/poi/hssf/record/EscherAggregate.java
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/java/org/apache/poi/ss/usermodel/Picture.java
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java

index 23fe366889db61051f9dea4734fdde1c3dba4e99..2452027a51d6ba8c3d191d0af91b0f93c2f8497c 100644 (file)
@@ -34,6 +34,7 @@
 
     <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>
index 2dbd877ab7d0cc36b202ff2a7c5b48daf78ae12c..93d37acc4d090c3aceb264b7c33c258579462781 100644 (file)
@@ -2055,10 +2055,10 @@ public final class InternalWorkbook {
     /**
      * 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
@@ -2092,7 +2092,7 @@ public final class InternalWorkbook {
                             if(bs instanceof EscherBSERecord) escherBSERecords.add((EscherBSERecord)bs);
                         }
                     }
-                    return;
+                    return drawingManager;
                 }
             }
         }
@@ -2122,6 +2122,7 @@ public final class InternalWorkbook {
                 }
             }
         }
+        return drawingManager;
     }
 
     /**
index 64ef36eafa67d7c1c8f20ca91e7c744930a4ba2d..78893e1aa7de0eb9a13d1cc7a3ba8579f635b8e9 100644 (file)
@@ -74,6 +74,7 @@ public abstract class AbstractEscherHolderRecord extends Record {
     }
     private void convertToEscherRecords( int offset, int size, byte[] data )
     {
+         escherRecords.clear();
         EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
         int pos = offset;
         while ( pos < offset + size )
index 577e4c67436c5ef8add440275e40ab3080264a12..50d5e5d3f3a34ab88d91796c4bfd7cfcdbf865bb 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.poi.hssf.usermodel.HSSFShape;
 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;
 
@@ -622,7 +623,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
                                case ST_TEXTBOX:
                                        HSSFTextbox box = new HSSFTextbox( null,
                                                        new HSSFClientAnchor() );
-                                       patriarch.getChildren().add( box );
+                                       patriarch.addShape( box );
 
                                        convertRecordsToUserModel( shapeContainer, box );
                                        break;
@@ -644,19 +645,11 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
                                                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:
@@ -683,6 +676,20 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
                // 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();
index 201b1c6d99317ff14254533609d5dc24f1431408..672f82cc734db4939d814ff3752e02fad93210fb 100644 (file)
@@ -24,9 +24,11 @@ import java.util.List;
 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;
 
@@ -72,7 +74,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
     {
         HSSFShapeGroup group = new HSSFShapeGroup(null, anchor);
         group.anchor = anchor;
-        _shapes.add(group);
+        addShape(group);
         return group;
     }
 
@@ -88,7 +90,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
     {
         HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
         shape.anchor = anchor;
-        _shapes.add(shape);
+        addShape(shape);
         return shape;
     }
 
@@ -104,10 +106,13 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
         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);
@@ -124,7 +129,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
     {
         HSSFPolygon shape = new HSSFPolygon(null, anchor);
         shape.anchor = anchor;
-        _shapes.add(shape);
+        addShape(shape);
         return shape;
     }
 
@@ -139,7 +144,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
     {
         HSSFTextbox shape = new HSSFTextbox(null, anchor);
         shape.anchor = anchor;
-        _shapes.add(shape);
+        addShape(shape);
         return shape;
     }
 
@@ -154,7 +159,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
     {
         HSSFComment shape = new HSSFComment(null, anchor);
         shape.anchor = anchor;
-        _shapes.add(shape);
+        addShape(shape);
         return shape;
     }
 
@@ -168,7 +173,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
          HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
          shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_COMBO_BOX);
          shape.anchor = anchor;
-         _shapes.add(shape);
+         addShape(shape);
          return shape;
      }
 
@@ -184,6 +189,15 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
         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.
      */
index 668acf4c795275aab5ec54c284ff725eaa4b60af..e89579fdbd4c5556fe429497f4cf594bffbd0d41 100644 (file)
@@ -21,10 +21,12 @@ import java.awt.Dimension;
 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...
@@ -55,7 +57,6 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
     private static final int PX_ROW = 15;
 
     private int _pictureIndex;
-    HSSFPatriarch _patriarch;  // TODO make private
 
     /**
      * Constructs a picture object.
@@ -221,4 +222,15 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
         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);
+    }
 }
index 62e7152fb897556d4352085f36efbdf30b59425e..3c586340fe096cfd434feb45183bad388041b5b8 100644 (file)
@@ -42,6 +42,7 @@ public abstract class HSSFShape {
     // 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
index 03d33749328e35833bfcf0198f6bf34cd7261cd3..7a821b78860ccc082c8150fb018ce13d8b821a2f 100644 (file)
@@ -1660,14 +1660,14 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
     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;
     }
index 0e4df4067208313c26a7babff4f6c15047eb69b3..ee8522929d51475c6bb8d2453db80d23c1775749 100644 (file)
@@ -52,7 +52,7 @@ public class HSSFSimpleShape
 
     int shapeType = OBJECT_TYPE_LINE;
 
-    HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
+    public HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
     {
         super( parent, anchor );
     }
index cb963ed33f25e9c6daa6ee5bc69ebbc47adca493..c0af3dda5475d925d9ee33f99d23f2ebada0b7b4 100644 (file)
@@ -39,6 +39,7 @@ import org.apache.poi.hssf.model.HSSFFormulaParser;
 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;
@@ -60,6 +61,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
 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;
 
 
 /**
@@ -542,7 +544,7 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
     /**
      * 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)}
@@ -1556,6 +1558,17 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
         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.
      *
@@ -1566,7 +1579,9 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
      */
     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)
@@ -1730,10 +1745,6 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
         return new HSSFCreationHelper(this);
     }
 
-    private static byte[] newUID() {
-        return new byte[16];
-    }
-
     /**
      *
      * Returns the locator of user-defined functions.
index 1959cad0ce7c782fa538a20a032e52ac793b1068..c79260c6ee14dcf60df3ff6085eb8fcc5014a993 100644 (file)
@@ -50,5 +50,12 @@ public interface Picture {
     void resize(double scale);
 
     ClientAnchor getPreferredSize();
+    
+    /**
+     * Return picture data for this picture
+     *
+     * @return picture data for this picture
+     */
+    PictureData getPictureData();
 
 }
index 9e51917a5f86a7e4a1fafa686628f118afb4556f..6c08a167a1a1090aacce60a213da71a138e6ca39 100644 (file)
@@ -20,6 +20,11 @@ package org.apache.poi.hssf.usermodel;
 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>.
@@ -49,4 +54,99 @@ public final class TestHSSFPicture extends BaseTestPicture {
         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()));
+    }
+
 }