]> source.dussan.org Git - poi.git/commitdiff
Initial support for SpreadsheetML drawings,implemented XSSFPicture, added ability...
authorYegor Kozlov <yegor@apache.org>
Fri, 10 Oct 2008 14:54:32 +0000 (14:54 +0000)
committerYegor Kozlov <yegor@apache.org>
Fri, 10 Oct 2008 14:54:32 +0000 (14:54 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@703490 13f79535-47bb-0310-9956-ffa450edef68

24 files changed:
src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java
src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
src/ooxml/java/org/apache/poi/POIXMLRelation.java
src/ooxml/java/org/apache/poi/xssf/dev/XSSFSave.java
src/ooxml/java/org/apache/poi/xssf/model/Drawing.java
src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java
src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java
src/ooxml/java/org/apache/poi/xssf/usermodel/ShapeTypes.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFactory.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPictureData.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/io/TestLoadSaveXSSF.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java [new file with mode: 0755]
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPicture.java [new file with mode: 0755]
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPictureData.java [new file with mode: 0755]
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
src/testcases/org/apache/poi/hssf/data/WithDrawing.xlsx [new file with mode: 0755]

index ae35bc00a8626bb33c57220801c61005c0f9c99b..ce4f92ceb569f47976ac4cb41c9918fba3b8f74d 100644 (file)
@@ -672,7 +672,7 @@ public interface Sheet extends Iterable<Row> {
      *
      * @return  The new patriarch.
      */
-    Patriarch createDrawingPatriarch();
+    //Patriarch createDrawingPatriarch();
 
     /**
      * Expands or collapses a column group.
index ed3e59fd00e3e2e67660f3a242b978bf2b8dfcae..979caeea30609e508beb475be001198121de185f 100755 (executable)
@@ -43,6 +43,7 @@ public class POIXMLDocumentPart {
         DEFAULT_XML_OPTIONS = new XmlOptions();\r
         DEFAULT_XML_OPTIONS.setSaveOuter();\r
         DEFAULT_XML_OPTIONS.setUseDefaultNamespace();\r
+        DEFAULT_XML_OPTIONS.setSaveAggressiveNamespaces();\r
     }\r
 \r
     protected PackagePart packagePart;\r
@@ -158,16 +159,30 @@ public class POIXMLDocumentPart {
      * @return the created child POIXMLDocumentPart\r
      */\r
     protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx){\r
+        return createRelationship(descriptor, cls, idx, false);\r
+    }\r
+\r
+    /**\r
+     * Create a new child POIXMLDocumentPart\r
+     *\r
+     * @param descriptor the part descriptor\r
+     * @param cls the Class object identifying the type of instance to create\r
+     * @param idx part number\r
+     * @param norel if true, then no relationship is added. \r
+     * @return the created child POIXMLDocumentPart\r
+     */\r
+    protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx, boolean norel){\r
         try {\r
 \r
             PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));\r
-            PackageRelationship rel =\r
-                packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());\r
+            PackageRelationship rel = null;\r
+            if(!norel) rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());\r
 \r
             PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType());\r
             POIXMLDocumentPart doc = cls.newInstance();\r
             doc.packageRel = rel;\r
             doc.packagePart = part;\r
+            doc.parent = this;\r
             addRelation(doc);\r
             return doc;\r
         } catch (Exception e){\r
index a786c02d4762cec70fecc2e090cd7debea4e6c41..fb001efdcc160b7fb83c0d36e7ffbb632094be49 100755 (executable)
@@ -23,22 +23,64 @@ package org.apache.poi;
  */\r
 public class POIXMLRelation {\r
 \r
+    /**\r
+     * Describes the content stored in a part.\r
+     */\r
     protected String _type;\r
+\r
+    /**\r
+     * The kind of connection between a source part and a target part in a package.\r
+     */\r
     protected String _relation;\r
+\r
+    /**\r
+     * The path component of a pack URI.\r
+     */\r
     protected String _defaultName;\r
 \r
     /**\r
      * Instantiates a POIXMLRelation.\r
+     *\r
+     * @param type content type\r
+     * @param rel  relationship\r
+     * @param defaultName default item name\r
      */\r
-    protected POIXMLRelation(String type, String rel, String defaultName) {\r
+    public POIXMLRelation(String type, String rel, String defaultName) {\r
         _type = type;\r
         _relation = rel;\r
         _defaultName = defaultName;\r
     }\r
 \r
-    public String getContentType() { return _type; }\r
-    public String getRelation() { return _relation; }\r
-    public String getDefaultFileName() { return _defaultName; }\r
+    /**\r
+     * Return the content type. Content types define a media type, a subtype, and an\r
+     * optional set of parameters, as defined in RFC 2616.\r
+     *\r
+     * @return the content type\r
+     */\r
+    public String getContentType() {\r
+        return _type;\r
+    }\r
+\r
+    /**\r
+     * Return the relationship, the kind of connection between a source part and a target part in a package.\r
+     * Relationships make the connections between parts directly discoverable without looking at the content\r
+     * in the parts, and without altering the parts themselves.\r
+     *\r
+     * @return the relationship\r
+     */\r
+    public String getRelation() {\r
+        return _relation;\r
+    }\r
+\r
+    /**\r
+     * Return the default part name. Part names are used to refer to a part in the context of a\r
+     * package, typically as part of a URI.\r
+     *\r
+     * @return the default part name\r
+     */\r
+    public String getDefaultFileName() {\r
+        return _defaultName;\r
+    }\r
 \r
     /**\r
      * Returns the filename for the nth one of these,\r
index 7ca4a3d691f7e33631fef30e585af7cdd17946cc..148a02fcb200afd6f2c437ca752573a4e7ae5675 100755 (executable)
@@ -31,7 +31,6 @@ public class XSSFSave {
         for (int i = 0; i < args.length; i++) {\r
             XSSFWorkbook wb = new XSSFWorkbook(args[i]);\r
 \r
-            System.out.println("wb.getNumberOfSheets(): " + wb.getNumberOfSheets());\r
             int sep = args[i].lastIndexOf('.');\r
             String outfile = args[i].substring(0, sep) + "-save.xlsx";\r
             FileOutputStream out = new FileOutputStream(outfile);\r
index 58dc8057082a2a50df5c49c8fb828617223a50e5..c151841798b60383af5beeb02d8e1caca6904f58 100644 (file)
@@ -16,7 +16,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
  * A drawing object in XSSF. May well have raw pictures
  *  attached to it as children.
  */
-public class Drawing implements XSSFChildContainingModel {
+public class Drawing implements XSSFModel {
        private CTDrawing drawing;
        private String originalId;
        
@@ -77,20 +77,11 @@ public class Drawing implements XSSFChildContainingModel {
         * Generates and adds XSSFActiveXData children
         */
        public void generateChild(PackagePart childPart, String childRelId) {
-               XSSFPictureData pd = new XSSFPictureData(childPart, childRelId);
-               pictures.add(pd);
-       }
+               //XSSFPictureData pd = new XSSFPictureData(childPart, childRelId);
+               //pictures.add(pd);
+        throw new RuntimeException("deprecated");
+    }
 
-       public WritableChild getChildForWriting(int index) {
-               if(index >= pictures.size()) {
-                       throw new IllegalArgumentException("Can't get child at " + index + " when size is " + getNumberOfChildren());
-               }
-               return new WritableChild(
-                               pictures.get(index),
-                               XSSFRelation.IMAGES
-               );
-       }
-       
        public ArrayList<XSSFPictureData> getPictures()
        {
                return this.pictures;
index c004905412d04349947597b47ec47ddf49eb9a8d..e854d19d02349d21ed36a70074d49f49d5c026d1 100644 (file)
@@ -198,9 +198,7 @@ public class SharedStringsTable extends POIXMLDocumentPart implements XSSFModel,
      * @throws IOException if an error occurs while writing.
      */
     public void writeTo(OutputStream out) throws IOException {
-        XmlOptions options = new XmlOptions();
-        options.setSaveOuter();
-        options.setUseDefaultNamespace();
+        XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
 
         //re-create the sst table every time saving a workbook
         SstDocument doc = SstDocument.Factory.newInstance();
index c3dd80839289f0bec7f61c3f175c4dc7e9e41584..568d56c15740923306946f275faa6d8abc603a2f 100644 (file)
@@ -330,13 +330,7 @@ public class StylesTable extends POIXMLDocumentPart implements StylesSource, XSS
         * @throws IOException if an error occurs while writing.
         */
        public void writeTo(OutputStream out) throws IOException {
-               XmlOptions options = new XmlOptions();
-               options.setSaveOuter();
-               options.setUseDefaultNamespace();
-
-               // Requests use of whitespace for easier reading
-               options.setSavePrettyPrint();
-
+               XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
 
                // Work on the current one
                // Need to do this, as we don't handle
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/ShapeTypes.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/ShapeTypes.java
new file mode 100755 (executable)
index 0000000..4b2cdf8
--- /dev/null
@@ -0,0 +1,212 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+/**\r
+ * All know type of automatic shapes in DrawingML\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class ShapeTypes {\r
+    public static final int LINE = 1;\r
+    public static final int LINE_INV = 2;\r
+    public static final int TRIANGLE = 3;\r
+    public static final int RT_TRIANGLE = 4;\r
+    public static final int RECT = 5;\r
+    public static final int DIAMOND = 6;\r
+    public static final int PARALLELOGRAM = 7;\r
+    public static final int TRAPEZOID = 8;\r
+    public static final int NON_ISOSCELES_TRAPEZOID = 9;\r
+    public static final int PENTAGON = 10;\r
+    public static final int HEXAGON = 11;\r
+    public static final int HEPTAGON = 12;\r
+    public static final int OCTAGON = 13;\r
+    public static final int DECAGON = 14;\r
+    public static final int DODECAGON = 15;\r
+    public static final int STAR_4 = 16;\r
+    public static final int STAR_5 = 17;\r
+    public static final int STAR_6 = 18;\r
+    public static final int STAR_7 = 19;\r
+    public static final int STAR_8 = 20;\r
+    public static final int STAR_10 = 21;\r
+    public static final int STAR_12 = 22;\r
+    public static final int STAR_16 = 23;\r
+    public static final int STAR_24 = 24;\r
+    public static final int STAR_32 = 25;\r
+    public static final int ROUND_RECT = 26;\r
+    public static final int ROUND_1_RECT = 27;\r
+    public static final int ROUND_2_SAME_RECT = 28;\r
+    public static final int ROUND_2_DIAG_RECT = 29;\r
+    public static final int SNIP_ROUND_RECT = 30;\r
+    public static final int SNIP_1_RECT = 31;\r
+    public static final int SNIP_2_SAME_RECT = 32;\r
+    public static final int SNIP_2_DIAG_RECT = 33;\r
+    public static final int PLAQUE = 34;\r
+    public static final int ELLIPSE = 35;\r
+    public static final int TEARDROP = 36;\r
+    public static final int HOME_PLATE = 37;\r
+    public static final int CHEVRON = 38;\r
+    public static final int PIE_WEDGE = 39;\r
+    public static final int PIE = 40;\r
+    public static final int BLOCK_ARC = 41;\r
+    public static final int DONUT = 42;\r
+    public static final int NO_SMOKING = 43;\r
+    public static final int RIGHT_ARROW = 44;\r
+    public static final int LEFT_ARROW = 45;\r
+    public static final int UP_ARROW = 46;\r
+    public static final int DOWN_ARROW = 47;\r
+    public static final int STRIPED_RIGHT_ARROW = 48;\r
+    public static final int NOTCHED_RIGHT_ARROW = 49;\r
+    public static final int BENT_UP_ARROW = 50;\r
+    public static final int LEFT_RIGHT_ARROW = 51;\r
+    public static final int UP_DOWN_ARROW = 52;\r
+    public static final int LEFT_UP_ARROW = 53;\r
+    public static final int LEFT_RIGHT_UP_ARROW = 54;\r
+    public static final int QUAD_ARROW = 55;\r
+    public static final int LEFT_ARROW_CALLOUT = 56;\r
+    public static final int RIGHT_ARROW_CALLOUT = 57;\r
+    public static final int UP_ARROW_CALLOUT = 58;\r
+    public static final int DOWN_ARROW_CALLOUT = 59;\r
+    public static final int LEFT_RIGHT_ARROW_CALLOUT = 60;\r
+    public static final int UP_DOWN_ARROW_CALLOUT = 61;\r
+    public static final int QUAD_ARROW_CALLOUT = 62;\r
+    public static final int BENT_ARROW = 63;\r
+    public static final int UTURN_ARROW = 64;\r
+    public static final int CIRCULAR_ARROW = 65;\r
+    public static final int LEFT_CIRCULAR_ARROW = 66;\r
+    public static final int LEFT_RIGHT_CIRCULAR_ARROW = 67;\r
+    public static final int CURVED_RIGHT_ARROW = 68;\r
+    public static final int CURVED_LEFT_ARROW = 69;\r
+    public static final int CURVED_UP_ARROW = 70;\r
+    public static final int CURVED_DOWN_ARROW = 71;\r
+    public static final int SWOOSH_ARROW = 72;\r
+    public static final int CUBE = 73;\r
+    public static final int CAN = 74;\r
+    public static final int LIGHTNING_BOLT = 75;\r
+    public static final int HEART = 76;\r
+    public static final int SUN = 77;\r
+    public static final int MOON = 78;\r
+    public static final int SMILEY_FACE = 79;\r
+    public static final int IRREGULAR_SEAL_1 = 80;\r
+    public static final int IRREGULAR_SEAL_2 = 81;\r
+    public static final int FOLDED_CORNER = 82;\r
+    public static final int BEVEL = 83;\r
+    public static final int FRAME = 84;\r
+    public static final int HALF_FRAME = 85;\r
+    public static final int CORNER = 86;\r
+    public static final int DIAG_STRIPE = 87;\r
+    public static final int CHORD = 88;\r
+    public static final int ARC = 89;\r
+    public static final int LEFT_BRACKET = 90;\r
+    public static final int RIGHT_BRACKET = 91;\r
+    public static final int LEFT_BRACE = 92;\r
+    public static final int RIGHT_BRACE = 93;\r
+    public static final int BRACKET_PAIR = 94;\r
+    public static final int BRACE_PAIR = 95;\r
+    public static final int STRAIGHT_CONNECTOR_1 = 96;\r
+    public static final int BENT_CONNECTOR_2 = 97;\r
+    public static final int BENT_CONNECTOR_3 = 98;\r
+    public static final int BENT_CONNECTOR_4 = 99;\r
+    public static final int BENT_CONNECTOR_5 = 100;\r
+    public static final int CURVED_CONNECTOR_2 = 101;\r
+    public static final int CURVED_CONNECTOR_3 = 102;\r
+    public static final int CURVED_CONNECTOR_4 = 103;\r
+    public static final int CURVED_CONNECTOR_5 = 104;\r
+    public static final int CALLOUT_1 = 105;\r
+    public static final int CALLOUT_2 = 106;\r
+    public static final int CALLOUT_3 = 107;\r
+    public static final int ACCENT_CALLOUT_1 = 108;\r
+    public static final int ACCENT_CALLOUT_2 = 109;\r
+    public static final int ACCENT_CALLOUT_3 = 110;\r
+    public static final int BORDER_CALLOUT_1 = 111;\r
+    public static final int BORDER_CALLOUT_2 = 112;\r
+    public static final int BORDER_CALLOUT_3 = 113;\r
+    public static final int ACCENT_BORDER_CALLOUT_1 = 114;\r
+    public static final int ACCENT_BORDER_CALLOUT_2 = 115;\r
+    public static final int ACCENT_BORDER_CALLOUT_3 = 116;\r
+    public static final int WEDGE_RECT_CALLOUT = 117;\r
+    public static final int WEDGE_ROUND_RECT_CALLOUT = 118;\r
+    public static final int WEDGE_ELLIPSE_CALLOUT = 119;\r
+    public static final int CLOUD_CALLOUT = 120;\r
+    public static final int CLOUD = 121;\r
+    public static final int RIBBON = 122;\r
+    public static final int RIBBON_2 = 123;\r
+    public static final int ELLIPSE_RIBBON = 124;\r
+    public static final int ELLIPSE_RIBBON_2 = 125;\r
+    public static final int LEFT_RIGHT_RIBBON = 126;\r
+    public static final int VERTICAL_SCROLL = 127;\r
+    public static final int HORIZONTAL_SCROLL = 128;\r
+    public static final int WAVE = 129;\r
+    public static final int DOUBLE_WAVE = 130;\r
+    public static final int PLUS = 131;\r
+    public static final int FLOW_CHART_PROCESS = 132;\r
+    public static final int FLOW_CHART_DECISION = 133;\r
+    public static final int FLOW_CHART_INPUT_OUTPUT = 134;\r
+    public static final int FLOW_CHART_PREDEFINED_PROCESS = 135;\r
+    public static final int FLOW_CHART_INTERNAL_STORAGE = 136;\r
+    public static final int FLOW_CHART_DOCUMENT = 137;\r
+    public static final int FLOW_CHART_MULTIDOCUMENT = 138;\r
+    public static final int FLOW_CHART_TERMINATOR = 139;\r
+    public static final int FLOW_CHART_PREPARATION = 140;\r
+    public static final int FLOW_CHART_MANUAL_INPUT = 141;\r
+    public static final int FLOW_CHART_MANUAL_OPERATION = 142;\r
+    public static final int FLOW_CHART_CONNECTOR = 143;\r
+    public static final int FLOW_CHART_PUNCHED_CARD = 144;\r
+    public static final int FLOW_CHART_PUNCHED_TAPE = 145;\r
+    public static final int FLOW_CHART_SUMMING_JUNCTION = 146;\r
+    public static final int FLOW_CHART_OR = 147;\r
+    public static final int FLOW_CHART_COLLATE = 148;\r
+    public static final int FLOW_CHART_SORT = 149;\r
+    public static final int FLOW_CHART_EXTRACT = 150;\r
+    public static final int FLOW_CHART_MERGE = 151;\r
+    public static final int FLOW_CHART_OFFLINE_STORAGE = 152;\r
+    public static final int FLOW_CHART_ONLINE_STORAGE = 153;\r
+    public static final int FLOW_CHART_MAGNETIC_TAPE = 154;\r
+    public static final int FLOW_CHART_MAGNETIC_DISK = 155;\r
+    public static final int FLOW_CHART_MAGNETIC_DRUM = 156;\r
+    public static final int FLOW_CHART_DISPLAY = 157;\r
+    public static final int FLOW_CHART_DELAY = 158;\r
+    public static final int FLOW_CHART_ALTERNATE_PROCESS = 159;\r
+    public static final int FLOW_CHART_OFFPAGE_CONNECTOR = 160;\r
+    public static final int ACTION_BUTTON_BLANK = 161;\r
+    public static final int ACTION_BUTTON_HOME = 162;\r
+    public static final int ACTION_BUTTON_HELP = 163;\r
+    public static final int ACTION_BUTTON_INFORMATION = 164;\r
+    public static final int ACTION_BUTTON_FORWARD_NEXT = 165;\r
+    public static final int ACTION_BUTTON_BACK_PREVIOUS = 166;\r
+    public static final int ACTION_BUTTON_END = 167;\r
+    public static final int ACTION_BUTTON_BEGINNING = 168;\r
+    public static final int ACTION_BUTTON_RETURN = 169;\r
+    public static final int ACTION_BUTTON_DOCUMENT = 170;\r
+    public static final int ACTION_BUTTON_SOUND = 171;\r
+    public static final int ACTION_BUTTON_MOVIE = 172;\r
+    public static final int GEAR_6 = 173;\r
+    public static final int GEAR_9 = 174;\r
+    public static final int FUNNEL = 175;\r
+    public static final int MATH_PLUS = 176;\r
+    public static final int MATH_MINUS = 177;\r
+    public static final int MATH_MULTIPLY = 178;\r
+    public static final int MATH_DIVIDE = 179;\r
+    public static final int MATH_EQUAL = 180;\r
+    public static final int MATH_NOT_EQUAL = 181;\r
+    public static final int CORNER_TABS = 182;\r
+    public static final int SQUARE_TABS = 183;\r
+    public static final int PLAQUE_TABS = 184;\r
+    public static final int CHART_X = 185;\r
+    public static final int CHART_STAR = 186;\r
+    public static final int CHART_PLUS = 187;\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java
new file mode 100755 (executable)
index 0000000..0a6129e
--- /dev/null
@@ -0,0 +1,187 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;\r
+\r
+/**\r
+ * A client anchor is attached to an excel worksheet.  It anchors against\r
+ * top-left and buttom-right cells.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class XSSFClientAnchor {\r
+\r
+    /**\r
+     * Starting anchor point\r
+     */\r
+    private CTMarker cell1;\r
+\r
+    /**\r
+     * Ending anchor point\r
+     */\r
+    private CTMarker cell2;\r
+\r
+    /**\r
+     * Creates a new client anchor and defaults all the anchor positions to 0.\r
+     */\r
+    public XSSFClientAnchor() {\r
+        cell1 = CTMarker.Factory.newInstance();\r
+        cell1.setCol(0);\r
+        cell1.setColOff(0);\r
+        cell1.setRow(0);\r
+        cell1.setRowOff(0);\r
+        cell2 = CTMarker.Factory.newInstance();\r
+        cell2.setCol(0);\r
+        cell2.setColOff(0);\r
+        cell2.setRow(0);\r
+        cell2.setRowOff(0);\r
+    }\r
+\r
+    /**\r
+     * Creates a new client anchor and sets the top-left and bottom-right\r
+     * coordinates of the anchor.\r
+     *\r
+     * @param dx1  the x coordinate within the first cell.\r
+     * @param dy1  the y coordinate within the first cell.\r
+     * @param dx2  the x coordinate within the second cell.\r
+     * @param dy2  the y coordinate within the second cell.\r
+     * @param col1 the column (0 based) of the first cell.\r
+     * @param row1 the row (0 based) of the first cell.\r
+     * @param col2 the column (0 based) of the second cell.\r
+     * @param row2 the row (0 based) of the second cell.\r
+     */\r
+    public XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2) {\r
+        this();\r
+        cell1.setCol(col1);\r
+        cell1.setColOff(dx1);\r
+        cell1.setRow(row1);\r
+        cell1.setRowOff(dy1);\r
+        cell2.setCol(col2);\r
+        cell2.setColOff(dx2);\r
+        cell2.setRow(row2);\r
+        cell2.setRowOff(dy2);\r
+    }\r
+\r
+    /**\r
+     * Create XSSFClientAnchor from existing xml beans\r
+     *\r
+     * @param cell1 starting anchor point\r
+     * @param cell2 ending anchor point\r
+     */\r
+    protected XSSFClientAnchor(CTMarker cell1, CTMarker cell2) {\r
+        this.cell1 = cell1;\r
+        this.cell2 = cell2;\r
+    }\r
+\r
+    public int getCol1() {\r
+        return cell1.getCol();\r
+    }\r
+\r
+    public void setCol1(short col1) {\r
+        cell1.setCol(col1);\r
+    }\r
+\r
+    public int getCol2() {\r
+        return cell2.getCol();\r
+    }\r
+\r
+    public void setCol2(short col2) {\r
+        cell2.setCol(col2);\r
+    }\r
+\r
+    public int getRow1() {\r
+        return cell1.getRow();\r
+    }\r
+\r
+    public void setRow1(int row1) {\r
+        cell1.setRow(row1);\r
+    }\r
+\r
+    public int getRow2() {\r
+        return cell2.getRow();\r
+    }\r
+\r
+    public void setRow2(int row2) {\r
+        cell2.setRow(row2);\r
+    }\r
+\r
+    public int getDx1() {\r
+        return (int)cell1.getColOff();\r
+    }\r
+\r
+    public void setDx1(int dx1) {\r
+        cell1.setColOff(dx1);\r
+    }\r
+\r
+    public int getDy1() {\r
+        return (int)cell1.getRowOff();\r
+    }\r
+\r
+    public void setDy1(int dy1) {\r
+        cell1.setRowOff(dy1);\r
+    }\r
+\r
+    public int getDy2() {\r
+        return (int)cell2.getRowOff();\r
+    }\r
+\r
+    public void setDy2(int dy2) {\r
+        cell2.setRowOff(dy2);\r
+    }\r
+\r
+    public int getDx2() {\r
+        return (int)cell2.getColOff();\r
+    }\r
+\r
+    public void setDx2(int dx2) {\r
+        cell2.setColOff(dx2);\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object o) {\r
+        if (o == null || !(o instanceof XSSFClientAnchor)) return false;\r
+\r
+        XSSFClientAnchor anchor = (XSSFClientAnchor) o;\r
+        return cell1.toString().equals(anchor.getFrom().toString()) &&\r
+               cell2.toString().equals(anchor.getTo().toString()) ;\r
+\r
+    }\r
+\r
+    @Override\r
+    public String toString(){\r
+        return "from : " + cell1.toString()  + "; to: " + cell2.toString();\r
+    }\r
+\r
+    /**\r
+     * Return starting anchor point\r
+     *\r
+     * @return starting anchor point\r
+     */\r
+    public CTMarker getFrom(){\r
+        return cell1;\r
+    }\r
+\r
+    /**\r
+     * Return ending anchor point\r
+     *\r
+     * @return ending anchor point\r
+     */\r
+    public CTMarker getTo(){\r
+        return cell2;\r
+    }\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
new file mode 100755 (executable)
index 0000000..b451b4e
--- /dev/null
@@ -0,0 +1,155 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.apache.xmlbeans.XmlException;\r
+import org.apache.xmlbeans.XmlOptions;\r
+import org.openxml4j.opc.*;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs;\r
+import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;\r
+\r
+import javax.xml.namespace.QName;\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.util.Map;\r
+import java.util.HashMap;\r
+\r
+/**\r
+ * Represents a SpreadsheetML drawing\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class XSSFDrawing extends POIXMLDocumentPart {\r
+    /**\r
+     * Root element of the SpreadsheetML Drawing part\r
+     */\r
+    private CTDrawing drawing;\r
+\r
+    /**\r
+     * Create a new SpreadsheetML drawing\r
+     *\r
+     * @see org.apache.poi.xssf.usermodel.XSSFWorksheet#createDrawingPatriarch()\r
+     */\r
+    public XSSFDrawing() {\r
+        super(null, null);\r
+        drawing = newDrawing();\r
+    }\r
+\r
+    /**\r
+     * Construct a SpreadsheetML drawing from a package part\r
+     *\r
+     * @param part the package part holding the drawing data,\r
+     * the content type must be <code>application/vnd.openxmlformats-officedocument.drawing+xml</code>\r
+     * @param rel  the package relationship holding this drawing,\r
+     * the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing\r
+     */\r
+    public XSSFDrawing(PackagePart part, PackageRelationship rel) throws IOException, XmlException {\r
+        super(part, rel);\r
+        drawing = CTDrawing.Factory.parse(part.getInputStream());\r
+    }\r
+\r
+    /**\r
+     * Construct a new CTDrawing bean. By default, it's just an empty placeholder for drawing objects\r
+     *\r
+     * @return a new CTDrawing bean\r
+     */\r
+    private static CTDrawing newDrawing(){\r
+        return CTDrawing.Factory.newInstance();\r
+    }\r
+\r
+    /**\r
+     * Return the underlying CTDrawing bean, the root element of the SpreadsheetML Drawing part.\r
+     *\r
+     * @return the underlying CTDrawing bean\r
+     */\r
+    public CTDrawing getCTDrawing(){\r
+        return drawing;\r
+    }\r
+\r
+    @Override\r
+    protected void commit() throws IOException {\r
+        XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);\r
+\r
+        /*\r
+            Saved drawings must have the following namespaces set:\r
+            <xdr:wsDr\r
+                xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"\r
+                xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">\r
+        */\r
+        xmlOptions.setSaveSyntheticDocumentElement(new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr"));\r
+        Map map = new HashMap();\r
+        map.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a");\r
+        map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");\r
+        xmlOptions.setSaveSuggestedPrefixes(map);\r
+\r
+        PackagePart part = getPackagePart();\r
+        OutputStream out = part.getOutputStream();\r
+        drawing.save(out, xmlOptions);\r
+        out.close();\r
+    }\r
+\r
+    /**\r
+     * Creates a picture.\r
+     *\r
+     * @param anchor    the client anchor describes how this picture is attached to the sheet.\r
+     * @param pictureIndex the index of the picture in the workbook collection of pictures,\r
+     *   {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()} .\r
+     *\r
+     * @return  the newly created picture shape.\r
+     */\r
+    public XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex)\r
+    {\r
+        XSSFWorkbook wb = (XSSFWorkbook)getParent().getParent();\r
+        XSSFPictureData data = wb.getAllPictures().get(pictureIndex);\r
+        PackagePartName ppName = data.getPackagePart().getPartName();\r
+        PackageRelationship rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, XSSFRelation.IMAGES.getRelation());\r
+        addRelation(new XSSFPictureData(data.getPackagePart(), rel));\r
+        CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);\r
+        return new XSSFPicture(this, rel, ctAnchor);\r
+    }\r
+\r
+    /**\r
+     * Creates a simple shape.  This includes such shapes as lines, rectangles,\r
+     * and ovals.\r
+     *\r
+     * @param anchor    the client anchor describes how this group is attached\r
+     *                  to the sheet.\r
+     * @return  the newly created shape.\r
+     */\r
+    public XSSFSimpleShape createSimpleShape(XSSFClientAnchor anchor)\r
+    {\r
+        CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor);\r
+        return new XSSFSimpleShape(this, ctAnchor);\r
+    }\r
+\r
+    /**\r
+     * Create and initialize a CTTwoCellAnchor that anchors a shape against top-left and bottom-right cells.\r
+     *\r
+     * @return a new CTTwoCellAnchor\r
+     */\r
+    private CTTwoCellAnchor createTwoCellAnchor(XSSFClientAnchor anchor){\r
+        CTTwoCellAnchor ctAnchor = drawing.addNewTwoCellAnchor();\r
+        ctAnchor.setEditAs(STEditAs.ONE_CELL);\r
+        ctAnchor.setFrom(anchor.getFrom());\r
+        ctAnchor.setTo(anchor.getTo());\r
+        ctAnchor.addNewClientData();\r
+        return ctAnchor;\r
+    }\r
+}\r
index 44f8054b3c097df33a66a178dbfa203e10315ebe..52b8d63f9a82fceb27eaf8880f097f24543d9062 100755 (executable)
@@ -41,6 +41,8 @@ public class XSSFFactory extends POIXMLFactory  {
         parts.put(XSSFRelation.SHARED_STRINGS.getRelation(), SharedStringsTable.class);\r
         parts.put(XSSFRelation.STYLES.getRelation(), StylesTable.class);\r
         parts.put(XSSFRelation.SHEET_COMMENTS.getRelation(), CommentsTable.class);\r
+        parts.put(XSSFRelation.DRAWINGS.getRelation(), XSSFDrawing.class);\r
+        parts.put(XSSFRelation.IMAGES.getRelation(), XSSFPictureData.class);\r
     }\r
 \r
     public POIXMLDocumentPart create(PackageRelationship rel, PackagePart p){\r
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java
new file mode 100755 (executable)
index 0000000..93a7caa
--- /dev/null
@@ -0,0 +1,325 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.*;\r
+import org.apache.poi.ss.usermodel.Workbook;\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.openxml4j.opc.PackageRelationship;\r
+import org.openxml4j.opc.PackagePart;\r
+import org.w3c.dom.NodeList;\r
+import org.w3c.dom.Element;\r
+import javax.imageio.ImageIO;\r
+import javax.imageio.ImageReader;\r
+import javax.imageio.stream.ImageInputStream;\r
+import java.awt.*;\r
+import java.awt.image.BufferedImage;\r
+import java.io.IOException;\r
+import java.util.Iterator;\r
+\r
+/**\r
+ * Represents a picture shape in a SpreadsheetML drawing.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class XSSFPicture extends XSSFShape {\r
+    private static final POILogger logger = POILogFactory.getLogger(XSSFPicture.class);\r
+\r
+    /**\r
+     * width of 1px in columns with default width\r
+     */\r
+    private static final float PX_DEFAULT = 0.125f;\r
+    /**\r
+     * width of 1px in columns with overridden width\r
+     */\r
+    private static final float PX_MODIFIED = 0.143f;\r
+\r
+    /**\r
+     * Height of 1px of a row\r
+     */\r
+    private static final int PX_ROW = 15;\r
+\r
+    /**\r
+     * This object specifies a picture object and all its properties\r
+     */\r
+    private CTPicture ctPicture;\r
+\r
+    /**\r
+     * Construct a new XSSFPicture object. This constructor is called from\r
+     *  {@link XSSFDrawing#createPicture(XSSFClientAnchor, int)}\r
+     *\r
+     * @param parent the XSSFDrawing that owns this picture\r
+     * @param rel    the relationship to the picture data\r
+     * @param anchor the two cell anchor placeholder for this picture,\r
+     *   this object encloses the CTPicture bean that holds all the picture properties\r
+     */\r
+    protected XSSFPicture(XSSFDrawing parent, PackageRelationship rel, CTTwoCellAnchor anchor){\r
+        super(parent, anchor);\r
+        //Create a new picture and attach it to the specified two-cell anchor\r
+        ctPicture = newPicture(rel);\r
+        anchor.setPic(ctPicture);\r
+    }\r
+\r
+    /**\r
+     * Create a new CTPicture bean and initialize its required attributes\r
+     *\r
+     * @param rel the relationship to the picture data\r
+     * @return a new CTPicture bean\r
+     */\r
+    private static CTPicture newPicture(PackageRelationship rel){\r
+        CTPicture pic = CTPicture.Factory.newInstance();\r
+\r
+        CTPictureNonVisual nvpr = pic.addNewNvPicPr();\r
+        CTNonVisualDrawingProps nvProps = nvpr.addNewCNvPr();\r
+        //YK: TODO shape IDs must be unique across workbook\r
+        int shapeId = 1;\r
+        nvProps.setId(shapeId);\r
+        nvProps.setName("Picture " + shapeId);\r
+        nvProps.setDescr(rel.getTargetURI().toString());\r
+        CTNonVisualPictureProperties nvPicProps = nvpr.addNewCNvPicPr();\r
+        nvPicProps.addNewPicLocks().setNoChangeAspect(true);\r
+\r
+        CTBlipFillProperties blip = pic.addNewBlipFill();\r
+        blip.addNewBlip().setEmbed(rel.getId());\r
+        blip.addNewStretch().addNewFillRect();\r
+\r
+        CTShapeProperties sppr = pic.addNewSpPr();\r
+        CTTransform2D t2d = sppr.addNewXfrm();\r
+        CTPositiveSize2D ext = t2d.addNewExt();\r
+        //should be original picture width and height expressed in EMUs\r
+        ext.setCx(0);\r
+        ext.setCy(0);\r
+\r
+        CTPoint2D off = t2d.addNewOff();\r
+        off.setX(0);\r
+        off.setY(0);\r
+\r
+        CTPresetGeometry2D prstGeom = sppr.addNewPrstGeom();\r
+        prstGeom.setPrst(STShapeType.RECT);\r
+        prstGeom.addNewAvLst();\r
+        return pic;\r
+    }\r
+\r
+    /**\r
+     * Return the underlying CTPicture bean that holds all properties for this picture\r
+     *\r
+     * @return the underlying CTPicture bean\r
+     */\r
+    public CTPicture getCTPicture(){\r
+        return ctPicture;\r
+    }\r
+\r
+    /**\r
+     * Reset the image to the original size.\r
+     */\r
+    public void resize(){\r
+        XSSFClientAnchor anchor = getAnchor();\r
+\r
+        XSSFClientAnchor pref = getPreferredSize();\r
+\r
+        int row2 = anchor.getRow1() + (pref.getRow2() - pref.getRow1());\r
+        int col2 = anchor.getCol1() + (pref.getCol2() - pref.getCol1());\r
+\r
+        anchor.setCol2((short)col2);\r
+        anchor.setDx1(0);\r
+        anchor.setDx2(pref.getDx2());\r
+\r
+        anchor.setRow2(row2);\r
+        anchor.setDy1(0);\r
+        anchor.setDy2(pref.getDy2());\r
+    }\r
+\r
+    /**\r
+     * Calculate the preferred size for this picture.\r
+     *\r
+     * @return XSSFClientAnchor with the preferred size for this image\r
+     */\r
+    public XSSFClientAnchor getPreferredSize(){\r
+        XSSFClientAnchor anchor = getAnchor();\r
+\r
+        XSSFPictureData data = getPictureData();\r
+        Dimension size = getImageDimension(data.getPackagePart(), data.getPictureType());\r
+\r
+        float w = 0;\r
+\r
+        //space in the leftmost cell\r
+        w += anchor.getDx1()/EMU_PER_POINT;\r
+        short col2 = (short)(anchor.getCol1() + 1);\r
+        int dx2 = 0;\r
+\r
+        while(w < size.width){\r
+            w += getColumnWidthInPixels(col2++);\r
+        }\r
+\r
+        if(w > size.width) {\r
+            //calculate dx2, offset in the rightmost cell\r
+            col2--;\r
+            float cw = getColumnWidthInPixels(col2);\r
+            float delta = w - size.width;\r
+            dx2 = (int)(EMU_PER_POINT*(cw-delta));\r
+        }\r
+        anchor.setCol2(col2);\r
+        anchor.setDx2(dx2);\r
+\r
+        float h = 0;\r
+        h += (1 - anchor.getDy1()/256)* getRowHeightInPixels(anchor.getRow1());\r
+        int row2 = anchor.getRow1() + 1;\r
+        int dy2 = 0;\r
+\r
+        while(h < size.height){\r
+            h += getRowHeightInPixels(row2++);\r
+        }\r
+        if(h > size.height) {\r
+            row2--;\r
+            float ch = getRowHeightInPixels(row2);\r
+            float delta = h - size.height;\r
+            dy2 = (int)((ch-delta)/ch*256);\r
+        }\r
+        anchor.setRow2(row2);\r
+        anchor.setDy2(dy2);\r
+\r
+        return anchor;\r
+    }\r
+\r
+    private float getColumnWidthInPixels(int column){\r
+        XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();\r
+        int cw = sheet.getColumnWidth(column);\r
+        float px = getPixelWidth(column);\r
+\r
+        return cw/px;\r
+    }\r
+\r
+    private float getRowHeightInPixels(int i){\r
+        XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();\r
+\r
+        XSSFRow row = sheet.getRow(i);\r
+        float height;\r
+        if(row != null) height = row.getHeight();\r
+        else height = sheet.getDefaultRowHeight();\r
+\r
+        return height/PX_ROW;\r
+    }\r
+\r
+    private float getPixelWidth(int column){\r
+        XSSFSheet sheet = (XSSFSheet)getDrawing().getParent();\r
+\r
+        int def = sheet.getDefaultColumnWidth();\r
+        int cw = sheet.getColumnWidth(column);\r
+\r
+        return cw == def ? PX_DEFAULT : PX_MODIFIED;\r
+    }\r
+\r
+    /**\r
+     * Return the dimension of this image\r
+     *\r
+     * @param part the package part holding raw picture data\r
+     * @param type type of the picture: {@link Workbook#PICTURE_TYPE_JPEG, Workbook#PICTURE_TYPE_PNG or Workbook#PICTURE_TYPE_DIB)\r
+     *\r
+     * @return image dimension in pixels\r
+     */\r
+    protected static Dimension getImageDimension(PackagePart part, int type){\r
+        Dimension size = new Dimension();\r
+\r
+        switch (type){\r
+            //we can calculate the preferred size only for JPEG and PNG\r
+            //other formats like WMF, EMF and PICT are not supported in Java\r
+            case Workbook.PICTURE_TYPE_JPEG:\r
+            case Workbook.PICTURE_TYPE_PNG:\r
+            case Workbook.PICTURE_TYPE_DIB:\r
+                try {\r
+                    //read the image using javax.imageio.*\r
+                    ImageInputStream iis = ImageIO.createImageInputStream( part.getInputStream() );\r
+                    Iterator i = ImageIO.getImageReaders( iis );\r
+                    ImageReader r = (ImageReader) i.next();\r
+                    r.setInput( iis );\r
+                    BufferedImage img = r.read(0);\r
+\r
+                    int[] dpi = getResolution(r);\r
+\r
+                    //if DPI is zero then assume standard 96 DPI\r
+                    //since cannot divide by zero\r
+                    if (dpi[0] == 0) dpi[0] = 96;\r
+                    if (dpi[1] == 0) dpi[1] = 96;\r
+\r
+                    size.width = img.getWidth()*96/dpi[0];\r
+                    size.height = img.getHeight()*96/dpi[1];\r
+\r
+                } catch (IOException e){\r
+                    //silently return if ImageIO failed to read the image\r
+                    logger.log(POILogger.WARN, e);\r
+                }\r
+\r
+                break;\r
+            default:\r
+                logger.log(POILogger.WARN, "Only JPEG, PNG and DIB pictures can be automatically sized");\r
+        }\r
+        return size;\r
+    }\r
+\r
+    /**\r
+     * The metadata of PNG and JPEG can contain the width of a pixel in millimeters.\r
+     * Return the the "effective" dpi calculated as <code>25.4/HorizontalPixelSize</code>\r
+     * and <code>25.4/VerticalPixelSize</code>.  Where 25.4 is the number of mm in inch.\r
+     *\r
+     * @return array of two elements: <code>{horisontalPdi, verticalDpi}</code>.\r
+     * {96, 96} is the default.\r
+     */\r
+    protected static int[] getResolution(ImageReader r) throws IOException {\r
+        int hdpi=96, vdpi=96;\r
+        double mm2inch = 25.4;\r
+\r
+        NodeList lst;\r
+        Element node = (Element)r.getImageMetadata(0).getAsTree("javax_imageio_1.0");\r
+        lst = node.getElementsByTagName("HorizontalPixelSize");\r
+        if(lst != null && lst.getLength() == 1) hdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));\r
+\r
+        lst = node.getElementsByTagName("VerticalPixelSize");\r
+        if(lst != null && lst.getLength() == 1) vdpi = (int)(mm2inch/Float.parseFloat(((Element)lst.item(0)).getAttribute("value")));\r
+\r
+        return new int[]{hdpi, vdpi};\r
+    }\r
+\r
+    /**\r
+     * return the anchor that is used by this shape.\r
+     *\r
+     * @return  the anchor that is used by this shape.\r
+     */\r
+    public XSSFClientAnchor getAnchor(){\r
+        CTTwoCellAnchor ctAnchor = (CTTwoCellAnchor)getShapeContainer();\r
+        return new XSSFClientAnchor(ctAnchor.getFrom(), ctAnchor.getTo());\r
+    }\r
+\r
+    /**\r
+     * Return picture data for this shape\r
+     *\r
+     * @return picture data for this shape\r
+     */\r
+    public XSSFPictureData getPictureData() {\r
+        String blipId = ctPicture.getBlipFill().getBlip().getEmbed();\r
+        for (POIXMLDocumentPart part : getDrawing().getRelations()) {\r
+            if(part.getPackageRelationship().getId().equals(blipId)){\r
+                return (XSSFPictureData)part;\r
+            }\r
+        }\r
+        logger.log(POILogger.WARN, "Picture data was not found for blipId=" + blipId);\r
+        return null;\r
+    }\r
+\r
+}\r
index f7fb5b27ada02ee644c3eadbb0a15bf553ea62ea..fdc49fcaca55a8da2ed2aa5c6703928a3d35226d 100644 (file)
 package org.apache.poi.xssf.usermodel;
 
 import java.io.IOException;
-import java.io.OutputStream;
-
 import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.model.XSSFWritableModel;
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLException;
+import org.apache.poi.POIXMLRelation;
 import org.openxml4j.opc.PackagePart;
+import org.openxml4j.opc.PackageRelationship;
 
 /**
- * Raw picture data, normally attached to a 
- *  vmlDrawing
+ * Raw picture data, normally attached to a SpreadsheetML Drawing.
+ * As a rule, pictures are stored in the /xl/media/ part of a SpreadsheetML package.
  */
-public class XSSFPictureData implements PictureData, XSSFWritableModel {
-    private PackagePart packagePart;
-    private String originalId;
+public class XSSFPictureData extends POIXMLDocumentPart implements PictureData {
 
-    public XSSFPictureData(PackagePart packagePart, String originalId) {
-        this(packagePart);
-        this.originalId = originalId;
-    }
-    
-    public XSSFPictureData(PackagePart packagePart) {
-        this.packagePart = packagePart;
+    /**
+     * Relationships for each known picture type
+     */
+    protected static final POIXMLRelation[] RELATIONS;
+    static {
+        RELATIONS = new POIXMLRelation[8];
+        RELATIONS[Workbook.PICTURE_TYPE_EMF] = new POIXMLRelation("image/x-emf", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.emf");
+        RELATIONS[Workbook.PICTURE_TYPE_WMF] = new POIXMLRelation("image/x-wmf", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.wmf");
+        RELATIONS[Workbook.PICTURE_TYPE_PICT] = new POIXMLRelation("image/pict", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.pict");
+        RELATIONS[Workbook.PICTURE_TYPE_JPEG] = new POIXMLRelation("image/jpeg", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.jpeg");
+        RELATIONS[Workbook.PICTURE_TYPE_PNG] = new POIXMLRelation("image/png", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.png");
+        RELATIONS[Workbook.PICTURE_TYPE_DIB] = new POIXMLRelation("image/dib", XSSFRelation.IMAGES.getRelation(), "/xl/media/image#.dib");
     }
 
-    public String getOriginalId() {
-       return originalId;
+    /**
+     * Create a new XSSFPictureData node
+     *
+     * @see org.apache.poi.xssf.usermodel.XSSFWorkbook#addPicture(byte[], int)
+     */
+    public XSSFPictureData() {
+        super(null, null);
     }
-    
-    protected PackagePart getPart() {
-       return packagePart;
+
+    /**
+     * Construct XSSFPictureData from a package part
+     *
+     * @param part the package part holding the drawing data,
+     * @param rel  the package relationship holding this drawing,
+     * the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/image
+     */
+    public XSSFPictureData(PackagePart part, PackageRelationship rel) {
+        super(part, rel);
     }
-    
-       public void writeTo(OutputStream out) throws IOException {
-               IOUtils.copy(packagePart.getInputStream(), out);
-       }
 
+    /**
+     * Gets the picture data as a byte array.
+     * <p>
+     * Note, that this call might be expensive since all the picture data is copied into a temporary byte array.
+     * You can grab the picture data directly from the underlying package part as follows:
+     * <br/>
+     * <code>
+     * InputStream is = getPackagePart().getInputStream();
+     * </code>
+     * </p>
+     *
+     * @return the picture data.
+     */
     public byte[] getData() {
-       try {
-               return IOUtils.toByteArray(packagePart.getInputStream());
-       } catch(IOException e) {
-               throw new RuntimeException(e);
-       }
+        try {
+            return IOUtils.toByteArray(getPackagePart().getInputStream());
+        } catch(IOException e) {
+            throw new POIXMLException(e);
+        }
     }
 
+    /**
+     * Suggests a file extension for this image.
+     *
+     * @return the file extension.
+     */
     public String suggestFileExtension() {
-       return packagePart.getPartName().getExtension();
+        return getPackagePart().getPartName().getExtension();
+    }
+
+    /**
+     * Return an integer constant that specifies type of this picture
+     *
+     * @return an integer constant that specifies type of this picture 
+     * @see Workbook#PICTURE_TYPE_EMF
+     * @see Workbook#PICTURE_TYPE_WMF
+     * @see Workbook#PICTURE_TYPE_PICT
+     * @see Workbook#PICTURE_TYPE_JPEG
+     * @see Workbook#PICTURE_TYPE_PNG
+     * @see Workbook#PICTURE_TYPE_DIB
+     */
+    public int getPictureType(){
+        String contentType = getPackagePart().getContentType();
+        for (int i = 0; i < RELATIONS.length; i++) {
+            if(RELATIONS[i] == null) continue;
+
+            if(RELATIONS[i].getContentType().equals(contentType)){
+                return i;
+            }
+        }
+        return 0;
     }
 }
index 42781a59268de8b18591a1e902c7c04a2d88a09c..53197200b1c43ee9741eba7d0372a6e8c2b4fc56 100644 (file)
@@ -83,7 +83,7 @@ public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
                    StylesTable.class
        );
        public static final XSSFRelation DRAWINGS = new XSSFRelation(
-                       "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
+                       "application/vnd.openxmlformats-officedocument.drawing+xml",
                        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
                        "/xl/drawings/drawing#.xml",
                        null
@@ -95,9 +95,10 @@ public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
                        Drawing.class
        );
     public static final XSSFRelation IMAGES = new XSSFRelation(
-               "image/x-emf", // TODO
+            //client will substitute $type and $ext with the appropriate values depending on the passed data
+            "image/$type",
                "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
-               "/xl/media/image#.emf",
+               "/xl/media/image#.$ext",
                null
     );
        public static final XSSFRelation<CommentsTable> SHEET_COMMENTS = create(
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java
new file mode 100755 (executable)
index 0000000..861c96b
--- /dev/null
@@ -0,0 +1,93 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.apache.xmlbeans.XmlObject;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTAbsoluteAnchor;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor;\r
+import org.openxmlformats.schemas.drawingml.x2006.chartDrawing.CTGroupShape;\r
+\r
+/**\r
+ * Represents a shape in a SpreadsheetML drawing.\r
+ * \r
+ * @author Yegor Kozlov\r
+ */\r
+public abstract class XSSFShape {\r
+    public static final int EMU_PER_POINT = 12700;\r
+\r
+\r
+    /**\r
+     * Shape container. Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape\r
+     */\r
+    private XmlObject spContainer;\r
+\r
+    /**\r
+     * Parent drawing\r
+     */\r
+    private XSSFDrawing drawing;\r
+\r
+    /**\r
+     * The parent shape, always not-null for shapes in groups\r
+     */\r
+    private XSSFShape parent;\r
+\r
+    /**\r
+     * Construct a new XSSFSimpleShape object.\r
+     *\r
+     * @param parent the XSSFDrawing that owns this shape\r
+     * @param anchor an object that encloses the shape bean,\r
+     *   can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape\r
+     */\r
+    protected XSSFShape(XSSFDrawing parent, XmlObject anchor){\r
+        drawing = parent;\r
+        if(!(anchor instanceof CTTwoCellAnchor) && !(anchor instanceof CTOneCellAnchor) &&\r
+           !(anchor instanceof CTAbsoluteAnchor) && !(anchor instanceof CTGroupShape)) {\r
+            throw new IllegalArgumentException("anchor must be one of the following types: " +\r
+                    "CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape");\r
+        }\r
+        spContainer = anchor;\r
+    }\r
+\r
+    /**\r
+     * Return the anchor bean that encloses this shape.\r
+     * Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape.\r
+     *\r
+     * @return the anchor bean that encloses this shape\r
+     */\r
+    public XmlObject getShapeContainer(){\r
+        return spContainer;\r
+    }\r
+\r
+    /**\r
+     * Return the drawing that owns this shape\r
+     *\r
+     * @return the parent drawing that owns this shape\r
+     */\r
+    public XSSFDrawing getDrawing(){\r
+        return drawing;\r
+    }\r
+\r
+    /**\r
+     * Gets the parent shape.\r
+     */\r
+    public XSSFShape getParent()\r
+    {\r
+        return parent;\r
+    }\r
+\r
+}\r
index 638fea7f14aded987ea10b3083a7a117ceee2664..4db48fe2c7a35ee0712a08fa7fc34ae2160bac1f 100644 (file)
@@ -19,11 +19,7 @@ package org.apache.poi.xssf.usermodel;
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 import javax.xml.namespace.QName;
 
 import org.apache.poi.hssf.util.PaneInformation;
@@ -31,7 +27,6 @@ import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.CommentsSource;
 import org.apache.poi.ss.usermodel.Footer;
 import org.apache.poi.ss.usermodel.Header;
-import org.apache.poi.ss.usermodel.Patriarch;
 import org.apache.poi.ss.usermodel.PrintSetup;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
@@ -40,16 +35,18 @@ import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.ss.util.Region;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.model.Control;
-import org.apache.poi.xssf.model.Drawing;
 import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLException;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.POILogFactory;
 import org.apache.xmlbeans.XmlOptions;
 import org.apache.xmlbeans.XmlException;
 import org.openxml4j.opc.PackagePart;
 import org.openxml4j.opc.PackageRelationship;
 import org.openxml4j.opc.PackageRelationshipCollection;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
+import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
 
 
 /**
@@ -62,6 +59,8 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
  * </p>
  */
 public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
+    private static POILogger logger = POILogFactory.getLogger(XSSFSheet.class);
+
     protected CTSheet sheet;
     protected CTWorksheet worksheet;
     protected CTDialogsheet dialogsheet;
@@ -72,7 +71,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
     protected CTMergeCells ctMergeCells;
 
 
-    protected List<Drawing> drawings;
     protected List<Control> controls;
 
 
@@ -149,7 +147,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
         ctFormat.setDefaultRowHeight(15.0);
 
         CTSheetView ctView = worksheet.addNewSheetViews().addNewSheetView();
-        ctView.setTabSelected(true);
         ctView.setWorkbookViewId(0);
 
         worksheet.addNewDimension().setRef("A1");
@@ -167,11 +164,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
         return worksheet;
     }
 
-    public List<Drawing> getDrawings()
-    {
-        return drawings;
-        }
-
     public List<Control> getControls()
     {
         return controls;
@@ -263,9 +255,42 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
         columnHelper.setColBestFit(column, true);
     }
 
-    public Patriarch createDrawingPatriarch() {
-        // TODO Auto-generated method stub
-        return null;
+    /**
+     * Create a new SpreadsheetML drawing. If this sheet already contains a drawing - return that.
+     *
+     * @return a SpreadsheetML drawing
+     */
+    public XSSFDrawing createDrawingPatriarch() {
+        XSSFDrawing drawing = null;
+        CTDrawing ctDrawing = worksheet.getDrawing();
+        if(ctDrawing == null) {
+            //drawingNumber = #drawings.size() + 1
+            int drawingNumber = getPackagePart().getPackage().getPartsByRelationshipType(XSSFRelation.DRAWINGS.getRelation()).size() + 1;
+            drawing = (XSSFDrawing)createRelationship(XSSFRelation.DRAWINGS, XSSFDrawing.class, drawingNumber);
+            String relId = drawing.getPackageRelationship().getId();
+
+            //add CT_Drawing element which indicates that this sheet contains drawing components built on the drawingML platform.
+            //The relationship Id references the part containing the drawingML definitions.
+            ctDrawing = worksheet.addNewDrawing();
+            ctDrawing.setId(relId);
+        } else {
+            //search the referenced drawing in the list of the sheet's relations
+            for(POIXMLDocumentPart p : getRelations()){
+                if(p instanceof XSSFDrawing) {
+                    XSSFDrawing dr = (XSSFDrawing)p;
+                    String drId = dr.getPackageRelationship().getId();
+                    if(drId.equals(ctDrawing.getId())){
+                        drawing = dr;
+                        break;
+                    }
+                    break;
+                }
+            }
+            if(drawing == null){
+                logger.log(POILogger.ERROR, "Can't find drawing with id=" + ctDrawing.getId() + " in the list of the sheet's relationships");
+            }
+        }
+        return drawing;
     }
 
     /**
@@ -406,14 +431,16 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
     }
 
     public int getColumnWidth(int columnIndex) {
-        return (int) columnHelper.getColumn(columnIndex, false).getWidth();
+        CTCol col = columnHelper.getColumn(columnIndex, false);
+        return col == null ? getDefaultColumnWidth() : (int)col.getWidth();
     }
     public short getColumnWidth(short column) {
         return (short) getColumnWidth(column & 0xFFFF);
     }
 
     public int getDefaultColumnWidth() {
-        return (int)getSheetTypeSheetFormatPr().getDefaultColWidth();
+        CTSheetFormatPr pr = getSheetTypeSheetFormatPr();
+        return pr.isSetDefaultColWidth() ? (int)pr.getDefaultColWidth() : (int)pr.getBaseColWidth();
     }
 
     public short getDefaultRowHeight() {
@@ -1570,14 +1597,15 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
 
         XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
         xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
+
+        Map map = new HashMap();
+        map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
+        xmlOptions.setSaveSuggestedPrefixes(map);
+
         PackagePart part = getPackagePart();
         OutputStream out = part.getOutputStream();
         worksheet.save(out, xmlOptions);
         out.close();
     }
 
-    protected void setParent(POIXMLDocumentPart p){
-        this.parent = p;
-    }
-
 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
new file mode 100755 (executable)
index 0000000..a564013
--- /dev/null
@@ -0,0 +1,178 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.*;\r
+\r
+/**\r
+ * Represents an auto-shape in a SpreadsheetML drawing.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class XSSFSimpleShape extends XSSFShape {\r
+\r
+    private CTShape ctShape;\r
+\r
+    /**\r
+     * Construct a new XSSFSimpleShape object.\r
+     *\r
+     * @param parent the XSSFDrawing that owns this shape\r
+     * @param anchor the two cell anchor placeholder for this shape,\r
+     *               this object encloses the shape bean that holds all the shape properties\r
+     */\r
+    protected XSSFSimpleShape(XSSFDrawing parent, CTTwoCellAnchor anchor) {\r
+        super(parent, anchor);\r
+        ctShape = anchor.addNewSp();\r
+        newShape(ctShape);\r
+    }\r
+\r
+    /**\r
+     * Initialize default structure of a new auto-shape\r
+     *\r
+     * @param shape newly created shape to initialize\r
+     */\r
+    private static void newShape(CTShape shape) {\r
+        CTShapeNonVisual nv = shape.addNewNvSpPr();\r
+        CTNonVisualDrawingProps nvp = nv.addNewCNvPr();\r
+        int shapeId = 1;\r
+        nvp.setId(shapeId);\r
+        nvp.setName("Shape " + shapeId);\r
+        nv.addNewCNvSpPr();\r
+\r
+        CTShapeProperties sp = shape.addNewSpPr();\r
+        CTTransform2D t2d = sp.addNewXfrm();\r
+        CTPositiveSize2D p1 = t2d.addNewExt();\r
+        p1.setCx(0);\r
+        p1.setCy(0);\r
+        CTPoint2D p2 = t2d.addNewOff();\r
+        p2.setX(0);\r
+        p2.setY(0);\r
+\r
+        CTPresetGeometry2D geom = sp.addNewPrstGeom();\r
+        geom.setPrst(STShapeType.RECT);\r
+        geom.addNewAvLst();\r
+\r
+        CTShapeStyle style = shape.addNewStyle();\r
+        CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr();\r
+        scheme.setVal(STSchemeColorVal.ACCENT_1);\r
+        scheme.addNewShade().setVal(50000);\r
+        style.getLnRef().setIdx(2);\r
+\r
+        CTStyleMatrixReference fillref = style.addNewFillRef();\r
+        fillref.setIdx(1);\r
+        fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);\r
+\r
+        CTStyleMatrixReference effectRef = style.addNewEffectRef();\r
+        effectRef.setIdx(0);\r
+        effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1);\r
+\r
+        CTFontReference fontRef = style.addNewFontRef();\r
+        fontRef.setIdx(STFontCollectionIndex.MINOR);\r
+        fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1);\r
+\r
+        CTTextBody body = shape.addNewTxBody();\r
+        CTTextBodyProperties bodypr = body.addNewBodyPr();\r
+        bodypr.setAnchor(STTextAnchoringType.CTR);\r
+        bodypr.setRtlCol(false);\r
+        CTTextParagraph p = body.addNewP();\r
+        p.addNewPPr().setAlgn(STTextAlignType.CTR);\r
+\r
+        body.addNewLstStyle();\r
+    }\r
+\r
+    /**\r
+     * Gets the shape type, one of the constants defined in {@link ShapeTypes}.\r
+     *\r
+     * @return the shape type\r
+     * @see ShapeTypes\r
+     */\r
+    public int getShapeType() {\r
+        return ctShape.getSpPr().getPrstGeom().getPrst().intValue();\r
+    }\r
+\r
+    /**\r
+     * Sets the shape types.\r
+     *\r
+     * @param type the shape type, one of the constants defined in {@link ShapeTypes}.\r
+     * @see ShapeTypes\r
+     */\r
+    public void setShapeType(int type) {\r
+        ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));\r
+    }\r
+\r
+\r
+    /**\r
+     * Whether this shape is not filled with a color\r
+     *\r
+     * @return true if this shape is not filled with a color.\r
+     */\r
+    public boolean isNoFill() {\r
+        return ctShape.getSpPr().isSetNoFill();\r
+    }\r
+\r
+    /**\r
+     * Sets whether this shape is filled or transparent.\r
+     *\r
+     * @param noFill if true then no fill will be applied to the shape element.\r
+     */\r
+    public void setNoFill(boolean noFill) {\r
+        CTShapeProperties props = ctShape.getSpPr();\r
+        //unset solid and pattern fills if they are set\r
+        if (props.isSetPattFill()) props.unsetPattFill();\r
+        if (props.isSetSolidFill()) props.unsetSolidFill();\r
+\r
+        props.setNoFill(CTNoFillProperties.Factory.newInstance());\r
+    }\r
+\r
+    /**\r
+     * Sets the color used to fill this shape using the solid fill pattern.\r
+     */\r
+    public void setFillColor(int red, int green, int blue) {\r
+        CTShapeProperties props = ctShape.getSpPr();\r
+        CTSolidColorFillProperties fill = props.isSetSolidFill() ? props.getSolidFill() : props.addNewSolidFill();\r
+        CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
+        rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue});\r
+        fill.setSrgbClr(rgb);\r
+    }\r
+\r
+    /**\r
+     * The color applied to the lines of this shape.\r
+     */\r
+    public void setLineStyleColor( int red, int green, int blue ) {\r
+        CTShapeProperties props = ctShape.getSpPr();\r
+        CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn();\r
+        CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln.getSolidFill() : ln.addNewSolidFill();\r
+        CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
+        rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue});\r
+        fill.setSrgbClr(rgb);\r
+    }\r
+\r
+    /**\r
+     * Specifies the width to be used for the underline stroke.\r
+     *\r
+     * @param lineWidth width in points\r
+     */\r
+    public void setLineWidth( double lineWidth ) {\r
+        CTShapeProperties props = ctShape.getSpPr();\r
+        CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn();\r
+        ln.setW((int)(lineWidth*EMU_PER_POINT));\r
+    }\r
+\r
+}\r
index 674a422440801007c5b588d493f17a1454f66074..bcc61660f6f8e8efa85add1629fb3b4191f69207 100644 (file)
@@ -19,10 +19,9 @@ package org.apache.poi.xssf.usermodel;
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.util.*;
 import javax.xml.namespace.QName;
 import org.apache.poi.POIXMLDocument;
 import org.apache.poi.POIXMLDocumentPart;
@@ -35,6 +34,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.PackageHelper;
+import org.apache.poi.util.IOUtils;
 import org.apache.poi.xssf.model.*;
 import org.apache.poi.POIXMLException;
 import org.apache.xmlbeans.XmlObject;
@@ -44,6 +44,7 @@ import org.openxml4j.exceptions.OpenXML4JException;
 import org.openxml4j.opc.*;
 import org.openxml4j.opc.Package;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
+import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
 
 /**
  * High level representation of a SpreadsheetML workbook.  This is the first object most users
@@ -93,6 +94,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
      */
     private MissingCellPolicy missingCellPolicy = Row.RETURN_NULL_AND_BLANK;
 
+    /**
+     * array of pictures for this workbook
+     */
+    private List<XSSFPictureData> pictures;
+
     private static POILogger log = POILogFactory.getLogger(XSSFWorkbook.class);
 
     /**
@@ -250,9 +256,33 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
         return this.workbook;
     }
 
+    /**
+     * Adds a picture to the workbook.
+     *
+     * @param pictureData       The bytes of the picture
+     * @param format            The format of the picture.
+     *
+     * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} .
+     * @see #PICTURE_TYPE_EMF
+     * @see #PICTURE_TYPE_WMF
+     * @see #PICTURE_TYPE_PICT
+     * @see #PICTURE_TYPE_JPEG
+     * @see #PICTURE_TYPE_PNG
+     * @see #PICTURE_TYPE_DIB
+     * @see #getAllPictures()
+     */
     public int addPicture(byte[] pictureData, int format) {
-        // TODO Auto-generated method stub
-        return 0;
+        int imageNumber = getAllPictures().size() + 1;
+        XSSFPictureData img = (XSSFPictureData)createRelationship(XSSFPictureData.RELATIONS[format], XSSFPictureData.class, imageNumber, true);
+        try {
+            OutputStream out = img.getPackagePart().getOutputStream();
+            out.write(pictureData);
+            out.close();
+        } catch (IOException e){
+            throw new POIXMLException(e);
+        }
+        pictures.add(img);
+        return imageNumber - 1;
     }
 
     public XSSFSheet cloneSheet(int sheetNum) {
@@ -363,13 +393,12 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
 
         int sheetNumber = getNumberOfSheets() + 1;
         XSSFSheet wrapper = (XSSFSheet)createRelationship(XSSFRelation.WORKSHEET, XSSFSheet.class, sheetNumber);
-        wrapper.setParent(this);
 
         CTSheet sheet = addSheet(sheetname);
         wrapper.sheet = sheet;
         sheet.setId(wrapper.getPackageRelationship().getId());
         sheet.setSheetId(sheetNumber);
-
+        if(sheets.size() == 0) wrapper.setSelected(true);
         this.sheets.add(wrapper);
         return wrapper;
     }
@@ -438,27 +467,21 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
      *
      * @return the list of pictures (a list of {@link XSSFPictureData} objects.)
      */
-    public List<PictureData> getAllPictures() {
-        // In OOXML pictures are referred to in sheets
-        List<PictureData> pictures = new LinkedList<PictureData>();
-        for(POIXMLDocumentPart p : getRelations()){
-            if (p instanceof XSSFSheet) {
-                PackagePart sheetPart = p.getPackagePart();
-                try {
-                    PackageRelationshipCollection prc = sheetPart.getRelationshipsByType(XSSFRelation.DRAWINGS.getRelation());
-                    for (PackageRelationship rel : prc) {
-                        PackagePart drawingPart = getTargetPart(rel);
-                        PackageRelationshipCollection prc2 = drawingPart.getRelationshipsByType(XSSFRelation.IMAGES.getRelation());
-                        for (PackageRelationship rel2 : prc2) {
-                            PackagePart imagePart = getTargetPart(rel2);
-                            XSSFPictureData pd = new XSSFPictureData(imagePart);
-                            pictures.add(pd);
+    public List<XSSFPictureData> getAllPictures() {
+        if(pictures == null) {
+            //In OOXML pictures are referred to in sheets,
+            //dive into sheet's relations, select drawings and their images
+            pictures = new ArrayList();
+            for(XSSFSheet sh : sheets){
+                for(POIXMLDocumentPart dr : sh.getRelations()){
+                    if(dr instanceof XSSFDrawing){
+                        for(POIXMLDocumentPart img : dr.getRelations()){
+                            if(img instanceof XSSFPictureData){
+                                pictures.add((XSSFPictureData)img);
+                            }
                         }
                     }
-                } catch (InvalidFormatException e) {
-                    throw new POIXMLException(e.getMessage(), e);
                 }
-
             }
         }
         return pictures;
@@ -705,7 +728,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
      */
     public void removeSheetAt(int index) {
         validateSheetIndex(index);
-        
+
         this.sheets.remove(index);
         this.workbook.getSheets().removeSheet(index);
     }
@@ -878,6 +901,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
 
         XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
         xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorkbook.type.getName().getNamespaceURI(), "workbook"));
+        Map map = new HashMap();
+        map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
+        xmlOptions.setSaveSuggestedPrefixes(map);
+
         PackagePart part = getPackagePart();
         OutputStream out = part.getOutputStream();
         workbook.save(out, xmlOptions);
index 6b590df934b279aec768ceaddb007b99a4c2f8f5..94e8c090073d16a98a9a8709a36e9abad32e95df 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.poi.ss.usermodel.PictureData;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFPictureData;
 
 
 public class TestLoadSaveXSSF extends TestCase {
@@ -42,7 +43,7 @@ public class TestLoadSaveXSSF extends TestCase {
             filename = "src/ooxml/testcases/org/apache/poi/xssf/data";
         }
     }
-    
+
     public void testLoadSample() throws Exception {
         XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "sample.xlsx").getAbsolutePath());
         assertEquals(3, workbook.getNumberOfSheets());
@@ -55,7 +56,7 @@ public class TestLoadSaveXSSF extends TestCase {
         cell = row.getCell((short) 0);
         assertEquals("Lorem", cell.getRichStringCellValue().getString());
     }
-    
+
     // TODO filename string hard coded in XSSFWorkbook constructor in order to make ant test-ooxml target be successfull.
     public void testLoadStyles() throws Exception {
         XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "styles.xlsx").getAbsolutePath());
@@ -69,7 +70,7 @@ public class TestLoadSaveXSSF extends TestCase {
     // TODO filename string hard coded in XSSFWorkbook constructor in order to make ant test-ooxml target be successfull.
     public void testLoadPictures() throws Exception {
         XSSFWorkbook workbook = new XSSFWorkbook(new File(filename, "picture.xlsx").getAbsolutePath());
-        List<PictureData> pictures = workbook.getAllPictures();
+        List<XSSFPictureData> pictures = workbook.getAllPictures();
         assertEquals(1, pictures.size());
     }
 
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java
new file mode 100755 (executable)
index 0000000..c2ff6ac
--- /dev/null
@@ -0,0 +1,70 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.xssf.XSSFTestDataSamples;\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;\r
+\r
+import java.util.List;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestXSSFDrawing extends TestCase {\r
+    public void testRead(){\r
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");\r
+        XSSFSheet sheet = wb.getSheetAt(0);\r
+        //the sheet has one relationship and it is XSSFDrawing\r
+        List<POIXMLDocumentPart> rels = sheet.getRelations();\r
+        assertEquals(1, rels.size());\r
+        assertTrue(rels.get(0) instanceof XSSFDrawing);\r
+\r
+        XSSFDrawing drawing = (XSSFDrawing)rels.get(0);\r
+        //sheet.createDrawingPatriarch() should return the same instance of XSSFDrawing\r
+        assertSame(drawing, sheet.createDrawingPatriarch());\r
+        String drawingId = drawing.getPackageRelationship().getId();\r
+\r
+        //there should be a relation to this drawing in the worksheet\r
+        assertTrue(sheet.getWorksheet().isSetDrawing());\r
+        assertEquals(drawingId, sheet.getWorksheet().getDrawing().getId());\r
+\r
+    }\r
+\r
+    public void testNew(){\r
+        XSSFWorkbook wb = new XSSFWorkbook();\r
+        XSSFSheet sheet = wb.createSheet();\r
+        //multiple calls of createDrawingPatriarch should return the same instance of XSSFDrawing\r
+        XSSFDrawing dr1 = sheet.createDrawingPatriarch();\r
+        XSSFDrawing dr2 = sheet.createDrawingPatriarch();\r
+        assertSame(dr1, dr2);\r
+\r
+        List<POIXMLDocumentPart> rels = sheet.getRelations();\r
+        assertEquals(1, rels.size());\r
+        assertTrue(rels.get(0) instanceof XSSFDrawing);\r
+\r
+        XSSFDrawing drawing = (XSSFDrawing)rels.get(0);\r
+        String drawingId = drawing.getPackageRelationship().getId();\r
+\r
+        //there should be a relation to this drawing in the worksheet\r
+        assertTrue(sheet.getWorksheet().isSetDrawing());\r
+        assertEquals(drawingId, sheet.getWorksheet().getDrawing().getId());\r
+\r
+    }\r
+}\r
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPicture.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPicture.java
new file mode 100755 (executable)
index 0000000..eb405f1
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.xssf.XSSFTestDataSamples;\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;\r
+\r
+import java.util.List;\r
+import java.util.Arrays;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestXSSFPicture extends TestCase {\r
+\r
+    public void testCreate(){\r
+        XSSFWorkbook wb = new XSSFWorkbook();\r
+        XSSFSheet sheet = wb.createSheet();\r
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();\r
+\r
+        byte[] jpegData = "test jpeg data".getBytes();\r
+\r
+        List<XSSFPictureData> pictures = wb.getAllPictures();\r
+        assertEquals(0, pictures.size());\r
+\r
+        int jpegIdx = wb.addPicture(jpegData, XSSFWorkbook.PICTURE_TYPE_JPEG);\r
+        assertEquals(1, pictures.size());\r
+        assertEquals("jpeg", pictures.get(jpegIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(jpegData, pictures.get(jpegIdx).getData()));\r
+\r
+        XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 1, 1, 10, 30);\r
+        XSSFPicture shape = drawing.createPicture(anchor, jpegIdx);\r
+        assertTrue(anchor.equals(shape.getAnchor()));\r
+        assertNotNull(shape.getPictureData());\r
+        assertTrue(Arrays.equals(jpegData, shape.getPictureData().getData()));\r
+\r
+    }\r
+}\r
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPictureData.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFPictureData.java
new file mode 100755 (executable)
index 0000000..50b90e7
--- /dev/null
@@ -0,0 +1,104 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.xssf.XSSFTestDataSamples;\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;\r
+\r
+import java.util.List;\r
+import java.util.Arrays;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * @author Yegor Kozlov\r
+ */\r
+public class TestXSSFPictureData extends TestCase {\r
+    public void testRead(){\r
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");\r
+        List<XSSFPictureData> pictures = wb.getAllPictures();\r
+        //wb.getAllPictures() should return the same instance across multiple calls\r
+        assertSame(pictures, wb.getAllPictures());\r
+\r
+        assertEquals(5, pictures.size());\r
+        String[] ext = {"jpeg", "emf", "png", "emf", "wmf"};\r
+        for (int i = 0; i < pictures.size(); i++) {\r
+            assertEquals(ext[i], pictures.get(i).suggestFileExtension());\r
+        }\r
+\r
+        int num = pictures.size();\r
+\r
+        byte[] pictureData = {0xA, 0xB, 0XC, 0xD, 0xE, 0xF};\r
+\r
+        int idx = wb.addPicture(pictureData, XSSFWorkbook.PICTURE_TYPE_JPEG);\r
+        assertEquals(num + 1, pictures.size());\r
+        //idx is 0-based index in the #pictures array\r
+        assertEquals(pictures.size() - 1, idx);\r
+        XSSFPictureData pict = pictures.get(idx);\r
+        assertEquals("jpeg", pict.suggestFileExtension());\r
+        assertTrue(Arrays.equals(pictureData, pict.getData()));\r
+    }\r
+\r
+    public void testNew(){\r
+        XSSFWorkbook wb = new XSSFWorkbook();\r
+        XSSFSheet sheet = wb.createSheet();\r
+        XSSFDrawing drawing = sheet.createDrawingPatriarch();\r
+\r
+        byte[] jpegData = "test jpeg data".getBytes();\r
+        byte[] wmfData =  "test wmf data".getBytes();\r
+        byte[] pngData =  "test png data".getBytes();\r
+\r
+        List<XSSFPictureData> pictures = wb.getAllPictures();\r
+        assertEquals(0, pictures.size());\r
+\r
+        int jpegIdx = wb.addPicture(jpegData, XSSFWorkbook.PICTURE_TYPE_JPEG);\r
+        assertEquals(1, pictures.size());\r
+        assertEquals("jpeg", pictures.get(jpegIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(jpegData, pictures.get(jpegIdx).getData()));\r
+\r
+        int wmfIdx = wb.addPicture(wmfData, XSSFWorkbook.PICTURE_TYPE_WMF);\r
+        assertEquals(2, pictures.size());\r
+        assertEquals("wmf", pictures.get(wmfIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(wmfData, pictures.get(wmfIdx).getData()));\r
+\r
+        int pngIdx = wb.addPicture(pngData, XSSFWorkbook.PICTURE_TYPE_PNG);\r
+        assertEquals(3, pictures.size());\r
+        assertEquals("png", pictures.get(pngIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(pngData, pictures.get(pngIdx).getData()));\r
+\r
+        //TODO finish usermodel API for XSSFPicture\r
+        XSSFPicture p1 = drawing.createPicture(new XSSFClientAnchor(), jpegIdx);\r
+        XSSFPicture p2 = drawing.createPicture(new XSSFClientAnchor(), wmfIdx);\r
+        XSSFPicture p3 = drawing.createPicture(new XSSFClientAnchor(), pngIdx);\r
+\r
+        //check that the added pictures are accessible after write\r
+        wb = XSSFTestDataSamples.writeOutAndReadBack(wb);\r
+        List<XSSFPictureData> pictures2 = wb.getAllPictures();\r
+        assertEquals(3, pictures2.size());\r
+\r
+        assertEquals("jpeg", pictures2.get(jpegIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(jpegData, pictures2.get(jpegIdx).getData()));\r
+\r
+        assertEquals("wmf", pictures2.get(wmfIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(wmfData, pictures2.get(wmfIdx).getData()));\r
+\r
+        assertEquals("png", pictures2.get(pngIdx).suggestFileExtension());\r
+        assertTrue(Arrays.equals(pngData, pictures2.get(pngIdx).getData()));\r
+\r
+    }\r
+}\r
index 402725aca56fef64b7669787072aa64c08b43e84..0400c5b4d7cc231333bda1e59aed16309e8d5b98 100644 (file)
@@ -41,7 +41,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
 
 
 public class TestXSSFSheet extends TestCase {
-    
+
     public void testRowIterator() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -55,7 +55,7 @@ public class TestXSSFSheet extends TestCase {
         assertEquals(row2, it.next());
         assertFalse(it.hasNext());
     }
-    
+
     public void testGetRow() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -63,17 +63,17 @@ public class TestXSSFSheet extends TestCase {
         Cell cell = row1.createCell((short) 0);
         cell.setCellType(Cell.CELL_TYPE_NUMERIC);
         cell.setCellValue((double) 1000);
-        
+
         // Test getting a row and check its cell's value
         Row row_got = sheet.getRow(0);
         Cell cell_got = row_got.getCell((short) 0);
         assertEquals((double) 1000, cell_got.getNumericCellValue());
     }
-    
+
     public void testCreateRow() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
-        
+
         // Test row creation with consecutive indexes
         Row row1 = sheet.createRow(0);
         Row row2 = sheet.createRow(1);
@@ -84,11 +84,11 @@ public class TestXSSFSheet extends TestCase {
         assertEquals(row1, it.next());
         assertTrue(it.hasNext());
         assertEquals(row2, it.next());
-        
+
         // Test row creation with non consecutive index
         Row row101 = sheet.createRow(100);
         assertNotNull(row101);
-        
+
         // Test overwriting an existing row
         Row row2_ovrewritten = sheet.createRow(1);
         Cell cell = row2_ovrewritten.createCell((short) 0);
@@ -102,7 +102,7 @@ public class TestXSSFSheet extends TestCase {
         assertEquals(row2_ovrewritten, row2_overwritten_copy);
         assertEquals(row2_overwritten_copy.getCell((short) 0).getNumericCellValue(), (double) 100);
     }
-    
+
     public void testRemoveRow() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -114,7 +114,7 @@ public class TestXSSFSheet extends TestCase {
         assertNull(sheet.getRow(2));
         assertNotNull(sheet.getRow(1));
     }
-    
+
     public void testGetSetDefaultRowHeight() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -131,17 +131,17 @@ public class TestXSSFSheet extends TestCase {
         sheet.setDefaultRowHeightInPoints((short) 17);
         assertEquals((short) 340, sheet.getDefaultRowHeight());
     }
-    
+
     public void testGetSetDefaultColumnWidth() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
         // Test that default column width set by the constructor
-        assertEquals((short) 0, sheet.getDefaultColumnWidth());
+        assertEquals((short) 8, sheet.getDefaultColumnWidth());
         // Set a new default column width and get its value
         sheet.setDefaultColumnWidth((short) 14);
         assertEquals((short) 14, sheet.getDefaultColumnWidth());
     }
-    
+
     public void testGetFirstLastRowNum() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -149,9 +149,9 @@ public class TestXSSFSheet extends TestCase {
         Row row1 = sheet.createRow(0);
         Row row2 = sheet.createRow(1);
         assertEquals(0, sheet.getFirstRowNum());
-        assertEquals(9, sheet.getLastRowNum());    
+        assertEquals(9, sheet.getLastRowNum());
     }
-    
+
     public void testGetPhysicalNumberOfRows() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -160,7 +160,7 @@ public class TestXSSFSheet extends TestCase {
         Row row2 = sheet.createRow(1);
         assertEquals(3, sheet.getPhysicalNumberOfRows());
     }
-    
+
     public void testGetSetRowBreaks() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -173,7 +173,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.setRowBreak(1);
         assertEquals(2, sheet.getRowBreaks().length);
     }
-    
+
     public void testRemoveRowBreak() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -184,7 +184,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.removeRowBreak(1);
         assertEquals(1, sheet.getRowBreaks().length);
     }
-    
+
     public void testGetSetColumnBreaks() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -195,7 +195,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.setColumnBreak((short) 11223);
         assertEquals(2, sheet.getColumnBreaks().length);
     }
-    
+
     public void testRemoveColumnBreak() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -209,7 +209,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.removeColumnBreak((short) 15);
         assertEquals(1, sheet.getColumnBreaks().length);
     }
-    
+
     public void testIsRowColumnBroken() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -220,7 +220,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.setColumnBreak((short) 3);
         assertTrue(sheet.isColumnBroken((short) 3));
     }
-    
+
     public void testGetSetAutoBreaks() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -228,7 +228,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.setAutobreaks(false);
         assertFalse(sheet.getAutobreaks());
     }
-    
+
     public void testIsSetFitToPage() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -238,7 +238,7 @@ public class TestXSSFSheet extends TestCase {
         sheet.setFitToPage(false);
         assertFalse(sheet.getFitToPage());
     }
-    
+
     public void testGetSetMargin() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
@@ -270,7 +270,7 @@ public class TestXSSFSheet extends TestCase {
         assertEquals((double) 14, sheet.getMargin((short) 5));
         sheet.setMargin((short) 5, 15);
         assertEquals((double) 15, sheet.getMargin((short) 5));
-        
+
         // Test that nothing happens if another margin constant is given (E.G. 65)
         sheet.setMargin((short) 65, 15);
         assertEquals((double) 10, sheet.getMargin((short) 0));
@@ -280,83 +280,83 @@ public class TestXSSFSheet extends TestCase {
         assertEquals((double) 14, sheet.getMargin((short) 4));
         assertEquals((double) 15, sheet.getMargin((short) 5));
     }
-    
+
     public void testGetFooter() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         XSSFSheet sheet = (XSSFSheet)workbook.createSheet("Sheet 1");
         assertNotNull(sheet.getFooter());
         sheet.getFooter().setCenter("test center footer");
         assertEquals("test center footer", sheet.getFooter().getCenter());
-        
+
         // Default is odd footer
         assertNotNull(sheet.getOddFooter());
         assertEquals("test center footer", sheet.getOddFooter().getCenter());
     }
-    
+
     public void testExistingHeaderFooter() throws Exception {
                File xml = new File(
                                System.getProperty("HSSF.testdata.path") +
                                File.separator + "45540_classic_Header.xlsx"
                );
                assertTrue(xml.exists());
-       
+
                XSSFWorkbook workbook = new XSSFWorkbook(xml.toString());
                XSSFOddHeader hdr;
                XSSFOddFooter ftr;
-               
+
                // Sheet 1 has a header with center and right text
                XSSFSheet s1 = (XSSFSheet)workbook.getSheetAt(0);
                assertNotNull(s1.getHeader());
                assertNotNull(s1.getFooter());
-               hdr = (XSSFOddHeader)s1.getHeader(); 
-               ftr = (XSSFOddFooter)s1.getFooter(); 
-               
+               hdr = (XSSFOddHeader)s1.getHeader();
+               ftr = (XSSFOddFooter)s1.getFooter();
+
                assertEquals("&Ctestdoc&Rtest phrase", hdr.getText());
                assertEquals(null, ftr.getText());
-               
+
                assertEquals("", hdr.getLeft());
                assertEquals("testdoc", hdr.getCenter());
                assertEquals("test phrase", hdr.getRight());
-               
+
                assertEquals("", ftr.getLeft());
                assertEquals("", ftr.getCenter());
                assertEquals("", ftr.getRight());
-               
-               
+
+
                // Sheet 2 has a footer, but it's empty
                XSSFSheet s2 = (XSSFSheet)workbook.getSheetAt(1);
                assertNotNull(s2.getHeader());
                assertNotNull(s2.getFooter());
-               hdr = (XSSFOddHeader)s2.getHeader(); 
-               ftr = (XSSFOddFooter)s2.getFooter(); 
-               
+               hdr = (XSSFOddHeader)s2.getHeader();
+               ftr = (XSSFOddFooter)s2.getFooter();
+
                assertEquals(null, hdr.getText());
                assertEquals("&L&F", ftr.getText());
-               
+
                assertEquals("", hdr.getLeft());
                assertEquals("", hdr.getCenter());
                assertEquals("", hdr.getRight());
-               
+
                assertEquals("&F", ftr.getLeft());
                assertEquals("", ftr.getCenter());
                assertEquals("", ftr.getRight());
-               
-               
+
+
                // Save and reload
                XSSFWorkbook wb = XSSFTestDataSamples.writeOutAndReadBack(workbook);
-               
+
                hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader();
-               ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter(); 
-               
+               ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter();
+
                assertEquals("", hdr.getLeft());
                assertEquals("testdoc", hdr.getCenter());
                assertEquals("test phrase", hdr.getRight());
-               
+
                assertEquals("", ftr.getLeft());
                assertEquals("", ftr.getCenter());
                assertEquals("", ftr.getRight());
     }
-    
+
     public void testGetAllHeadersFooters() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         XSSFSheet sheet = (XSSFSheet) workbook.createSheet("Sheet 1");
@@ -366,27 +366,27 @@ public class TestXSSFSheet extends TestCase {
         assertNotNull(sheet.getOddHeader());
         assertNotNull(sheet.getEvenHeader());
         assertNotNull(sheet.getFirstHeader());
-        
+
         assertEquals("", sheet.getOddFooter().getLeft());
         sheet.getOddFooter().setLeft("odd footer left");
         assertEquals("odd footer left", sheet.getOddFooter().getLeft());
-        
+
         assertEquals("", sheet.getEvenFooter().getLeft());
         sheet.getEvenFooter().setLeft("even footer left");
         assertEquals("even footer left", sheet.getEvenFooter().getLeft());
-        
+
         assertEquals("", sheet.getFirstFooter().getLeft());
         sheet.getFirstFooter().setLeft("first footer left");
         assertEquals("first footer left", sheet.getFirstFooter().getLeft());
-        
+
         assertEquals("", sheet.getOddHeader().getLeft());
         sheet.getOddHeader().setLeft("odd header left");
         assertEquals("odd header left", sheet.getOddHeader().getLeft());
-        
+
         assertEquals("", sheet.getOddHeader().getRight());
         sheet.getOddHeader().setRight("odd header right");
         assertEquals("odd header right", sheet.getOddHeader().getRight());
-        
+
         assertEquals("", sheet.getOddHeader().getCenter());
         sheet.getOddHeader().setCenter("odd header center");
         assertEquals("odd header center", sheet.getOddHeader().getCenter());
@@ -395,49 +395,49 @@ public class TestXSSFSheet extends TestCase {
         assertEquals("odd footer left", sheet.getFooter().getLeft());
         assertEquals("odd header center", sheet.getHeader().getCenter());
     }
-    
+
     public void testGetSetColumnWidth() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
         sheet.setColumnWidth((short) 1,(short)  22);
         assertEquals(22, sheet.getColumnWidth((short) 1));
-        
+
         // Now check the low level stuff, and check that's all
         //  been set correctly
         XSSFSheet xs = (XSSFSheet)sheet;
         CTWorksheet cts = xs.getWorksheet();
-        
+
         CTCols[] cols_s = cts.getColsArray();
         assertEquals(1, cols_s.length);
         CTCols cols = cols_s[0];
         assertEquals(1, cols.sizeOfColArray());
         CTCol col = cols.getColArray(0);
-        
+
         // XML is 1 based, POI is 0 based
         assertEquals(2, col.getMin());
         assertEquals(2, col.getMax());
         assertEquals(22.0, col.getWidth());
-        
-        
+
+
         // Now set another
         sheet.setColumnWidth((short) 3,(short)  33);
-        
+
         cols_s = cts.getColsArray();
         assertEquals(1, cols_s.length);
         cols = cols_s[0];
         assertEquals(2, cols.sizeOfColArray());
-        
+
         col = cols.getColArray(0);
         assertEquals(2, col.getMin()); // POI 1
         assertEquals(2, col.getMax());
         assertEquals(22.0, col.getWidth());
-        
+
         col = cols.getColArray(1);
         assertEquals(4, col.getMin()); // POI 3
         assertEquals(4, col.getMax());
         assertEquals(33.0, col.getWidth());
     }
-    
+
     public void testGetSetColumnHidden() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         Sheet sheet = workbook.createSheet("Sheet 1");
diff --git a/src/testcases/org/apache/poi/hssf/data/WithDrawing.xlsx b/src/testcases/org/apache/poi/hssf/data/WithDrawing.xlsx
new file mode 100755 (executable)
index 0000000..862cd37
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/WithDrawing.xlsx differ