]> source.dussan.org Git - poi.git/commitdiff
#60656 - Support export file that contains emf and render it correctly
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 23 Nov 2018 02:08:28 +0000 (02:08 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 23 Nov 2018 02:08:28 +0000 (02:08 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1847209 13f79535-47bb-0310-9956-ffa450edef68

src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java
src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java

index 55d8c4cc2324fd97d5310a1c44434323c2329e93..5e04e932d67d320504627e6d9623bf282b686ba5 100644 (file)
@@ -23,7 +23,9 @@ import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
 import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
 
 import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -31,6 +33,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.function.Function;
 
+import org.apache.poi.hemf.draw.HemfDrawProperties;
 import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
@@ -632,6 +635,7 @@ public class HemfMisc {
     public static class EmfModifyWorldTransform implements HemfRecord {
         protected final AffineTransform xForm = new AffineTransform();
         protected HemfModifyWorldTransformMode modifyWorldTransformMode;
+        protected HemfHeader header;
 
         @Override
         public HemfRecordType getEmfRecordType() {
@@ -652,17 +656,50 @@ public class HemfMisc {
             return size + LittleEndianConsts.INT_SIZE;
         }
 
+        @Override
+        public void setHeader(HemfHeader header) {
+            this.header = header;
+        }
+
         @Override
         public void draw(HemfGraphics ctx) {
             if (modifyWorldTransformMode == null) {
                 return;
             }
 
+            final HemfDrawProperties prop = ctx.getProperties();
+
             final AffineTransform tx;
             switch (modifyWorldTransformMode) {
                 case MWT_LEFTMULTIPLY:
+
+                    AffineTransform wsTrans;
+                    final Rectangle2D win = prop.getWindow();
+                    boolean noSetWindowExYet = win.getWidth() == 1 && win.getHeight() == 1;
+                    if (noSetWindowExYet) {
+                        // TODO: understand world-space transformation [MSDN-WRLDPGSPC]
+                        // experimental and horrible solved, because the world-space transformation behind it
+                        // is not understood :(
+                        // only found one example which had landscape bounds and transform of 90 degress
+
+                        try {
+                            wsTrans = xForm.createInverse();
+                        } catch (NoninvertibleTransformException e) {
+                            wsTrans = new AffineTransform();
+                        }
+
+                        Rectangle2D emfBounds = header.getBoundsRectangle();
+
+                        if (xForm.getShearX() == -1.0 && xForm.getShearY() == 1.0) {
+                            // rotate 90 deg
+                            wsTrans.translate(-emfBounds.getHeight(), emfBounds.getHeight());
+                        }
+                    } else {
+                        wsTrans = adaptXForm(ctx.getTransform());
+                    }
+
                     tx = ctx.getTransform();
-                    tx.concatenate(adaptXForm(tx));
+                    tx.concatenate(wsTrans);
                     break;
                 case MWT_RIGHTMULTIPLY:
                     tx = ctx.getTransform();
@@ -690,7 +727,7 @@ public class HemfMisc {
             Function<Double,Double> nn = (d) -> (d == 0. ? 0. : d);
             double yDiff = Math.signum(nn.apply(xForm.getTranslateY())) == Math.signum(nn.apply(other.getTranslateY())) ? 1. : -1.;
             double xDiff = Math.signum(nn.apply(xForm.getTranslateX())) == Math.signum(nn.apply(other.getTranslateX())) ? 1. : -1.;
-            return new AffineTransform(
+                return new AffineTransform(
                     xForm.getScaleX() == 0 ? 1. : xForm.getScaleX(),
                     yDiff * xForm.getShearY(),
                     xDiff * xForm.getShearX(),
index 4fb2cc22d484eab2ec2494b96d8d516c85ef2cf3..41e9f3044296d23089fe00d6d3305d90e01a8ea1 100644 (file)
@@ -52,4 +52,10 @@ public interface HemfRecord {
             ((HwmfRecord) this).draw(ctx);
         }
     }
+
+    /**
+     * Sets the header reference, in case the record needs to refer to it
+     * @param header the emf header
+     */
+    default void setHeader(HemfHeader header) {}
 }
index 8d49fdd0e1a9acc78b14008a2266dc0dd998bf06..6d53ae23ea4f28220b9c8d5ff9834e3323d3a72e 100644 (file)
@@ -67,7 +67,14 @@ public class HemfPicture implements Iterable<HemfRecord> {
             // in case the (first) parsing throws an exception, we can provide the
             // records up to that point
             isParsed = true;
-            new HemfRecordIterator(stream).forEachRemaining(records::add);
+            HemfHeader[] header = new HemfHeader[1];
+            new HemfRecordIterator(stream).forEachRemaining(r -> {
+                if (r instanceof HemfHeader) {
+                    header[0] = (HemfHeader) r;
+                }
+                r.setHeader(header[0]);
+                records.add(r);
+            });
         }
         return records;
     }
@@ -116,23 +123,34 @@ public class HemfPicture implements Iterable<HemfRecord> {
         return new Dimension2DDouble(Math.abs(width*coeff), Math.abs(height*coeff));
     }
 
+    private static double minX(Rectangle2D bounds) {
+        return Math.min(bounds.getMinX(), bounds.getMaxX());
+    }
+
+    private static double minY(Rectangle2D bounds) {
+        return Math.min(bounds.getMinY(), bounds.getMaxY());
+    }
+
     public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
         HemfHeader header = (HemfHeader)getRecords().get(0);
 
         AffineTransform at = ctx.getTransform();
         try {
             Rectangle2D emfBounds = header.getBoundsRectangle();
-            ctx.translate(graphicsBounds.getCenterX()-emfBounds.getCenterX(), graphicsBounds.getCenterY()-emfBounds.getCenterY());
 
             // scale output bounds to image bounds
-            ctx.translate(emfBounds.getCenterX(), emfBounds.getCenterY());
+            ctx.translate(minX(graphicsBounds), minY(graphicsBounds));
             ctx.scale(graphicsBounds.getWidth()/emfBounds.getWidth(), graphicsBounds.getHeight()/emfBounds.getHeight());
-            ctx.translate(-emfBounds.getCenterX(), -emfBounds.getCenterY());
+            ctx.translate(-minX(emfBounds), -minY(emfBounds));
 
             int idx = 0;
             HemfGraphics g = new HemfGraphics(ctx, emfBounds);
             for (HemfRecord r : getRecords()) {
-                g.draw(r);
+                try {
+                    g.draw(r);
+                } catch (RuntimeException ignored) {
+
+                }
                 idx++;
             }
         } finally {
index dd189a0f55b5d0c0bba4bbee1ffc3fe662dbbf75..2f9811fc63779fe90e2e4272bfa3a7628e66802f 100644 (file)
@@ -374,9 +374,6 @@ public class HwmfGraphics {
         final HwmfDrawProperties prop = getProperties();
 
         final AffineTransform at = graphicsCtx.getTransform();
-        if (at.getScaleX() == 0. || at.getScaleY() == 0.) {
-            return;
-        }
 
         try {
             at.createInverse();
@@ -687,11 +684,4 @@ public class HwmfGraphics {
             graphicsCtx.setTransform(at);
         }
     }
-
-    /**
-     * @return the bounding box
-     */
-    public Rectangle2D getBbox() {
-        return (Rectangle2D)bbox.clone();
-    }
 }