]> source.dussan.org Git - poi.git/commitdiff
WMF fixes
authorAndreas Beeker <kiwiwings@apache.org>
Tue, 5 Jan 2016 23:40:47 +0000 (23:40 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Tue, 5 Jan 2016 23:40:47 +0000 (23:40 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723198 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
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/HwmfWindowing.java
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java

index 2ef64a8ed9ee7130e1c48f64387c10bfef37ca0b..a61390704ac571fda4d16b806f9a0212625a4d21 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.poi.hwmf.draw;
 import java.awt.BasicStroke;\r
 import java.awt.Color;\r
 import java.awt.Graphics2D;\r
+import java.awt.GraphicsConfiguration;\r
 import java.awt.Paint;\r
 import java.awt.Rectangle;\r
 import java.awt.Shape;\r
@@ -36,6 +37,7 @@ import java.util.NoSuchElementException;
 \r
 import org.apache.poi.hwmf.record.HwmfBrushStyle;\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.HwmfObjectTableEntry;\r
 import org.apache.poi.hwmf.record.HwmfPenStyle;\r
@@ -49,6 +51,7 @@ public class HwmfGraphics {
     private List<HwmfObjectTableEntry> objectTable = new ArrayList<HwmfObjectTableEntry>();\r
     /** Bounding box from the placeable header */ \r
     private final Rectangle2D bbox;\r
+    private final AffineTransform initialAT;\r
 \r
     /**\r
      * Initialize a graphics context for wmf rendering\r
@@ -59,6 +62,7 @@ public class HwmfGraphics {
     public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {\r
         this.graphicsCtx = graphicsCtx;\r
         this.bbox = (Rectangle2D)bbox.clone();\r
+        this.initialAT = graphicsCtx.getTransform();\r
     }\r
 \r
     public HwmfDrawProperties getProperties() {\r
@@ -72,7 +76,6 @@ public class HwmfGraphics {
             return;\r
         }\r
 \r
-        Shape tshape = fitShapeToView(shape);\r
         BasicStroke stroke = getStroke();\r
 \r
         // first draw a solid background line (depending on bkmode)\r
@@ -80,56 +83,26 @@ public class HwmfGraphics {
         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
+            graphicsCtx.draw(shape);\r
         }\r
 \r
         // then draw the (dashed) line\r
         graphicsCtx.setStroke(stroke);\r
         graphicsCtx.setColor(prop.getPenColor().getColor());\r
-        graphicsCtx.draw(tshape);\r
+        graphicsCtx.draw(shape);\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
+            graphicsCtx.fill(shape);\r
         }\r
 \r
         draw(shape);\r
     }\r
 \r
-    protected Shape fitShapeToView(Shape shape) {\r
-        int scaleUnits = prop.getMapMode().scale;\r
-        Rectangle2D view = prop.getViewport();\r
-        Rectangle2D win = prop.getWindow();\r
-        if (view == null) {\r
-            view = win;\r
-        }\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.scale(scaleX, scaleY);\r
-//        at.translate(-view.getX(), -view.getY());\r
-        at.translate(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());\r
-\r
-        Shape tshape = at.createTransformedShape(shape);\r
-        return tshape;\r
-    }\r
-\r
     protected BasicStroke getStroke() {\r
         Rectangle2D view = prop.getViewport();\r
         Rectangle2D win = prop.getWindow();\r
@@ -285,4 +258,47 @@ public class HwmfGraphics {
         }\r
         prop = propStack.remove(stackIndex);\r
     }\r
+\r
+    public void updateWindowMapMode() {\r
+        GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();\r
+        Rectangle2D win = prop.getWindow();\r
+        HwmfMapMode mapMode = prop.getMapMode();\r
+        graphicsCtx.setTransform(initialAT);\r
+\r
+        switch (mapMode) {\r
+        default:\r
+        case MM_ANISOTROPIC:\r
+            // scale output bounds to image bounds\r
+            graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getHeight()/bbox.getHeight());\r
+            graphicsCtx.translate(-bbox.getX(), -bbox.getY());\r
+\r
+            // scale window bounds to output bounds\r
+            graphicsCtx.translate(win.getCenterX(), win.getCenterY());\r
+            graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());\r
+            graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());\r
+            break;\r
+        case MM_ISOTROPIC:\r
+            // TODO: to be validated ...\r
+            // like anisotropic, but use x-axis as reference\r
+            graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getWidth()/bbox.getWidth());\r
+            graphicsCtx.translate(-bbox.getX(), -bbox.getY());\r
+            graphicsCtx.translate(win.getCenterX(), win.getCenterY());\r
+            graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth());\r
+            graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());\r
+            break;\r
+        case MM_LOMETRIC:\r
+        case MM_HIMETRIC:\r
+        case MM_LOENGLISH:\r
+        case MM_HIENGLISH:\r
+        case MM_TWIPS:\r
+            // TODO: to be validated ...\r
+            graphicsCtx.transform(gc.getNormalizingTransform());\r
+            graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);\r
+            graphicsCtx.translate(-bbox.getX(), -bbox.getY());\r
+            break;\r
+        case MM_TEXT:\r
+            // TODO: to be validated ...\r
+            break;\r
+        }\r
+    }\r
 }\r
index 06f9b03af060406a77ca46bfb02d133eb745a5a3..4ed79ceb49a912a2cbd4966ed9ca4abc62d96181 100644 (file)
@@ -664,7 +664,7 @@ public class HwmfDraw {
 \r
         @Override\r
         public void draw(HwmfGraphics ctx) {\r
-\r
+            ctx.applyObjectTableEntry(objectIndex);\r
         }\r
     }\r
  }\r
index adaf91cc44c1f0ff0f21c27c148774cec304d0e9..749faa29bd87c5a24a6b155b662b7d4cff3a401a 100644 (file)
@@ -221,6 +221,7 @@ public class HwmfMisc {
         @Override\r
         public void draw(HwmfGraphics ctx) {\r
             ctx.getProperties().setMapMode(mapMode);\r
+            ctx.updateWindowMapMode();\r
         }\r
     }\r
 \r
index 0823e807c6647b236522d1ae139865b454d0dcc6..ae403d5f13bb2aa28d1af4c6737c06f5105edd59 100644 (file)
@@ -17,6 +17,7 @@
 \r
 package org.apache.poi.hwmf.record;\r
 \r
+import java.awt.Color;\r
 import java.io.IOException;\r
 \r
 import org.apache.poi.hwmf.draw.HwmfGraphics;\r
@@ -26,18 +27,58 @@ import org.apache.poi.util.LittleEndianInputStream;
 public class HwmfPalette {\r
     \r
     public static class PaletteEntry {\r
+        enum PaletteEntryFlag {\r
+            /**\r
+             * Specifies that the logical palette entry be used for palette animation. This value\r
+             * prevents other windows from matching colors to the palette entry because the color frequently\r
+             * changes. If an unused system-palette entry is available, the color is placed in that entry.\r
+             * Otherwise, the color is not available for animation.\r
+             */\r
+            PC_RESERVED(0x01),\r
+            /**\r
+             * Specifies that the low-order word of the logical palette entry designates a hardware\r
+             * palette index. This value allows the application to show the contents of the display device palette.\r
+             */\r
+            PC_EXPLICIT(0x02),\r
+            /**\r
+             * Specifies that the color be placed in an unused entry in the system palette\r
+             * instead of being matched to an existing color in the system palette. If there are no unused entries\r
+             * in the system palette, the color is matched normally. Once this color is in the system palette,\r
+             * colors in other logical palettes can be matched to this color.\r
+             */\r
+            PC_NOCOLLAPSE(0x04)\r
+            ;\r
+            \r
+            int flag;\r
+            \r
+            PaletteEntryFlag(int flag) {\r
+                this.flag = flag;\r
+            }\r
+\r
+            static PaletteEntryFlag valueOf(int flag) {\r
+                for (PaletteEntryFlag pef : values()) {\r
+                    if (pef.flag == flag) return pef;\r
+                }\r
+                return null;\r
+            }        \r
+\r
+        }\r
+        \r
         // Values (1 byte):  An 8-bit unsigned integer that defines how the palette entry is to be used. \r
         // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.\r
         // 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
-        private int values, blue, green, red;\r
+        private PaletteEntryFlag values;\r
+        private Color colorRef;\r
         \r
         public int init(LittleEndianInputStream leis) throws IOException {\r
-            values = leis.readUByte();\r
-            blue = leis.readUByte();\r
-            green = leis.readUByte();\r
-            red = leis.readUByte();\r
+            values = PaletteEntryFlag.valueOf(leis.readUByte());\r
+            int blue = leis.readUByte();\r
+            int green = leis.readUByte();\r
+            int red = leis.readUByte();\r
+            colorRef = new Color(red, green, blue);\r
+            \r
             return 4*LittleEndianConsts.BYTE_SIZE;\r
         }\r
     }\r
@@ -57,7 +98,7 @@ public class HwmfPalette {
          */\r
         private int numberOfEntries;\r
         \r
-        PaletteEntry entries[];\r
+        private PaletteEntry entries[];\r
         \r
         @Override\r
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
index 5af1ab826c33c7c159fc528a65bbc3814e54a034..6dbde2bc4ff8fc7fd4642ce706c5453d7f600894 100644 (file)
@@ -167,6 +167,7 @@ public class HwmfWindowing {
         @Override\r
         public void draw(HwmfGraphics ctx) {\r
             ctx.getProperties().setWindowOrg(x, y);\r
+            ctx.updateWindowMapMode();\r
         }\r
 \r
         public int getY() {\r
@@ -211,6 +212,7 @@ public class HwmfWindowing {
         @Override\r
         public void draw(HwmfGraphics ctx) {\r
             ctx.getProperties().setWindowExt(width, height);\r
+            ctx.updateWindowMapMode();\r
         }\r
 \r
         public int getHeight() {\r
@@ -254,6 +256,7 @@ public class HwmfWindowing {
         public void draw(HwmfGraphics ctx) {\r
             Rectangle2D window = ctx.getProperties().getWindow();\r
             ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);\r
+            ctx.updateWindowMapMode();\r
         }\r
     }\r
 \r
@@ -307,6 +310,7 @@ public class HwmfWindowing {
             double width = window.getWidth() * xNum / xDenom;\r
             double height = window.getHeight() * yNum / yDenom;\r
             ctx.getProperties().setWindowExt(width, height);\r
+            ctx.updateWindowMapMode();\r
         }\r
     }\r
 \r
index 7d953aa03a893303595bfb93937d2353022896c8..19385d4fee9a8c0b043f9cf6b5054ec3c829a799 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.poi.hwmf.usermodel;\r
 \r
 import java.awt.Graphics2D;\r
+import java.awt.geom.AffineTransform;\r
 import java.awt.geom.Rectangle2D;\r
 import java.io.BufferedInputStream;\r
 import java.io.IOException;\r
@@ -84,9 +85,14 @@ public class HwmfPicture {
     }\r
 \r
     public void draw(Graphics2D ctx) {\r
-        HwmfGraphics g = new HwmfGraphics(ctx, getBounds());\r
-        for (HwmfRecord r : records)  {\r
-            r.draw(g);\r
+        AffineTransform at = ctx.getTransform();\r
+        try {\r
+            HwmfGraphics g = new HwmfGraphics(ctx, getBounds());\r
+            for (HwmfRecord r : records)  {\r
+                r.draw(g);\r
+            }\r
+        } finally {\r
+            ctx.setTransform(at);\r
         }\r
     }\r
 \r
index 1c9f4c1a12858473e9ee5184d4676992d5a9c4f5..8d14f0c7dce7107aac64263929dddc8f3b1e86ae 100644 (file)
@@ -79,9 +79,6 @@ public class TestHwmfParsing {
         g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);\r
         g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);\r
         \r
-        g.scale(width/bounds.getWidth(), height/bounds.getHeight());\r
-        g.translate(-bounds.getX(), -bounds.getY());\r
-        \r
         wmf.draw(g);\r
 \r
         g.dispose();\r