]> source.dussan.org Git - poi.git/commitdiff
WMF fixes
authorAndreas Beeker <kiwiwings@apache.org>
Tue, 29 Dec 2015 00:45:59 +0000 (00:45 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Tue, 29 Dec 2015 00:45:59 +0000 (00:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1722046 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java

diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
new file mode 100644 (file)
index 0000000..64ee4cc
--- /dev/null
@@ -0,0 +1,189 @@
+/* ====================================================================\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.Color;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+\r
+import org.apache.poi.hwmf.record.HwmfBrushStyle;\r
+import org.apache.poi.hwmf.record.HwmfColorRef;\r
+import org.apache.poi.hwmf.record.HwmfFill.WmfSetPolyfillMode.HwmfPolyfillMode;\r
+import org.apache.poi.hwmf.record.HwmfHatchStyle;\r
+import org.apache.poi.hwmf.record.HwmfMapMode;\r
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle;\r
+\r
+public class HwmfDrawProperties {\r
+    private Rectangle2D window = new Rectangle2D.Double(0, 0, 1, 1);\r
+    private Rectangle2D viewport = new Rectangle2D.Double(0, 0, 1, 1);\r
+    private Point2D location = new Point2D.Double(0,0);\r
+    private HwmfMapMode mapMode = HwmfMapMode.MM_ANISOTROPIC;\r
+    private HwmfColorRef backgroundColor = new HwmfColorRef(Color.BLACK);\r
+    private HwmfBrushStyle brushStyle = HwmfBrushStyle.BS_SOLID;\r
+    private HwmfColorRef brushColor = new HwmfColorRef(Color.BLACK);\r
+    private HwmfHatchStyle brushHatch = HwmfHatchStyle.HS_HORIZONTAL;\r
+    private BufferedImage brushBitmap = null;\r
+    private double penWidth = 1;\r
+    private HwmfPenStyle penStyle = HwmfPenStyle.valueOf(0);\r
+    private HwmfColorRef penColor = new HwmfColorRef(Color.BLACK);\r
+    private double penMiterLimit = 10;\r
+    private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;\r
+    private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;\r
+\r
+    public void setViewportExt(double width, double height) {\r
+        double x = viewport.getX();\r
+        double y = viewport.getY();\r
+        double w = (width != 0) ? width : viewport.getWidth();\r
+        double h = (height != 0) ? height : viewport.getHeight();\r
+        viewport.setRect(x, y, w, h);\r
+    }\r
+\r
+    public void setViewportOrg(double x, double y) {\r
+        double w = viewport.getWidth();\r
+        double h = viewport.getHeight();\r
+        viewport.setRect(x, y, w, h);\r
+    }\r
+\r
+    public Rectangle2D getViewport() {\r
+        return (Rectangle2D)viewport.clone();\r
+    }\r
+\r
+    public void setWindowExt(double width, double height) {\r
+        double x = window.getX();\r
+        double y = window.getY();\r
+        double w = (width != 0) ? width : window.getWidth();\r
+        double h = (height != 0) ? height : window.getHeight();\r
+        window.setRect(x, y, w, h);\r
+    }\r
+\r
+    public void setWindowOrg(double x, double y) {\r
+        double w = window.getWidth();\r
+        double h = window.getHeight();\r
+        window.setRect(x, y, w, h);\r
+    }\r
+\r
+    public Rectangle2D getWindow() {\r
+        return (Rectangle2D)window.clone();\r
+    }\r
+\r
+    public void setLocation(double x, double y) {\r
+        location.setLocation(x, y);\r
+    }\r
+\r
+    public Point2D getLocation() {\r
+        return (Point2D)location.clone();\r
+    }\r
+\r
+    public void setMapMode(HwmfMapMode mapMode) {\r
+        this.mapMode = mapMode;\r
+    }\r
+\r
+    public HwmfMapMode getMapMode() {\r
+        return mapMode;\r
+    }\r
+\r
+    public HwmfBrushStyle getBrushStyle() {\r
+        return brushStyle;\r
+    }\r
+\r
+    public void setBrushStyle(HwmfBrushStyle brushStyle) {\r
+        this.brushStyle = brushStyle;\r
+    }\r
+\r
+    public HwmfHatchStyle getBrushHatch() {\r
+        return brushHatch;\r
+    }\r
+\r
+    public void setBrushHatch(HwmfHatchStyle brushHatch) {\r
+        this.brushHatch = brushHatch;\r
+    }\r
+\r
+    public HwmfColorRef getBrushColor() {\r
+        return brushColor;\r
+    }\r
+\r
+    public void setBrushColor(HwmfColorRef brushColor) {\r
+        this.brushColor = brushColor;\r
+    }\r
+\r
+    public HwmfBkMode getBkMode() {\r
+        return bkMode;\r
+    }\r
+\r
+    public void setBkMode(HwmfBkMode bkMode) {\r
+        this.bkMode = bkMode;\r
+    }\r
+\r
+    public HwmfPenStyle getPenStyle() {\r
+        return penStyle;\r
+    }\r
+\r
+    public void setPenStyle(HwmfPenStyle penStyle) {\r
+        this.penStyle = penStyle;\r
+    }\r
+\r
+    public HwmfColorRef getPenColor() {\r
+        return penColor;\r
+    }\r
+\r
+    public void setPenColor(HwmfColorRef penColor) {\r
+        this.penColor = penColor;\r
+    }\r
+\r
+    public double getPenWidth() {\r
+        return penWidth;\r
+    }\r
+\r
+    public void setPenWidth(double penWidth) {\r
+        this.penWidth = penWidth;\r
+    }\r
+\r
+    public double getPenMiterLimit() {\r
+        return penMiterLimit;\r
+    }\r
+\r
+    public void setPenMiterLimit(double penMiterLimit) {\r
+        this.penMiterLimit = penMiterLimit;\r
+    }\r
+\r
+    public HwmfColorRef getBackgroundColor() {\r
+        return backgroundColor;\r
+    }\r
+\r
+    public void setBackgroundColor(HwmfColorRef backgroundColor) {\r
+        this.backgroundColor = backgroundColor;\r
+    }\r
+\r
+    public HwmfPolyfillMode getPolyfillMode() {\r
+        return polyfillMode;\r
+    }\r
+\r
+    public void setPolyfillMode(HwmfPolyfillMode polyfillMode) {\r
+        this.polyfillMode = polyfillMode;\r
+    }\r
+\r
+    public BufferedImage getBrushBitmap() {\r
+        return brushBitmap;\r
+    }\r
+\r
+    public void setBrushBitmap(BufferedImage brushBitmap) {\r
+        this.brushBitmap = brushBitmap;\r
+    }\r
+}\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
new file mode 100644 (file)
index 0000000..4a07cc3
--- /dev/null
@@ -0,0 +1,185 @@
+/* ====================================================================\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.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.Paint;\r
+import java.awt.Rectangle;\r
+import java.awt.Shape;\r
+import java.awt.TexturePaint;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.util.ArrayDeque;\r
+import java.util.Deque;\r
+\r
+import org.apache.poi.hwmf.record.HwmfBrushStyle;\r
+import org.apache.poi.hwmf.record.HwmfHatchStyle;\r
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;\r
+import org.apache.poi.util.Units;\r
+\r
+public class HwmfGraphics {\r
+    private final Graphics2D graphicsCtx;\r
+    private final Deque<HwmfDrawProperties> propStack = new ArrayDeque<HwmfDrawProperties>();\r
+    HwmfDrawProperties prop;\r
+\r
+    public HwmfGraphics(Graphics2D graphicsCtx) {\r
+        this.graphicsCtx = graphicsCtx;\r
+        prop = new HwmfDrawProperties();\r
+        propStack.push(prop);\r
+    }\r
+\r
+    public HwmfDrawProperties getProperties() {\r
+        return prop;\r
+    }\r
+\r
+    public void draw(Shape shape) {\r
+        HwmfLineDash lineDash = prop.getPenStyle().getLineDash();\r
+        if (lineDash == HwmfLineDash.NULL) {\r
+            // line is not drawn\r
+            return;\r
+        }\r
+\r
+        Shape tshape = fitShapeToView(shape);\r
+        BasicStroke stroke = getStroke();\r
+\r
+        // first draw a solid background line (depending on bkmode)\r
+        // only makes sense if the line is not solid\r
+        if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {\r
+            graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));\r
+            graphicsCtx.setColor(prop.getBackgroundColor().getColor());\r
+            graphicsCtx.draw(tshape);\r
+        }\r
+\r
+        // then draw the (dashed) line\r
+        graphicsCtx.setStroke(stroke);\r
+        graphicsCtx.setColor(prop.getPenColor().getColor());\r
+        graphicsCtx.draw(tshape);\r
+    }\r
+\r
+    public void fill(Shape shape) {\r
+        if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {\r
+            GeneralPath gp = new GeneralPath(shape);\r
+            gp.setWindingRule(prop.getPolyfillMode().awtFlag);\r
+            Shape tshape = fitShapeToView(gp);\r
+            graphicsCtx.setPaint(getFill());\r
+            graphicsCtx.fill(tshape);\r
+        }\r
+\r
+        draw(shape);\r
+    }\r
+\r
+    protected Shape fitShapeToView(Shape shape) {\r
+        int scaleUnits = prop.getMapMode().scale;\r
+        Rectangle2D view = prop.getViewport(), win = prop.getWindow();\r
+        double scaleX, scaleY;\r
+        switch (scaleUnits) {\r
+        case -1:\r
+            scaleX = view.getWidth() / win.getWidth();\r
+            scaleY = view.getHeight() / win.getHeight();\r
+            break;\r
+        case 0:\r
+            scaleX = scaleY = 1;\r
+            break;\r
+        default:\r
+            scaleX = scaleY = scaleUnits / (double)Units.POINT_DPI;\r
+        }\r
+\r
+        AffineTransform at = new AffineTransform();\r
+        at.translate(view.getX(), view.getY());\r
+        at.scale(scaleX, scaleY);\r
+        at.translate(-win.getX(), -win.getY());\r
+        at.translate(-view.getX(), -view.getY());\r
+\r
+        return at.createTransformedShape(shape);\r
+    }\r
+\r
+    protected BasicStroke getStroke() {\r
+        Rectangle2D view = prop.getViewport(), win = prop.getWindow();\r
+        float width = (float)(prop.getPenWidth() * view.getWidth() / win.getWidth());\r
+        HwmfPenStyle ps = prop.getPenStyle();\r
+        int cap = ps.getLineCap().awtFlag;\r
+        int join = ps.getLineJoin().awtFlag;\r
+        float miterLimit = (float)prop.getPenMiterLimit();\r
+        float dashes[] = ps.getLineDash().dashes;\r
+        boolean dashAlt = ps.isAlternateDash();\r
+        // This value is not an integer index into the dash pattern array.\r
+        // Instead, it is a floating-point value that specifies a linear distance.\r
+        float dashStart = (dashAlt && dashes.length > 1) ? dashes[0] : 0;\r
+\r
+        return new BasicStroke(width, cap, join, miterLimit, dashes, dashStart);\r
+    }\r
+\r
+    protected Paint getFill() {\r
+        switch (prop.getBrushStyle()) {\r
+        default:\r
+        case BS_INDEXED:\r
+        case BS_PATTERN8X8:\r
+        case BS_DIBPATTERN8X8:\r
+        case BS_MONOPATTERN:\r
+        case BS_NULL: return null;\r
+        case BS_PATTERN:\r
+        case BS_DIBPATTERN:\r
+        case BS_DIBPATTERNPT: return getPatternPaint();\r
+        case BS_SOLID: return getSolidFill();\r
+        case BS_HATCHED: return getHatchedFill();\r
+        }\r
+    }\r
+\r
+    protected Paint getSolidFill() {\r
+        return prop.getBrushColor().getColor();\r
+    }\r
+\r
+    protected Paint getHatchedFill() {\r
+        int dim = 7, mid = 3;\r
+        BufferedImage bi = new BufferedImage(dim, dim, BufferedImage.TYPE_4BYTE_ABGR);\r
+        Graphics2D g = bi.createGraphics();\r
+        Color c = (prop.getBkMode() == HwmfBkMode.TRANSPARENT)\r
+            ? new Color(0, true)\r
+            : prop.getBackgroundColor().getColor();\r
+        g.setColor(c);\r
+        g.fillRect(0, 0, dim, dim);\r
+        g.setColor(prop.getBrushColor().getColor());\r
+        HwmfHatchStyle h = prop.getBrushHatch();\r
+        if (h == HwmfHatchStyle.HS_HORIZONTAL || h == HwmfHatchStyle.HS_CROSS) {\r
+            g.drawLine(0, mid, dim, mid);\r
+        }\r
+        if (h == HwmfHatchStyle.HS_VERTICAL || h == HwmfHatchStyle.HS_CROSS) {\r
+            g.drawLine(mid, 0, mid, dim);\r
+        }\r
+        if (h == HwmfHatchStyle.HS_FDIAGONAL || h == HwmfHatchStyle.HS_DIAGCROSS) {\r
+            g.drawLine(0, 0, dim, dim);\r
+        }\r
+        if (h == HwmfHatchStyle.HS_BDIAGONAL || h == HwmfHatchStyle.HS_DIAGCROSS) {\r
+            g.drawLine(0, dim, dim, 0);\r
+        }\r
+        g.dispose();\r
+        return new TexturePaint(bi, new Rectangle(0,0,dim,dim));\r
+    }\r
+\r
+    protected Paint getPatternPaint() {\r
+        BufferedImage bi = prop.getBrushBitmap();\r
+        return (bi == null) ? null\r
+            : new TexturePaint(bi, new Rectangle(0,0,bi.getWidth(),bi.getHeight()));\r
+    }\r
+}\r
index 52ea1d9f141f532eaa41797b24aef6e1f387eeb9..15495de012325d1f84f70ca97ceb7e60fa058a16 100644 (file)
 package org.apache.poi.hwmf.record;\r
 \r
 import java.awt.image.BufferedImage;\r
-import java.io.ByteArrayInputStream;\r
+import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 \r
-import javax.imageio.stream.ImageInputStream;\r
-import javax.imageio.stream.MemoryCacheImageInputStream;\r
-\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -75,31 +72,45 @@ public class HwmfBitmap16 {
             assert(skipSize == 18);\r
             size += 18+LittleEndianConsts.INT_SIZE;\r
         }\r
+\r
+        int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;\r
+        byte buf[] = new byte[bytes];\r
+        leis.read(buf);\r
         \r
-        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+        FileOutputStream fos = new FileOutputStream("bla16.bmp");\r
+        fos.write(buf);\r
+        fos.close();\r
         \r
-        int size2 = 0;\r
-        byte buf[] = new byte[widthBytes];\r
-        for (int h=0; h<height; h++) {\r
-            leis.read(buf);\r
-            size2 += widthBytes;\r
-\r
-            ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));\r
-\r
-            for (int w=0; w<width; w++) {\r
-                long bitsAtPixel = iis.readBits(bitsPixel);\r
-                // TODO: is bitsPixel a multiple of 3 (r,g,b)\r
-                // which colortable should be used for the various bit sizes???\r
-                \r
-            }\r
-        }\r
         \r
-        int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;\r
-        assert (bytes == size2);\r
-\r
-        size += size2;\r
+//        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+//        \r
+//        int size2 = 0;\r
+//        byte buf[] = new byte[widthBytes];\r
+//        for (int h=0; h<height; h++) {\r
+//            leis.read(buf);\r
+//            size2 += widthBytes;\r
+//\r
+//            ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));\r
+//\r
+//            for (int w=0; w<width; w++) {\r
+//                long bitsAtPixel = iis.readBits(bitsPixel);\r
+//                // TODO: is bitsPixel a multiple of 3 (r,g,b)\r
+//                // which colortable should be used for the various bit sizes???\r
+//                \r
+//            }\r
+//        }\r
+//        \r
+//        assert (bytes == size2);\r
+//\r
+//        size += size2;\r
         \r
         \r
         return size;\r
     }\r
+\r
+    public BufferedImage getImage() {\r
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);\r
+        return bi;\r
+    }\r
+\r
 }\r
index c3317d1dc3c689e5fd1318220411593ad8c9145b..12f9b30a9f22673770b5c8f5c8cc69deea952436 100644 (file)
@@ -19,12 +19,16 @@ package org.apache.poi.hwmf.record;
 \r
 import java.awt.Color;\r
 import java.awt.image.BufferedImage;\r
-import java.awt.image.IndexColorModel;\r
-import java.awt.image.WritableRaster;\r
+import java.io.BufferedInputStream;\r
+import java.io.ByteArrayInputStream;\r
 import java.io.IOException;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 \r
+import javax.imageio.ImageIO;\r
+\r
+import org.apache.poi.hssf.record.RecordFormatException;\r
+import org.apache.poi.util.LittleEndian;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -59,25 +63,25 @@ public class HwmfBitmapDib {
          * Each pixel in the bitmap is represented by a 16-bit value.\r
          * <br/>\r
          * If the Compression field of the BitmapInfoHeader Object is BI_RGB, the Colors field of DIB\r
-         *  is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of \r
-         *  red, green, and blue are represented with 5 bits for each color component. The value for blue \r
-         *  is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant \r
-         *  bit is not used. The color table is used for optimizing colors on palette-based devices, and \r
-         *  contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+         *  is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of\r
+         *  red, green, and blue are represented with 5 bits for each color component. The value for blue\r
+         *  is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant\r
+         *  bit is not used. The color table is used for optimizing colors on palette-based devices, and\r
+         *  contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader\r
          *  Object.\r
          * <br/>\r
-         * If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field \r
+         * If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field\r
          *  contains three DWORD color masks that specify the red, green, and blue components,\r
          *  respectively, of each pixel. Each WORD in the bitmap array represents a single pixel.\r
          * <br/>\r
-         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be \r
+         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be\r
          *  contiguous and SHOULD NOT overlap the bits of another mask.\r
          */\r
         BI_BITCOUNT_4(0x0010),\r
         /**\r
-         * The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is \r
-         *  NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, \r
-         *  and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on \r
+         * The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is\r
+         *  NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green,\r
+         *  and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on\r
          *  palette-based devices, and MUST contain the number of entries specified by the ColorUsed\r
          *  field of the BitmapInfoHeader Object.\r
          */\r
@@ -85,23 +89,23 @@ public class HwmfBitmapDib {
         /**\r
          * The bitmap has a maximum of 2^24 colors.\r
          * <br/>\r
-         * If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field \r
-         *  of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of \r
-         *  blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The \r
-         *  Colors color table is used for optimizing colors used on palette-based devices, and MUST \r
-         *  contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+         * If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field\r
+         *  of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of\r
+         *  blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The\r
+         *  Colors color table is used for optimizing colors used on palette-based devices, and MUST\r
+         *  contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader\r
          *  Object.\r
          * <br/>\r
          * If the Compression field of the BitmapInfoHeader Object is set to BI_BITFIELDS, the Colors\r
-         *  field contains three DWORD color masks that specify the red, green, and blue components, \r
+         *  field contains three DWORD color masks that specify the red, green, and blue components,\r
          *  respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.\r
          * <br/>\r
-         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be \r
-         *  contiguous and should not overlap the bits of another mask. All the bits in the pixel do not \r
+         * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be\r
+         *  contiguous and should not overlap the bits of another mask. All the bits in the pixel do not\r
          *  need to be used.\r
          */\r
         BI_BITCOUNT_6(0x0020);\r
-        \r
+\r
         int flag;\r
         BitCount(int flag) {\r
             this.flag = flag;\r
@@ -139,18 +143,18 @@ public class HwmfBitmapDib {
          */\r
         BI_BITFIELDS(0x0003),\r
         /**\r
-         * The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in \r
-         * certain bitmap operations, such as JPEG pass-through. The application MUST query for the \r
-         * pass-through support, since not all devices support JPEG pass-through. Using non-RGB \r
-         * bitmaps MAY limit the portability of the metafile to other devices. For instance, display device \r
+         * The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in\r
+         * certain bitmap operations, such as JPEG pass-through. The application MUST query for the\r
+         * pass-through support, since not all devices support JPEG pass-through. Using non-RGB\r
+         * bitmaps MAY limit the portability of the metafile to other devices. For instance, display device\r
          * contexts generally do not support this pass-through.\r
          */\r
         BI_JPEG(0x0004),\r
         /**\r
-         * The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be \r
-         * used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query \r
-         * for the pass-through support, because not all devices support JPEG/PNG pass-through. Using \r
-         * non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance, \r
+         * The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be\r
+         * used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query\r
+         * for the pass-through support, because not all devices support JPEG/PNG pass-through. Using\r
+         * non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance,\r
          * display device contexts generally do not support this pass-through.\r
          */\r
         BI_PNG(0x0005),\r
@@ -170,7 +174,7 @@ public class HwmfBitmapDib {
          * color indexes.\r
          */\r
         BI_CMYKRLE4(0x000D);\r
-        \r
+\r
         int flag;\r
         Compression(int flag) {\r
             this.flag = flag;\r
@@ -180,93 +184,113 @@ public class HwmfBitmapDib {
                 if (c.flag == flag) return c;\r
             }\r
             return null;\r
-        }        \r
+        }\r
     }\r
+\r
+    private static final int BMP_HEADER_SIZE = 14;\r
     \r
-    \r
-    int headerSize;\r
-    int headerWidth;\r
-    int headerHeight;\r
-    int headerPlanes;\r
-    BitCount headerBitCount;\r
-    Compression headerCompression;\r
-    long headerImageSize = -1;\r
-    int headerXPelsPerMeter = -1;\r
-    int headerYPelsPerMeter = -1;\r
-    long headerColorUsed = -1;\r
-    long headerColorImportant = -1;\r
-    \r
-    Color colorTable[];\r
-    int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;\r
-    \r
-    public int init(LittleEndianInputStream leis) throws IOException {\r
-        int size = 0;\r
-        size += readHeader(leis);\r
-        size += readColors(leis);\r
-        int size2;\r
-        switch (headerBitCount) {\r
-            default:\r
-            case BI_BITCOUNT_0:\r
-                throw new RuntimeException("JPG and PNG formats aren't supported yet.");\r
-            case BI_BITCOUNT_1:\r
-            case BI_BITCOUNT_2:\r
-            case BI_BITCOUNT_3:\r
-                size2 = readBitmapIndexed(leis);\r
-                break;\r
-            case BI_BITCOUNT_4:\r
-            case BI_BITCOUNT_5:\r
-            case BI_BITCOUNT_6:\r
-                size2 = readBitmapDirect(leis);\r
-                break;\r
-        }\r
+    private int headerSize;\r
+    private int headerWidth;\r
+    private int headerHeight;\r
+    private int headerPlanes;\r
+    private BitCount headerBitCount;\r
+    private Compression headerCompression;\r
+    private long headerImageSize = -1;\r
+    @SuppressWarnings("unused")\r
+    private int headerXPelsPerMeter = -1;\r
+    @SuppressWarnings("unused")\r
+    private int headerYPelsPerMeter = -1;\r
+    private long headerColorUsed = -1;\r
+    @SuppressWarnings("unused")\r
+    private long headerColorImportant = -1;\r
+\r
+    @SuppressWarnings("unused")\r
+    private Color colorTable[];\r
+    @SuppressWarnings("unused")\r
+    private int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;\r
+\r
+    // size of header and color table, for start of image data calculation\r
+    private int introSize;\r
+    private byte imageData[];\r
+\r
+    public int init(LittleEndianInputStream leis, int recordSize) throws IOException {\r
+        leis.mark(10000);\r
         \r
-        assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == size2);\r
-        assert ( headerSize == 0x0C || headerImageSize == size2 );\r
+        // need to read the header to calculate start of bitmap data correct\r
+        introSize = readHeader(leis);\r
+        assert(introSize == headerSize);\r
+        introSize += readColors(leis);\r
+        assert(introSize < 10000);\r
+\r
+        int fileSize = (headerImageSize != 0) ? (int)(introSize+headerImageSize) : recordSize;\r
         \r
-        size += size2;\r
+        imageData = new byte[fileSize];\r
+        leis.reset();\r
+        leis.read(imageData, 0, fileSize);\r
         \r
-        return size;\r
+        assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == headerImageSize);\r
+\r
+        return fileSize;\r
     }\r
 \r
     protected int readHeader(LittleEndianInputStream leis) throws IOException {\r
         int size = 0;\r
-        \r
+\r
         /**\r
          * DIBHeaderInfo (variable): Either a BitmapCoreHeader Object or a\r
          * BitmapInfoHeader Object that specifies information about the image.\r
-         * \r
+         *\r
          * The first 32 bits of this field is the HeaderSize value.\r
          * If it is 0x0000000C, then this is a BitmapCoreHeader; otherwise, this is a BitmapInfoHeader.\r
          */\r
         headerSize = leis.readInt();\r
         size += LittleEndianConsts.INT_SIZE;\r
-        \r
-        // BitmapCoreHeader\r
-        // A 16-bit unsigned integer that defines the width of the DIB, in pixels.\r
-        headerWidth = leis.readUShort();\r
-        // A 16-bit unsigned integer that defines the height of the DIB, in pixels.\r
-        headerHeight = leis.readUShort();\r
-        // A 16-bit unsigned integer that defines the number of planes for the target\r
-        // device. This value MUST be 0x0001.\r
-        headerPlanes = leis.readUShort();\r
-        // A 16-bit unsigned integer that defines the format of each pixel, and the\r
-        // maximum number of colors in the DIB.\r
-        headerBitCount = BitCount.valueOf(leis.readUShort());\r
-        size += 4*LittleEndianConsts.SHORT_SIZE;\r
 \r
-        if (headerSize > 0x0C) {\r
+        if (headerSize == 0x0C) {\r
+            // BitmapCoreHeader\r
+            // A 16-bit unsigned integer that defines the width of the DIB, in pixels.\r
+            headerWidth = leis.readUShort();\r
+            // A 16-bit unsigned integer that defines the height of the DIB, in pixels.\r
+            headerHeight = leis.readUShort();\r
+            // A 16-bit unsigned integer that defines the number of planes for the target\r
+            // device. This value MUST be 0x0001.\r
+            headerPlanes = leis.readUShort();\r
+            // A 16-bit unsigned integer that defines the format of each pixel, and the\r
+            // maximum number of colors in the DIB.\r
+            headerBitCount = BitCount.valueOf(leis.readUShort());\r
+            size += 4*LittleEndianConsts.SHORT_SIZE;\r
+        } else {\r
             // BitmapInfoHeader\r
-            // A 32-bit unsigned integer that defines the compression mode of the \r
-            // DIB. \r
+            // A 32-bit signed integer that defines the width of the DIB, in pixels.\r
+            // This value MUST be positive.\r
+            // This field SHOULD specify the width of the decompressed image file,\r
+            // if the Compression value specifies JPEG or PNG format.\r
+            headerWidth = leis.readInt();\r
+            // A 32-bit signed integer that defines the height of the DIB, in pixels.\r
+            // This value MUST NOT be zero.\r
+            // - If this value is positive, the DIB is a bottom-up bitmap,\r
+            //   and its origin is the lower-left corner.\r
+            //   This field SHOULD specify the height of the decompressed image file,\r
+            //   if the Compression value specifies JPEG or PNG format.\r
+            // - If this value is negative, the DIB is a top-down bitmap,\r
+            //   and its origin is the upper-left corner. Top-down bitmaps do not support compression.\r
+            headerHeight = leis.readInt();\r
+            // A 16-bit unsigned integer that defines the number of planes for the target\r
+            // device. This value MUST be 0x0001.\r
+            headerPlanes = leis.readUShort();\r
+            // A 16-bit unsigned integer that defines the format of each pixel, and the\r
+            // maximum number of colors in the DIB.\r
+            headerBitCount = BitCount.valueOf(leis.readUShort());\r
+            // A 32-bit unsigned integer that defines the compression mode of the DIB.\r
             // This value MUST NOT specify a compressed format if the DIB is a top-down bitmap,\r
             // as indicated by the Height value.\r
             headerCompression = Compression.valueOf((int)leis.readUInt());\r
             // A 32-bit unsigned integer that defines the size, in bytes, of the image.\r
             // If the Compression value is BI_RGB, this value SHOULD be zero and MUST be ignored.\r
-            // If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG \r
+            // If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG\r
             // or PNG image buffer, respectively.\r
             headerImageSize = leis.readUInt();\r
-            // A 32-bit signed integer that defines the horizontal resolution, \r
+            // A 32-bit signed integer that defines the horizontal resolution,\r
             // in pixels-per-meter, of the target device for the DIB.\r
             headerXPelsPerMeter = leis.readInt();\r
             // A 32-bit signed integer that defines the vertical resolution,\r
@@ -278,8 +302,9 @@ public class HwmfBitmapDib {
             // A 32-bit unsigned integer that defines the number of color indexes that are\r
             // required for displaying the DIB. If this value is zero, all color indexes are required.\r
             headerColorImportant = leis.readUInt();\r
-            size += 6*LittleEndianConsts.INT_SIZE;\r
+            size += 8*LittleEndianConsts.INT_SIZE+2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+        assert(size == headerSize);\r
         return size;\r
     }\r
 \r
@@ -297,7 +322,7 @@ public class HwmfBitmapDib {
             return readRGBQuad(leis, 16);\r
         case BI_BITCOUNT_3:\r
             // 256 colors\r
-            return readRGBQuad(leis, 256);\r
+            return readRGBQuad(leis, (int)headerColorUsed);\r
         case BI_BITCOUNT_5:\r
             colorMaskRed=0xFF;\r
             colorMaskGreen=0xFF;\r
@@ -316,7 +341,7 @@ public class HwmfBitmapDib {
                 colorMaskRed = leis.readInt();\r
                 return 3*LittleEndianConsts.INT_SIZE;\r
             }\r
-        case BI_BITCOUNT_6:    \r
+        case BI_BITCOUNT_6:\r
             if (headerCompression == Compression.BI_RGB) {\r
                 colorMaskBlue = colorMaskGreen = colorMaskRed = 0xFF;\r
                 return 0;\r
@@ -329,7 +354,7 @@ public class HwmfBitmapDib {
             }\r
         }\r
     }\r
-    \r
+\r
     protected int readRGBQuad(LittleEndianInputStream leis, int count) throws IOException {\r
         int size = 0;\r
         List<Color> colorList = new ArrayList<Color>();\r
@@ -346,96 +371,32 @@ public class HwmfBitmapDib {
         colorTable = colorList.toArray(new Color[colorList.size()]);\r
         return size;\r
     }\r
-    \r
-    protected int readBitmapIndexed(LittleEndianInputStream leis) throws IOException {\r
-        assert(colorTable != null);\r
-        byte r[] = new byte[colorTable.length];\r
-        byte g[] = new byte[colorTable.length];\r
-        byte b[] = new byte[colorTable.length];\r
-        for (int i=0; i<colorTable.length; i++) {\r
-            r[i] = (byte)colorTable[i].getRed();\r
-            g[i] = (byte)colorTable[i].getGreen();\r
-            b[i] = (byte)colorTable[i].getBlue();\r
-        }\r
-        int bits = 32-Integer.numberOfLeadingZeros(colorTable.length);\r
-        IndexColorModel cm = new IndexColorModel(bits,colorTable.length,r,g,b);\r
-        \r
-        BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_BYTE_INDEXED, cm);\r
-        WritableRaster wr = bi.getRaster();\r
-        \r
-        int pixelCount = headerWidth*headerHeight;\r
-        int size = 0;\r
-        for (int pixel=0; pixel<pixelCount; size++) {\r
-            int v = leis.readUByte();\r
-            switch (headerBitCount) {\r
-            default:\r
-                throw new RuntimeException("invalid bitcount for indexed image");\r
-            case BI_BITCOUNT_1:\r
-                for (int j=0; j<8 && pixel<pixelCount; j++,pixel++) {\r
-                    wr.setSample(pixel/headerWidth,pixel%headerWidth,0,(v>>(7-j))&1);\r
-                }\r
-                break;\r
-            case BI_BITCOUNT_2:\r
-                wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, (v>>4)&15);\r
-                pixel++;\r
-                if (pixel<pixelCount) {\r
-                    wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v&15);\r
-                    pixel++;\r
-                }\r
-                break;\r
-            case BI_BITCOUNT_3:\r
-                wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v);\r
-                pixel++;\r
-                break;\r
-            }\r
+\r
+    public BufferedImage getImage() {\r
+        if (imageData == null) {\r
+            throw new RecordFormatException("bitmap not initialized ... need to call init() before");\r
         }\r
-        return size;\r
-    }\r
-    \r
-    protected int readBitmapDirect(LittleEndianInputStream leis) throws IOException {\r
-        assert(colorTable == null);\r
-        \r
-        BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_RGB);\r
-        WritableRaster wr = bi.getRaster();\r
+\r
+        // create the image data and leave the parsing to the ImageIO api\r
+        byte buf[] = new byte[BMP_HEADER_SIZE+imageData.length];\r
+\r
+        // https://en.wikipedia.org/wiki/BMP_file_format #  Bitmap file header\r
+        buf[0] = (byte)'B';\r
+        buf[1] = (byte)'M';\r
+        // the full size of the bmp\r
+        LittleEndian.putInt(buf, 2, (int)(BMP_HEADER_SIZE + introSize + headerImageSize));\r
+        // the next 4 bytes are unused\r
+        LittleEndian.putInt(buf, 6, 0);\r
+        // start of image = BMP header length + dib header length + color tables length\r
+        LittleEndian.putInt(buf, 10, BMP_HEADER_SIZE + introSize);\r
         \r
-        int bitShiftRed=0,bitShiftGreen=0,bitShiftBlue=0;\r
-        if (headerCompression == Compression.BI_BITFIELDS) {\r
-            bitShiftGreen = 32-Integer.numberOfLeadingZeros(this.colorMaskBlue);\r
-            bitShiftRed = 32-Integer.numberOfLeadingZeros(this.colorMaskGreen);\r
-        }\r
+        System.arraycopy(imageData, 0, buf, BMP_HEADER_SIZE, imageData.length);\r
         \r
-        int pixelCount = headerWidth*headerHeight;\r
-        int size = 0;\r
-        int rgb[] = new int[3];\r
-        for (int pixel=0; pixel<pixelCount; pixel++) {\r
-            int v;\r
-            switch (headerBitCount) {\r
-            default:\r
-                throw new RuntimeException("invalid bitcount for indexed image");\r
-            case BI_BITCOUNT_4:\r
-                v = leis.readUShort();\r
-                rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
-                rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
-                rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
-                size += LittleEndianConsts.SHORT_SIZE;\r
-                break;\r
-            case BI_BITCOUNT_5:\r
-                rgb[2] = leis.readUByte();\r
-                rgb[1] = leis.readUByte();\r
-                rgb[0] = leis.readUByte();\r
-                size += 3*LittleEndianConsts.BYTE_SIZE;\r
-                break;\r
-            case BI_BITCOUNT_6:\r
-                v = leis.readInt();\r
-                rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
-                rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
-                rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
-                size += LittleEndianConsts.INT_SIZE;\r
-                break;\r
-            }\r
-            wr.setPixel(pixel/headerWidth,pixel%headerWidth,rgb);\r
+        try {\r
+            return ImageIO.read(new ByteArrayInputStream(buf));\r
+        } catch (IOException e) {\r
+            // ... shouldn't happen\r
+            throw new RecordFormatException("invalid bitmap data", e);\r
         }\r
-        \r
-        return size;\r
     }\r
 }\r
index 9a5288feae579ce08aa89fdbafdd97319e438e99..ff11d486291a59c89635309e3d1d3d331643f2d4 100644 (file)
@@ -23,15 +23,21 @@ import java.io.IOException;
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
+/**\r
+ * A 32-bit ColorRef Object that defines the color value.\r
+ * Red (1 byte):  An 8-bit unsigned integer that defines the relative intensity of red.\r
+ * Green (1 byte):  An 8-bit unsigned integer that defines the relative intensity of green.\r
+ * Blue (1 byte):  An 8-bit unsigned integer that defines the relative intensity of blue.\r
+ * Reserved (1 byte):  An 8-bit unsigned integer that MUST be 0x00.\r
+ */\r
 public class HwmfColorRef {\r
-    /**\r
-     * A 32-bit ColorRef Object that defines the color value.\r
-     * Red (1 byte):  An 8-bit unsigned integer that defines the relative intensity of red.\r
-     * Green (1 byte):  An 8-bit unsigned integer that defines the relative intensity of green.\r
-     * Blue (1 byte):  An 8-bit unsigned integer that defines the relative intensity of blue.\r
-     * Reserved (1 byte):  An 8-bit unsigned integer that MUST be 0x00.\r
-     */\r
-    Color colorRef;\r
+    private Color colorRef = Color.BLACK;\r
+    \r
+    public HwmfColorRef() {}\r
+    \r
+    public HwmfColorRef(Color colorRef) {\r
+        this.colorRef = colorRef;\r
+    }\r
     \r
     public int init(LittleEndianInputStream leis) throws IOException {\r
         int red = leis.readUByte();\r
@@ -44,4 +50,7 @@ public class HwmfColorRef {
         return 4*LittleEndianConsts.BYTE_SIZE;\r
     }\r
 \r
+    public Color getColor() {\r
+        return colorRef;\r
+    }\r
 }\r
index 81526dd0b6e35fa9ca19d614d93b4255387d87bc..a65b7b45bf50aaf54276118cce8b9e7844348a13 100644 (file)
 \r
 package org.apache.poi.hwmf.record;\r
 \r
+import java.awt.Polygon;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.Line2D;\r
+import java.awt.geom.Point2D;\r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -28,102 +33,140 @@ public class HwmfDraw {
      * point.\r
      */\r
     public static class WmfMoveTo implements HwmfRecord {\r
-        \r
+\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units.\r
          */\r
-        int y;\r
-        \r
+        private int y;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units.\r
          */\r
-        int x;\r
-        \r
+        private int x;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.moveTo;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             y = leis.readShort();\r
             x = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+        \r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setLocation(x, y);\r
+        }\r
     }\r
-    \r
+\r
     /**\r
      * The META_LINETO record draws a line from the drawing position that is defined in the playback\r
      * device context up to, but not including, the specified point.\r
      */\r
     public static class WmfLineTo implements HwmfRecord {\r
-        \r
+\r
         /**\r
          * A 16-bit signed integer that defines the vertical component of the drawing\r
          * destination position, in logical units.\r
          */\r
-        int y;\r
-        \r
+        private int y;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the horizontal component of the drawing\r
          * destination position, in logical units.\r
          */\r
-        int x;\r
-        \r
+        private int x;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.lineTo;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             y = leis.readShort();\r
             x = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+        \r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            Point2D start = ctx.getProperties().getLocation();\r
+            Line2D line = new Line2D.Double(start.getX(), start.getY(), x, y);\r
+            ctx.draw(line);\r
+            ctx.getProperties().setLocation(x, y);\r
+        }\r
     }\r
-    \r
+\r
     /**\r
      * The META_POLYGON record paints a polygon consisting of two or more vertices connected by\r
      * straight lines. The polygon is outlined by using the pen and filled by using the brush and polygon fill\r
      * mode that are defined in the playback device context.\r
      */\r
     public static class WmfPolygon implements HwmfRecord {\r
-        \r
+\r
         /**\r
          * A 16-bit signed integer that defines the number of points in the array.\r
          */\r
-        int numberofPoints;\r
-        \r
+        private int numberofPoints;\r
+\r
         short xPoints[], yPoints[];\r
-        \r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.polygon;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             numberofPoints = leis.readShort();\r
             xPoints = new short[numberofPoints];\r
             yPoints = new short[numberofPoints];\r
-            \r
+\r
             for (int i=0; i<numberofPoints; i++) {\r
                 // A 16-bit signed integer that defines the horizontal (x) coordinate of the point.\r
                 xPoints[i] = leis.readShort();\r
                 // A 16-bit signed integer that defines the vertical (y) coordinate of the point.\r
                 yPoints[i] = leis.readShort();\r
             }\r
-            \r
+\r
             return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;\r
         }\r
+        \r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.fill(getShape());\r
+        }\r
+        \r
+        protected Polygon getShape() {\r
+            Polygon polygon = new Polygon();\r
+            for(int i = 0; i < numberofPoints; i++) {\r
+                polygon.addPoint(xPoints[i], yPoints[i]);\r
+            }\r
+            return polygon;\r
+        }\r
     }\r
-    \r
+\r
     /**\r
      * The META_POLYLINE record draws a series of line segments by connecting the points in the\r
      * specified array.\r
      */\r
     public static class WmfPolyline extends WmfPolygon {\r
-        \r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.polyline;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.draw(getShape());\r
+        }\r
     }\r
-    \r
+\r
     /**\r
      * The META_ELLIPSE record draws an ellipse. The center of the ellipse is the center of the specified\r
      * bounding rectangle. The ellipse is outlined by using the pen and is filled by using the brush; these\r
@@ -134,27 +177,29 @@ public class HwmfDraw {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int bottomRect;\r
+        private int bottomRect;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int rightRect;\r
+        private int rightRect;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the bounding rectangle.\r
          */\r
-        int topRect;\r
+        private int topRect;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the bounding rectangle.\r
          */\r
-        int leftRect;\r
-        \r
+        private int leftRect;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.ellipse;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             bottomRect = leis.readShort();\r
             rightRect = leis.readShort();\r
@@ -162,6 +207,11 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+        \r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
 \r
@@ -173,27 +223,29 @@ public class HwmfDraw {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
          * the region to be framed.\r
          */\r
-        int region;  \r
+        private int region;\r
         /**\r
          * A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
          * Brush to use for filling the region.\r
          */\r
-        int brush;\r
+        private int brush;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the\r
          * region frame.\r
          */\r
-        int height;\r
+        private int height;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the\r
          * region frame.\r
          */\r
-        int width;\r
-        \r
+        private int width;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.frameRegion;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             region = leis.readUShort();\r
             brush = leis.readUShort();\r
@@ -201,6 +253,11 @@ public class HwmfDraw {
             width = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+        \r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -209,33 +266,35 @@ public class HwmfDraw {
      * device context. The polygons drawn by this function can overlap.\r
      */\r
     public static class WmfPolyPolygon implements HwmfRecord {\r
-        \r
+\r
         /**\r
          * A 16-bit unsigned integer that defines the number of polygons in the object.\r
          */\r
-        int numberOfPolygons;\r
-        \r
+        private int numberOfPolygons;\r
+\r
         /**\r
          * A NumberOfPolygons array of 16-bit unsigned integers that define the number of\r
          * points for each polygon in the object.\r
          */\r
-        int pointsPerPolygon[];\r
-        \r
+        private int pointsPerPolygon[];\r
+\r
         /**\r
          * An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
          */\r
-        int xPoints[][];\r
+        private int xPoints[][];\r
 \r
         /**\r
          * An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
          */\r
-        int yPoints[][];\r
-        \r
-        \r
+        private int yPoints[][];\r
+\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.polyPolygon;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             // see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)\r
             numberOfPolygons = leis.readUShort();\r
@@ -244,26 +303,31 @@ public class HwmfDraw {
             yPoints = new int[numberOfPolygons][];\r
 \r
             int size = LittleEndianConsts.SHORT_SIZE;\r
-            \r
+\r
             for (int i=0; i<numberOfPolygons; i++) {\r
                 pointsPerPolygon[i] = leis.readUShort();\r
                 size += LittleEndianConsts.SHORT_SIZE;\r
             }\r
-            \r
+\r
             for (int i=0; i<numberOfPolygons; i++) {\r
-                \r
+\r
                 xPoints[i] = new int[pointsPerPolygon[i]];\r
                 yPoints[i] = new int[pointsPerPolygon[i]];\r
-                \r
+\r
                 for (int j=0; j<pointsPerPolygon[i]; j++) {\r
                     xPoints[i][j] = leis.readUShort();\r
                     yPoints[i][j] = leis.readUShort();\r
                     size += 2*LittleEndianConsts.SHORT_SIZE;\r
                 }\r
             }\r
-            \r
+\r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -275,27 +339,29 @@ public class HwmfDraw {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the rectangle.\r
          */\r
-        int bottomRect;\r
+        private int bottomRect;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the rectangle.\r
          */\r
-        int rightRect;\r
+        private int rightRect;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int topRect;\r
+        private int topRect;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the rectangle.\r
          */\r
-        int leftRect;\r
-        \r
+        private int leftRect;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.frameRegion;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             bottomRect = leis.readShort();\r
             rightRect = leis.readShort();\r
@@ -303,6 +369,11 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -313,25 +384,27 @@ public class HwmfDraw {
         /**\r
          * A ColorRef Object that defines the color value.\r
          */\r
-        HwmfColorRef colorRef; \r
+        HwmfColorRef colorRef;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
          * to be set.\r
          */\r
-        int y;\r
-        \r
+        private int y;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
          * to be set.\r
          */\r
-        int x;\r
-        \r
-        \r
+        private int x;\r
+\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setPixel;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             colorRef = new HwmfColorRef();\r
             int size = colorRef.init(leis);\r
@@ -339,6 +412,11 @@ public class HwmfDraw {
             x = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE+size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -350,43 +428,45 @@ public class HwmfDraw {
          * A 16-bit signed integer that defines the height, in logical coordinates, of the\r
          * ellipse used to draw the rounded corners.\r
          */\r
-        int height;\r
-        \r
+        private int height;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical coordinates, of the\r
          * ellipse used to draw the rounded corners.\r
          */\r
-        int width;\r
-        \r
+        private int width;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the rectangle.\r
          */\r
-        int bottomRect;\r
-        \r
+        private int bottomRect;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the rectangle.\r
          */\r
-        int rightRect;\r
-        \r
+        private int rightRect;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int topRect;\r
-        \r
+        private int topRect;\r
+\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the rectangle.\r
          */\r
-        int leftRect;\r
-        \r
-        \r
+        private int leftRect;\r
+\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.roundRect;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             height = leis.readShort();\r
             width = leis.readShort();\r
@@ -396,8 +476,13 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 6*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
-    \r
+\r
 \r
 \r
     /**\r
@@ -410,47 +495,49 @@ public class HwmfDraw {
          * A 16-bit signed integer that defines the y-coordinate, in logical\r
          * coordinates, of the endpoint of the second radial.\r
          */\r
-        int yRadial2;\r
+        private int yRadial2;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical\r
          * coordinates, of the endpoint of the second radial.\r
          */\r
-        int xRadial2;\r
+        private int xRadial2;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical\r
          * coordinates, of the endpoint of the first radial.\r
          */\r
-        int yRadial1;\r
+        private int yRadial1;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical\r
          * coordinates, of the endpoint of the first radial.\r
          */\r
-        int xRadial1;  \r
+        private int xRadial1;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int bottomRect;\r
+        private int bottomRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int rightRect;\r
+        private int rightRect;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the bounding rectangle.\r
          */\r
-        int topRect;\r
+        private int topRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the bounding rectangle.\r
          */\r
-        int leftRect;\r
-        \r
+        private int leftRect;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.pie;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yRadial2 = leis.readShort();\r
             xRadial2 = leis.readShort();\r
@@ -462,6 +549,12 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 8*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -472,47 +565,49 @@ public class HwmfDraw {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the ending point of the radial line defining the ending point of the arc.\r
          */\r
-        int yEndArc; \r
+        private int yEndArc;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the ending point of the radial line defining the ending point of the arc.\r
          */\r
-        int xEndArc; \r
+        private int xEndArc;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the ending point of the radial line defining the starting point of the arc.\r
          */\r
-        int yStartArc;\r
+        private int yStartArc;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the ending point of the radial line defining the starting point of the arc.\r
          */\r
-        int xStartArc;\r
+        private int xStartArc;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int bottomRect;\r
+        private int bottomRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int rightRect;\r
+        private int rightRect;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the bounding rectangle.\r
          */\r
-        int topRect;\r
+        private int topRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the bounding rectangle.\r
          */\r
-        int leftRect;\r
-        \r
+        private int leftRect;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.arc;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yEndArc = leis.readShort();\r
             xEndArc = leis.readShort();\r
@@ -524,6 +619,11 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 8*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -533,51 +633,53 @@ public class HwmfDraw {
      */\r
     public static class WmfChord implements HwmfRecord {\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical\r
          * coordinates, of the endpoint of the second radial.\r
          */\r
-        int yRadial2;\r
+        private int yRadial2;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical\r
          * coordinates, of the endpoint of the second radial.\r
          */\r
-        int xRadial2;\r
+        private int xRadial2;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical\r
          * coordinates, of the endpoint of the first radial.\r
          */\r
-        int yRadial1;\r
+        private int yRadial1;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical\r
          * coordinates, of the endpoint of the first radial.\r
          */\r
-        int xRadial1;\r
+        private int xRadial1;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int bottomRect;\r
+        private int bottomRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the lower-right corner of the bounding rectangle.\r
          */\r
-        int rightRect;\r
+        private int rightRect;\r
         /**\r
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the bounding rectangle.\r
          */\r
-        int topRect;\r
+        private int topRect;\r
         /**\r
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+         * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
          * the upper-left corner of the bounding rectangle.\r
          */\r
-        int leftRect;\r
-        \r
-        \r
+        private int leftRect;\r
+\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.chord;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yRadial2 = leis.readShort();\r
             xRadial2 = leis.readShort();\r
@@ -589,31 +691,43 @@ public class HwmfDraw {
             leftRect = leis.readShort();\r
             return 8*LittleEndianConsts.SHORT_SIZE;\r
         }\r
-    }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
+}\r
 \r
 \r
     /**\r
-     * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The \r
-     * new object replaces the previous object of the same type, unless if the previous object is a palette \r
-     * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be \r
-     * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not \r
+     * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The\r
+     * new object replaces the previous object of the same type, unless if the previous object is a palette\r
+     * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be\r
+     * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not\r
      * support replacing the palette object type.\r
      */\r
     public static class WmfSelectObject implements HwmfRecord {\r
-        \r
+\r
         /**\r
          * A 16-bit unsigned integer used to index into the WMF Object Table to\r
          * get the object to be selected.\r
          */\r
-        int objectIndex;\r
-        \r
+        private int objectIndex;\r
+\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.selectObject;\r
         }\r
-        \r
+\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             objectIndex = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
  }\r
index d9cddc9e9b8bc720197cf9b630d60b6e8acd3d94..7d616271dfc59ebe1c99e4d338ae1357ec0a75af 100644 (file)
@@ -19,6 +19,8 @@ package org.apache.poi.hwmf.record;
 \r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
+import org.apache.poi.util.HexDump;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -28,21 +30,23 @@ public class HwmfEscape implements HwmfRecord {
      * A 16-bit unsigned integer that defines the escape function. The \r
      * value MUST be from the MetafileEscapes enumeration.\r
      */\r
-    int escapeFunction;\r
+    private int escapeFunction;\r
     /**\r
      * A 16-bit unsigned integer that specifies the size, in bytes, of the \r
      * EscapeData field.\r
      */\r
-    int byteCount;\r
+    private int byteCount;\r
     /**\r
      * An array of bytes of size ByteCount.\r
      */\r
-    byte escapeData[];\r
+    private byte escapeData[];\r
     \r
+    @Override\r
     public HwmfRecordType getRecordType() {\r
         return HwmfRecordType.escape;\r
     }\r
     \r
+    @Override\r
     public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
         escapeFunction = leis.readUShort();\r
         byteCount = leis.readUShort();\r
@@ -50,4 +54,16 @@ public class HwmfEscape implements HwmfRecord {
         leis.read(escapeData);\r
         return 2*LittleEndianConsts.SHORT_SIZE+byteCount;\r
     }\r
+\r
+    @Override\r
+    public void draw(HwmfGraphics ctx) {\r
+        \r
+    }\r
+    \r
+    public String toString() {\r
+        StringBuilder sb = new StringBuilder();\r
+        sb.append("escape - function: "+escapeFunction+"\n");\r
+        sb.append(HexDump.dump(escapeData, 0, 0));\r
+        return sb.toString();\r
+    }\r
 }\r
index 316d3fcf0ba65aee9732e75e80c8bc2218cd54bd..ee38c7b94e69c36c6ebfbdf892eaaf42c4a17125 100644 (file)
 \r
 package org.apache.poi.hwmf.record;\r
 \r
+import java.awt.geom.Path2D;\r
+import java.awt.image.BufferedImage;\r
+import java.io.File;\r
 import java.io.IOException;\r
 \r
+import javax.imageio.ImageIO;\r
+\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
 public class HwmfFill {\r
+    /**\r
+     * A record which contains an image (to be extracted)\r
+     */\r
+    public interface HwmfImageRecord {\r
+        BufferedImage getImage();\r
+    }\r
+    \r
+    \r
     /**\r
      * The META_FILLREGION record fills a region using a specified brush.\r
      */\r
@@ -32,23 +46,30 @@ public class HwmfFill {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
          * the region to be filled.\r
          */\r
-        int region;\r
+        private int region;\r
 \r
         /**\r
          * A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
          * brush to use for filling the region.\r
          */\r
-        int brush;\r
+        private int brush;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.fillRegion;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             region = leis.readUShort();\r
             brush = leis.readUShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -71,6 +92,11 @@ public class HwmfFill {
             region = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
     \r
     \r
@@ -83,23 +109,25 @@ public class HwmfFill {
         /**\r
          * A 32-bit ColorRef Object that defines the color value.\r
          */\r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * point where filling is to start.\r
          */\r
-        int yStart;\r
+        private int yStart;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * point where filling is to start.\r
          */\r
-        int xStart;\r
+        private int xStart;\r
         \r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.floodFill;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             colorRef = new HwmfColorRef();\r
             int size = colorRef.init(leis);\r
@@ -107,6 +135,11 @@ public class HwmfFill {
             xStart = leis.readShort();\r
             return size+2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -114,21 +147,57 @@ public class HwmfFill {
      * graphics operations that fill polygons.\r
      */\r
     public static class WmfSetPolyfillMode implements HwmfRecord {\r
+        /**\r
+         * A 16-bit unsigned integer that defines polygon fill mode.\r
+         * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002\r
+         */\r
+        public enum HwmfPolyfillMode {\r
+            /**\r
+             * Selects alternate mode (fills the area between odd-numbered and\r
+             * even-numbered polygon sides on each scan line).\r
+             */\r
+            ALTERNATE(0x0001, Path2D.WIND_EVEN_ODD),\r
+            /**\r
+             * Selects winding mode (fills any region with a nonzero winding value).\r
+             */\r
+            WINDING(0x0002, Path2D.WIND_NON_ZERO);\r
+\r
+            public int wmfFlag;\r
+            public int awtFlag;\r
+            HwmfPolyfillMode(int wmfFlag, int awtFlag) {\r
+                this.wmfFlag = wmfFlag;\r
+                this.awtFlag = awtFlag;\r
+            }\r
+\r
+            static HwmfPolyfillMode valueOf(int wmfFlag) {\r
+                for (HwmfPolyfillMode pm : values()) {\r
+                    if (pm.wmfFlag == wmfFlag) return pm;\r
+                }\r
+                return null;\r
+            }\r
+        }\r
         \r
         /**\r
          * A 16-bit unsigned integer that defines polygon fill mode.\r
          * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002\r
          */\r
-        int polyFillMode;\r
+        private HwmfPolyfillMode polyfillMode;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setPolyFillMode;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            polyFillMode = leis.readUShort();\r
+            polyfillMode = HwmfPolyfillMode.valueOf(leis.readUShort());\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setPolyfillMode(polyfillMode);\r
+        }\r
     }\r
 \r
 \r
@@ -151,29 +220,31 @@ public class HwmfFill {
          * Filling continues outward in all directions as long as the color is encountered.\r
          * This style is useful for filling areas with multicolored boundaries.\r
          */\r
-        int mode;\r
+        private int mode;\r
         \r
         /**\r
          * A 32-bit ColorRef Object that defines the color value.\r
          */\r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
          * to be set.\r
          */\r
-        int y;\r
+        private int y;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
          * to be set.\r
          */\r
-        int x;  \r
+        private int x;  \r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.extFloodFill;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             mode = leis.readUShort();\r
             colorRef = new HwmfColorRef();\r
@@ -182,6 +253,11 @@ public class HwmfFill {
             x = leis.readShort();\r
             return size+3*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -193,16 +269,23 @@ public class HwmfFill {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
          * the region to be inverted.\r
          */\r
-        int region;\r
+        private int region;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.invertRegion;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             region = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
     \r
 \r
@@ -217,39 +300,41 @@ public class HwmfFill {
          * A 32-bit unsigned integer that defines the raster operation code.\r
          * This code MUST be one of the values in the Ternary Raster Operation enumeration table.\r
          */\r
-        HwmfTernaryRasterOp rasterOperation;\r
+        private HwmfTernaryRasterOp rasterOperation;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the rectangle.\r
          */\r
-        int height;\r
+        private int height;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the rectangle.\r
          */\r
-        int width;\r
+        private int width;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle to be filled.\r
          */\r
-        int yLeft;\r
+        private int yLeft;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle to be filled.\r
          */\r
-        int xLeft;\r
+        private int xLeft;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.patBlt;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
 \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
             \r
             height = leis.readShort();\r
@@ -259,6 +344,11 @@ public class HwmfFill {
 \r
             return 6*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -269,44 +359,44 @@ public class HwmfFill {
          * in the playback device context, and the destination pixels are to be combined to form the new \r
          * image. This code MUST be one of the values in the Ternary Raster Operation Enumeration\r
          */\r
-        HwmfTernaryRasterOp rasterOperation;\r
+        private HwmfTernaryRasterOp rasterOperation;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
          */\r
-        int srcHeight; \r
+        private int srcHeight; \r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
          */\r
-        int srcWidth; \r
+        private int srcWidth; \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
          * of the source rectangle.\r
          */\r
-        int ySrc;\r
+        private int ySrc;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
          * of the source rectangle.\r
          */\r
-        int xSrc;\r
+        private int xSrc;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the destination rectangle.\r
          */\r
-        int destHeight;\r
+        private int destHeight;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the destination rectangle.\r
          */\r
-        int destWidth;\r
+        private int destWidth;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
          * corner of the destination rectangle.\r
          */\r
-        int yDest;\r
+        private int yDest;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
          * corner of the destination rectangle.\r
          */\r
-        int xDest;\r
+        private int xDest;\r
         \r
         /**\r
          * A variable-sized Bitmap16 Object that defines source image content.\r
@@ -314,19 +404,21 @@ public class HwmfFill {
          */\r
         HwmfBitmap16 target;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.stretchBlt;\r
         }\r
         \r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
 \r
             int size = 0;\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
             \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
 \r
             srcHeight = leis.readShort();\r
@@ -351,6 +443,11 @@ public class HwmfFill {
             \r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
     /**\r
@@ -360,13 +457,13 @@ public class HwmfFill {
      * The source of the color data is a DIB, and the destination of the transfer is\r
      * the current output region in the playback device context.\r
      */\r
-    public static class WmfStretchDib implements HwmfRecord {\r
+    public static class WmfStretchDib implements HwmfRecord, HwmfImageRecord {\r
         /**\r
          * A 32-bit unsigned integer that defines how the source pixels, the current brush in\r
          * the playback device context, and the destination pixels are to be combined to\r
          * form the new image.\r
          */\r
-        HwmfTernaryRasterOp rasterOperation;\r
+        private HwmfTernaryRasterOp rasterOperation;\r
 \r
         /**\r
          * A 16-bit unsigned integer that defines whether the Colors field of the\r
@@ -376,63 +473,65 @@ public class HwmfFill {
          * DIB_PAL_COLORS = 0x0001,\r
          * DIB_PAL_INDICES = 0x0002\r
          */\r
-        int colorUsage;\r
+        private int colorUsage;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the\r
          * source rectangle.\r
          */\r
-        int srcHeight;\r
+        private int srcHeight;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the\r
          * source rectangle.\r
          */\r
-        int srcWidth; \r
+        private int srcWidth; \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * source rectangle.\r
          */\r
-        int ySrc;\r
+        private int ySrc;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
          * source rectangle.\r
          */\r
-        int xSrc;\r
+        private int xSrc;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the \r
          * destination rectangle.\r
          */\r
-        int destHeight;\r
+        private int destHeight;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the \r
          * destination rectangle.\r
          */\r
-        int destWidth;\r
+        private int destWidth;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
          * upper-left corner of the destination rectangle.\r
          */\r
-        int yDst;\r
+        private int yDst;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
          * upper-left corner of the destination rectangle.\r
          */\r
-        int xDst;\r
+        private int xDst;\r
         /**\r
          * A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the \r
          * source of the color data.\r
          */\r
-        HwmfBitmapDib dib;\r
+        private HwmfBitmapDib dib;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.stretchDib;\r
         }\r
         \r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
             \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
 \r
             colorUsage = leis.readUShort();\r
@@ -447,9 +546,20 @@ public class HwmfFill {
             \r
             int size = 11*LittleEndianConsts.SHORT_SIZE;\r
             dib = new HwmfBitmapDib();\r
-            size += dib.init(leis);\r
+            size += dib.init(leis, (int)(recordSize-6-size));\r
+\r
             return size;\r
         }        \r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
+\r
+        @Override\r
+        public BufferedImage getImage() {\r
+            return dib.getImage();\r
+        }\r
     }\r
     \r
     public static class WmfBitBlt implements HwmfRecord {\r
@@ -458,57 +568,59 @@ public class HwmfFill {
          * A 32-bit unsigned integer that defines how the source pixels, the current brush in the playback \r
          * device context, and the destination pixels are to be combined to form the new image.\r
          */\r
-        HwmfTernaryRasterOp rasterOperation;\r
+        private HwmfTernaryRasterOp rasterOperation;\r
         \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
         of the source rectangle.\r
          */\r
-        int ySrc; \r
+        private int ySrc; \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
         of the source rectangle.\r
          */\r
-        int xSrc; \r
+        private int xSrc; \r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the source and \r
         destination rectangles.\r
          */\r
-        int height;\r
+        private int height;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the source and destination \r
         rectangles.\r
          */\r
-        int width;\r
+        private int width;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
         corner of the destination rectangle.\r
          */\r
-        int yDest;\r
+        private int yDest;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
         corner of the destination rectangle.\r
          */\r
-        int xDest;\r
+        private int xDest;\r
         \r
         /**\r
          * A variable-sized Bitmap16 Object that defines source image content.\r
          * This object MUST be specified, even if the raster operation does not require a source.\r
          */\r
-        HwmfBitmap16 target;\r
+        private HwmfBitmap16 target;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.bitBlt;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
 \r
             int size = 0;\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
             \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
 \r
             ySrc = leis.readShort();\r
@@ -535,6 +647,11 @@ public class HwmfFill {
             \r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
     }\r
 \r
 \r
@@ -543,7 +660,7 @@ public class HwmfFill {
      * using deviceindependent color data.\r
      * The source of the color data is a DIB\r
      */\r
-    public static class WmfSetDibToDev implements HwmfRecord {\r
+    public static class WmfSetDibToDev implements HwmfRecord, HwmfImageRecord {\r
 \r
         /**\r
          * A 16-bit unsigned integer that defines whether the Colors field of the\r
@@ -553,55 +670,57 @@ public class HwmfFill {
          * DIB_PAL_COLORS = 0x0001,\r
          * DIB_PAL_INDICES = 0x0002\r
          */\r
-        int colorUsage;  \r
+        private int colorUsage;  \r
         /**\r
          * A 16-bit unsigned integer that defines the number of scan lines in the source.\r
          */\r
-        int scanCount;\r
+        private int scanCount;\r
         /**\r
          * A 16-bit unsigned integer that defines the starting scan line in the source.\r
          */\r
-        int startScan;  \r
+        private int startScan;  \r
         /**\r
          * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
          * source rectangle.\r
          */\r
-        int yDib;  \r
+        private int yDib;  \r
         /**\r
          * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
          * source rectangle.\r
          */\r
-        int xDib;  \r
+        private int xDib;  \r
         /**\r
          * A 16-bit unsigned integer that defines the height, in logical units, of the\r
          * source and destination rectangles.\r
          */\r
-        int height;\r
+        private int height;\r
         /**\r
          * A 16-bit unsigned integer that defines the width, in logical units, of the\r
          * source and destination rectangles.\r
          */\r
-        int width;\r
+        private int width;\r
         /**\r
          * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the destination rectangle.\r
          */\r
-        int yDest;\r
+        private int yDest;\r
         /**\r
          * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the destination rectangle.\r
          */\r
-        int xDest;\r
+        private int xDest;\r
         /**\r
          * A variable-sized DeviceIndependentBitmap Object that is the source of the color data.\r
          */\r
-        HwmfBitmapDib dib;        \r
+        private HwmfBitmapDib dib;        \r
         \r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setDibToDev;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             colorUsage = leis.readUShort();\r
             scanCount = leis.readUShort();\r
@@ -615,14 +734,24 @@ public class HwmfFill {
             \r
             int size = 9*LittleEndianConsts.SHORT_SIZE;\r
             dib = new HwmfBitmapDib();\r
-            size += dib.init(leis);\r
+            size += dib.init(leis, (int)(recordSize-6-size));\r
             \r
             return size;\r
         }        \r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
+\r
+        @Override\r
+        public BufferedImage getImage() {\r
+            return dib.getImage();\r
+        }\r
     }\r
 \r
 \r
-    public static class WmfDibBitBlt implements HwmfRecord {\r
+    public static class WmfDibBitBlt implements HwmfRecord, HwmfImageRecord {\r
 \r
         /**\r
          * A 32-bit unsigned integer that defines how the source pixels, the current brush\r
@@ -633,51 +762,53 @@ public class HwmfFill {
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the source rectangle.\r
          */\r
-        int ySrc;\r
+        private int ySrc;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the source rectangle.\r
          */\r
-        int xSrc;\r
+        private int xSrc;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the source and \r
          * destination rectangles.\r
          */\r
-        int height;\r
+        private int height;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the source and destination\r
          * rectangles.\r
          */\r
-        int width;\r
+        private int width;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left\r
          * corner of the destination rectangle.\r
          */\r
-        int yDest;\r
+        private int yDest;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
          * corner of the destination rectangle.\r
          */\r
-        int xDest;\r
+        private int xDest;\r
         \r
         /**\r
          * A variable-sized DeviceIndependentBitmap Object that defines image content.\r
          * This object MUST be specified, even if the raster operation does not require a source.\r
          */\r
-        HwmfBitmapDib target;\r
+        private HwmfBitmapDib target;\r
         \r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.dibBitBlt;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
 \r
             int size = 0;\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
             \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
 \r
             ySrc = leis.readShort();\r
@@ -696,76 +827,88 @@ public class HwmfFill {
             size += 4*LittleEndianConsts.SHORT_SIZE;\r
             if (hasBitmap) {\r
                 target = new HwmfBitmapDib();\r
-                size += target.init(leis);\r
+                size += target.init(leis, (int)(recordSize-6-size));\r
             }\r
             \r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
+\r
+        @Override\r
+        public BufferedImage getImage() {\r
+            return target.getImage();\r
+        }\r
     }\r
 \r
-    public static class WmfDibStretchBlt implements HwmfRecord {\r
+    public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord {\r
         /**\r
          * A 32-bit unsigned integer that defines how the source pixels, the current brush\r
          * in the playback device context, and the destination pixels are to be combined to form the\r
          * new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.\r
          */\r
-        HwmfTernaryRasterOp rasterOperation;\r
+        private HwmfTernaryRasterOp rasterOperation;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
          */\r
-        int srcHeight;\r
+        private int srcHeight;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
          */\r
-        int srcWidth;\r
+        private int srcWidth;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the source rectangle.\r
          */\r
-        int ySrc;\r
+        private int ySrc;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the source rectangle.\r
          */\r
-        int xSrc;\r
+        private int xSrc;\r
         /**\r
          * A 16-bit signed integer that defines the height, in logical units, of the\r
          * destination rectangle.\r
          */\r
-        int destHeight;\r
+        private int destHeight;\r
         /**\r
          * A 16-bit signed integer that defines the width, in logical units, of the\r
          * destination rectangle.\r
          */\r
-        int destWidth;\r
+        private int destWidth;\r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units,\r
          * of the upper-left corner of the destination rectangle.\r
          */\r
-        int yDest;\r
+        private int yDest;\r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units,\r
          * of the upper-left corner of the destination rectangle.\r
          */\r
-        int xDest;\r
+        private int xDest;\r
         /**\r
          * A variable-sized DeviceIndependentBitmap Object that defines image content.\r
          * This object MUST be specified, even if the raster operation does not require a source.\r
          */\r
         HwmfBitmapDib target;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.dibStretchBlt;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
 \r
             int size = 0;\r
-            int rasterOpIndex = leis.readUShort();\r
             int rasterOpCode = leis.readUShort();\r
+            int rasterOpIndex = leis.readUShort();\r
             \r
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
             assert(rasterOpCode == rasterOperation.opCode);\r
 \r
             srcHeight = leis.readShort();\r
@@ -785,10 +928,20 @@ public class HwmfFill {
             size += 4*LittleEndianConsts.SHORT_SIZE;\r
             if (hasBitmap) {\r
                 target = new HwmfBitmapDib();\r
-                size += target.init(leis);\r
+                size += target.init(leis, (int)(recordSize-6-size));\r
             }\r
             \r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            \r
+        }\r
+\r
+        @Override\r
+        public BufferedImage getImage() {\r
+            return target.getImage();\r
+        }\r
     }\r
 }\r
index af6703ef0ceb85752d1fd06cbc3f67bdebbcd186..d1a99e641a3ad49d50c0487e77222accaad40424 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.hwmf.record;
 import java.io.IOException;\r
 import java.nio.charset.Charset;\r
 \r
+import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
 /**\r
@@ -440,7 +441,7 @@ public class HwmfFont {
      *\r
      * @see WmfClipPrecision\r
      */\r
-    int clipPrecision;\r
+    WmfClipPrecision clipPrecision;\r
 \r
     /**\r
      * An 8-bit unsigned integer that defines the output quality.\r
@@ -477,22 +478,23 @@ public class HwmfFont {
         strikeOut = leis.readByte() != 0;\r
         charSet = WmfCharset.valueOf(leis.readUByte());\r
         outPrecision = WmfOutPrecision.valueOf(leis.readUByte());\r
+        clipPrecision = WmfClipPrecision.valueOf(leis.readUByte());\r
         quality = WmfFontQuality.valueOf(leis.readUByte());\r
         int pitchAndFamily = leis.readUByte();\r
         family = WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);\r
         pitch = WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);\r
         \r
-        byte buf[] = new byte[32], readBytes;\r
-        for (readBytes = 0; readBytes < 32; readBytes++) {\r
-            if ((buf[readBytes] = leis.readByte()) == 0) {\r
-                break;\r
+        byte buf[] = new byte[32], b, readBytes = 0;\r
+        do {\r
+            if (readBytes == 32) {\r
+                throw new IOException("Font facename can't be determined.");\r
             }\r
-        }\r
-        if (readBytes == 1 || readBytes == 32) {\r
-            throw new IOException("Font facename can't be determined.");\r
-        }\r
+\r
+            buf[readBytes++] = b = leis.readByte();\r
+        } while (b != 0 && b != -1 && readBytes <= 32);\r
+        \r
         facename = new String(buf, 0, readBytes-1, Charset.forName("ISO-8859-1"));\r
         \r
-        return 17+readBytes;\r
+        return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;\r
     }\r
 }\r
index 18922bfe711668a8ec1ad69572c29254bff64882..00108c4ac8d5555d55a10067b457b4781dc61643 100644 (file)
@@ -21,17 +21,17 @@ package org.apache.poi.hwmf.record;
  * The HatchStyle Enumeration specifies the hatch pattern.\r
  */\r
 public enum HwmfHatchStyle {\r
-    /** A horizontal hatch */\r
+    /** ----- - A horizontal hatch */\r
     HS_HORIZONTAL(0x0000),\r
-    /** A vertical hatch */\r
+    /** ||||| - A vertical hatch */\r
     HS_VERTICAL(0x0001),\r
-    /** A 45-degree downward, left-to-right hatch. */\r
+    /** \\\\\ - A 45-degree downward, left-to-right hatch. */\r
     HS_FDIAGONAL(0x0002),\r
-    /** A 45-degree upward, left-to-right hatch. */\r
+    /** ///// - A 45-degree upward, left-to-right hatch. */\r
     HS_BDIAGONAL(0x0003),\r
-    /** A horizontal and vertical cross-hatch. */\r
+    /** +++++ - A horizontal and vertical cross-hatch. */\r
     HS_CROSS(0x0004),\r
-    /** A 45-degree crosshatch. */\r
+    /** xxxxx - A 45-degree crosshatch. */\r
     HS_DIAGCROSS(0x0005);\r
 \r
     int flag;\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java
new file mode 100644 (file)
index 0000000..28a26a8
--- /dev/null
@@ -0,0 +1,114 @@
+/* ====================================================================\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.record;\r
+\r
+/**\r
+ * A 16-bit unsigned integer that defines the mapping mode.\r
+ *\r
+ * The MapMode defines how logical units are mapped to physical units;\r
+ * that is, assuming that the origins in both the logical and physical coordinate systems\r
+ * are at the same point on the drawing surface, what is the physical coordinate (x',y')\r
+ * that corresponds to logical coordinate (x,y).\r
+ *\r
+ * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that\r
+ * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical\r
+ * coordinate (4,5) would map to physical coordinate (4,5) in pixels.\r
+ *\r
+ * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous\r
+ * example. Given the following definition of that mapping mode, logical coordinate (4,-5)\r
+ * would map to physical coordinate (0.04,0.05) in inches.\r
+ */\r
+public enum HwmfMapMode {\r
+    /**\r
+     *  Each logical unit is mapped to one device pixel.\r
+     *  Positive x is to the right; positive y is down.\r
+     */\r
+    MM_TEXT(0x0001, 0),\r
+    \r
+    /**\r
+     *  Each logical unit is mapped to 0.1 millimeter.\r
+     *  Positive x is to the right; positive y is up.\r
+     */\r
+    MM_LOMETRIC(0x0002, 254),\r
+    \r
+    /**\r
+     *  Each logical unit is mapped to 0.01 millimeter.\r
+     *  Positive x is to the right; positive y is up.\r
+     */\r
+    MM_HIMETRIC(0x0003, 2540),\r
+    \r
+    /**\r
+     *  Each logical unit is mapped to 0.01 inch.\r
+     *  Positive x is to the right; positive y is up.\r
+     */\r
+    MM_LOENGLISH(0x0004, 100),\r
+    \r
+    /**\r
+     *  Each logical unit is mapped to 0.001 inch.\r
+     *  Positive x is to the right; positive y is up.\r
+     */\r
+    MM_HIENGLISH(0x0005, 1000),\r
+    \r
+    /**\r
+     *  Each logical unit is mapped to one twentieth (1/20) of a point.\r
+     *  In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.\r
+     *  This unit is also known as a "twip".\r
+     *  Positive x is to the right; positive y is up.\r
+     */\r
+    MM_TWIPS(0x0006, 1440),\r
+    \r
+    /**\r
+     *  Logical units are mapped to arbitrary device units with equally scaled axes;\r
+     *  that is, one unit along the x-axis is equal to one unit along the y-axis.\r
+     *  The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the\r
+     *  orientation of the axes.\r
+     *  The processing application SHOULD make adjustments as necessary to ensure the x and y\r
+     *  units remain the same size. For example, when the window extent is set, the viewport\r
+     *  SHOULD be adjusted to keep the units isotropic.\r
+     */\r
+    MM_ISOTROPIC(0x0007, -1),\r
+    \r
+    /**\r
+     *  Logical units are mapped to arbitrary units with arbitrarily scaled axes.\r
+     */\r
+    MM_ANISOTROPIC(0x0008, -1);\r
+    \r
+    /**\r
+     * native flag\r
+     */\r
+    public final int flag;\r
+    \r
+    /**\r
+     * transformation units - usually scale relative to current dpi.\r
+     * when scale == 0, then don't scale\r
+     * when scale == -1, then scale relative to window dimension. \r
+     */\r
+    public final int scale;\r
+    \r
+    HwmfMapMode(int flag, int scale) {\r
+        this.flag = flag;\r
+        this.scale = scale;\r
+    }\r
+\r
+    static HwmfMapMode valueOf(int flag) {\r
+        for (HwmfMapMode mm : values()) {\r
+            if (mm.flag == flag) return mm;\r
+        }\r
+        return null;\r
+    }        \r
+}
\ No newline at end of file
index ef539fb209c83d5fe5f2a1decb3773e10f63a365..be59c2dd80268a0c662964a2a57d07394473a40f 100644 (file)
 \r
 package org.apache.poi.hwmf.record;\r
 \r
+import java.awt.image.BufferedImage;\r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
+import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -28,22 +32,38 @@ public class HwmfMisc {
      * The META_SAVEDC record saves the playback device context for later retrieval.\r
      */\r
     public static class WmfSaveDc implements HwmfRecord {\r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.saveDc; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.saveDc;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             return 0;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
      * The META_SETRELABS record is reserved and not supported.\r
      */\r
     public static class WmfSetRelabs implements HwmfRecord {\r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.setRelabs; }\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.setRelabs;\r
+        }\r
 \r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             return 0;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -57,16 +77,23 @@ public class HwmfMisc {
          * member is positive, nSavedDC represents a specific instance of the state to be restored. If\r
          * this member is negative, nSavedDC represents an instance relative to the current state.\r
          */\r
-        int nSavedDC;\r
+        private int nSavedDC;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.restoreDc;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             nSavedDC = leis.readShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -75,16 +102,23 @@ public class HwmfMisc {
      */\r
     public static class WmfSetBkColor implements HwmfRecord {\r
 \r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setBkColor;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             colorRef = new HwmfColorRef();\r
             return colorRef.init(leis);\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setBackgroundColor(colorRef);\r
+        }\r
     }\r
 \r
     /**\r
@@ -96,18 +130,38 @@ public class HwmfMisc {
 \r
         /**\r
          * A 16-bit unsigned integer that defines background mix mode.\r
-         * This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002\r
          */\r
-        int bkMode;\r
+        public enum HwmfBkMode {\r
+            TRANSPARENT(0x0001), OPAQUE(0x0002);\r
+\r
+            int flag;\r
+            HwmfBkMode(int flag) {\r
+                this.flag = flag;\r
+            }\r
+\r
+            static HwmfBkMode valueOf(int flag) {\r
+                for (HwmfBkMode bs : values()) {\r
+                    if (bs.flag == flag) return bs;\r
+                }\r
+                return null;\r
+            }\r
+        }\r
+\r
+        private HwmfBkMode bkMode;\r
 \r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setBkMode;\r
         }\r
 \r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            bkMode = leis.readUShort();\r
+            bkMode = HwmfBkMode.valueOf(leis.readUShort());\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setBkMode(bkMode);\r
+        }\r
     }\r
 \r
     /**\r
@@ -122,19 +176,26 @@ public class HwmfMisc {
          * LAYOUT_RTL = 0x0001\r
          * LAYOUT_BITMAPORIENTATIONPRESERVED = 0x0008\r
          */\r
-        int layout;\r
+        private int layout;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setLayout;\r
         }\r
 \r
         @SuppressWarnings("unused")\r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             layout = leis.readUShort();\r
             // A 16-bit field that MUST be ignored.\r
             int reserved = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -144,72 +205,23 @@ public class HwmfMisc {
      */\r
     public static class WmfSetMapMode implements HwmfRecord {\r
 \r
-        /**\r
-         * A 16-bit unsigned integer that defines the mapping mode.\r
-         *\r
-         * The MapMode defines how logical units are mapped to physical units;\r
-         * that is, assuming that the origins in both the logical and physical coordinate systems\r
-         * are at the same point on the drawing surface, what is the physical coordinate (x',y')\r
-         * that corresponds to logical coordinate (x,y).\r
-         *\r
-         * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that\r
-         * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical\r
-         * coordinate (4,5) would map to physical coordinate (4,5) in pixels.\r
-         *\r
-         * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous\r
-         * example. Given the following definition of that mapping mode, logical coordinate (4,-5)\r
-         * would map to physical coordinate (0.04,0.05) in inches.\r
-         *\r
-         * This MUST be one of the following:\r
-         *\r
-         * MM_TEXT (= 0x0001):\r
-         *  Each logical unit is mapped to one device pixel.\r
-         *  Positive x is to the right; positive y is down.\r
-         *\r
-         * MM_LOMETRIC (= 0x0002):\r
-         *  Each logical unit is mapped to 0.1 millimeter.\r
-         *  Positive x is to the right; positive y is up.\r
-         *\r
-         * MM_HIMETRIC (= 0x0003):\r
-         *  Each logical unit is mapped to 0.01 millimeter.\r
-         *  Positive x is to the right; positive y is up.\r
-         *\r
-         * MM_LOENGLISH (= 0x0004):\r
-         *  Each logical unit is mapped to 0.01 inch.\r
-         *  Positive x is to the right; positive y is up.\r
-         *\r
-         * MM_HIENGLISH (= 0x0005):\r
-         *  Each logical unit is mapped to 0.001 inch.\r
-         *  Positive x is to the right; positive y is up.\r
-         *\r
-         * MM_TWIPS (= 0x0006):\r
-         *  Each logical unit is mapped to one twentieth (1/20) of a point.\r
-         *  In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.\r
-         *  This unit is also known as a "twip".\r
-         *  Positive x is to the right; positive y is up.\r
-         *\r
-         * MM_ISOTROPIC (= 0x0007):\r
-         *  Logical units are mapped to arbitrary device units with equally scaled axes;\r
-         *  that is, one unit along the x-axis is equal to one unit along the y-axis.\r
-         *  The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the\r
-         *  orientation of the axes.\r
-         *  The processing application SHOULD make adjustments as necessary to ensure the x and y\r
-         *  units remain the same size. For example, when the window extent is set, the viewport\r
-         *  SHOULD be adjusted to keep the units isotropic.\r
-         *\r
-         * MM_ANISOTROPIC (= 0x0008):\r
-         *  Logical units are mapped to arbitrary units with arbitrarily scaled axes.\r
-         */\r
-        int mapMode;\r
+        private HwmfMapMode mapMode;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setMapMode;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            mapMode = leis.readUShort();\r
+            mapMode = HwmfMapMode.valueOf(leis.readUShort());\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setMapMode(mapMode);\r
+        }\r
     }\r
 \r
     /**\r
@@ -223,16 +235,23 @@ public class HwmfMisc {
          * match a font's aspect ratio to the current device's aspect ratio. If bit 0 is\r
          * set, the mapper selects only matching fonts.\r
          */\r
-        long mapperValues;\r
+        private long mapperValues;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setMapperFlags;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             mapperValues = leis.readUInt();\r
             return LittleEndianConsts.INT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -262,16 +281,23 @@ public class HwmfMisc {
          * R2_MERGEPEN = 0x000F,\r
          * R2_WHITE = 0x0010\r
          */\r
-        int drawMode;\r
+        private int drawMode;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setRop2;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             drawMode = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -288,25 +314,32 @@ public class HwmfMisc {
          * COLORONCOLOR = 0x0003,\r
          * HALFTONE = 0x0004\r
          */\r
-        int setStretchBltMode;\r
+        private int setStretchBltMode;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setStretchBltMode;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             setStretchBltMode = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
      * 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 {\r
+    public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord {\r
 \r
-        HwmfBrushStyle style;\r
+        private HwmfBrushStyle style;\r
 \r
         /**\r
          * A 16-bit unsigned integer that defines whether the Colors field of a DIB\r
@@ -320,15 +353,17 @@ public class HwmfMisc {
          * DIB_PAL_COLORS = 0x0001,\r
          * DIB_PAL_INDICES = 0x0002\r
          */\r
-        int colorUsage;\r
+        private int colorUsage;\r
 \r
-        HwmfBitmapDib patternDib;\r
-        HwmfBitmap16 pattern16;\r
+        private HwmfBitmapDib patternDib;\r
+        private HwmfBitmap16 pattern16;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.dibCreatePatternBrush;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             style = HwmfBrushStyle.valueOf(leis.readUShort());\r
             colorUsage = leis.readUShort();\r
@@ -339,12 +374,9 @@ public class HwmfMisc {
             case BS_DIBPATTERN:\r
             case BS_DIBPATTERNPT:\r
             case BS_HATCHED:\r
-                patternDib = new HwmfBitmapDib();\r
-                size += patternDib.init(leis);\r
-                break;\r
             case BS_PATTERN:\r
-                pattern16 = new HwmfBitmap16();\r
-                size += pattern16.init(leis);\r
+                patternDib = new HwmfBitmapDib();\r
+                size += patternDib.init(leis, (int)(recordSize-6-size));\r
                 break;\r
             case BS_INDEXED:\r
             case BS_DIBPATTERN8X8:\r
@@ -354,6 +386,24 @@ public class HwmfMisc {
             }\r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            HwmfDrawProperties prop = ctx.getProperties();\r
+            prop.setBrushStyle(style);\r
+            prop.setBrushBitmap(getImage());\r
+        }\r
+\r
+        @Override\r
+        public BufferedImage getImage() {\r
+            if (patternDib != null) {\r
+                return patternDib.getImage();\r
+            } else if (pattern16 != null) {\r
+                return pattern16.getImage();\r
+            } else {\r
+                return null;\r
+            }\r
+        }\r
     }\r
 \r
     /**\r
@@ -364,84 +414,94 @@ public class HwmfMisc {
     public static class WmfDeleteObject implements HwmfRecord {\r
         /**\r
          * A 16-bit unsigned integer used to index into the WMF Object Table to\r
-        get the object to be deleted.\r
+         * get the object to be deleted.\r
          */\r
-        int objectIndex;\r
+        private int objectIndex;\r
 \r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.deleteObject; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.deleteObject;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             objectIndex = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     public static class WmfCreatePatternBrush implements HwmfRecord {\r
 \r
-        HwmfBitmap16 pattern;\r
+        private HwmfBitmap16 pattern;\r
 \r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createPatternBrush; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createPatternBrush;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             pattern = new HwmfBitmap16(true);\r
             return pattern.init(leis);\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     public static class WmfCreatePenIndirect implements HwmfRecord {\r
 \r
-        /**\r
-         * A 16-bit unsigned integer that specifies the pen style.\r
-         * The value MUST be defined from the PenStyle Enumeration table.\r
-         *\r
-         * PS_COSMETIC = 0x0000,\r
-         * PS_ENDCAP_ROUND = 0x0000,\r
-         * PS_JOIN_ROUND = 0x0000,\r
-         * PS_SOLID = 0x0000,\r
-         * PS_DASH = 0x0001,\r
-         * PS_DOT = 0x0002,\r
-         * PS_DASHDOT = 0x0003,\r
-         * PS_DASHDOTDOT = 0x0004,\r
-         * PS_NULL = 0x0005,\r
-         * PS_INSIDEFRAME = 0x0006,\r
-         * PS_USERSTYLE = 0x0007,\r
-         * PS_ALTERNATE = 0x0008,\r
-         * PS_ENDCAP_SQUARE = 0x0100,\r
-         * PS_ENDCAP_FLAT = 0x0200,\r
-         * PS_JOIN_BEVEL = 0x1000,\r
-         * PS_JOIN_MITER = 0x2000\r
-         */\r
-        int penStyle;\r
+        private HwmfPenStyle penStyle;\r
         /**\r
          * A 32-bit PointS Object that specifies a point for the object dimensions.\r
          * The xcoordinate is the pen width. The y-coordinate is ignored.\r
          */\r
-        int xWidth, yWidth;\r
+        private int xWidth;\r
+        @SuppressWarnings("unused")\r
+        private int yWidth;\r
         /**\r
          * A 32-bit ColorRef Object that specifies the pen color value.\r
          */\r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
 \r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createPenIndirect; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createPenIndirect;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            penStyle = leis.readUShort();\r
+            penStyle = HwmfPenStyle.valueOf(leis.readUShort());\r
             xWidth = leis.readShort();\r
             yWidth = leis.readShort();\r
             colorRef = new HwmfColorRef();\r
-            int size = 3*LittleEndianConsts.SHORT_SIZE;\r
-            size += colorRef.init(leis);\r
-            return size;\r
+            int size = colorRef.init(leis);\r
+            return size+3*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            HwmfDrawProperties p = ctx.getProperties();\r
+            p.setPenStyle(penStyle);\r
+            p.setPenColor(colorRef);\r
+            p.setPenWidth(xWidth);\r
         }\r
     }\r
 \r
     /**\r
      * The META_CREATEBRUSHINDIRECT record creates a Brush Object\r
      * from a LogBrush Object.\r
-     * \r
+     *\r
      * The following table shows the relationship between values in the BrushStyle,\r
      * ColorRef and BrushHatch fields in a LogBrush Object. Only supported brush styles are listed.\r
-     * \r
+     *\r
      * <table>\r
      * <tr>\r
      *   <th>BrushStyle</th>\r
@@ -481,26 +541,37 @@ public class HwmfMisc {
      * </table>\r
      */\r
     public static class WmfCreateBrushIndirect implements HwmfRecord {\r
-        HwmfBrushStyle brushStyle;\r
+        private HwmfBrushStyle brushStyle;\r
 \r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
 \r
         /**\r
          * A 16-bit field that specifies the brush hatch type.\r
          * Its interpretation depends on the value of BrushStyle.\r
-         * \r
+         *\r
          */\r
-        HwmfHatchStyle brushHatch;\r
+        private HwmfHatchStyle brushHatch;\r
 \r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createBrushIndirect; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.createBrushIndirect;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             brushStyle = HwmfBrushStyle.valueOf(leis.readUShort());\r
             colorRef = new HwmfColorRef();\r
             int size = colorRef.init(leis);\r
             brushHatch = HwmfHatchStyle.valueOf(leis.readUShort());\r
-            size += 4;\r
-            return size;\r
+            return size+2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            HwmfDrawProperties p = ctx.getProperties();\r
+            p.setBrushStyle(brushStyle);\r
+            p.setBrushColor(colorRef);\r
+            p.setBrushHatch(brushHatch);\r
         }\r
     }\r
 }
\ No newline at end of file
index cbd0a6011997175a02ebc606ec0b141c53d16164..d55f9e454e2564ddab0aee9527deb3be0c1206aa 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.hwmf.record;
 \r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
@@ -30,7 +31,7 @@ public class HwmfPalette {
         // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.\r
         // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.\r
         // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.\r
-        int values, blue, green, red;\r
+        private int values, blue, green, red;\r
         \r
         public int init(LittleEndianInputStream leis) throws IOException {\r
             values = leis.readUByte();\r
@@ -48,16 +49,17 @@ public class HwmfPalette {
          * used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.\r
          * When used with META_CREATEPALETTE, it MUST be 0x0300\r
          */\r
-        int start;\r
+        private int start;\r
         \r
         /**\r
          * NumberOfEntries (2 bytes):  A 16-bit unsigned integer that defines the number of objects in\r
          * aPaletteEntries.  \r
          */\r
-        int numberOfEntries;\r
+        private int numberOfEntries;\r
         \r
         PaletteEntry entries[];\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             start = leis.readUShort();\r
             numberOfEntries = leis.readUShort();\r
@@ -69,15 +71,26 @@ public class HwmfPalette {
             }\r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
      * The META_CREATEPALETTE record creates a Palette Object\r
      */\r
     public static class WmfCreatePalette extends WmfPaletteParent {\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.createPalette;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -85,9 +98,15 @@ public class HwmfPalette {
      * palette that is defined in the playback device context.\r
      */\r
     public static class WmfSetPaletteEntries extends WmfPaletteParent {\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setPalEntries;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
@@ -101,14 +120,21 @@ public class HwmfPalette {
          */\r
         int numberOfEntries;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.resizePalette;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             numberOfEntries = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }        \r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -119,16 +145,23 @@ public class HwmfPalette {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
          * the Palette Object to be selected.\r
          */\r
-        int palette;\r
+        private int palette;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.selectPalette;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             palette = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }        \r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -136,11 +169,20 @@ public class HwmfPalette {
      * is defined in the playback device context to the system palette.\r
      */\r
     public static class WmfRealizePalette implements HwmfRecord {\r
-        public HwmfRecordType getRecordType() { return HwmfRecordType.realizePalette; }\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.realizePalette;\r
+        }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             return 0;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -156,8 +198,14 @@ public class HwmfPalette {
      * this record SHOULD have no effect.\r
      */\r
     public static class WmfAnimatePalette extends WmfPaletteParent {\r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.animatePalette;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 }\r
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
new file mode 100644 (file)
index 0000000..4e908ac
--- /dev/null
@@ -0,0 +1,171 @@
+/* ====================================================================\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.record;\r
+\r
+import java.awt.BasicStroke;\r
+\r
+import org.apache.poi.util.BitField;\r
+import org.apache.poi.util.BitFieldFactory;\r
+\r
+/**\r
+ * The 16-bit PenStyle Enumeration is used to specify different types of pens\r
+ * that can be used in graphics operations.\r
+ * \r
+ * Various styles can be combined by using a logical OR statement, one from\r
+ * each subsection of Style, EndCap, Join, and Type (Cosmetic).\r
+ * \r
+ * The defaults in case the other values of the subsection aren't set are\r
+ * solid, round end caps, round joins and cosmetic type.\r
+ */\r
+public class HwmfPenStyle {\r
+    public enum HwmfLineCap {\r
+        /** Rounded ends */\r
+        ROUND(0, BasicStroke.CAP_ROUND),\r
+        /** Square protrudes by half line width */\r
+        SQUARE(1, BasicStroke.CAP_SQUARE),\r
+        /** Line ends at end point*/\r
+        FLAT(2, BasicStroke.CAP_BUTT);        \r
+\r
+        public int wmfFlag;\r
+        public int awtFlag;\r
+        HwmfLineCap(int wmfFlag, int awtFlag) {\r
+            this.wmfFlag = wmfFlag;\r
+            this.awtFlag = awtFlag;\r
+        }\r
+\r
+        static HwmfLineCap valueOf(int wmfFlag) {\r
+            for (HwmfLineCap hs : values()) {\r
+                if (hs.wmfFlag == wmfFlag) return hs;\r
+            }\r
+            return null;\r
+        }    \r
+    }\r
+    \r
+    public enum HwmfLineJoin {\r
+        /**Line joins are round. */\r
+        ROUND(0, BasicStroke.JOIN_ROUND),\r
+        /** Line joins are beveled. */\r
+        BEVEL(1, BasicStroke.JOIN_BEVEL),\r
+        /**\r
+         * Line joins are mitered when they are within the current limit set by the\r
+         * SETMITERLIMIT META_ESCAPE record. A join is beveled when it would exceed the limit\r
+         */\r
+        MITER(2, BasicStroke.JOIN_MITER);\r
+\r
+        public int wmfFlag;\r
+        public int awtFlag;\r
+        HwmfLineJoin(int wmfFlag, int awtFlag) {\r
+            this.wmfFlag = wmfFlag;\r
+            this.awtFlag = awtFlag;\r
+        }\r
+\r
+        static HwmfLineJoin valueOf(int wmfFlag) {\r
+            for (HwmfLineJoin hs : values()) {\r
+                if (hs.wmfFlag == wmfFlag) return hs;\r
+            }\r
+            return null;\r
+        }    \r
+    }\r
+    \r
+    public enum HwmfLineDash {\r
+        /**\r
+         * The pen is solid.\r
+         */\r
+        SOLID(0x0000, 10),\r
+        /**\r
+         * The pen is dashed. (-----) \r
+         */\r
+        DASH(0x0001, 10, 8),\r
+        /**\r
+         * The pen is dotted. (.....)\r
+         */\r
+        DOT(0x0002, 2, 4),\r
+        /**\r
+         * The pen has alternating dashes and dots. (_._._._)\r
+         */\r
+        DASHDOT(0x0003, 10, 8, 2, 8),\r
+        /**\r
+         * The pen has dashes and double dots. (_.._.._)\r
+         */\r
+        DASHDOTDOT(0x0004, 10, 4, 2, 4, 2, 4),\r
+        /**\r
+         * The pen is invisible.\r
+         */\r
+        NULL(0x0005),\r
+        /**\r
+         * The pen is solid. When this pen is used in any drawing record that takes a\r
+         * bounding rectangle, the dimensions of the figure are shrunk so that it fits\r
+         * entirely in the bounding rectangle, taking into account the width of the pen.\r
+         */\r
+        INSIDEFRAME(0x0006, 10),\r
+        /**\r
+         * The pen uses a styling array supplied by the user.\r
+         * (this is currently not supported and drawn as solid ... no idea where the user\r
+         * styling is supposed to come from ...)\r
+         */\r
+        USERSTYLE(0x0007, 10);\r
+        \r
+\r
+        public int wmfFlag;\r
+        public float[] dashes;\r
+        HwmfLineDash(int wmfFlag, float... dashes) {\r
+            this.wmfFlag = wmfFlag;\r
+            this.dashes = dashes;\r
+        }\r
+\r
+        static HwmfLineDash valueOf(int wmfFlag) {\r
+            for (HwmfLineDash hs : values()) {\r
+                if (hs.wmfFlag == wmfFlag) return hs;\r
+            }\r
+            return null;\r
+        }    \r
+    }\r
+    \r
+    private static final BitField SUBSECTION_DASH      = BitFieldFactory.getInstance(0x0007);\r
+    private static final BitField SUBSECTION_ALTERNATE = BitFieldFactory.getInstance(0x0008);\r
+    private static final BitField SUBSECTION_ENDCAP    = BitFieldFactory.getInstance(0x0300);\r
+    private static final BitField SUBSECTION_JOIN      = BitFieldFactory.getInstance(0x3000);\r
+    \r
+    private int flag;\r
+    \r
+    public static HwmfPenStyle valueOf(int flag) {\r
+        HwmfPenStyle ps = new HwmfPenStyle();\r
+        ps.flag = flag;\r
+        return ps;\r
+    }\r
+    \r
+    public HwmfLineCap getLineCap() {\r
+        return HwmfLineCap.valueOf(SUBSECTION_ENDCAP.getValue(flag));\r
+    }\r
+\r
+    public HwmfLineJoin getLineJoin() {\r
+        return HwmfLineJoin.valueOf(SUBSECTION_JOIN.getValue(flag));\r
+    }\r
+    \r
+    public HwmfLineDash getLineDash() {\r
+        return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag));\r
+    }\r
+    \r
+\r
+    /**\r
+     * The pen sets every other pixel (this style is applicable only for cosmetic pens).\r
+     */\r
+    public boolean isAlternateDash() {\r
+        return SUBSECTION_ALTERNATE.isSet(flag);\r
+    }\r
+}\r
index d600b09e4c639087a6e808876cf42de6bdfe0aa8..7fd5ba5632057b8123e6457f098a136e42a24456 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.hwmf.record;
 \r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
 public interface HwmfRecord {\r
@@ -32,4 +33,11 @@ public interface HwmfRecord {
      * @throws IOException\r
      */\r
     int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;\r
+    \r
+    /**\r
+     * Apply the record settings to the graphics context\r
+     *\r
+     * @param ctx the graphics context to modify\r
+     */\r
+    void draw(HwmfGraphics ctx);\r
 }\r
index 315eb116130b2b132b576ef976e9afb35aba2102..5ee3100fc04a7b2fdad09140735c8b008c45600f 100644 (file)
@@ -285,7 +285,7 @@ public enum HwmfTernaryRasterOp {
         this.opCmd=opCmd;\r
     }\r
     \r
-    public static HwmfTernaryRasterOp fromOpIndex(int opIndex) {\r
+    public static HwmfTernaryRasterOp valueOf(int opIndex) {\r
         for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {\r
             if (bb.opIndex == opIndex) {\r
                 return bb;\r
index 84dc4b1c0370f63e4e675191f63625d519d3b154..6d332607f372d2a3a37d6d17e8f65372c2938676 100644 (file)
@@ -19,9 +19,12 @@ package org.apache.poi.hwmf.record;
 \r
 import java.io.IOException;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
+import org.apache.poi.util.LocaleUtil;\r
+import org.apache.poi.util.RecordFormatException;\r
 \r
 public class HwmfText {\r
 \r
@@ -38,16 +41,23 @@ public class HwmfText {
          * this value is transformed and rounded to the nearest pixel. For details about setting the\r
          * mapping mode, see META_SETMAPMODE\r
          */\r
-        int charExtra;\r
+        private int charExtra;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setTextCharExtra;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             charExtra = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
@@ -55,16 +65,23 @@ public class HwmfText {
      */\r
     public static class WmfSetTextColor implements HwmfRecord {\r
         \r
-        HwmfColorRef colorRef;\r
+        private HwmfColorRef colorRef;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setTextColor;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             colorRef = new HwmfColorRef();\r
             return colorRef.init(leis);\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
@@ -76,7 +93,7 @@ public class HwmfText {
         /**\r
          * A 16-bit unsigned integer that specifies the number of space characters in the line.\r
          */\r
-        int breakCount;\r
+        private int breakCount;\r
         \r
         /**\r
          * A 16-bit unsigned integer that specifies the total extra space, in logical\r
@@ -84,17 +101,24 @@ public class HwmfText {
          * identified by the BreakExtra member is transformed and rounded to the nearest pixel. For\r
          * details about setting the mapping mode, see {@link WmfSetMapMode}.\r
          */\r
-        int breakExtra;\r
+        private int breakExtra;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setBkColor;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             breakCount = leis.readUShort();\r
             breakExtra = leis.readUShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
@@ -105,7 +129,7 @@ public class HwmfText {
         /**\r
          * A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.\r
          */\r
-        int stringLength;\r
+        private int stringLength;\r
         /**\r
          * The size of this field MUST be a multiple of two. If StringLength is an odd\r
          * number, then this field MUST be of a size greater than or equal to StringLength + 1.\r
@@ -114,31 +138,38 @@ public class HwmfText {
          * length of the string.\r
          * The string is written at the location specified by the XStart and YStart fields.\r
          */\r
-        String text;\r
+        private String text;\r
         /**\r
          * A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical\r
          * units, of the point where drawing is to start.\r
          */\r
-        int yStart;\r
+        private int yStart;\r
         /**\r
          * A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in\r
          * logical units, of the point where drawing is to start.\r
          */\r
-        int xStart;  \r
+        private int xStart;  \r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.textOut;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             stringLength = leis.readShort();\r
-            byte buf[] = new byte[stringLength+(stringLength%2)];\r
+            byte buf[] = new byte[stringLength+(stringLength&1)];\r
             leis.readFully(buf);\r
-            text = new String(buf, "UTF16-LE").trim();\r
+            text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252).trim();\r
             yStart = leis.readShort();\r
             xStart = leis.readShort();\r
             return 3*LittleEndianConsts.SHORT_SIZE+buf.length;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     /**\r
@@ -152,16 +183,16 @@ public class HwmfText {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, where the \r
         text string is to be located.\r
          */\r
-        int y;  \r
+        private int y;  \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, where the \r
         text string is to be located.\r
          */\r
-        int x;  \r
+        private int x;  \r
         /**\r
          * A 16-bit signed integer that defines the length of the string.\r
          */\r
-        int stringLength;\r
+        private int stringLength;\r
         /**\r
          * A 16-bit unsigned integer that defines the use of the application-defined \r
          * rectangle. This member can be a combination of one or more values in the \r
@@ -196,7 +227,7 @@ public class HwmfText {
          * Indicates that both horizontal and vertical character displacement values \r
          * SHOULD be provided.\r
          */\r
-        int fwOpts;\r
+        private int fwOpts;\r
         /**\r
          * An optional 8-byte Rect Object (section 2.2.2.18) that defines the \r
          * dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.\r
@@ -205,43 +236,58 @@ public class HwmfText {
          * Each value is a 16-bit signed integer that defines the coordinate, in logical coordinates, of \r
          * the upper-left corner of the rectangle\r
          */\r
-        int left,top,right,bottom;\r
+        private int left,top,right,bottom;\r
         /**\r
          * A variable-length string that specifies the text to be drawn. The string does \r
          * not need to be null-terminated, because StringLength specifies the length of the string. If \r
          * the length is odd, an extra byte is placed after it so that the following member (optional Dx) is \r
          * aligned on a 16-bit boundary.\r
          */\r
-        String text;\r
+        private String text;\r
         /**\r
          * An optional array of 16-bit signed integers that indicate the distance between \r
          * origins of adjacent character cells. For example, Dx[i] logical units separate the origins of \r
          * character cell i and character cell i + 1. If this field is present, there MUST be the same \r
          * number of values as there are characters in the string.\r
          */\r
-        int dx[];\r
+        private int dx[];\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.extTextOut;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             y = leis.readShort();\r
             x = leis.readShort();\r
             stringLength = leis.readShort();\r
             fwOpts = leis.readUShort();\r
-            left = leis.readShort();\r
-            top = leis.readShort();\r
-            right = leis.readShort();\r
-            bottom = leis.readShort();\r
             \r
-            byte buf[] = new byte[stringLength+(stringLength%2)];\r
+            int size = 4*LittleEndianConsts.SHORT_SIZE;\r
+            \r
+            if (fwOpts != 0) {\r
+                // the bounding rectangle is optional and only read when fwOpts are given\r
+                left = leis.readShort();\r
+                top = leis.readShort();\r
+                right = leis.readShort();\r
+                bottom = leis.readShort();\r
+                size += 4*LittleEndianConsts.SHORT_SIZE;\r
+            }\r
+            \r
+            byte buf[] = new byte[stringLength+(stringLength&1)];\r
             leis.readFully(buf);\r
-            text = new String(buf, "UTF16-LE");\r
+            text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252);\r
+            size += buf.length;\r
             \r
-            int size = 8*LittleEndianConsts.SHORT_SIZE+buf.length;\r
-            if (size < recordSize) {\r
-                dx = new int[text.length()];\r
+            // -6 bytes of record function and length header\r
+            int remainingRecordSize = (int)(recordSize-6);\r
+            if (size < remainingRecordSize) {\r
+                if (size + stringLength*LittleEndianConsts.SHORT_SIZE < remainingRecordSize) {\r
+                    throw new RecordFormatException("can't read Dx array - given recordSize doesn't contain enough values for string length "+stringLength);\r
+                }\r
+                \r
+                dx = new int[stringLength];\r
                 for (int i=0; i<dx.length; i++) {\r
                     dx[i] = leis.readShort();\r
                 }\r
@@ -250,6 +296,11 @@ public class HwmfText {
             \r
             return size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
 \r
@@ -320,28 +371,42 @@ public class HwmfText {
          * VTA_BASELINE (0x0018):\r
          * The reference point MUST be on the baseline of the text.\r
          */\r
-        int textAlignmentMode;\r
+        private int textAlignmentMode;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setTextAlign;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             textAlignmentMode = leis.readUShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
     \r
     public static class WmfCreateFontIndirect implements HwmfRecord {\r
-        HwmfFont font;\r
+        private HwmfFont font;\r
         \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.createFontIndirect;\r
         }\r
         \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             font = new HwmfFont();\r
             return font.init(leis);\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 }\r
index ee8943b232623180f3c5c9df7d10410ab7543ba8..1cb19e005f794b6f7a45712c98ff44268572ab54 100644 (file)
 \r
 package org.apache.poi.hwmf.record;\r
 \r
+import java.awt.geom.Rectangle2D;\r
 import java.io.IOException;\r
 import java.util.ArrayList;\r
 import java.util.List;\r
 \r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
 import org.apache.poi.util.LittleEndianConsts;\r
 import org.apache.poi.util.LittleEndianInputStream;\r
 \r
 public class HwmfWindowing {\r
 \r
-    /**\r
-     * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the\r
-     * specified offsets.\r
-     */\r
-    public static class WmfOffsetClipRgn implements HwmfRecord {\r
-\r
-        /**\r
-         * A 16-bit signed integer that defines the number of logical units to move up or down.\r
-         */\r
-        int yOffset;\r
-\r
-        /**\r
-         * A 16-bit signed integer that defines the number of logical units to move left or right.\r
-         */\r
-        int xOffset;\r
-\r
-        public HwmfRecordType getRecordType() {\r
-            return HwmfRecordType.offsetClipRgn;\r
-        }\r
-\r
-        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            yOffset = leis.readShort();\r
-            xOffset = leis.readShort();\r
-            return 2*LittleEndianConsts.SHORT_SIZE;\r
-        }\r
-    }\r
-\r
-\r
     /**\r
      * The META_SETVIEWPORTORG record defines the viewport origin in the playback device context.\r
      */\r
@@ -62,22 +36,29 @@ public class HwmfWindowing {
         /**\r
          * A 16-bit signed integer that defines the vertical offset, in device units.\r
          */\r
-        int y;\r
+        private int y;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the horizontal offset, in device units.\r
          */\r
-        int x;\r
+        private int x;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setViewportOrg;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             y = leis.readShort();\r
             x = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setViewportOrg(x, y);\r
+        }\r
     }\r
 \r
     /**\r
@@ -90,23 +71,30 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the vertical extent\r
          * of the viewport in device units.\r
          */\r
-        int y;\r
+        private int height;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the horizontal extent\r
          * of the viewport in device units.\r
          */\r
-        int x;\r
+        private int width;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setViewportExt;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            y = leis.readShort();\r
-            x = leis.readShort();\r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setViewportExt(width, height);\r
+        }\r
     }\r
 \r
     /**\r
@@ -118,22 +106,30 @@ public class HwmfWindowing {
         /**\r
          * A 16-bit signed integer that defines the vertical offset, in device units.\r
          */\r
-        int yOffset;\r
+        private int yOffset;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the horizontal offset, in device units.\r
          */\r
-        int xOffset;\r
+        private int xOffset;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.offsetViewportOrg;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yOffset = leis.readShort();\r
             xOffset = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            Rectangle2D viewport = ctx.getProperties().getViewport();\r
+            ctx.getProperties().setViewportOrg(viewport.getX()+xOffset, viewport.getY()+yOffset);\r
+        }\r
     }\r
 \r
     /**\r
@@ -144,22 +140,29 @@ public class HwmfWindowing {
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units.\r
          */\r
-        int y;\r
+        private int y;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units.\r
          */\r
-        int x;\r
+        private int x;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setWindowOrg;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             y = leis.readShort();\r
             x = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setWindowOrg(x, y);\r
+        }\r
     }\r
 \r
     /**\r
@@ -172,23 +175,30 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the vertical extent of\r
          * the window in logical units.\r
          */\r
-        int y;\r
+        private int height;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the horizontal extent of\r
          * the window in logical units.\r
          */\r
-        int x;\r
+        private int width;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.setWindowExt;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
-            y = leis.readShort();\r
-            x = leis.readShort();\r
+            height = leis.readShort();\r
+            width = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            ctx.getProperties().setWindowExt(width, height);\r
+        }\r
     }\r
 \r
     /**\r
@@ -200,22 +210,30 @@ public class HwmfWindowing {
         /**\r
          * A 16-bit signed integer that defines the vertical offset, in device units.\r
          */\r
-        int yOffset;\r
+        private int yOffset;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the horizontal offset, in device units.\r
          */\r
-        int xOffset;\r
+        private int xOffset;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.offsetWindowOrg;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yOffset = leis.readShort();\r
             xOffset = leis.readShort();\r
             return 2*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            Rectangle2D window = ctx.getProperties().getWindow();\r
+            ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);\r
+        }\r
     }\r
 \r
     /**\r
@@ -228,30 +246,32 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the amount by which to divide the\r
          * result of multiplying the current y-extent by the value of the yNum member.\r
          */\r
-        int yDenom;\r
+        private int yDenom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to multiply the\r
          * current y-extent.\r
          */\r
-        int yNum;\r
+        private int yNum;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to divide the\r
          * result of multiplying the current x-extent by the value of the xNum member.\r
          */\r
-        int xDenom;\r
+        private int xDenom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to multiply the\r
          * current x-extent.\r
          */\r
-        int xNum;\r
+        private int xNum;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.scaleWindowExt;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yDenom = leis.readShort();\r
             yNum = leis.readShort();\r
@@ -259,6 +279,14 @@ public class HwmfWindowing {
             xNum = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            Rectangle2D window = ctx.getProperties().getWindow();\r
+            double width = window.getWidth() * xNum / xDenom;\r
+            double height = window.getHeight() * yNum / yDenom;\r
+            ctx.getProperties().setWindowExt(width, height);\r
+        }\r
     }\r
 \r
 \r
@@ -273,30 +301,32 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the amount by which to divide the\r
          * result of multiplying the current y-extent by the value of the yNum member.\r
          */\r
-        int yDenom;\r
+        private int yDenom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to multiply the\r
          * current y-extent.\r
          */\r
-        int yNum;\r
+        private int yNum;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to divide the\r
          * result of multiplying the current x-extent by the value of the xNum member.\r
          */\r
-        int xDenom;\r
+        private int xDenom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the amount by which to multiply the\r
          * current x-extent.\r
          */\r
-        int xNum;\r
+        private int xNum;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.scaleViewportExt;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             yDenom = leis.readShort();\r
             yNum = leis.readShort();\r
@@ -304,6 +334,48 @@ public class HwmfWindowing {
             xNum = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+            Rectangle2D viewport = ctx.getProperties().getViewport();\r
+            double width = viewport.getWidth() * xNum / xDenom;\r
+            double height = viewport.getHeight() * yNum / yDenom;\r
+            ctx.getProperties().setViewportExt(width, height);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the\r
+     * specified offsets.\r
+     */\r
+    public static class WmfOffsetClipRgn implements HwmfRecord {\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the number of logical units to move up or down.\r
+         */\r
+        private int yOffset;\r
+\r
+        /**\r
+         * A 16-bit signed integer that defines the number of logical units to move left or right.\r
+         */\r
+        private int xOffset;\r
+\r
+        @Override\r
+        public HwmfRecordType getRecordType() {\r
+            return HwmfRecordType.offsetClipRgn;\r
+        }\r
+\r
+        @Override\r
+        public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+            yOffset = leis.readShort();\r
+            xOffset = leis.readShort();\r
+            return 2*LittleEndianConsts.SHORT_SIZE;\r
+        }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
@@ -316,30 +388,32 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int bottom;\r
+        private int bottom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int right;\r
+        private int right;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int top;\r
+        private int top;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int left;\r
+        private int left;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.excludeClipRect;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             bottom = leis.readShort();\r
             right = leis.readShort();\r
@@ -347,6 +421,11 @@ public class HwmfWindowing {
             left = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
 \r
@@ -360,30 +439,32 @@ public class HwmfWindowing {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int bottom;\r
+        private int bottom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int right;\r
+        private int right;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int top;\r
+        private int top;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int left;\r
+        private int left;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.intersectClipRect;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             bottom = leis.readShort();\r
             right = leis.readShort();\r
@@ -391,11 +472,15 @@ public class HwmfWindowing {
             left = leis.readShort();\r
             return 4*LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     /**\r
-     * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the\r
-     * intersection of the existing clipping region and the specified rectangle.\r
+     * The META_SELECTCLIPREGION record specifies a Region Object to be the current clipping region.\r
      */\r
     public static class WmfSelectClipRegion implements HwmfRecord {\r
 \r
@@ -403,16 +488,23 @@ public class HwmfWindowing {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get\r
          * the region to be clipped.\r
          */\r
-        int region;\r
+        private int region;\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.selectClipRegion;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             region = leis.readShort();\r
             return LittleEndianConsts.SHORT_SIZE;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 \r
     public static class WmfScanObject {\r
@@ -421,30 +513,30 @@ public class HwmfWindowing {
          * coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right\r
          * endpoints are required to specify each scanline.\r
          */\r
-        int count;\r
+        private int count;\r
         /**\r
          * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline.\r
          */\r
-        int top;\r
+        private int top;\r
         /**\r
          * A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline.\r
          */\r
-        int bottom;\r
+        private int bottom;\r
         /**\r
          * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
          * in logical units, of the left endpoint of the scanline.\r
          */\r
-        int left_scanline[];\r
+        private int left_scanline[];\r
         /**\r
          * A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
          * in logical units, of the right endpoint of the scanline.\r
          */\r
-        int right_scanline[];\r
+        private int right_scanline[];\r
         /**\r
          * A 16-bit unsigned integer that MUST be the same as the value of the Count\r
          * field; it is present to allow upward travel in the structure.\r
          */\r
-        int count2;\r
+        private int count2;\r
 \r
         public int init(LittleEndianInputStream leis) {\r
             count = leis.readUShort();\r
@@ -465,62 +557,64 @@ public class HwmfWindowing {
         /**\r
          * A 16-bit signed integer. A value that MUST be ignored.\r
          */\r
-        int nextInChain;\r
+        private int nextInChain;\r
         /**\r
          * A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006.\r
          */\r
-        int objectType;\r
+        private int objectType;\r
         /**\r
          * A 32-bit unsigned integer. A value that MUST be ignored.\r
          */\r
-        int objectCount;\r
+        private int objectCount;\r
         /**\r
          * A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes.\r
          */\r
-        int regionSize;\r
+        private int regionSize;\r
         /**\r
          * A 16-bit signed integer that defines the number of scanlines composing the region.\r
          */\r
-        int scanCount;\r
+        private int scanCount;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the maximum number of points in any one scan in this region.\r
          */\r
-        int maxScan;\r
+        private int maxScan;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int bottom;\r
+        private int bottom;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * lower-right corner of the rectangle.\r
          */\r
-        int right;\r
+        private int right;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int top;\r
+        private int top;\r
 \r
         /**\r
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
          * upper-left corner of the rectangle.\r
          */\r
-        int left;\r
+        private int left;\r
 \r
         /**\r
          * An array of Scan objects that define the scanlines in the region.\r
          */\r
-        WmfScanObject scanObjects[];\r
+        private WmfScanObject scanObjects[];\r
 \r
+        @Override\r
         public HwmfRecordType getRecordType() {\r
             return HwmfRecordType.createRegion;\r
         }\r
 \r
+        @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
             nextInChain = leis.readShort();\r
             objectType = leis.readShort();\r
@@ -545,5 +639,10 @@ public class HwmfWindowing {
 \r
             return 20 + size;\r
         }\r
+\r
+        @Override\r
+        public void draw(HwmfGraphics ctx) {\r
+\r
+        }\r
     }\r
 }\r
index b99b6b00d911cf304b0f359c4f422854585a9ca7..5abf2a66aafec2ff7ed3d8fda9f5d2693db23ae6 100644 (file)
@@ -17,6 +17,8 @@
 \r
 package org.apache.poi.hwmf.usermodel;\r
 \r
+import java.io.BufferedInputStream;\r
+import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 import java.io.InputStream;\r
 import java.util.ArrayList;\r
@@ -37,7 +39,8 @@ public class HwmfPicture {
     }\r
     \r
     public HwmfPicture(InputStream inputStream) throws IOException {\r
-        LittleEndianInputStream leis = new LittleEndianInputStream(inputStream);\r
+        BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);\r
+        LittleEndianInputStream leis = new LittleEndianInputStream(bis);\r
         HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);\r
         HwmfHeader header = new HwmfHeader(leis);\r
         \r
@@ -65,8 +68,15 @@ public class HwmfPicture {
             }\r
             \r
             consumedSize += wr.init(leis, recordSize, recordFunction);\r
-            if (consumedSize < recordSize) {\r
-                leis.skip(recordSize - consumedSize);\r
+            int remainingSize = (int)(recordSize - consumedSize);\r
+            assert(remainingSize >= 0);\r
+            if (remainingSize > 0) {\r
+                byte remaining[] = new byte[remainingSize];\r
+                leis.read(remaining);\r
+                FileOutputStream fos = new FileOutputStream("remaining.dat");\r
+                fos.write(remaining);\r
+                fos.close();\r
+//                 leis.skip(remainingSize);\r
             }\r
         }\r
     }\r
index ac5d6c016f782ef1fbfbba567a77368d7301015a..a1f2cbf1d0ad092d7314a42d2389d23f5fdf6a51 100644 (file)
@@ -19,14 +19,27 @@ package org.apache.poi.hwmf;
 \r
 import static org.junit.Assert.assertEquals;\r
 \r
+import java.awt.image.BufferedImage;\r
+import java.io.ByteArrayInputStream;\r
 import java.io.File;\r
+import java.io.FileFilter;\r
 import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 import java.util.List;\r
+import java.util.Locale;\r
+\r
+import javax.imageio.ImageIO;\r
 \r
 import org.apache.poi.POIDataSamples;\r
+import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;\r
 import org.apache.poi.hwmf.record.HwmfRecord;\r
 import org.apache.poi.hwmf.usermodel.HwmfPicture;\r
+import org.apache.poi.sl.usermodel.PictureData;\r
+import org.apache.poi.sl.usermodel.PictureData.PictureType;\r
+import org.apache.poi.sl.usermodel.SlideShow;\r
+import org.apache.poi.sl.usermodel.SlideShowFactory;\r
+import org.junit.Ignore;\r
 import org.junit.Test;\r
 \r
 public class TestHwmfParsing {\r
@@ -39,4 +52,58 @@ public class TestHwmfParsing {
         List<HwmfRecord> records = wmf.getRecords();\r
         assertEquals(581, records.size());\r
     }\r
+\r
+    @Test\r
+    @Ignore\r
+    public void extract() throws IOException {\r
+        File dir = new File("test-data/slideshow");\r
+        File files[] = dir.listFiles(new FileFilter() {\r
+            public boolean accept(File pathname) {\r
+                return pathname.getName().matches("(?i).*\\.pptx?$");\r
+            }\r
+        });\r
+\r
+        boolean outputFiles = false;\r
+\r
+        File outdir = new File("build/ppt");\r
+        if (outputFiles) {\r
+            outdir.mkdirs();\r
+        }\r
+        int wmfIdx = 1;\r
+        for (File f : files) {\r
+            try {\r
+                SlideShow<?,?> ss = SlideShowFactory.create(f);\r
+                for (PictureData pd : ss.getPictureData()) {\r
+                    if (pd.getType() != PictureType.WMF) continue;\r
+                    byte wmfData[] = pd.getData();\r
+                    if (outputFiles) {\r
+                        String filename = String.format(Locale.ROOT, "pic%04d.wmf", wmfIdx);\r
+                        FileOutputStream fos = new FileOutputStream(new File(outdir, filename));\r
+                        fos.write(wmfData);\r
+                        fos.close();\r
+                    }\r
+\r
+                    HwmfPicture wmf = new HwmfPicture(new ByteArrayInputStream(wmfData));\r
+\r
+                    int bmpIndex = 1;\r
+                    for (HwmfRecord r : wmf.getRecords()) {\r
+                        if (r instanceof HwmfImageRecord) {\r
+                            BufferedImage bi = ((HwmfImageRecord)r).getImage();\r
+                            if (outputFiles) {\r
+                                String filename = String.format(Locale.ROOT, "pic%04d-%04d.png", wmfIdx, bmpIndex);\r
+                                ImageIO.write(bi, "PNG", new File(outdir, filename));\r
+                            }\r
+                            bmpIndex++;\r
+                        }\r
+                    }\r
+\r
+                    wmfIdx++;\r
+                }\r
+                ss.close();\r
+            } catch (Exception e) {\r
+                System.out.println(f+" ignored.");\r
+            }\r
+        }\r
+    }\r
+\r
 }\r