]> source.dussan.org Git - poi.git/commitdiff
Bug 60656 - EMF image support in slideshows
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 23 Jun 2019 22:21:15 +0000 (22:21 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 23 Jun 2019 22:21:15 +0000 (22:21 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1861952 13f79535-47bb-0310-9956-ffa450edef68

21 files changed:
src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
src/java/org/apache/poi/sl/draw/DrawPaint.java
src/java/org/apache/poi/sl/draw/DrawPictureShape.java
src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
src/java/org/apache/poi/sl/draw/ImageRenderer.java
src/java/org/apache/poi/util/Units.java
src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
src/scratchpad/src/org/apache/poi/hemf/draw/HemfImageRenderer.java
src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfImageRenderer.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.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 145791f401362a82c278d454bccfcc478b702927..140fc777f21acbbb50c114279830dd637e45dbef 100644 (file)
@@ -23,6 +23,7 @@ import java.awt.Graphics2D;
 import java.awt.Insets;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
@@ -237,7 +238,7 @@ public class BitmapImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public BufferedImage getImage(Dimension dim) {
+    public BufferedImage getImage(Dimension2D dim) {
         double w_old = img.getWidth();
         double h_old = img.getHeight();
         BufferedImage scaled = new BufferedImage((int)w_old, (int)h_old, BufferedImage.TYPE_INT_ARGB);
index f012161b3c3727b6517fa518151f6b7d52bcd903..fea1da46614159d59714a16bd592eded192f2fd6 100644 (file)
@@ -234,46 +234,50 @@ public class DrawPaint {
 
     @SuppressWarnings("WeakerAccess")
     protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) {
-        InputStream is = fill.getImageData();
-        if (is == null) {
-            return TRANSPARENT;
-        }
         assert(graphics != null);
 
-        ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, fill.getContentType());
+        final String contentType = fill.getContentType();
 
-        try {
-            try {
-                renderer.loadImage(is, fill.getContentType());
-            } finally {
-                is.close();
-            }
-        } catch (IOException e) {
-            LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
-            return TRANSPARENT;
-        }
+        ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, contentType);
 
         int alpha = fill.getAlpha();
         if (0 <= alpha && alpha < 100000) {
             renderer.setAlpha(alpha/100000.f);
         }
 
+        // TODO: handle tile settings, currently the pattern is always streched 100% in height/width
         Rectangle2D textAnchor = shape.getAnchor();
-        BufferedImage image;
-        if ("image/x-wmf".equals(fill.getContentType())) {
-            // don't rely on wmf dimensions, use dimension of anchor
-            // TODO: check pixels vs. points for image dimension
-            image = renderer.getImage(new Dimension((int)textAnchor.getWidth(), (int)textAnchor.getHeight()));
-        } else {
-            image = renderer.getImage();
-        }
 
-        if(image == null) {
-            LOG.log(POILogger.ERROR, "Can't load image data");
+        try (InputStream is = fill.getImageData()) {
+            if (is == null) {
+                return TRANSPARENT;
+            }
+
+            renderer.loadImage(is, contentType);
+
+            final BufferedImage image;
+            switch (contentType) {
+                case "image/x-wmf":
+                case "image/x-emf":
+                    // don't rely on wmf dimensions, use dimension of anchor
+                    // TODO: check pixels vs. points for image dimension
+                    image = renderer.getImage(new Dimension((int)textAnchor.getWidth(), (int)textAnchor.getHeight()));
+                    break;
+                default:
+                    image = renderer.getImage();
+                    break;
+            }
+
+            if(image == null) {
+                LOG.log(POILogger.ERROR, "Can't load image data");
+                return TRANSPARENT;
+            }
+
+            return new java.awt.TexturePaint(image, textAnchor);
+        } catch (IOException e) {
+            LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
             return TRANSPARENT;
         }
-
-        return new java.awt.TexturePaint(image, textAnchor);
     }
 
     /**
index 84e7c91b3349f45e8f94d6035e54cf769eb22ad3..84d3ab785a0e1a617af78643dbf4289cc447a606 100644 (file)
@@ -56,9 +56,10 @@ public class DrawPictureShape extends DrawSimpleShape {
             }
 
             try {
-                ImageRenderer renderer = getImageRenderer(graphics, data.getContentType());
-                if (renderer.canRender(data.getContentType())) {
-                    renderer.loadImage(data.getData(), data.getContentType());
+                String ct = data.getContentType();
+                ImageRenderer renderer = getImageRenderer(graphics, ct);
+                if (renderer.canRender(ct)) {
+                    renderer.loadImage(data.getData(), ct);
                     renderer.drawImage(graphics, anchor, insets);
                     return;
                 }
index d535d71fa6615b5d868458efcd9f0b3d302ee60e..3b32fb3152efaf63aa7e50f13c07dabd5b52799a 100644 (file)
@@ -27,23 +27,10 @@ import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
-import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.EventFilter;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-
-import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
+
 import org.apache.poi.sl.draw.geom.Context;
 import org.apache.poi.sl.draw.geom.CustomGeometry;
 import org.apache.poi.sl.draw.geom.Outline;
@@ -54,8 +41,6 @@ import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
 import org.apache.poi.sl.usermodel.Shadow;
 import org.apache.poi.sl.usermodel.SimpleShape;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.StaxHelper;
 import org.apache.poi.util.Units;
 
 
index 330c02ab0112220803cd000e89d049d34852c87f..dd4e875b10a5bba980963e6b2e9096ef924a5882 100644 (file)
@@ -18,9 +18,9 @@
  */
 package org.apache.poi.sl.draw;
 
-import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.Insets;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
@@ -101,7 +101,7 @@ public interface ImageRenderer {
     /**
      * @return the dimension of the buffered image
      */
-    Dimension getDimension();
+    Dimension2D getDimension();
 
     /**
      * @param alpha the alpha [0..1] to be added to the image (possibly already containing an alpha channel)
@@ -119,7 +119,7 @@ public interface ImageRenderer {
      * 
      * @since POI 3.15-beta2
      */
-    BufferedImage getImage(Dimension dim);
+    BufferedImage getImage(Dimension2D dim);
     
     /**
      * Render picture data into the supplied graphics
index 709e3f10cc517c9cd29666bad825a68ba12a44a2..a2e85e0aa0e1339f20ed12a0272519a2a3dc5257 100644 (file)
@@ -16,9 +16,8 @@
 ==================================================================== */
 package org.apache.poi.util;
 
-/**
- * @author Yegor Kozlov
- */
+import java.awt.geom.Dimension2D;
+
 public class Units {
     /**
      * In Escher absolute distances are specified in
@@ -146,7 +145,13 @@ public class Units {
         points /= PIXEL_DPI;
         return points;
     }
-    
+
+    public static Dimension2D pointsToPixel(Dimension2D pointsDim) {
+        double width = pointsDim.getWidth() * PIXEL_DPI / POINT_DPI;
+        double height = pointsDim.getHeight() * PIXEL_DPI / POINT_DPI;
+        return new Dimension2DDouble(width, height);
+    }
+
     public static int charactersToEMU(double characters) {
         return (int) characters * EMU_PER_CHARACTER;
     }
index 4fc144f57091fe1cee251491a0b9e1a65b506ce8..22250c56b6e5e67c4620792c9993c1da5b47e1fb 100644 (file)
 
 package org.apache.poi.xslf.draw;
 
-import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.Insets;
 import java.awt.RenderingHints;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
@@ -42,6 +42,7 @@ import org.apache.batik.util.XMLResourceDescriptor;
 import org.apache.poi.sl.draw.Drawable;
 import org.apache.poi.sl.draw.ImageRenderer;
 import org.apache.poi.sl.usermodel.PictureData;
+import org.apache.poi.util.Dimension2DDouble;
 import org.w3c.dom.Document;
 
 public class SVGImageRenderer implements ImageRenderer {
@@ -75,9 +76,9 @@ public class SVGImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public Dimension getDimension() {
+    public Dimension2D getDimension() {
         Rectangle2D r = svgRoot.getPrimitiveBounds();
-        return new Dimension((int)Math.ceil(r.getWidth()), (int)Math.ceil(r.getHeight()));
+        return new Dimension2DDouble(Math.ceil(r.getWidth()), Math.ceil(r.getHeight()));
     }
 
     @Override
@@ -91,7 +92,7 @@ public class SVGImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public BufferedImage getImage(Dimension dim) {
+    public BufferedImage getImage(Dimension2D dim) {
         BufferedImage bi = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
         Graphics2D g2d = (Graphics2D) bi.getGraphics();
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -101,7 +102,7 @@ public class SVGImageRenderer implements ImageRenderer {
         g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
         g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
         g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference(bi));
-        Dimension dimSVG = getDimension();
+        Dimension2D dimSVG = getDimension();
 
         double scaleX = dim.getWidth() / dimSVG.getWidth();
         double scaleY = dim.getHeight() / dimSVG.getHeight();
@@ -122,7 +123,7 @@ public class SVGImageRenderer implements ImageRenderer {
     public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {
         graphics.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, graphics.getRenderingHint(Drawable.BUFFERED_IMAGE));
 
-        Dimension bounds = getDimension();
+        Dimension2D bounds = getDimension();
 
         AffineTransform at = new AffineTransform();
         at.translate(anchor.getX(), anchor.getY());
index 9c4e23f060f204f2acbbb0fac42ae6903b64346a..1a0c96fa3026c5b4af724d38e6499e50cb6848a5 100644 (file)
@@ -21,8 +21,8 @@ package org.apache.poi.xslf.usermodel;
 
 import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
 
-import java.awt.Dimension;
 import java.awt.Insets;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
@@ -305,7 +305,7 @@ public class XSLFPictureShape extends XSLFSimpleShape
             renderer.loadImage(is, svgPic.getType().contentType);
         }
 
-        Dimension dim = renderer.getDimension();
+        Dimension2D dim = renderer.getDimension();
         Rectangle2D anc = (anchor != null) ? anchor
             : new Rectangle2D.Double(0,0, Units.pixelToPoints((int)dim.getWidth()), Units.pixelToPoints((int)dim.getHeight()));
 
index 8227b46460b815faeadd37f6306ab74df70cee4c..8b056847b8b2efd38b737a9a7a1fbce8bb9f3095 100644 (file)
@@ -60,6 +60,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
 import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
@@ -149,6 +150,15 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
         PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
             @Override
             public boolean fetch(XSLFShape shape) {
+                PackagePart pp = shape.getSheet().getPackagePart();
+                if (shape instanceof XSLFPictureShape) {
+                    CTPicture pic = (CTPicture)shape.getXmlObject();
+                    if (pic.getBlipFill() != null) {
+                        setValue(selectPaint(pic.getBlipFill(), pp));
+                        return true;
+                    }
+                }
+
                 XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties());
                 if (fp == null) {
                     return false;
@@ -159,7 +169,6 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
                     return true;
                 }
 
-                PackagePart pp = shape.getSheet().getPackagePart();
                 PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
                 if (paint != null) {
                     setValue(paint);
index 1de2b1bea82cafa5cc65fe719077b5f9557984fc..b8bea4aea0eb2fcfa4c8458306ba18b3e6c6b2b5 100644 (file)
@@ -29,6 +29,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.regex.Pattern;
 
 import javax.imageio.ImageIO;
 
@@ -39,21 +40,30 @@ import org.apache.poi.sl.usermodel.SlideShowFactory;
 
 /**
  * An utility to convert slides of a .pptx slide show to a PNG image
- *
- * @author Yegor Kozlov
  */
 public class PPTX2PNG {
 
-    static void usage(String error){
+    private static final String INPUT_PAT_REGEX =
+        "(?<slideno>[^|]+)\\|(?<format>[^|]+)\\|(?<basename>.+)\\.(?<ext>[^.]++)";
+
+    private static final Pattern INPUT_PATTERN = Pattern.compile(INPUT_PAT_REGEX);
+
+    private static final String OUTPUT_PAT_REGEX = "${basename}-${slideno}.${format}";
+
+
+    private static void usage(String error){
         String msg =
             "Usage: PPTX2PNG [options] <ppt or pptx file>\n" +
             (error == null ? "" : ("Error: "+error+"\n")) +
             "Options:\n" +
-            "    -scale <float>   scale factor\n" +
-            "    -slide <integer> 1-based index of a slide to render\n" +
-            "    -format <type>   png,gif,jpg (,null for testing)" +
-            "    -outdir <dir>    output directory, defaults to origin of the ppt/pptx file" +
-            "    -quiet           do not write to console (for normal processing)";
+            "    -scale <float>    scale factor\n" +
+            "    -slide <integer>  1-based index of a slide to render\n" +
+            "    -format <type>    png,gif,jpg (,null for testing)\n" +
+            "    -outdir <dir>     output directory, defaults to origin of the ppt/pptx file\n" +
+            "    -outfile <file>   output filename, defaults to '"+OUTPUT_PAT_REGEX+"'\n" +
+            "    -outpat <pattern> output filename pattern, defaults to '"+OUTPUT_PAT_REGEX+"'\n" +
+            "                      patterns: basename, slideno, format, ext\n" +
+            "    -quiet            do not write to console (for normal processing)";
 
         System.out.println(msg);
         // no System.exit here, as we also run in junit tests!
@@ -70,23 +80,43 @@ public class PPTX2PNG {
         File file = null;
         String format = "png";
         File outdir = null;
+        String outfile = null;
         boolean quiet = false;
+        String outpattern = OUTPUT_PAT_REGEX;
 
         for (int i = 0; i < args.length; i++) {
-            if (args[i].startsWith("-")) {
-                if ("-scale".equals(args[i])) {
-                    scale = Float.parseFloat(args[++i]); // lgtm[java/index-out-of-bounds]
-                } else if ("-slide".equals(args[i])) {
-                    slidenumStr = args[++i]; // lgtm[java/index-out-of-bounds]
-                } else if ("-format".equals(args[i])) {
-                    format = args[++i]; // lgtm[java/index-out-of-bounds]
-                } else if ("-outdir".equals(args[i])) {
-                    outdir = new File(args[++i]); // lgtm[java/index-out-of-bounds]
-                } else if ("-quiet".equals(args[i])) {
+            String opt = (i+1 < args.length) ? args[i+1] : null;
+            switch (args[i]) {
+                case "-scale":
+                    scale = Float.parseFloat(opt);
+                    i++;
+                    break;
+                case "-slide":
+                    slidenumStr = opt;
+                    i++;
+                    break;
+                case "-format":
+                    format = opt;
+                    i++;
+                    break;
+                case "-outdir":
+                    outdir = new File(opt);
+                    i++;
+                    break;
+                case "-outfile":
+                    outfile = opt;
+                    i++;
+                    break;
+                case "-outpat":
+                    outpattern = opt;
+                    i++;
+                    break;
+                case "-quiet":
                     quiet = true;
-                }
-            } else {
-                file = new File(args[i]);
+                    break;
+                default:
+                    file = new File(args[i]);
+                    break;
             }
         }
 
@@ -135,7 +165,7 @@ public class PPTX2PNG {
                 Slide<?, ?> slide = slides.get(slideNo);
                 String title = slide.getTitle();
                 if (!quiet) {
-                    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));
+                    System.out.println("Rendering slide " + (slideNo+1) + (title == null ? "" : ": " + title.trim()));
                 }
 
                 BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
@@ -155,10 +185,9 @@ public class PPTX2PNG {
 
                 // save the result
                 if (!"null".equals(format)) {
-                    String outname = file.getName().replaceFirst(".pptx?", "");
-                    outname = String.format(Locale.ROOT, "%1$s-%2$04d.%3$s", outname, slideNo, format);
-                    File outfile = new File(outdir, outname);
-                    ImageIO.write(img, format, outfile);
+                    String inname = String.format(Locale.ROOT, "%04d|%s|%s", slideNo+1, format, file.getName());
+                    String outname = (outfile != null) ? outfile : INPUT_PATTERN.matcher(inname).replaceAll(outpattern);
+                    ImageIO.write(img, format, new File(outdir, outname));
                 }
 
                 graphics.dispose();
index 9a206a48caf2886047523353dfb2c5a1807e77da..62c5503dbdd7c2b20fc2f7144306da301cc5e8a2 100644 (file)
@@ -94,9 +94,10 @@ public class TestPPTX2PNG {
         assumeFalse("ignore HSLF / .ppt files in no-scratchpad run", xslfOnly && pptFile.toLowerCase(Locale.ROOT).endsWith("ppt"));
         
         String[] args = {
-            "-format", "null", // png,gif,jpg or null for test
+            "-format", "png", // png,gif,jpg or null for test
             "-slide", "-1", // -1 for all
             "-outdir", new File("build/tmp/").getCanonicalPath(),
+            "-outpat", "${basename}-${slideno}-${ext}.${format}",
             "-quiet",
             (basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath()
         };
index 712c2e6c0e41a2e965fbb9ce6fdbf930f4c15eda..3a4ea04c4c583e58ee39176cf9556dba2bc10131 100644 (file)
@@ -60,15 +60,8 @@ public class HemfImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public Dimension getDimension() {
-        int width = 0, height = 0;
-        if (image != null) {
-            Dimension2D dim = image.getSize();
-            width = Units.pointsToPixel(dim.getWidth());
-            // keep aspect ratio for height
-            height = Units.pointsToPixel(dim.getHeight());
-        }
-        return new Dimension(width, height);
+    public Dimension2D getDimension() {
+        return Units.pointsToPixel(image == null ? new Dimension() : image.getSize());
     }
 
     @Override
@@ -82,7 +75,7 @@ public class HemfImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public BufferedImage getImage(Dimension dim) {
+    public BufferedImage getImage(Dimension2D dim) {
         if (image == null) {
             return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
         }
index 6e062cdc48aec2c2954a495ae8792540069c83a9..d96f0c24cf05ab4d97db6f0f893fcfce06dd66cf 100644 (file)
@@ -19,6 +19,7 @@ package org.apache.poi.hemf.usermodel;
 
 
 import java.awt.Graphics2D;
+import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
@@ -152,9 +153,10 @@ public class HemfPicture implements Iterable<HemfRecord> {
     }
 
     public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
-        HemfHeader header = (HemfHeader)getRecords().get(0);
+        final HemfHeader header = (HemfHeader)getRecords().get(0);
 
-        AffineTransform at = ctx.getTransform();
+        final Shape clip = ctx.getClip();
+        final AffineTransform at = ctx.getTransform();
         try {
             Rectangle2D emfBounds = header.getBoundsRectangle();
 
@@ -175,6 +177,7 @@ public class HemfPicture implements Iterable<HemfRecord> {
             }
         } finally {
             ctx.setTransform(at);
+            ctx.setClip(clip);
         }
     }
 
index 63885af3f3777c4392b579364f01244e8d9df6c7..251c4172f0835f2eb0cb8cb57809a2e8b99f3003 100644 (file)
@@ -415,9 +415,9 @@ public final class HSLFFill {
         EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
         int propVal = (p == null) ? 0 : p.getPropertyValue();
 
-        return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
-            ? null
-            : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY);
+        return (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal))
+            ? shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY)
+            : null;
     }
 
     /**
@@ -459,9 +459,9 @@ public final class HSLFFill {
         EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
         int propVal = (p == null) ? 0 : p.getPropertyValue();
 
-        return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
-            ? null
-            : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY);
+        return (FILL_USE_FILLED.isSet(propVal) && FILL_FILLED.isSet(propVal))
+            ? shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY)
+            : null;
     }
 
     /**
index a4c27749451ea3e1ca2303f06d9dabb096904b82..0a3eecd00cf41ed67d73176a59bfa1e0694554e1 100644 (file)
@@ -43,6 +43,7 @@ import java.util.BitSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.TreeMap;
 
 import org.apache.commons.codec.Charsets;
@@ -352,8 +353,9 @@ public class HwmfGraphics {
         case MM_ISOTROPIC:
             // TODO: to be validated ...
             // like anisotropic, but use x-axis as reference
+            graphicsCtx.translate(bbox.getCenterX(), bbox.getCenterY());
             graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth());
-            graphicsCtx.translate(-win.getX(), -win.getY());
+            graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
             break;
         case MM_LOMETRIC:
         case MM_HIMETRIC:
@@ -407,11 +409,8 @@ public class HwmfGraphics {
             }
         }
 
-        String textString = "";
-        if (text != null) {
-            textString = new String(text, charset).trim();
-            textString = textString.substring(0, Math.min(textString.length(), length));
-        }
+        String textString = new String(text, charset).trim();
+        textString = textString.substring(0, Math.min(textString.length(), length));
 
         if (textString.isEmpty()) {
             return;
@@ -504,7 +503,7 @@ public class HwmfGraphics {
 
         final Shape clipShape = graphicsCtx.getClip();
         try {
-            if (clip != null) {
+            if (clip != null && !clip.getBounds2D().isEmpty()) {
                 graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY());
                 graphicsCtx.rotate(angle);
                 graphicsCtx.translate(clip.getCenterX(), clip.getCenterY());
@@ -647,59 +646,28 @@ public class HwmfGraphics {
         graphicsCtx.setTransform(tx);
     }
 
-    private static int clipCnt = 0;
-
+    /**
+     * Set the new clipping region
+     *
+     * @param clip the next clipping region to be processed
+     * @param regionMode the mode and operation of how to apply the next clipping region
+     * @param useInitialAT if true, the clipping is applied on the initial (world) coordinate system
+     */
     public void setClip(Shape clip, HwmfRegionMode regionMode, boolean useInitialAT) {
         final AffineTransform at = graphicsCtx.getTransform();
         if (useInitialAT) {
             graphicsCtx.setTransform(initialAT);
         }
+
         final Shape oldClip = graphicsCtx.getClip();
-        final boolean isEmpty = clip.getBounds2D().isEmpty();
-        switch (regionMode) {
-            case RGN_AND:
-                if (!isEmpty) {
-                    graphicsCtx.clip(clip);
-                }
-                break;
-            case RGN_OR:
-                if (!isEmpty) {
-                    if (oldClip == null) {
-                        graphicsCtx.setClip(clip);
-                    } else {
-                        Area area = new Area(oldClip);
-                        area.add(new Area(clip));
-                        graphicsCtx.setClip(area);
-                    }
-                }
-                break;
-            case RGN_XOR:
-                if (!isEmpty) {
-                    if (oldClip == null) {
-                        graphicsCtx.setClip(clip);
-                    } else {
-                        Area area = new Area(oldClip);
-                        area.exclusiveOr(new Area(clip));
-                        graphicsCtx.setClip(area);
-                    }
-                }
-                break;
-            case RGN_DIFF:
-                if (!isEmpty) {
-                    if (oldClip != null) {
-                        Area area = new Area(oldClip);
-                        area.subtract(new Area(clip));
-                        graphicsCtx.setClip(area);
-                    }
-                }
-                break;
-            case RGN_COPY: {
-                graphicsCtx.setClip(isEmpty ? null : clip);
-                break;
-            }
+        final Shape newClip = regionMode.applyOp(oldClip, clip);
+        if (!Objects.equals(oldClip, newClip)) {
+            graphicsCtx.setClip(newClip);
         }
+
         if (useInitialAT) {
             graphicsCtx.setTransform(at);
         }
+        prop.setClip(graphicsCtx.getClip());
     }
 }
index a87db042d6777da0f7e789ef30abe7c09d7d26e0..f30bdc34d22304e8afe3d44ac1cb66625ed9f6f5 100644 (file)
@@ -21,6 +21,7 @@ import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.Insets;
 import java.awt.RenderingHints;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.RescaleOp;
@@ -64,15 +65,8 @@ public class HwmfImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public Dimension getDimension() {
-        int width = 0, height = 0;
-        if (image != null) {
-            Dimension dim = image.getSize();
-            width = Units.pointsToPixel(dim.getWidth());
-            // keep aspect ratio for height
-            height = Units.pointsToPixel(dim.getHeight());
-        }
-        return new Dimension(width, height);
+    public Dimension2D getDimension() {
+        return Units.pointsToPixel(image == null ? new Dimension() : image.getSize());
     }
 
     @Override
@@ -86,7 +80,7 @@ public class HwmfImageRenderer implements ImageRenderer {
     }
 
     @Override
-    public BufferedImage getImage(Dimension dim) {
+    public BufferedImage getImage(Dimension2D dim) {
         if (image == null) {
             return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); 
         }
index 920e302e2a6b9e75c459c8cd009962c28d3d1e27..20c48b8ee14a09a43fa9864a21ce76106566cf14 100644 (file)
@@ -715,7 +715,17 @@ public class HwmfFill {
         }
     }
 
-    public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry {
+    /**
+     * The META_DIBSTRETCHBLT record specifies the transfer of a block of pixels in device-independent format
+     * according to a raster operation, with possible expansion or contraction.
+     *
+     * The destination of the transfer is the current output region in the playback device context.
+     * There are two forms of META_DIBSTRETCHBLT, one which specifies a device-independent bitmap (DIB) as the source,
+     * and the other which uses the playback device context as the source. Definitions follow for the fields that are
+     * the same in the two forms of META_DIBSTRETCHBLT. The subsections that follow specify the packet structures of
+     * the two forms of META_DIBSTRETCHBLT.
+     */
+    public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord {
         /**
          * A 32-bit unsigned integer that defines how the source pixels, the current brush
          * in the playback device context, and the destination pixels are to be combined to form the
@@ -748,7 +758,7 @@ public class HwmfFill {
             int rasterOpIndex = leis.readUShort();
             
             rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
-            assert(rasterOpCode == rasterOperation.opCode);
+            assert(rasterOperation != null && rasterOpCode == rasterOperation.opCode);
 
             int size = 2*LittleEndianConsts.SHORT_SIZE;
 
@@ -769,12 +779,18 @@ public class HwmfFill {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.addObjectTableEntry(this);
-        }
-
-        @Override
-        public void applyObject(HwmfGraphics ctx) {
-
+            HwmfDrawProperties prop = ctx.getProperties();
+            prop.setRasterOp(rasterOperation);
+            // TODO: implement second operation based on playback device context
+            if (target != null) {
+                HwmfBkMode mode = prop.getBkMode();
+                prop.setBkMode(HwmfBkMode.TRANSPARENT);
+                Color fgColor = prop.getPenColor().getColor();
+                Color bgColor = prop.getBackgroundColor().getColor();
+                BufferedImage bi = target.getImage(fgColor, bgColor, true);
+                ctx.drawImage(bi, srcBounds, dstBounds);
+                prop.setBkMode(mode);
+            }
         }
 
         @Override
index 3a56e52e703d9cc6d9035ce847aed26a2e622f2a..d6bc3fcb0760676fb5c674e6748340ad2156f351 100644 (file)
 
 package org.apache.poi.hwmf.record;
 
-import org.apache.poi.hemf.record.emf.HemfFill;
+import java.awt.Shape;
+import java.awt.geom.Area;
+import java.util.function.BiFunction;
 
 public enum HwmfRegionMode {
     /**
      * The new clipping region includes the intersection (overlapping areas)
      * of the current clipping region and the current path (or new region).
      */
-    RGN_AND(0x01),
+    RGN_AND(0x01, HwmfRegionMode::andOp),
     /**
      * The new clipping region includes the union (combined areas)
      * of the current clipping region and the current path (or new region).
      */
-    RGN_OR(0x02),
+    RGN_OR(0x02, HwmfRegionMode::orOp),
     /**
      * The new clipping region includes the union of the current clipping region
      * and the current path (or new region) but without the overlapping areas
      */
-    RGN_XOR(0x03),
+    RGN_XOR(0x03, HwmfRegionMode::xorOp),
     /**
      * The new clipping region includes the areas of the current clipping region
      * with those of the current path (or new region) excluded.
      */
-    RGN_DIFF(0x04),
+    RGN_DIFF(0x04, HwmfRegionMode::diffOp),
     /**
      * The new clipping region is the current path (or the new region).
      */
-    RGN_COPY(0x05);
+    RGN_COPY(0x05, HwmfRegionMode::copyOp);
 
-    int flag;
-    HwmfRegionMode(int flag) {
+    private final int flag;
+    private final BiFunction<Shape,Shape,Shape> op;
+
+    HwmfRegionMode(int flag, BiFunction<Shape,Shape,Shape> op) {
         this.flag = flag;
+        this.op = op;
     }
 
     public static HwmfRegionMode valueOf(int flag) {
@@ -56,4 +61,68 @@ public enum HwmfRegionMode {
         }
         return null;
     }
+
+    public int getFlag() {
+        return flag;
+    }
+
+    public Shape applyOp(Shape oldClip, Shape newClip) {
+        return op.apply(oldClip, newClip);
+    }
+
+    private static Shape andOp(final Shape oldClip, final Shape newClip) {
+        assert(newClip != null);
+        if (newClip.getBounds2D().isEmpty()) {
+            return oldClip;
+        } else if (oldClip == null) {
+            return newClip;
+        } else {
+            Area newArea = new Area(oldClip);
+            newArea.intersect(new Area(newClip));
+            return newArea.getBounds2D().isEmpty() ? newClip : newArea;
+        }
+    }
+
+    private static Shape orOp(final Shape oldClip, final Shape newClip) {
+        assert(newClip != null);
+        if (newClip.getBounds2D().isEmpty()) {
+            return oldClip;
+        } else if (oldClip == null) {
+            return newClip;
+        } else {
+            Area newArea = new Area(oldClip);
+            newArea.add(new Area(newClip));
+            return newArea;
+        }
+    }
+
+    private static Shape xorOp(final Shape oldClip, final Shape newClip) {
+        assert(newClip != null);
+        if (newClip.getBounds2D().isEmpty()) {
+            return oldClip;
+        } else if (oldClip == null) {
+            return newClip;
+        } else {
+            Area newArea = new Area(oldClip);
+            newArea.exclusiveOr(new Area(newClip));
+            return newArea;
+        }
+    }
+
+    private static Shape diffOp(final Shape oldClip, final Shape newClip) {
+        assert(newClip != null);
+        if (newClip.getBounds2D().isEmpty()) {
+            return oldClip;
+        } else if (oldClip == null) {
+            return newClip;
+        } else {
+            Area newArea = new Area(oldClip);
+            newArea.subtract(new Area(newClip));
+            return newArea;
+        }
+    }
+
+    private static Shape copyOp(final Shape oldClip, final Shape newClip) {
+        return (newClip == null || newClip.getBounds2D().isEmpty()) ? null : newClip;
+    }
 }
index 4b1862286b344a02b96ba52fcb89c45bf97f0124..442884e78c019d263a7a3130ddc39c617f7ecdfe 100644 (file)
@@ -25,6 +25,7 @@ import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
 import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
 
 import java.awt.Shape;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Area;
 import java.awt.geom.Dimension2D;
 import java.awt.geom.Point2D;
@@ -380,7 +381,7 @@ public class HwmfWindowing {
      * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the
      * specified offsets.
      */
-    public static class WmfOffsetClipRgn implements HwmfRecord, HwmfObjectTableEntry {
+    public static class WmfOffsetClipRgn implements HwmfRecord {
 
         protected final Point2D offset = new Point2D.Double();
 
@@ -396,11 +397,14 @@ public class HwmfWindowing {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.addObjectTableEntry(this);
-        }
-        
-        @Override
-        public void applyObject(HwmfGraphics ctx) {
+            final Shape oldClip = ctx.getProperties().getClip();
+            if (oldClip == null) {
+                return;
+            }
+            AffineTransform at = new AffineTransform();
+            at.translate(offset.getX(),offset.getY());
+            final Shape newClip = at.createTransformedShape(oldClip);
+            ctx.setClip(newClip, HwmfRegionMode.RGN_COPY, false);
         }
 
         @Override
@@ -413,7 +417,7 @@ public class HwmfWindowing {
      * The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the
      * existing clipping region minus the specified rectangle.
      */
-    public static class WmfExcludeClipRect implements HwmfRecord, HwmfObjectTableEntry {
+    public static class WmfExcludeClipRect implements HwmfRecord {
 
         /** a rectangle in logical units */
         protected final Rectangle2D bounds = new Rectangle2D.Double();
@@ -430,14 +434,9 @@ public class HwmfWindowing {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.addObjectTableEntry(this);
-        }
-        
-        @Override
-        public void applyObject(HwmfGraphics ctx) {
             ctx.setClip(normalizeBounds(bounds), HwmfRegionMode.RGN_DIFF, false);
         }
-
+        
         @Override
         public String toString() {
             return boundsToString(bounds);
@@ -449,7 +448,7 @@ public class HwmfWindowing {
      * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the
      * intersection of the existing clipping region and the specified rectangle.
      */
-    public static class WmfIntersectClipRect implements HwmfRecord, HwmfObjectTableEntry {
+    public static class WmfIntersectClipRect implements HwmfRecord {
 
         /** a rectangle in logical units */
         protected final Rectangle2D bounds = new Rectangle2D.Double();
@@ -466,14 +465,9 @@ public class HwmfWindowing {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.addObjectTableEntry(this);
+            ctx.setClip(bounds, HwmfRegionMode.RGN_AND, false);
         }
         
-        @Override
-        public void applyObject(HwmfGraphics ctx) {
-            ctx.setClip(bounds, HwmfRegionMode.RGN_AND, true);
-        }
-
         @Override
         public String toString() {
             return boundsToString(bounds);
index da61291066da00735ae6f74f239895dde3594964..cb4e92133da3a6d714669045a31a87135e7e1e9f 100644 (file)
 
 package org.apache.poi.hwmf.usermodel;
 
-import java.awt.Dimension;
 import java.awt.Graphics2D;
+import java.awt.Shape;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
-import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfHeader;
 import org.apache.poi.hwmf.record.HwmfPlaceableHeader;
@@ -35,6 +37,7 @@ import org.apache.poi.hwmf.record.HwmfRecord;
 import org.apache.poi.hwmf.record.HwmfRecordType;
 import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowExt;
 import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg;
+import org.apache.poi.util.Dimension2DDouble;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.POILogFactory;
@@ -110,7 +113,7 @@ public class HwmfPicture {
     }
 
     public void draw(Graphics2D ctx) {
-        Dimension dim = getSize();
+        Dimension2D dim = getSize();
         int width = Units.pointsToPixel(dim.getWidth());
         // keep aspect ratio for height
         int height = Units.pointsToPixel(dim.getHeight());
@@ -119,52 +122,86 @@ public class HwmfPicture {
     }
     
     public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
-        AffineTransform at = ctx.getTransform();
+        final Shape clip = ctx.getClip();
+        final AffineTransform at = ctx.getTransform();
         try {
             Rectangle2D wmfBounds = getBounds();
+            Rectangle2D innerBounds = getInnnerBounds();
+            if (innerBounds == null) {
+                innerBounds = wmfBounds;
+            }
+
             // scale output bounds to image bounds
             ctx.translate(graphicsBounds.getX(), graphicsBounds.getY());
             ctx.scale(graphicsBounds.getWidth()/wmfBounds.getWidth(), graphicsBounds.getHeight()/wmfBounds.getHeight());
-            
-            HwmfGraphics g = new HwmfGraphics(ctx, wmfBounds);
+
+            ctx.translate(-wmfBounds.getX(), -wmfBounds.getY());
+            ctx.translate(innerBounds.getCenterX(), innerBounds.getCenterY());
+            ctx.scale(wmfBounds.getWidth()/innerBounds.getWidth(), wmfBounds.getHeight()/innerBounds.getHeight());
+            ctx.translate(-wmfBounds.getCenterX(), -wmfBounds.getCenterY());
+
+            HwmfGraphics g = new HwmfGraphics(ctx, innerBounds);
+            HwmfDrawProperties prop = g.getProperties();
+            prop.setViewportOrg(innerBounds.getX(), innerBounds.getY());
+            prop.setViewportExt(innerBounds.getWidth(), innerBounds.getHeight());
+
             int idx = 0;
             for (HwmfRecord r : records) {
+                prop = g.getProperties();
+                Shape propClip = prop.getClip();
+                Shape ctxClip = ctx.getClip();
+                if (!Objects.equals(propClip, ctxClip)) {
+                    int a = 5;
+                }
                 r.draw(g);
                 idx++;
             }
         } finally {
             ctx.setTransform(at);
+            ctx.setClip(clip);
         }
     }
 
     /**
      * Returns the bounding box in device-independent units. Usually this is taken from the placeable header.
-     * 
+     *
      * @return the bounding box
+     *
+     * @throws RuntimeException if neither WmfSetWindowOrg/Ext nor the placeableHeader are set
      */
     public Rectangle2D getBounds() {
         if (placeableHeader != null) {
             return placeableHeader.getBounds();
-        } else {
-            WmfSetWindowOrg wOrg = null;
-            WmfSetWindowExt wExt = null;
-            for (HwmfRecord r : getRecords()) {
-                if (wOrg != null && wExt != null) {
-                    break;
-                }
-                if (r instanceof WmfSetWindowOrg) {
-                    wOrg = (WmfSetWindowOrg)r;
-                } else if (r instanceof WmfSetWindowExt) {
-                    wExt = (WmfSetWindowExt)r;
-                }
-            }
-            if (wOrg == null || wExt == null) {
-                throw new RuntimeException("invalid wmf file - window records are incomplete.");
+        }
+        Rectangle2D inner = getInnnerBounds();
+        if (inner != null) {
+            return inner;
+        }
+        throw new RuntimeException("invalid wmf file - window records are incomplete.");
+    }
+
+    /**
+     * Returns the bounding box in device-independent units taken from the WmfSetWindowOrg/Ext records
+     *
+     * @return the bounding box or null, if the WmfSetWindowOrg/Ext records aren't set
+     */
+    public Rectangle2D getInnnerBounds() {
+        WmfSetWindowOrg wOrg = null;
+        WmfSetWindowExt wExt = null;
+        for (HwmfRecord r : getRecords()) {
+            if (r instanceof WmfSetWindowOrg) {
+                wOrg = (WmfSetWindowOrg)r;
+            } else if (r instanceof WmfSetWindowExt) {
+                wExt = (WmfSetWindowExt)r;
             }
-            return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight());
-        }        
+            if (wOrg != null && wExt != null) {
+                return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight());
+        }
+        }
+        return null;
     }
-    
+
+
     public HwmfPlaceableHeader getPlaceableHeader() {
         return placeableHeader;
     }
@@ -178,13 +215,13 @@ public class HwmfPicture {
      *
      * @return the image size in points
      */
-    public Dimension getSize() {
+    public Dimension2D getSize() {
         double inch = (placeableHeader == null) ? 1440 : placeableHeader.getUnitsPerInch();
         Rectangle2D bounds = getBounds();
         
         //coefficient to translate from WMF dpi to 72dpi
         double coeff = Units.POINT_DPI/inch;
-        return new Dimension((int)Math.round(bounds.getWidth()*coeff), (int)Math.round(bounds.getHeight()*coeff));
+        return new Dimension2DDouble(bounds.getWidth()*coeff, bounds.getHeight()*coeff);
     }
 
     public Iterable<HwmfEmbedded> getEmbeddings() {
index 5b0651a93f0be4962fbb8ccf3c476d8db56d6f5b..64fb8563b3de2c60f3fece1b38b377f3282731ea 100644 (file)
@@ -20,16 +20,16 @@ package org.apache.poi.hwmf;
 import static org.apache.poi.POITestCase.assertContains;
 import static org.junit.Assert.assertEquals;
 
-import javax.imageio.ImageIO;
-import java.awt.Dimension;
 import java.awt.Graphics2D;
 import java.awt.RenderingHints;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -41,6 +41,8 @@ import java.util.Locale;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
+import javax.imageio.ImageIO;
+
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
 import org.apache.poi.hwmf.record.HwmfFont;
@@ -84,22 +86,22 @@ public class TestHwmfParsing {
     @Ignore("This is work-in-progress and not a real unit test ...")
     public void paint() throws IOException {
         boolean dumpEmbedded = true;
+        boolean dumpRecords = false;
 
-//        File f = samples.getFile("santa.wmf");
-         File f = new File("testme.wmf");
+        File f = new File("testme.wmf");
         FileInputStream fis = new FileInputStream(f);
         HwmfPicture wmf = new HwmfPicture(fis);
         fis.close();
         
-        Dimension dim = wmf.getSize();
-        int width = Units.pointsToPixel(dim.getWidth());
+        Dimension2D dim = wmf.getSize();
+        double width = Units.pointsToPixel(dim.getWidth());
         // keep aspect ratio for height
-        int height = Units.pointsToPixel(dim.getHeight());
+        double height = Units.pointsToPixel(dim.getHeight());
         double scale = (width > height) ? 1500 / width : 1500 / width;
-        width *= scale;
-        height *= scale;
+        width = Math.abs(width * scale);
+        height = Math.abs(height * scale);
 
-        BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        BufferedImage bufImg = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = bufImg.createGraphics();
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
         g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
@@ -122,6 +124,17 @@ public class TestHwmfParsing {
                 embIdx++;
             }
         }
+
+        if (dumpRecords) {
+            try (FileWriter fw = new FileWriter("wmf-records.log")) {
+                for (HwmfRecord r : wmf.getRecords()) {
+                    fw.write(r.getWmfRecordType().name());
+                    fw.write(":");
+                    fw.write(r.toString());
+                    fw.write("\n");
+                }
+            }
+        }
     }
 
     @Test
@@ -198,7 +211,7 @@ public class TestHwmfParsing {
                 }
 
                 if (renderWmf) {
-                    Dimension dim = wmf.getSize();
+                    Dimension2D dim = wmf.getSize();
                     int width = Units.pointsToPixel(dim.getWidth());
                     // keep aspect ratio for height
                     int height = Units.pointsToPixel(dim.getHeight());