You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2019/06/06 22:32:41 UTC

svn commit: r1860732 [2/2] - in /poi/trunk/src/scratchpad: src/org/apache/poi/hemf/draw/ src/org/apache/poi/hemf/record/emf/ src/org/apache/poi/hemf/record/emfplus/ src/org/apache/poi/hemf/usermodel/ src/org/apache/poi/hwmf/draw/ src/org/apache/poi/hwm...

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java Thu Jun  6 22:32:41 2019
@@ -23,12 +23,17 @@ import static org.apache.poi.hemf.record
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.io.IOException;
+import java.util.List;
 import java.util.function.Consumer;
 
+import org.apache.poi.hemf.draw.HemfDrawProperties;
+import org.apache.poi.hemf.draw.HemfGraphics;
+import org.apache.poi.hemf.record.emfplus.HemfPlusDraw.EmfPlusUnitType;
 import org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
 import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
 import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
 import org.apache.poi.hemf.record.emfplus.HemfPlusPath.EmfPlusPath;
+import org.apache.poi.hwmf.record.HwmfPenStyle;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.Internal;
@@ -215,6 +220,13 @@ public class HemfPlusPen {
         }
     }
 
+
+    @Internal
+    public interface EmfPlusCustomLineCap {
+        long init(LittleEndianInputStream leis) throws IOException;
+    }
+
+
     public static class EmfPlusPen implements EmfPlusObjectData {
 
 
@@ -283,16 +295,17 @@ public class HemfPlusPen {
 
         private int type;
         private int penDataFlags;
-        private HemfPlusDraw.EmfPlusUnitType unitType;
+        private EmfPlusUnitType unitType;
         private double penWidth;
-        private AffineTransform trans;
-        private EmfPlusLineCapType startCap, endCap;
-        private EmfPlusLineJoin join;
-        private Double mitterLimit;
-        private EmfPlusLineStyle style;
-        EmfPlusDashedLineCapType dashedLineCapType;
+        private final AffineTransform trans = new AffineTransform();
+        private EmfPlusLineCapType startCap = EmfPlusLineCapType.FLAT;
+        private EmfPlusLineCapType endCap = startCap;
+        private EmfPlusLineJoin join = EmfPlusLineJoin.ROUND;
+        private Double miterLimit = 1.;
+        private EmfPlusLineStyle style = EmfPlusLineStyle.SOLID;
+        private EmfPlusDashedLineCapType dashedLineCapType;
         private Double dashOffset;
-        private double[] dashedLineData;
+        private float[] dashedLineData;
         private EmfPlusPenAlignment penAlignment;
         private double[] compoundLineData;
         private EmfPlusCustomLineCap customStartCap;
@@ -310,17 +323,16 @@ public class HemfPlusPen {
             penDataFlags = leis.readInt();
             // A 32-bit unsigned integer that specifies the measuring units for the pen.
             // The value MUST be from the UnitType enumeration
-            unitType = HemfPlusDraw.EmfPlusUnitType.valueOf(leis.readInt());
+            unitType = EmfPlusUnitType.valueOf(leis.readInt());
             // A 32-bit floating-point value that specifies the width of the line drawn by the pen in the units specified
             // by the PenUnit field. If a zero width is specified, a minimum value is used, which is determined by the units.
             penWidth = leis.readFloat();
-            size += 4* LittleEndianConsts.INT_SIZE;
+            size += 4*LittleEndianConsts.INT_SIZE;
 
             if (TRANSFORM.isSet(penDataFlags)) {
                 // An optional EmfPlusTransformMatrix object that specifies a world space to device space transform for
                 // the pen. This field MUST be present if the PenDataTransform flag is set in the PenDataFlags field of
                 // the EmfPlusPenData object.
-                trans = new AffineTransform();
                 size += readXForm(leis, trans);
             }
 
@@ -354,7 +366,7 @@ public class HemfPlusPen {
                 // line walls on the inside the join to the intersection of the line walls outside the join. The miter
                 // length can be large when the angle between two lines is small. This field MUST be present if the
                 // PenDataMiterLimit flag is set in the PenDataFlags field of the EmfPlusPenData object.
-                mitterLimit = (double)leis.readFloat();
+                miterLimit = (double)leis.readFloat();
                 size += LittleEndianConsts.INT_SIZE;
             }
 
@@ -390,7 +402,7 @@ public class HemfPlusPen {
                 }
 
                 // An array of DashedLineDataSize floating-point values that specify the lengths of the dashes and spaces in a dashed line.
-                dashedLineData = new double[dashesSize];
+                dashedLineData = new float[dashesSize];
                 for (int i=0; i<dashesSize; i++) {
                     dashedLineData[i] = leis.readFloat();
                 }
@@ -435,6 +447,11 @@ public class HemfPlusPen {
             return size;
         }
 
+        @Override
+        public EmfPlusGraphicsVersion getGraphicsVersion() {
+            return graphicsVersion;
+        }
+
         private long initCustomCap(Consumer<EmfPlusCustomLineCap> setter, LittleEndianInputStream leis) throws IOException {
             EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
             long size = version.init(leis);
@@ -450,153 +467,209 @@ public class HemfPlusPen {
             return size;
         }
 
-        @Internal
-        public interface EmfPlusCustomLineCap {
-            long init(LittleEndianInputStream leis) throws IOException;
-        }
-
-        public static class EmfPlusPathArrowCap implements EmfPlusCustomLineCap {
-            /**
-             * If set, an EmfPlusFillPath object MUST be specified in the OptionalData field of the
-             * EmfPlusCustomLineCapData object for filling the custom line cap.
-             */
-            private static final BitField FILL_PATH = BitFieldFactory.getInstance(0x00000001);
-            /**
-             * If set, an EmfPlusLinePath object MUST be specified in the OptionalData field of the
-             * EmfPlusCustomLineCapData object for outlining the custom line cap.
-             */
-            private static final BitField LINE_PATH = BitFieldFactory.getInstance(0x00000002);
-
-
-            private int dataFlags;
-            private EmfPlusLineCapType baseCap;
-            private double baseInset;
-            private EmfPlusLineCapType startCap;
-            private EmfPlusLineCapType endCap;
-            private EmfPlusLineJoin join;
-            private double mitterLimit;
-            private double widthScale;
-            private final Point2D fillHotSpot = new Point2D.Double();
-            private final Point2D lineHotSpot = new Point2D.Double();
-            private EmfPlusPath fillPath;
-            private EmfPlusPath outlinePath;
-
-            @Override
-            public long init(LittleEndianInputStream leis) throws IOException {
-                // A 32-bit unsigned integer that specifies the data in the OptionalData field.
-                // This value MUST be composed of CustomLineCapData flags
-                dataFlags = leis.readInt();
-
-                // A 32-bit unsigned integer that specifies the value from the LineCap enumeration on which
-                // the custom line cap is based.
-                baseCap = EmfPlusLineCapType.valueOf(leis.readInt());
-
-                // A 32-bit floating-point value that specifies the distance between the
-                // beginning of the line cap and the end of the line.
-                baseInset = leis.readFloat();
+        @Override
+        public void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData) {
+            final HemfDrawProperties prop = ctx.getProperties();
+            // TOOD:
+            // - set width according unit type
+            // - provide logic for different start and end cap
+            // - provide standard caps like diamondd
+            // - support custom caps
+
+            // workaround for too wide pens ... just arbitrary reduce high values ...
+            prop.setPenWidth(penWidth > 20 ? 1 : penWidth);
+            prop.setPenStyle(new HwmfPenStyle(){
+                @Override
+                public HwmfLineCap getLineCap() {
+                    // ignore endCap for now
+                    switch(startCap) {
+                        default:
+                        case FLAT:
+                            return HwmfLineCap.FLAT;
+                        case ROUND:
+                            return HwmfLineCap.ROUND;
+                        case SQUARE:
+                            return HwmfLineCap.SQUARE;
+                    }
+                }
 
-                // A 32-bit unsigned integer that specifies the value in the LineCap enumeration that indicates the line
-                // cap used at the start/end of the line to be drawn.
-                startCap = EmfPlusLineCapType.valueOf(leis.readInt());
-                endCap = EmfPlusLineCapType.valueOf(leis.readInt());
+                @Override
+                public HwmfLineJoin getLineJoin() {
+                    switch (join) {
+                        default:
+                        case BEVEL:
+                            return HwmfLineJoin.BEVEL;
+                        case ROUND:
+                            return HwmfLineJoin.ROUND;
+                        case MITER_CLIPPED:
+                        case MITER:
+                            return HwmfLineJoin.MITER;
+                    }
+                }
 
-                // A 32-bit unsigned integer that specifies the value in the LineJoin enumeration, which specifies how
-                // to join two lines that are drawn by the same pen and whose ends meet. At the intersection of the two
-                // line ends, a line join makes the connection look more continuous.
-                join = EmfPlusLineJoin.valueOf(leis.readInt());
+                @Override
+                public HwmfLineDash getLineDash() {
+                    return dashedLineData == null ? HwmfLineDash.SOLID : HwmfLineDash.USERSTYLE;
+                }
 
-                // A 32-bit floating-point value that contains the limit of the thickness of the join on a mitered corner
-                // by setting the maximum allowed ratio of miter length to line width.
-                mitterLimit = leis.readFloat();
-
-                // A 32-bit floating-point value that specifies the amount by which to scale the custom line cap with
-                // respect to the width of the EmfPlusPen object that is used to draw the lines.
-                widthScale = leis.readFloat();
-
-                int size = 8* LittleEndianConsts.INT_SIZE;
-
-                // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
-                size += readPointF(leis, fillHotSpot);
-                size += readPointF(leis, lineHotSpot);
-
-                if (FILL_PATH.isSet(dataFlags)) {
-                    fillPath = new EmfPlusPath();
-                    size += fillPath.init(leis, -1, null, -1);
+                @Override
+                public float[] getLineDashes() {
+                    return dashedLineData;
                 }
 
-                if (LINE_PATH.isSet(dataFlags)) {
-                    outlinePath = new EmfPlusPath();
-                    size += outlinePath.init(leis, -1, null, -1);
+                @Override
+                public boolean isAlternateDash() {
+                    return (getLineDash() != HwmfLineDash.SOLID && dashOffset != null && dashOffset == 0);
                 }
 
-                return size;
-            }
+                @Override
+                public boolean isGeometric() {
+                    return (unitType == EmfPlusUnitType.World || unitType == EmfPlusUnitType.Display);
+                }
+            });
         }
+    }
 
-        public static class EmfPlusAdjustableArrowCap implements EmfPlusCustomLineCap {
-            private double width;
-            private double height;
-            private double middleInset;
-            private boolean isFilled;
-            private EmfPlusLineCapType startCap;
-            private EmfPlusLineCapType endCap;
-            private EmfPlusLineJoin join;
-            private double mitterLimit;
-            private double widthScale;
-            private final Point2D fillHotSpot = new Point2D.Double();
-            private final Point2D lineHotSpot = new Point2D.Double();
-
-            @Override
-            public long init(LittleEndianInputStream leis) throws IOException {
-                // A 32-bit floating-point value that specifies the width of the arrow cap.
-                // The width of the arrow cap is scaled by the width of the EmfPlusPen object that is used to draw the
-                // line being capped. For example, when drawing a capped line with a pen that has a width of 5 pixels,
-                // and the adjustable arrow cap object has a width of 3, the actual arrow cap is drawn 15 pixels wide.
-                width = leis.readFloat();
-
-                // A 32-bit floating-point value that specifies the height of the arrow cap.
-                // The height of the arrow cap is scaled by the width of the EmfPlusPen object that is used to draw the
-                // line being capped. For example, when drawing a capped line with a pen that has a width of 5 pixels,
-                // and the adjustable arrow cap object has a height of 3, the actual arrow cap is drawn 15 pixels high.
-                height = leis.readFloat();
-
-                // A 32-bit floating-point value that specifies the number of pixels between the outline of the arrow
-                // cap and the fill of the arrow cap.
-                middleInset = leis.readFloat();
-
-                // A 32-bit Boolean value that specifies whether the arrow cap is filled.
-                // If the arrow cap is not filled, only the outline is drawn.
-                isFilled = (leis.readInt() != 0);
+    public static class EmfPlusPathArrowCap implements EmfPlusCustomLineCap {
+        /**
+         * If set, an EmfPlusFillPath object MUST be specified in the OptionalData field of the
+         * EmfPlusCustomLineCapData object for filling the custom line cap.
+         */
+        private static final BitField FILL_PATH = BitFieldFactory.getInstance(0x00000001);
+        /**
+         * If set, an EmfPlusLinePath object MUST be specified in the OptionalData field of the
+         * EmfPlusCustomLineCapData object for outlining the custom line cap.
+         */
+        private static final BitField LINE_PATH = BitFieldFactory.getInstance(0x00000002);
 
-                // A 32-bit unsigned integer that specifies the value in the LineCap enumeration that indicates
-                // the line cap to be used at the start/end of the line to be drawn.
-                startCap = EmfPlusLineCapType.valueOf(leis.readInt());
-                endCap = EmfPlusLineCapType.valueOf(leis.readInt());
 
-                // 32-bit unsigned integer that specifies the value in the LineJoin enumeration that specifies how to
-                // join two lines that are drawn by the same pen and whose ends meet. At the intersection of the two
-                // line ends, a line join makes the connection look more continuous.
-                join = EmfPlusLineJoin.valueOf(leis.readInt());
+        private int dataFlags;
+        private EmfPlusLineCapType baseCap;
+        private double baseInset;
+        private EmfPlusLineCapType startCap;
+        private EmfPlusLineCapType endCap;
+        private EmfPlusLineJoin join;
+        private double mitterLimit;
+        private double widthScale;
+        private final Point2D fillHotSpot = new Point2D.Double();
+        private final Point2D lineHotSpot = new Point2D.Double();
+        private EmfPlusPath fillPath;
+        private EmfPlusPath outlinePath;
+
+        @Override
+        public long init(LittleEndianInputStream leis) throws IOException {
+            // A 32-bit unsigned integer that specifies the data in the OptionalData field.
+            // This value MUST be composed of CustomLineCapData flags
+            dataFlags = leis.readInt();
 
-                // A 32-bit floating-point value that specifies the limit of the thickness of the join on a mitered
-                // corner by setting the maximum allowed ratio of miter length to line width.
-                mitterLimit = leis.readFloat();
+            // A 32-bit unsigned integer that specifies the value from the LineCap enumeration on which
+            // the custom line cap is based.
+            baseCap = EmfPlusLineCapType.valueOf(leis.readInt());
 
-                // A 32-bit floating-point value that specifies the amount by which to scale an EmfPlusCustomLineCap
-                // object with respect to the width of the graphics pen that is used to draw the lines.
-                widthScale = leis.readFloat();
+            // A 32-bit floating-point value that specifies the distance between the
+            // beginning of the line cap and the end of the line.
+            baseInset = leis.readFloat();
 
-                int size = 9 * LittleEndianConsts.INT_SIZE;
+            // A 32-bit unsigned integer that specifies the value in the LineCap enumeration that indicates the line
+            // cap used at the start/end of the line to be drawn.
+            startCap = EmfPlusLineCapType.valueOf(leis.readInt());
+            endCap = EmfPlusLineCapType.valueOf(leis.readInt());
 
-                // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
-                size += readPointF(leis, fillHotSpot);
+            // A 32-bit unsigned integer that specifies the value in the LineJoin enumeration, which specifies how
+            // to join two lines that are drawn by the same pen and whose ends meet. At the intersection of the two
+            // line ends, a line join makes the connection look more continuous.
+            join = EmfPlusLineJoin.valueOf(leis.readInt());
 
-                // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
-                size += readPointF(leis, lineHotSpot);
+            // A 32-bit floating-point value that contains the limit of the thickness of the join on a mitered corner
+            // by setting the maximum allowed ratio of miter length to line width.
+            mitterLimit = leis.readFloat();
 
-                return size;
+            // A 32-bit floating-point value that specifies the amount by which to scale the custom line cap with
+            // respect to the width of the EmfPlusPen object that is used to draw the lines.
+            widthScale = leis.readFloat();
+
+            int size = 8* LittleEndianConsts.INT_SIZE;
+
+            // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
+            size += readPointF(leis, fillHotSpot);
+            size += readPointF(leis, lineHotSpot);
+
+            if (FILL_PATH.isSet(dataFlags)) {
+                fillPath = new EmfPlusPath();
+                size += fillPath.init(leis, -1, null, -1);
             }
+
+            if (LINE_PATH.isSet(dataFlags)) {
+                outlinePath = new EmfPlusPath();
+                size += outlinePath.init(leis, -1, null, -1);
+            }
+
+            return size;
         }
+    }
+
+    public static class EmfPlusAdjustableArrowCap implements EmfPlusCustomLineCap {
+        private double width;
+        private double height;
+        private double middleInset;
+        private boolean isFilled;
+        private EmfPlusLineCapType startCap;
+        private EmfPlusLineCapType endCap;
+        private EmfPlusLineJoin join;
+        private double mitterLimit;
+        private double widthScale;
+        private final Point2D fillHotSpot = new Point2D.Double();
+        private final Point2D lineHotSpot = new Point2D.Double();
+
+        @Override
+        public long init(LittleEndianInputStream leis) throws IOException {
+            // A 32-bit floating-point value that specifies the width of the arrow cap.
+            // The width of the arrow cap is scaled by the width of the EmfPlusPen object that is used to draw the
+            // line being capped. For example, when drawing a capped line with a pen that has a width of 5 pixels,
+            // and the adjustable arrow cap object has a width of 3, the actual arrow cap is drawn 15 pixels wide.
+            width = leis.readFloat();
+
+            // A 32-bit floating-point value that specifies the height of the arrow cap.
+            // The height of the arrow cap is scaled by the width of the EmfPlusPen object that is used to draw the
+            // line being capped. For example, when drawing a capped line with a pen that has a width of 5 pixels,
+            // and the adjustable arrow cap object has a height of 3, the actual arrow cap is drawn 15 pixels high.
+            height = leis.readFloat();
+
+            // A 32-bit floating-point value that specifies the number of pixels between the outline of the arrow
+            // cap and the fill of the arrow cap.
+            middleInset = leis.readFloat();
+
+            // A 32-bit Boolean value that specifies whether the arrow cap is filled.
+            // If the arrow cap is not filled, only the outline is drawn.
+            isFilled = (leis.readInt() != 0);
+
+            // A 32-bit unsigned integer that specifies the value in the LineCap enumeration that indicates
+            // the line cap to be used at the start/end of the line to be drawn.
+            startCap = EmfPlusLineCapType.valueOf(leis.readInt());
+            endCap = EmfPlusLineCapType.valueOf(leis.readInt());
+
+            // 32-bit unsigned integer that specifies the value in the LineJoin enumeration that specifies how to
+            // join two lines that are drawn by the same pen and whose ends meet. At the intersection of the two
+            // line ends, a line join makes the connection look more continuous.
+            join = EmfPlusLineJoin.valueOf(leis.readInt());
+
+            // A 32-bit floating-point value that specifies the limit of the thickness of the join on a mitered
+            // corner by setting the maximum allowed ratio of miter length to line width.
+            mitterLimit = leis.readFloat();
+
+            // A 32-bit floating-point value that specifies the amount by which to scale an EmfPlusCustomLineCap
+            // object with respect to the width of the graphics pen that is used to draw the lines.
+            widthScale = leis.readFloat();
 
+            int size = 9 * LittleEndianConsts.INT_SIZE;
+
+            // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
+            size += readPointF(leis, fillHotSpot);
+
+            // An EmfPlusPointF object that is not currently used. It MUST be set to {0.0, 0.0}.
+            size += readPointF(leis, lineHotSpot);
+
+            return size;
+        }
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java Thu Jun  6 22:32:41 2019
@@ -20,7 +20,7 @@ package org.apache.poi.hemf.record.emfpl
 
 import java.io.IOException;
 
-import org.apache.poi.hemf.record.emf.HemfRecordType;
+import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -45,4 +45,13 @@ public interface HemfPlusRecord {
      */
     long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException;
 
+
+
+    /**
+     * Draws the record, the default redirects to the parent WMF record drawing
+     * @param ctx the drawing context
+     */
+    default void draw(HemfGraphics ctx) {
+    }
+
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java Thu Jun  6 22:32:41 2019
@@ -21,9 +21,11 @@ import static org.apache.poi.hemf.record
 
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
+import java.util.List;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
+import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
 import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
 import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
@@ -92,12 +94,12 @@ public class HemfPlusRegion {
 
     public static class EmfPlusRegion implements EmfPlusObjectData {
 
-        private final EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
+        private final EmfPlusGraphicsVersion graphicsVersion = new EmfPlusGraphicsVersion();
         private EmfPlusRegionNodeData regionNode;
 
         @Override
         public long init(LittleEndianInputStream leis, long dataSize, EmfPlusObjectType objectType, int flags) throws IOException {
-            long size = version.init(leis);
+            long size = graphicsVersion.init(leis);
 
             // A 32-bit unsigned integer that specifies the number of child nodes in the RegionNode field.
             int nodeCount = leis.readInt();
@@ -111,7 +113,15 @@ public class HemfPlusRegion {
             return size;
         }
 
+        @Override
+        public void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData) {
+
+        }
 
+        @Override
+        public EmfPlusGraphicsVersion getGraphicsVersion() {
+            return graphicsVersion;
+        }
     }
 
 

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfEmbeddedIterator.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfEmbeddedIterator.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfEmbeddedIterator.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfEmbeddedIterator.java Thu Jun  6 22:32:41 2019
@@ -267,36 +267,7 @@ public class HemfEmbeddedIterator implem
      * Compress GDIs internal format to something useful
      */
     private void compressGDIBitmap(EmfPlusImage img, HwmfEmbedded emb, HwmfEmbeddedType et) {
-        final int width = img.getBitmapWidth();
-        final int height = img.getBitmapHeight();
-        final int stride = img.getBitmapStride();
-        final EmfPlusPixelFormat pf = img.getPixelFormat();
-
-        int[] nBits, bOffs;
-        switch (pf) {
-            case ARGB_32BPP:
-                nBits = new int[]{8, 8, 8, 8};
-                bOffs = new int[]{2, 1, 0, 3};
-                break;
-            case RGB_24BPP:
-                nBits = new int[]{8, 8, 8};
-                bOffs = new int[]{2, 1, 0};
-                break;
-            default:
-                throw new RuntimeException("not yet implemented");
-        }
-
-        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
-        ComponentColorModel cm = new ComponentColorModel
-                (cs, nBits, pf.isAlpha(), pf.isPreMultiplied(), Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
-        PixelInterleavedSampleModel csm =
-                new PixelInterleavedSampleModel(cm.getTransferType(), width, height, cm.getNumColorComponents(), stride, bOffs);
-
-        byte d[] = emb.getRawData();
-        WritableRaster raster = (WritableRaster) Raster.createRaster(csm, new DataBufferByte(d, d.length), null);
-
-        BufferedImage bi = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
-
+        BufferedImage bi = img.readGDIImage(emb.getRawData());
         try {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
             // use HwmfEmbeddedType literal for conversion

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java Thu Jun  6 22:32:41 2019
@@ -46,7 +46,6 @@ import org.apache.poi.util.Units;
  */
 @Internal
 public class HemfPicture implements Iterable<HemfRecord> {
-
     private final LittleEndianInputStream stream;
     private final List<HemfRecord> records = new ArrayList<>();
     private boolean isParsed = false;
@@ -96,32 +95,52 @@ public class HemfPicture implements Iter
     }
 
     /**
-     * Return the image size in points
+     * Returns the bounding box in device-independent units. Usually this is taken from the placeable header.
      *
-     * @return the image size in points
+     * @return the bounding box
      */
-    public Dimension2D getSize() {
+    public Rectangle2D getBounds() {
         HemfHeader header = (HemfHeader)getRecords().get(0);
-        final double coeff = (double) Units.EMU_PER_CENTIMETER / Units.EMU_PER_POINT / 10.;
         Rectangle2D dim = header.getFrameRectangle();
+        double x = dim.getX(), y = dim.getY();
         double width = dim.getWidth(), height = dim.getHeight();
-        if (dim.isEmpty() || Math.rint(width*coeff) == 0 || Math.rint(height*coeff) == 0) {
+        if (dim.isEmpty() || Math.rint(width) == 0 || Math.rint(height) == 0) {
             for (HemfRecord r : getRecords()) {
                 if (r instanceof HemfWindowing.EmfSetWindowExtEx) {
-                    Dimension2D d = ((HemfWindowing.EmfSetWindowExtEx)r).getSize();
+                    HemfWindowing.EmfSetWindowExtEx extEx = (HemfWindowing.EmfSetWindowExtEx)r;
+                    Dimension2D d = extEx.getSize();
                     width = d.getWidth();
                     height = d.getHeight();
                     // keep searching - sometimes there's another record
                 }
+                if (r instanceof HemfWindowing.EmfSetWindowOrgEx) {
+                    HemfWindowing.EmfSetWindowOrgEx orgEx = (HemfWindowing.EmfSetWindowOrgEx)r;
+                    x = orgEx.getX();
+                    y = orgEx.getY();
+                }
             }
         }
 
-        if (Math.rint(width*coeff) == 0 || Math.rint(height*coeff) == 0) {
-            width = 100;
-            height = 100;
+        return new Rectangle2D.Double(x, y, width, height);
+    }
+
+    /**
+     * Return the image size in points
+     *
+     * @return the image size in points
+     */
+    public Dimension2D getSize() {
+        final Rectangle2D bounds = getBounds();
+
+        if (bounds.isEmpty()) {
+            return new Dimension2DDouble(100,100);
         }
 
-        return new Dimension2DDouble(Math.abs(width*coeff), Math.abs(height*coeff));
+        final double coeff = (double) Units.EMU_PER_CENTIMETER / Units.EMU_PER_POINT / 10.;
+        double width = Math.abs(bounds.getWidth()*coeff);
+        double height = Math.abs(bounds.getHeight()*coeff);
+
+        return new Dimension2DDouble(width, height);
     }
 
     private static double minX(Rectangle2D bounds) {

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java Thu Jun  6 22:32:41 2019
@@ -17,8 +17,10 @@
 
 package org.apache.poi.hwmf.draw;
 
+import java.awt.AlphaComposite;
 import java.awt.BasicStroke;
 import java.awt.Color;
+import java.awt.Composite;
 import java.awt.Graphics2D;
 import java.awt.GraphicsConfiguration;
 import java.awt.Paint;
@@ -132,6 +134,9 @@ public class HwmfGraphics {
 
     public void fill(Shape shape) {
         HwmfDrawProperties prop = getProperties();
+
+        Composite old = graphicsCtx.getComposite();
+        graphicsCtx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
         if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
             if (prop.getBkMode() == HwmfBkMode.OPAQUE) {
                 graphicsCtx.setPaint(prop.getBackgroundColor().getColor());
@@ -141,20 +146,22 @@ public class HwmfGraphics {
             graphicsCtx.setPaint(getFill());
             graphicsCtx.fill(shape);
         }
+        graphicsCtx.setComposite(old);
 
         draw(shape);
     }
 
     protected BasicStroke getStroke() {
+        HwmfDrawProperties prop = getProperties();
+        HwmfPenStyle ps = prop.getPenStyle();
         // TODO: fix line width calculation
-        float width = (float)getProperties().getPenWidth();
+        float width = (float)prop.getPenWidth();
         if (width == 0) {
             width = 1;
         }
-        HwmfPenStyle ps = getProperties().getPenStyle();
         int cap = ps.getLineCap().awtFlag;
         int join = ps.getLineJoin().awtFlag;
-        float miterLimit = (float)getProperties().getPenMiterLimit();
+        float miterLimit = (float)prop.getPenMiterLimit();
         float[] dashes = ps.getLineDashes();
         boolean dashAlt = ps.isAlternateDash();
         // This value is not an integer index into the dash pattern array.
@@ -602,7 +609,14 @@ public class HwmfGraphics {
                 graphicsCtx.scale(dstBounds.getWidth()/srcBounds2.getWidth(), dstBounds.getHeight()/srcBounds2.getHeight());
                 graphicsCtx.translate(-srcBounds2.getX(), -srcBounds2.getY());
 
-                graphicsCtx.drawImage(img, 0, 0, prop.getBackgroundColor().getColor(), null);
+                if (prop.getBkMode() == HwmfBkMode.OPAQUE) {
+                    graphicsCtx.drawImage(img, 0, 0, prop.getBackgroundColor().getColor(), null);
+                } else {
+                    Composite old = graphicsCtx.getComposite();
+                    graphicsCtx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+                    graphicsCtx.drawImage(img, 0, 0, null);
+                    graphicsCtx.setComposite(old);
+                }
 
                 graphicsCtx.setTransform(at);
                 graphicsCtx.setClip(clip);

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java Thu Jun  6 22:32:41 2019
@@ -18,6 +18,7 @@
 package org.apache.poi.hwmf.record;
 
 import java.awt.Shape;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
 import java.awt.geom.Dimension2D;
@@ -749,17 +750,17 @@ public class HwmfDraw {
 
     @Internal
     public static String pointToString(Point2D point) {
-        return "{ x: "+point.getX()+", y: "+point.getY()+" }";
+        return (point == null) ? "null" : "{ x: "+point.getX()+", y: "+point.getY()+" }";
     }
 
     @Internal
     public static String boundsToString(Rectangle2D bounds) {
-        return "{ x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
+        return (bounds == null) ? "null" : "{ x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
     }
 
     @Internal
     public static String dimToString(Dimension2D dim) {
-        return "{ w: "+dim.getWidth()+", h: "+dim.getHeight()+" }";
+        return (dim == null) ? "null" : "{ w: "+dim.getWidth()+", h: "+dim.getHeight()+" }";
     }
 
     @Internal
@@ -772,5 +773,4 @@ public class HwmfDraw {
                 Math.abs(bounds.getHeight())
         );
     }
-
 }

Modified: poi/trunk/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java?rev=1860732&r1=1860731&r2=1860732&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java (original)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java Thu Jun  6 22:32:41 2019
@@ -24,22 +24,14 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertTrue;
 
 import java.awt.geom.Point2D;
-import java.io.BufferedWriter;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Stream;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hemf.record.emf.HemfComment;
@@ -64,11 +56,10 @@ public class HemfPictureTest {
     private static final POIDataSamples ss_samples = POIDataSamples.getSpreadSheetInstance();
     private static final POIDataSamples sl_samples = POIDataSamples.getSlideShowInstance();
 
-    /*
-    @Test
+/*    @Test
     @Ignore("Only for manual tests - need to add org.tukaani:xz:1.8 for this to work")
     public void paint() throws IOException {
-        byte buf[] = new byte[50_000_000];
+        final byte buf[] = new byte[50_000_000];
 
         // good test samples to validate rendering:
         // emfs/commoncrawl2/NB/NBWN2YH5VFCLZRFDQU7PB7IDD4UKY7DN_2.emf
@@ -78,15 +69,16 @@ public class HemfPictureTest {
 
         final boolean writeLog = false;
         final boolean dumpRecords = false;
-        final boolean savePng = false;
-        final boolean dumpEmbedded = true;
+        final boolean savePng = true;
+        final boolean dumpEmbedded = false;
 
         Set<String> passed = new HashSet<>();
 
-        try (BufferedWriter sucWrite = parseEmfLog(passed, "emf-success.txt");
-             BufferedWriter parseError = parseEmfLog(passed, "emf-parse.txt");
-             BufferedWriter renderError = parseEmfLog(passed, "emf-render.txt");
-             SevenZFile sevenZFile = new SevenZFile(new File("tmp/plus_emf.7z"))) {
+        try (BufferedWriter sucWrite = parseEmfLog(passed, "emf-success.txt")
+            ;BufferedWriter parseError = parseEmfLog(passed, "emf-parse.txt")
+            ;BufferedWriter renderError = parseEmfLog(passed, "emf-render.txt")
+            ;SevenZFile sevenZFile = new SevenZFile(new File("tmp/plus_emf.7z"))
+            ) {
             for (int idx=0;;idx++) {
                 SevenZArchiveEntry entry = sevenZFile.getNextEntry();
                 if (entry == null) break;
@@ -94,10 +86,14 @@ public class HemfPictureTest {
 
                 if (entry.isDirectory() || !etName.endsWith(".emf") || passed.contains(etName)) continue;
 
-                // if (!etName.equals("emfs/commoncrawl2/2S/2SYMYPLNJURGCXJKLNZCJQGIBHVMQTRS_0.emf")) continue;
 
-                // emfs/commoncrawl2/ZJ/ZJT2BZPLQR7DKSKYLYL6GRDEUM2KIO5F_4.emf
-                // emfs/govdocs1/005/005203.ppt_3.emf
+                // KEEDHN6XES4EKK52E3AJHKCARNTQF7PO_0.emf takes ages, time is spent while drawing paths
+//                if (!etName.contains("KEEDHN6XES4EKK52E3AJHKCARNTQF7PO_0.emf")) continue;
+
+                // F7GK5XOLERFURVTQALOCX3GJ6FH45LNQ strange colors
+                // ISS3ANIX2PL4PXR7SZSJSPBZI7YQQE3U stroke wrong
+//                if (!etName.contains("ISS3ANIX2PL4PXR7SZSJSPBZI7YQQE3U")) continue;
+
 
                 System.out.println(etName);
 
@@ -129,9 +125,9 @@ public class HemfPictureTest {
                     int embIdx = 0;
                     for (HwmfEmbedded emb : emf.getEmbeddings()) {
                         final File embName = new File("build/tmp", "emb_"+etName.replaceFirst(".+/", "").replace(".emf", "_"+embIdx + emb.getEmbeddedType().extension) );
-//                        try (FileOutputStream fos = new FileOutputStream(embName)) {
-//                            fos.write(emb.getRawData());
-//                        }
+                        try (FileOutputStream fos = new FileOutputStream(embName)) {
+                            fos.write(emb.getRawData());
+                        }
                         embIdx++;
                     }
                 }
@@ -154,17 +150,19 @@ public class HemfPictureTest {
                     BufferedImage bufImg = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB);
                     g = bufImg.createGraphics();
                     g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-                    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-                    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+                    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
+                    g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
+                    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
                     g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
 
                     g.setComposite(AlphaComposite.Clear);
                     g.fillRect(0, 0, (int)width, (int)height);
                     g.setComposite(AlphaComposite.Src);
 
+                    final File pngName = new File("build/tmp", etName.replaceFirst(".+/", "").replace(".emf", ".png"));
+
                     emf.draw(g, new Rectangle2D.Double(0, 0, width, height));
 
-                    final File pngName = new File("build/tmp", etName.replaceFirst(".+/", "").replace(".emf", ".png"));
                     if (savePng) {
                         ImageIO.write(bufImg, "PNG", pngName);
                     }
@@ -186,7 +184,7 @@ public class HemfPictureTest {
                 }
             }
         }
-    } */
+    }
 
     private static int hashException(Throwable e) {
         StringBuilder sb = new StringBuilder();
@@ -222,7 +220,7 @@ public class HemfPictureTest {
         }
 
         return Files.newBufferedWriter(log, StandardCharsets.UTF_8, soo);
-    }
+    }*/
 
     @Test
     public void testBasicWindows() throws Exception {



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org