]> source.dussan.org Git - poi.git/commitdiff
#56004 - Support for WMF rendering
authorAndreas Beeker <kiwiwings@apache.org>
Sat, 16 Jan 2016 00:11:01 +0000 (00:11 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sat, 16 Jan 2016 00:11:01 +0000 (00:11 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724897 13f79535-47bb-0310-9956-ffa450edef68

17 files changed:
src/java/org/apache/poi/ddf/EscherProperties.java
src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java [new file with mode: 0644]
src/java/org/apache/poi/sl/draw/DrawFactory.java
src/java/org/apache/poi/sl/draw/DrawGraphicalFrame.java [new file with mode: 0644]
src/java/org/apache/poi/sl/draw/DrawPaint.java
src/java/org/apache/poi/sl/draw/DrawPictureShape.java
src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
src/java/org/apache/poi/sl/draw/ImageRenderer.java
src/java/org/apache/poi/sl/usermodel/GraphicalFrame.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfSLImageRenderer.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java

index 7e52fea44eb3203d17d5fde6ed2c38879cfc1873..096a20c574545175e5fe15433a2ca3a5b343eb2a 100644 (file)
@@ -186,6 +186,10 @@ public final class EscherProperties {
        public static final short LINESTYLE__HITLINETEST = 509;
        public static final short LINESTYLE__LINEFILLSHAPE = 510;
        public static final short LINESTYLE__NOLINEDRAWDASH = 511;
+       public static final short LINESTYLE__NOLINEDRAWDASH_LEFT = 0x057F;
+       public static final short LINESTYLE__NOLINEDRAWDASH_TOP = 0x05BF;
+       public static final short LINESTYLE__NOLINEDRAWDASH_BOTTOM = 0x063F;
+       public static final short LINESTYLE__NOLINEDRAWDASH_RIGHT = 0x05FF;
        public static final short SHADOWSTYLE__TYPE = 512;
        public static final short SHADOWSTYLE__COLOR = 513;
        public static final short SHADOWSTYLE__HIGHLIGHT = 514;
@@ -488,6 +492,10 @@ public final class EscherProperties {
                addProp(m, LINESTYLE__HITLINETEST, "linestyle.hitlinetest");
                addProp(m, LINESTYLE__LINEFILLSHAPE, "linestyle.linefillshape");
                addProp(m, LINESTYLE__NOLINEDRAWDASH, "linestyle.nolinedrawdash", EscherPropertyMetaData.TYPE_BOOLEAN);
+        addProp(m, LINESTYLE__NOLINEDRAWDASH_LEFT, "linestyle.nolinedrawdash.left", EscherPropertyMetaData.TYPE_BOOLEAN);
+        addProp(m, LINESTYLE__NOLINEDRAWDASH_TOP, "linestyle.nolinedrawdash.top", EscherPropertyMetaData.TYPE_BOOLEAN);
+        addProp(m, LINESTYLE__NOLINEDRAWDASH_BOTTOM, "linestyle.nolinedrawdash.bottom", EscherPropertyMetaData.TYPE_BOOLEAN);
+        addProp(m, LINESTYLE__NOLINEDRAWDASH_RIGHT, "linestyle.nolinedrawdash.right", EscherPropertyMetaData.TYPE_BOOLEAN);
                addProp(m, SHADOWSTYLE__TYPE, "shadowstyle.type");
                addProp(m, SHADOWSTYLE__COLOR, "shadowstyle.color", EscherPropertyMetaData.TYPE_RGB);
                addProp(m, SHADOWSTYLE__HIGHLIGHT, "shadowstyle.highlight");
diff --git a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
new file mode 100644 (file)
index 0000000..5099246
--- /dev/null
@@ -0,0 +1,142 @@
+/* ====================================================================\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
+\r
+package org.apache.poi.sl.draw;\r
+\r
+import java.awt.Dimension;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.Insets;\r
+import java.awt.Shape;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.RescaleOp;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import javax.imageio.ImageIO;\r
+\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * For now this class renders only images supported by the javax.imageio.ImageIO framework.\r
+ **/\r
+public class BitmapImageRenderer implements ImageRenderer {\r
+    private final static POILogger LOG = POILogFactory.getLogger(ImageRenderer.class);\r
+\r
+    protected BufferedImage img;\r
+\r
+    @Override\r
+    public void loadImage(InputStream data, String contentType) throws IOException {\r
+        img = convertBufferedImage(ImageIO.read(data), contentType);\r
+    }\r
+\r
+    @Override\r
+    public void loadImage(byte data[], String contentType) throws IOException {\r
+        img = convertBufferedImage(ImageIO.read(new ByteArrayInputStream(data)), contentType);\r
+    }\r
+\r
+    /**\r
+     * Add alpha channel to buffered image\r
+     */\r
+    private static BufferedImage convertBufferedImage(BufferedImage img, String contentType) {\r
+        if (img == null) {\r
+            LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");\r
+            return null;\r
+        }\r
+\r
+        BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
+        Graphics g = bi.getGraphics();\r
+        g.drawImage(img, 0, 0, null);\r
+        g.dispose();\r
+        return bi;\r
+    }\r
+\r
+\r
+    /**\r
+     * @return the buffered image\r
+     */\r
+    public BufferedImage getImage() {\r
+        return img;\r
+    }\r
+\r
+    @Override\r
+    public Dimension getDimension() {\r
+        return (img == null)\r
+            ? new Dimension(0,0)\r
+            : new Dimension(img.getWidth(),img.getHeight());\r
+    }\r
+\r
+    @Override\r
+    public void setAlpha(double alpha) {\r
+        if (img == null) return;\r
+\r
+        Dimension dim = getDimension();\r
+        BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
+        Graphics2D g = newImg.createGraphics();\r
+        RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);\r
+        g.drawImage(img, op, 0, 0);\r
+        g.dispose();\r
+\r
+        img = newImg;\r
+    }\r
+\r
+\r
+    @Override\r
+    public boolean drawImage(\r
+        Graphics2D graphics,\r
+        Rectangle2D anchor) {\r
+        return drawImage(graphics, anchor, null);\r
+    }\r
+\r
+    @Override\r
+    public boolean drawImage(\r
+        Graphics2D graphics,\r
+        Rectangle2D anchor,\r
+        Insets clip) {\r
+        if (img == null) return false;\r
+\r
+        boolean isClipped = true;\r
+        if (clip == null) {\r
+            isClipped = false;\r
+            clip = new Insets(0,0,0,0);\r
+        }\r
+\r
+        int iw = img.getWidth();\r
+        int ih = img.getHeight();\r
+\r
+\r
+        double cw = (100000-clip.left-clip.right) / 100000.0;\r
+        double ch = (100000-clip.top-clip.bottom) / 100000.0;\r
+        double sx = anchor.getWidth()/(iw*cw);\r
+        double sy = anchor.getHeight()/(ih*ch);\r
+        double tx = anchor.getX()-(iw*sx*clip.left/100000.0);\r
+        double ty = anchor.getY()-(ih*sy*clip.top/100000.0);\r
+\r
+        AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;\r
+\r
+        Shape clipOld = graphics.getClip();\r
+        if (isClipped) graphics.clip(anchor.getBounds2D());\r
+        graphics.drawRenderedImage(img, at);\r
+        graphics.setClip(clipOld);\r
+\r
+        return true;\r
+    }\r
+}\r
index 19d3476470e1e60d554b6f591a973d6bb4a7e148..971feae185cc253648d0681c3ba88afc72d61a79 100644 (file)
@@ -26,6 +26,7 @@ import java.text.AttributedString;
 import org.apache.poi.sl.usermodel.Background;\r
 import org.apache.poi.sl.usermodel.ConnectorShape;\r
 import org.apache.poi.sl.usermodel.FreeformShape;\r
+import org.apache.poi.sl.usermodel.GraphicalFrame;\r
 import org.apache.poi.sl.usermodel.GroupShape;\r
 import org.apache.poi.sl.usermodel.MasterSheet;\r
 import org.apache.poi.sl.usermodel.PictureShape;\r
@@ -87,6 +88,8 @@ public class DrawFactory {
             return getDrawable((GroupShape<?,?>)shape);\r
         } else if (shape instanceof PictureShape) {\r
             return getDrawable((PictureShape<?,?>)shape);\r
+        } else if (shape instanceof GraphicalFrame) {\r
+            return getDrawable((GraphicalFrame<?,?>)shape);\r
         } else if (shape instanceof Background) {\r
             return getDrawable((Background<?,?>)shape);\r
         } else if (shape instanceof ConnectorShape) {\r
@@ -144,6 +147,10 @@ public class DrawFactory {
         return new DrawPictureShape(shape);\r
     }\r
     \r
+    public DrawGraphicalFrame getDrawable(GraphicalFrame<?,?> shape) {\r
+        return new DrawGraphicalFrame(shape);\r
+    }\r
+    \r
     public DrawTextParagraph getDrawable(TextParagraph<?,?,?> paragraph) {\r
         return new DrawTextParagraph(paragraph);\r
     }\r
diff --git a/src/java/org/apache/poi/sl/draw/DrawGraphicalFrame.java b/src/java/org/apache/poi/sl/draw/DrawGraphicalFrame.java
new file mode 100644 (file)
index 0000000..c4b75f1
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================\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
+\r
+package org.apache.poi.sl.draw;\r
+\r
+import java.awt.Graphics2D;\r
+\r
+import org.apache.poi.sl.usermodel.GraphicalFrame;\r
+import org.apache.poi.sl.usermodel.PictureShape;\r
+\r
+\r
+public class DrawGraphicalFrame extends DrawShape {\r
+\r
+    public DrawGraphicalFrame(GraphicalFrame<?,?> shape) {\r
+        super(shape);\r
+    }\r
+    \r
+    public void draw(Graphics2D context) {\r
+        PictureShape<?,?> ps = ((GraphicalFrame<?,?>)getShape()).getFallbackPicture();\r
+        if (ps == null) {\r
+            return;\r
+        }\r
+        DrawPictureShape dps = DrawFactory.getInstance(context).getDrawable(ps);\r
+        dps.draw(context);\r
+    }\r
+}\r
index 7aed90811f71d85846459e654efbda7803c5f2db..94001fd88c3031f2dbdc53dcf1291e16d3969f37 100644 (file)
@@ -130,8 +130,7 @@ public class DrawPaint {
         if (is == null) return null;\r
         assert(graphics != null);\r
         \r
-        ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);\r
-        if (renderer == null) renderer = new ImageRenderer();\r
+        ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, fill.getContentType());\r
 \r
         try {\r
             renderer.loadImage(is, fill.getContentType());\r
index 5976dbeaef10213a76beb55a19c6e6bc64afe31a..9721660580ccb840e73c0ef6d59f45d6faa72c07 100644 (file)
@@ -24,11 +24,17 @@ import java.awt.geom.Rectangle2D;
 import java.io.IOException;\r
 \r
 import org.apache.poi.sl.usermodel.PictureData;\r
+import org.apache.poi.sl.usermodel.PictureData.PictureType;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
 import org.apache.poi.sl.usermodel.PictureShape;\r
 import org.apache.poi.sl.usermodel.RectAlign;\r
 \r
 \r
 public class DrawPictureShape extends DrawSimpleShape {\r
+    private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class);\r
+    private static final String WMF_IMAGE_RENDERER = "org.apache.poi.hwmf.draw.HwmfSLImageRenderer";\r
+    \r
     public DrawPictureShape(PictureShape<?,?> shape) {\r
         super(shape);\r
     }\r
@@ -38,14 +44,11 @@ public class DrawPictureShape extends DrawSimpleShape {
         PictureData data = getShape().getPictureData();\r
         if(data == null) return;\r
 \r
-        ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);\r
-        if (renderer == null) renderer = new ImageRenderer();\r
-        \r
         Rectangle2D anchor = getAnchor(graphics, getShape());\r
-\r
         Insets insets = getShape().getClipping();\r
 \r
         try {\r
+            ImageRenderer renderer = getImageRenderer(graphics, data.getContentType());\r
             renderer.loadImage(data.getData(), data.getContentType());\r
             renderer.drawImage(graphics, anchor, insets);\r
         } catch (IOException e) {\r
@@ -54,6 +57,34 @@ public class DrawPictureShape extends DrawSimpleShape {
         }\r
     }    \r
 \r
+    /**\r
+     * Returns an ImageRenderer for the PictureData\r
+     *\r
+     * @param graphics\r
+     * @return\r
+     */\r
+    public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) {\r
+        ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);\r
+        if (renderer != null) {\r
+            return renderer;\r
+        }\r
+        \r
+        if (PictureType.WMF.contentType.equals(contentType)) {\r
+            try {\r
+                @SuppressWarnings("unchecked")\r
+                Class<? extends ImageRenderer> irc = (Class<? extends ImageRenderer>)\r
+                    Thread.currentThread().getContextClassLoader().loadClass(WMF_IMAGE_RENDERER);\r
+                return irc.newInstance();\r
+            } catch (Exception e) {\r
+                // WMF image renderer is not on the classpath, continuing with BitmapRenderer\r
+                // although this doesn't make much sense ...\r
+                LOG.log(POILogger.ERROR, "WMF image renderer is not on the classpath - include poi-scratchpad jar!", e);\r
+            }\r
+        }\r
+        \r
+        return new BitmapImageRenderer();\r
+    }\r
+    \r
     @Override\r
     protected PictureShape<?,?> getShape() {\r
         return (PictureShape<?,?>)shape;\r
index cdc665a617b2113461160edca0a62ba437825928..aa03f8a53bd728e657d40c1b84a996afc27d4b09 100644 (file)
@@ -98,6 +98,7 @@ public class DrawSimpleShape extends DrawShape {
         // then stroke the shape outline\r
         if(line != null) {\r
             graphics.setPaint(line);\r
+            graphics.setStroke(stroke);\r
             for(Outline o : elems){\r
                 if(o.getPath().isStroked()){\r
                     java.awt.Shape s = o.getOutline();\r
index ae8eccf98b27507e19d7f4df61b9d250ed90f8c6..fed5d078cc12c9739a8a66522c1a49ff881141cb 100644 (file)
@@ -31,13 +31,12 @@ import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;\r
 \r
 /**\r
- * For now this class renders only images supported by the javax.imageio.ImageIO\r
- * framework. Subclasses can override this class to support other formats, for\r
+ * Classes can implement this interfaces to support other formats, for\r
  * example, use Apache Batik to render WMF, PICT can be rendered using Apple QuickTime API for Java:\r
  *\r
  * <pre>\r
  * <code>\r
- * public class MyImageRendener extends ImageRendener {\r
+ * public class MyImageRendener implements ImageRendener {\r
  *     InputStream data;\r
  *\r
  *     public boolean drawImage(Graphics2D graphics,Rectangle2D anchor,Insets clip) {\r
@@ -79,127 +78,49 @@ import org.apache.poi.util.POILogger;
  * </code>\r
  * </pre>\r
  */\r
-public class ImageRenderer {\r
-    private final static POILogger LOG = POILogFactory.getLogger(ImageRenderer.class);\r
-    \r
-    protected BufferedImage img;\r
-\r
+public interface ImageRenderer {\r
     /**\r
      * Load and buffer the image\r
      *\r
      * @param data the raw image stream\r
      * @param contentType the content type\r
      */\r
-    public void loadImage(InputStream data, String contentType) throws IOException {\r
-        img = convertBufferedImage(ImageIO.read(data), contentType);\r
-    }\r
+    void loadImage(InputStream data, String contentType) throws IOException;\r
 \r
     /**\r
      * Load and buffer the image\r
      *\r
-     * @param data the raw image stream\r
+     * @param data the raw image bytes\r
      * @param contentType the content type\r
      */\r
-    public void loadImage(byte data[], String contentType) throws IOException {\r
-        img = convertBufferedImage(ImageIO.read(new ByteArrayInputStream(data)), contentType);\r
-    }\r
-\r
-    /**\r
-     * Add alpha channel to buffered image \r
-     */\r
-    private static BufferedImage convertBufferedImage(BufferedImage img, String contentType) {\r
-        if (img == null) {\r
-            LOG.log(POILogger.WARN, "Content-type: "+contentType+" is not support. Image ignored.");\r
-            return null;\r
-        }\r
-        \r
-        BufferedImage bi = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
-        Graphics g = bi.getGraphics();\r
-        g.drawImage(img, 0, 0, null);\r
-        g.dispose();\r
-        return bi;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * @return the buffered image\r
-     */\r
-    public BufferedImage getImage() {\r
-        return img;\r
-    }\r
+    void loadImage(byte data[], String contentType) throws IOException;\r
 \r
     /**\r
      * @return the dimension of the buffered image\r
      */\r
-    public Dimension getDimension() {\r
-        return (img == null)\r
-            ? new Dimension(0,0)\r
-            : new Dimension(img.getWidth(),img.getHeight());\r
-    }\r
+    Dimension getDimension();\r
 \r
     /**\r
      * @param alpha the alpha [0..1] to be added to the image (possibly already containing an alpha channel)\r
      */\r
-    public void setAlpha(double alpha) {\r
-        if (img == null) return;\r
-\r
-        Dimension dim = getDimension();\r
-        BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
-        Graphics2D g = newImg.createGraphics();\r
-        RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);\r
-        g.drawImage(img, op, 0, 0);\r
-        g.dispose();\r
-        \r
-        img = newImg;\r
-    }\r
-\r
+    void setAlpha(double alpha);\r
 \r
+    /**\r
+     * @return the image as buffered image\r
+     */\r
+    BufferedImage getImage();\r
+    \r
     /**\r
      * Render picture data into the supplied graphics\r
      *\r
      * @return true if the picture data was successfully rendered\r
      */\r
-    public boolean drawImage(\r
-        Graphics2D graphics,\r
-        Rectangle2D anchor) {\r
-        return drawImage(graphics, anchor, null);\r
-    }\r
+    boolean drawImage(Graphics2D graphics, Rectangle2D anchor);\r
 \r
     /**\r
      * Render picture data into the supplied graphics\r
      *\r
      * @return true if the picture data was successfully rendered\r
      */\r
-    public boolean drawImage(\r
-        Graphics2D graphics,\r
-        Rectangle2D anchor,\r
-        Insets clip) {\r
-        if (img == null) return false;\r
-\r
-        boolean isClipped = true;\r
-        if (clip == null) {\r
-            isClipped = false;\r
-            clip = new Insets(0,0,0,0);\r
-        }\r
-\r
-        int iw = img.getWidth();\r
-        int ih = img.getHeight();\r
-\r
-        \r
-        double cw = (100000-clip.left-clip.right) / 100000.0;\r
-        double ch = (100000-clip.top-clip.bottom) / 100000.0;\r
-        double sx = anchor.getWidth()/(iw*cw);\r
-        double sy = anchor.getHeight()/(ih*ch);\r
-        double tx = anchor.getX()-(iw*sx*clip.left/100000.0);\r
-        double ty = anchor.getY()-(ih*sy*clip.top/100000.0);\r
-\r
-        AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;\r
-\r
-        Shape clipOld = graphics.getClip();\r
-        if (isClipped) graphics.clip(anchor.getBounds2D());\r
-        graphics.drawRenderedImage(img, at);\r
-        graphics.setClip(clipOld);\r
-\r
-        return true;\r
-    }\r
-}\r
+    boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip);\r
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/sl/usermodel/GraphicalFrame.java b/src/java/org/apache/poi/sl/usermodel/GraphicalFrame.java
new file mode 100644 (file)
index 0000000..20621ef
--- /dev/null
@@ -0,0 +1,29 @@
+/* ====================================================================\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
+\r
+package org.apache.poi.sl.usermodel;\r
+\r
+public interface GraphicalFrame<\r
+    S extends Shape<S,P>,\r
+    P extends TextParagraph<S,P,?>\r
+> extends Shape<S,P>, PlaceableShape<S,P> {\r
+\r
+    /**\r
+     * @return a fallback representation as picture shape\r
+     */\r
+    PictureShape<S,P> getFallbackPicture();\r
+}\r
index 8e4977e7d87775a2d9219cd560d90b25fdbadc21..1b5a9dcbd90d2144c2f91f95093e5af9c1428c38 100644 (file)
@@ -27,25 +27,26 @@ import org.apache.poi.POIXMLException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
 import org.apache.poi.openxml4j.opc.PackagePart;\r
 import org.apache.poi.openxml4j.opc.PackageRelationship;\r
-import org.apache.poi.sl.draw.DrawNotImplemented;\r
-import org.apache.poi.sl.usermodel.PlaceableShape;\r
+import org.apache.poi.sl.usermodel.GraphicalFrame;\r
 import org.apache.poi.sl.usermodel.ShapeType;\r
 import org.apache.poi.util.Beta;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
 import org.apache.poi.util.Units;\r
 import org.apache.xmlbeans.XmlCursor;\r
+import org.apache.xmlbeans.XmlException;\r
 import org.apache.xmlbeans.XmlObject;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;\r
 \r
-/**\r
- * @author Yegor Kozlov\r
- */\r
 @Beta\r
-@DrawNotImplemented\r
-public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFShape, XSLFTextParagraph> {\r
+public class XSLFGraphicFrame extends XSLFShape implements GraphicalFrame<XSLFShape, XSLFTextParagraph> {\r
+    private static final POILogger LOG = POILogFactory.getLogger(XSLFGraphicFrame.class);\r
+\r
     /*package*/ XSLFGraphicFrame(CTGraphicalObjectFrame shape, XSLFSheet sheet){\r
         super(shape,sheet);\r
     }\r
@@ -104,7 +105,7 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
     public void setRotation(double theta){\r
        throw new IllegalArgumentException("Operation not supported");\r
     }\r
-   \r
+\r
     /**\r
      * Rotation angle in degrees\r
      * <p>\r
@@ -125,7 +126,7 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
     public void setFlipVertical(boolean flip){\r
        throw new IllegalArgumentException("Operation not supported");\r
     }\r
-    \r
+\r
     /**\r
      * Whether the shape is horizontally flipped\r
      *\r
@@ -189,4 +190,30 @@ public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape<XSLFSh
         }\r
     }\r
 \r
+    @Override\r
+    public XSLFPictureShape getFallbackPicture() {\r
+        String xquery =\r
+                  "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main'; "\r
+                + "declare namespace mc='http://schemas.openxmlformats.org/markup-compatibility/2006' "\r
+                + ".//mc:Fallback/*/p:pic"\r
+                ;\r
+        XmlObject xo = selectProperty(XmlObject.class, xquery);\r
+        if (xo == null) {\r
+            return null;\r
+        }\r
+\r
+        CTGroupShape gs;\r
+        try {\r
+            gs = CTGroupShape.Factory.parse(xo.newDomNode());\r
+        } catch (XmlException e) {\r
+            LOG.log(POILogger.WARN, "Can't parse fallback picture stream of graphical frame", e);\r
+            return null;\r
+        }\r
+\r
+        if (gs.sizeOfPicArray() == 0) {\r
+            return null;\r
+        }\r
+\r
+        return new XSLFPictureShape(gs.getPicArray(0), getSheet());\r
+    }\r
 }
\ No newline at end of file
index f25c9278edc6bea52d2bbd847afa0423ec47a01e..b9f98c3a807766dbccaa4582f448bdd6411d96dd 100644 (file)
@@ -257,7 +257,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
 \r
     public Placeholder getPlaceholder() {\r
         CTPlaceholder ph = getCTPlaceholder();\r
-        if (ph == null || !ph.isSetType()) {\r
+        if (ph == null || !(ph.isSetType() || ph.isSetIdx())) {\r
             return null;\r
         }\r
         return Placeholder.lookupOoxml(ph.getType().intValue());\r
index 1ccf24df1f051a1663f45de792a5b6cdfe249e2f..b80ef77fb87248d45cce67e9c9b9744d4f2dbd24 100644 (file)
@@ -37,6 +37,7 @@ public class TestPPTX2PNG {
         POIDataSamples samples = POIDataSamples.getSlideShowInstance();\r
 \r
         String[] testFiles = {"alterman_security.ppt","alterman_security.pptx","KEY02.pptx","themes.pptx","backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx",};\r
+//        String[] testFiles = {"41246-2.ppt","45543.ppt","53446.ppt","ParagraphStylesShorterThanCharStyles.ppt"};\r
         String[] args = {\r
             "-format", "null", // png,gif,jpg or null for test\r
             "-slide", "-1", // -1 for all\r
index b78a5c8fad811e71ad24c93ab796359767f081ed..a03c251ffedc7d3c1cb4b6d27ffabf0e9882bfb6 100644 (file)
@@ -100,7 +100,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         opt.setRecordId(EscherOptRecord.RECORD_ID);
         _escherContainer.addChildRecord(opt);
 
-        EscherRecord anchor; 
+        EscherRecord anchor;
         if(isChild) {
             anchor = new EscherChildAnchorRecord();
         } else {
@@ -155,7 +155,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
     }
 
     /**
-     * @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
+     * @return color of the line. If color is not set returns {@code null}
      */
     public Color getLineColor(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
@@ -164,7 +164,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         if(p != null && (p.getPropertyValue() & 0x8) == 0) return null;
 
         Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
-        return clr == null ? Color.black : clr;
+        return clr == null ? null : clr;
     }
 
     /**
@@ -187,7 +187,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDCAPSTYLE, pen == LineCap.FLAT ? -1 : pen.nativeId);
     }
-    
+
     /**
      * Gets line dashing.
      *
@@ -417,7 +417,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
 
         };
     }
-    
+
     public DecorationShape getLineHeadDecoration(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWHEAD);
@@ -428,7 +428,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWHEAD, decoShape == null ? -1 : decoShape.nativeId);
     }
-    
+
     public DecorationSize getLineHeadWidth(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWWIDTH);
@@ -439,7 +439,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWWIDTH, decoSize == null ? -1 : decoSize.nativeId);
     }
-    
+
     public DecorationSize getLineHeadLength(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWLENGTH);
@@ -450,7 +450,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTARTARROWLENGTH, decoSize == null ? -1 : decoSize.nativeId);
     }
-    
+
     public DecorationShape getLineTailDecoration(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWHEAD);
@@ -461,7 +461,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWHEAD, decoShape == null ? -1 : decoShape.nativeId);
     }
-    
+
     public DecorationSize getLineTailWidth(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWWIDTH);
@@ -472,7 +472,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWWIDTH, decoSize == null ? -1 : decoSize.nativeId);
     }
-    
+
     public DecorationSize getLineTailLength(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWLENGTH);
@@ -484,8 +484,8 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDARROWLENGTH, decoSize == null ? -1 : decoSize.nativeId);
     }
 
-    
-    
+
+
     public LineDecoration getLineDecoration() {
         return new LineDecoration() {
 
@@ -514,7 +514,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             }
         };
     }
-    
+
     @Override
     public Placeholder getPlaceholder() {
         List<? extends Record> clRecords = getClientRecords();
@@ -530,10 +530,10 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
                 return Placeholder.lookupNative(rtp.getPlaceholderId());
             }
         }
-        
+
         return null;
     }
-    
+
     @Override
     public void setPlaceholder(Placeholder placeholder) {
         EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
@@ -547,7 +547,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
 
         // Placeholders can't be grouped
         setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, (placeholder == null ? -1 : 262144));
-        
+
         HSLFEscherClientDataRecord clientData = getClientData(false);
         if (placeholder == null) {
             if (clientData != null) {
@@ -560,7 +560,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             }
             return;
         }
-        
+
         if (clientData == null) {
             clientData = getClientData(true);
         }
@@ -596,11 +596,11 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         } else {
             phId = (byte)placeholder.nativeSlideId;
         }
-        
+
         if (phId == -2) {
             throw new HSLFException("Placeholder "+placeholder.name()+" not supported for this sheet type ("+sheet.getClass()+")");
         }
-        
+
         switch (placeholder) {
             case HEADER:
             case FOOTER:
@@ -637,7 +637,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             setLineColor(null);
             return;
         }
-        
+
         // TODO: handle PaintStyle
         for (Object st : styles) {
             if (st instanceof Number) {
index 75e815f70b61af4124c2cc0fc2b1b85d207efd64..0c13d13074d0952373abc51e975f3f9df4d53853 100644 (file)
@@ -270,7 +270,6 @@ public class HwmfGraphics {
      * This methods gathers and sets the corresponding graphics transformations.\r
      */\r
     public void updateWindowMapMode() {\r
-        GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();\r
         Rectangle2D win = prop.getWindow();\r
         HwmfMapMode mapMode = prop.getMapMode();\r
         graphicsCtx.setTransform(initialAT);\r
@@ -292,12 +291,14 @@ public class HwmfGraphics {
         case MM_HIMETRIC:\r
         case MM_LOENGLISH:\r
         case MM_HIENGLISH:\r
-        case MM_TWIPS:\r
+        case MM_TWIPS: {\r
             // TODO: to be validated ...\r
+            GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();\r
             graphicsCtx.transform(gc.getNormalizingTransform());\r
             graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);\r
             graphicsCtx.translate(-win.getX(), -win.getY());\r
             break;\r
+        }\r
         case MM_TEXT:\r
             // TODO: to be validated ...\r
             break;\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfSLImageRenderer.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfSLImageRenderer.java
new file mode 100644 (file)
index 0000000..ad6cacb
--- /dev/null
@@ -0,0 +1,115 @@
+/* ====================================================================\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
+\r
+package org.apache.poi.hwmf.draw;\r
+\r
+import java.awt.Dimension;\r
+import java.awt.Graphics2D;\r
+import java.awt.Insets;\r
+import java.awt.RenderingHints;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.RescaleOp;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import org.apache.poi.hwmf.usermodel.HwmfPicture;\r
+import org.apache.poi.sl.draw.ImageRenderer;\r
+import org.apache.poi.sl.usermodel.PictureData;\r
+import org.apache.poi.util.Units;\r
+\r
+public class HwmfSLImageRenderer implements ImageRenderer {\r
+    HwmfPicture image = null;\r
+    double alpha = 0;\r
+    \r
+    @Override\r
+    public void loadImage(InputStream data, String contentType) throws IOException {\r
+        if (!PictureData.PictureType.WMF.contentType.equals(contentType)) {\r
+            throw new IOException("Invalid picture type");\r
+        }\r
+        image = new HwmfPicture(data);\r
+    }\r
+\r
+    @Override\r
+    public void loadImage(byte[] data, String contentType) throws IOException {\r
+        if (!PictureData.PictureType.WMF.contentType.equals(contentType)) {\r
+            throw new IOException("Invalid picture type");\r
+        }\r
+        image = new HwmfPicture(new ByteArrayInputStream(data));\r
+    }\r
+\r
+    @Override\r
+    public Dimension getDimension() {\r
+        int width = 0, height = 0;\r
+        if (image != null) {\r
+            Dimension dim = image.getSize();\r
+            width = Units.pointsToPixel(dim.getWidth());\r
+            // keep aspect ratio for height\r
+            height = Units.pointsToPixel(dim.getHeight());\r
+        }\r
+        return new Dimension(width, height);\r
+    }\r
+\r
+    @Override\r
+    public void setAlpha(double alpha) {\r
+        this.alpha = alpha;\r
+    }\r
+\r
+    @Override\r
+    public BufferedImage getImage() {\r
+        if (image == null) {\r
+            return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); \r
+        }\r
+        \r
+        Dimension dim = getDimension();\r
+        BufferedImage bufImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
+        Graphics2D g = bufImg.createGraphics();\r
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);\r
+        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);\r
+        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);\r
+        image.draw(g);\r
+        g.dispose();\r
+        \r
+        if (alpha != 0) {\r
+            BufferedImage newImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);\r
+            g = newImg.createGraphics();\r
+            RescaleOp op = new RescaleOp(new float[]{1.0f, 1.0f, 1.0f, (float)alpha}, new float[]{0,0,0,0}, null);\r
+            g.drawImage(bufImg, op, 0, 0);\r
+            g.dispose();\r
+            bufImg = newImg;\r
+        }\r
+        \r
+        return bufImg;\r
+    }\r
+\r
+    @Override\r
+    public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) {\r
+        return drawImage(graphics, anchor, null);\r
+    }\r
+\r
+    @Override\r
+    public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {\r
+        if (image == null) {\r
+            return false;\r
+        } else {\r
+            image.draw(graphics, anchor);\r
+            return true;\r
+        }\r
+    }\r
+}\r
index 90fd70dced07c0d27806145ee04322df6257da09..2d6ab4e77bbdd38c3ed5480b975521a291b3f408 100644 (file)
@@ -339,7 +339,7 @@ public class HwmfMisc {
      * The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a\r
      * pattern specified by a DeviceIndependentBitmap (DIB) Object\r
      */\r
-    public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord {\r
+    public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry {\r
 \r
         private HwmfBrushStyle style;\r
 \r
@@ -388,6 +388,11 @@ public class HwmfMisc {
 \r
         @Override\r
         public void draw(HwmfGraphics ctx) {\r
+            ctx.addObjectTableEntry(this);\r
+        }\r
+        \r
+        @Override\r
+        public void applyObject(HwmfGraphics ctx) {\r
             HwmfDrawProperties prop = ctx.getProperties();\r
             prop.setBrushStyle(style);\r
             prop.setBrushBitmap(getImage());\r
index 39a05e66008951b36f2c56e4bace1460d697b2c6..a5144d4ae3b6fb2ad6bd4e9264f61304cc53cf99 100644 (file)
@@ -102,11 +102,11 @@ public class HwmfPicture {
         try {\r
             Rectangle2D wmfBounds = getBounds();\r
             // scale output bounds to image bounds\r
+            ctx.translate(graphicsBounds.getX(), graphicsBounds.getY());\r
             ctx.scale(graphicsBounds.getWidth()/wmfBounds.getWidth(), graphicsBounds.getHeight()/wmfBounds.getHeight());\r
-            ctx.translate(-wmfBounds.getX(), -wmfBounds.getY());\r
             \r
             HwmfGraphics g = new HwmfGraphics(ctx, wmfBounds);\r
-            for (HwmfRecord r : records)  {\r
+            for (HwmfRecord r : records) {\r
                 r.draw(g);\r
             }\r
         } finally {\r