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/05/12 19:50:04 UTC
svn commit: r1859159 [2/2] - in /poi/trunk/src/scratchpad:
src/org/apache/poi/hemf/record/emfplus/ src/org/apache/poi/hemf/usermodel/
testcases/org/apache/poi/hemf/usermodel/
Added: 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=1859159&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java Sun May 12 19:50:04 2019
@@ -0,0 +1,602 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hemf.record.emfplus;
+
+import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
+import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readPointF;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.util.function.Consumer;
+
+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.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfPlusPen {
+ /**
+ * The LineCapType enumeration defines types of line caps to use at the ends of lines that are drawn
+ * with graphics pens.
+ */
+ public enum EmfPlusLineCapType {
+ /** Specifies a squared-off line cap. The end of the line MUST be the last point in the line. */
+ FLAT(0X00000000),
+ /**
+ * Specifies a square line cap. The center of the square MUST be located at
+ * the last point in the line. The width of the square is the line width.
+ */
+ SQUARE(0X00000001),
+ /**
+ * Specifies a circular line cap. The center of the circle MUST be located at
+ * the last point in the line. The diameter of the circle is the line width.
+ */
+ ROUND(0X00000002),
+ /**
+ * Specifies a triangular line cap. The base of the triangle MUST be located
+ * at the last point in the line. The base of the triangle is the line width.
+ */
+ TRIANGLE(0X00000003),
+ /** Specifies that the line end is not anchored. */
+ NO_ANCHOR(0X00000010),
+ /**
+ * Specifies that the line end is anchored with a square line cap. The center of the square MUST be located
+ * at the last point in the line. The height and width of the square are the line width.
+ */
+ SQUARE_ANCHOR(0X00000011),
+ /**
+ * Specifies that the line end is anchored with a circular line cap. The center of the circle MUST be located
+ * at the last point in the line. The circle SHOULD be wider than the line.
+ */
+ ROUND_ANCHOR(0X00000012),
+ /**
+ * Specifies that the line end is anchored with a diamond-shaped line cap, which is a square turned at
+ * 45 degrees. The center of the diamond MUST be located at the last point in the line.
+ * The diamond SHOULD be wider than the line.
+ */
+ DIAMOND_ANCHOR(0X00000013),
+ /**
+ * Specifies that the line end is anchored with an arrowhead shape. The arrowhead point MUST be located at
+ * the last point in the line. The arrowhead SHOULD be wider than the line.
+ */
+ ARROW_ANCHOR(0X00000014),
+ /** Mask used to check whether a line cap is an anchor cap. */
+ ANCHOR_MASK(0X000000F0),
+ /** Specifies a custom line cap. */
+ CUSTOM(0X000000FF)
+ ;
+
+ public final int id;
+
+ EmfPlusLineCapType(int id) {
+ this.id = id;
+ }
+
+ public static EmfPlusLineCapType valueOf(int id) {
+ for (EmfPlusLineCapType wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * The LineJoinType enumeration defines ways to join two lines that are drawn by the same graphics
+ * pen and whose ends meet.
+ */
+ public enum EmfPlusLineJoin {
+ MITER(0X00000000),
+ BEVEL(0X00000001),
+ ROUND(0X00000002),
+ MITER_CLIPPED(0X00000003)
+ ;
+
+ public final int id;
+
+ EmfPlusLineJoin(int id) {
+ this.id = id;
+ }
+
+ public static EmfPlusLineJoin valueOf(int id) {
+ for (EmfPlusLineJoin wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+
+ }
+
+ /** The LineStyle enumeration defines styles of lines that are drawn with graphics pens. */
+ public enum EmfPlusLineStyle {
+ /** Specifies a solid line. */
+ SOLID(0X00000000),
+ /** Specifies a dashed line. */
+ DASH(0X00000001),
+ /** Specifies a dotted line. */
+ DOT(0X00000002),
+ /** Specifies an alternating dash-dot line. */
+ DASH_DOT(0X00000003),
+ /** Specifies an alternating dash-dot-dot line. */
+ DASH_DOT_DOT(0X00000004),
+ /** Specifies a user-defined, custom dashed line. */
+ CUSTOM(0X00000005)
+ ;
+
+ public final int id;
+
+ EmfPlusLineStyle(int id) {
+ this.id = id;
+ }
+
+ public static EmfPlusLineStyle valueOf(int id) {
+ for (EmfPlusLineStyle wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * The DashedLineCapType enumeration defines types of line caps to use at the ends of dashed lines
+ * that are drawn with graphics pens.
+ */
+ public enum EmfPlusDashedLineCapType {
+ /** Specifies a flat dashed line cap. */
+ FLAT(0X00000000),
+ /** Specifies a round dashed line cap. */
+ ROUND(0X00000002),
+ /** Specifies a triangular dashed line cap. */
+ TRIANGLE(0X00000003)
+ ;
+
+ public final int id;
+
+ EmfPlusDashedLineCapType(int id) {
+ this.id = id;
+ }
+
+ public static EmfPlusDashedLineCapType valueOf(int id) {
+ for (EmfPlusDashedLineCapType wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * The PenAlignment enumeration defines the distribution of the width of the pen with respect to the
+ * line being drawn.
+ */
+ public enum EmfPlusPenAlignment {
+ /** Specifies that the EmfPlusPen object is centered over the theoretical line. */
+ CENTER(0X00000000),
+ /** Specifies that the pen is positioned on the inside of the theoretical line. */
+ INSET(0X00000001),
+ /** Specifies that the pen is positioned to the left of the theoretical line. */
+ LEFT(0X00000002),
+ /** Specifies that the pen is positioned on the outside of the theoretical line. */
+ OUTSET(0X00000003),
+ /** Specifies that the pen is positioned to the right of the theoretical line. */
+ RIGHT(0X00000004)
+ ;
+
+ public final int id;
+
+ EmfPlusPenAlignment(int id) {
+ this.id = id;
+ }
+
+ public static EmfPlusPenAlignment valueOf(int id) {
+ for (EmfPlusPenAlignment wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+ }
+
+ public static class EmfPlusPen implements EmfPlusObjectData {
+
+
+ /**
+ * If set, a 2x3 transform matrix MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField TRANSFORM = BitFieldFactory.getInstance(0x00000001);
+ /**
+ * If set, the style of a starting line cap MUST be specified in the OptionalData field of an
+ * EmfPlusPenData object.
+ */
+ private final static BitField START_CAP = BitFieldFactory.getInstance(0x00000002);
+ /**
+ * Indicates whether the style of an ending line cap MUST be specified in the OptionalData field
+ * of an EmfPlusPenData object.
+ */
+ private final static BitField END_CAP = BitFieldFactory.getInstance(0x00000004);
+ /**
+ * Indicates whether a line join type MUST be specified in the OptionalData
+ * field of an EmfPlusPenData object.
+ */
+ private final static BitField JOIN = BitFieldFactory.getInstance(0x00000008);
+ /**
+ * Indicates whether a miter limit MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField MITER_LIMIT = BitFieldFactory.getInstance(0x00000010);
+ /**
+ * Indicates whether a line style MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField LINE_STYLE = BitFieldFactory.getInstance(0x00000020);
+ /**
+ * Indicates whether a dashed line cap MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField DASHED_LINE_CAP = BitFieldFactory.getInstance(0x00000040);
+ /**
+ * Indicates whether a dashed line offset MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField DASHED_LINE_OFFSET = BitFieldFactory.getInstance(0x00000080);
+ /**
+ * Indicates whether an EmfPlusDashedLineData object MUST be specified in the
+ * OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField DASHED_LINE = BitFieldFactory.getInstance(0x00000100);
+ /**
+ * Indicates whether a pen alignment MUST be specified in the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField NON_CENTER = BitFieldFactory.getInstance(0x00000200);
+ /**
+ * Indicates whether the length and content of a EmfPlusCompoundLineData object are present in the
+ * OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField COMPOUND_LINE = BitFieldFactory.getInstance(0x00000400);
+ /**
+ * Indicates whether an EmfPlusCustomStartCapData object MUST be specified
+ * in the OptionalData field of an EmfPlusPenData object.y
+ */
+ private final static BitField CUSTOM_START_CAP = BitFieldFactory.getInstance(0x00000800);
+ /**
+ * Indicates whether an EmfPlusCustomEndCapData object MUST be specified in
+ * the OptionalData field of an EmfPlusPenData object.
+ */
+ private final static BitField CUSTOM_END_CAP = BitFieldFactory.getInstance(0x00001000);
+
+ private final EmfPlusGraphicsVersion graphicsVersion = new EmfPlusGraphicsVersion();
+
+
+ private int type;
+ private int penDataFlags;
+ private HemfPlusDraw.EmfPlusUnitType unitType;
+ private double penWidth;
+ private AffineTransform trans;
+ private EmfPlusLineCapType startCap, endCap;
+ private EmfPlusLineJoin join;
+ private Double mitterLimit;
+ private EmfPlusLineStyle style;
+ EmfPlusDashedLineCapType dashedLineCapType;
+ private Double dashOffset;
+ private double[] dashedLineData;
+ private EmfPlusPenAlignment penAlignment;
+ private double[] compoundLineData;
+ private EmfPlusCustomLineCap customStartCap;
+ private EmfPlusCustomLineCap customEndCap;
+
+ @Override
+ public long init(LittleEndianInputStream leis, long dataSize, EmfPlusObjectType objectType, int flags) throws IOException {
+ // An EmfPlusGraphicsVersion object that specifies the version of operating system graphics that
+ // was used to create this object.
+ long size = graphicsVersion.init(leis);
+ // This field MUST be set to zero.
+ type = leis.readInt();
+ // A 32-bit unsigned integer that specifies the data in the OptionalData field.
+ // This value MUST be composed of PenData flags
+ 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());
+ // 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;
+
+ 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);
+ }
+
+ if (START_CAP.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies the shape for the start of a line in the
+ // CustomStartCapData field. This field MUST be present if the PenDataStartCap flag is set in the
+ // PenDataFlags field of the EmfPlusPenData object, and the value MUST be defined in the LineCapType enumeration
+ startCap = EmfPlusLineCapType.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (END_CAP.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies the shape for the end of a line in the
+ // CustomEndCapData field. This field MUST be present if the PenDataEndCap flag is set in the
+ // PenDataFlags field of the EmfPlusPenData object, and the value MUST be defined in the LineCapType enumeration.
+ endCap = EmfPlusLineCapType.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (JOIN.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies how to join two lines that are drawn by the same pen
+ // and whose ends meet. This field MUST be present if the PenDataJoin flag is set in the PenDataFlags
+ // field of the EmfPlusPenData object, and the value MUST be defined in the LineJoinType enumeration
+ join = EmfPlusLineJoin.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (MITER_LIMIT.isSet(penDataFlags)) {
+ // An optional 32-bit floating-point value that specifies the miter limit, which is the maximum allowed
+ // ratio of miter length to line width. The miter length is the distance from the intersection of the
+ // 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();
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (LINE_STYLE.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies the style used for lines drawn with this pen object.
+ // This field MUST be present if the PenDataLineStyle flag is set in the PenDataFlags field of the
+ // EmfPlusPenData object, and the value MUST be defined in the LineStyle enumeration
+ style = EmfPlusLineStyle.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (DASHED_LINE_CAP.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies the shape for both ends of each dash in a dashed line.
+ // This field MUST be present if the PenDataDashedLineCap flag is set in the PenDataFlags field of the
+ // EmfPlusPenData object, and the value MUST be defined in the DashedLineCapType enumeration
+ dashedLineCapType = EmfPlusDashedLineCapType.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (DASHED_LINE_OFFSET.isSet(penDataFlags)) {
+ // An optional 32-bit floating-point value that specifies the distance from the start of a line to the
+ // start of the first space in a dashed line pattern. This field MUST be present if the
+ // PenDataDashedLineOffset flag is set in the PenDataFlags field of the EmfPlusPenData object.
+ dashOffset = (double)leis.readFloat();
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (DASHED_LINE.isSet(penDataFlags)) {
+ // A 32-bit unsigned integer that specifies the number of elements in the DashedLineData field.
+ int dashesSize = leis.readInt();
+ if (dashesSize < 0 || dashesSize > 1000) {
+ throw new RuntimeException("Invalid dash data size");
+ }
+
+ // An array of DashedLineDataSize floating-point values that specify the lengths of the dashes and spaces in a dashed line.
+ dashedLineData = new double[dashesSize];
+ for (int i=0; i<dashesSize; i++) {
+ dashedLineData[i] = leis.readFloat();
+ }
+
+ size += LittleEndianConsts.INT_SIZE * (dashesSize+1);
+ }
+
+ if (NON_CENTER.isSet(penDataFlags)) {
+ // An optional 32-bit signed integer that specifies the distribution of the pen width with respect to
+ // the coordinates of the line being drawn. This field MUST be present if the PenDataNonCenter flag is
+ // set in the PenDataFlags field of the EmfPlusPenData object, and the value MUST be defined in the
+ // PenAlignment enumeration
+ penAlignment = EmfPlusPenAlignment.valueOf(leis.readInt());
+ size += LittleEndianConsts.INT_SIZE;
+ }
+
+ if (COMPOUND_LINE.isSet(penDataFlags)) {
+ // A 32-bit unsigned integer that specifies the number of elements in the CompoundLineData field.
+ int compoundSize = leis.readInt();
+ if (compoundSize < 0 || compoundSize > 1000) {
+ throw new RuntimeException("Invalid compound line data size");
+ }
+
+ // An array of CompoundLineDataSize floating-point values that specify the compound line of a pen.
+ // The elements MUST be in increasing order, and their values MUST be between 0.0 and 1.0, inclusive.
+ compoundLineData = new double[compoundSize];
+
+ for (int i=0; i<compoundSize; i++) {
+ compoundLineData[i] = leis.readFloat();
+ }
+ size += LittleEndianConsts.INT_SIZE * (compoundSize+1);
+ }
+
+ if (CUSTOM_START_CAP.isSet(penDataFlags)) {
+ size += initCustomCap(c -> customStartCap = c, leis);
+ }
+
+ if (CUSTOM_END_CAP.isSet(penDataFlags)) {
+ size += initCustomCap(c -> customEndCap = c, leis);
+ }
+
+ return size;
+ }
+
+ private long initCustomCap(Consumer<EmfPlusCustomLineCap> setter, LittleEndianInputStream leis) throws IOException {
+ EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
+ long size = version.init(leis);
+
+ boolean adjustableArrow = (leis.readInt() != 0);
+ size += LittleEndianConsts.INT_SIZE;
+
+ EmfPlusCustomLineCap cap = (adjustableArrow) ? new EmfPlusAdjustableArrowCap() : new EmfPlusPathArrowCap();
+ size += cap.init(leis);
+
+ setter.accept(cap);
+
+ 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();
+
+ // 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());
+
+ // 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());
+
+ // 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);
+ }
+
+ 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;
+ }
+ }
+
+ }
+}
Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusPen.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: 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=1859159&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java Sun May 12 19:50:04 2019
@@ -0,0 +1,173 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hemf.record.emfplus;
+
+import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readRectF;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+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.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfPlusRegion {
+ public enum EmfPlusRegionNodeDataType {
+ /**
+ * Specifies a region node with child nodes. A Boolean AND operation SHOULD be applied to the left and right
+ * child nodes specified by an EmfPlusRegionNodeChildNodes object
+ */
+ AND(0X00000001, EmfPlusRegionNode::new),
+ /**
+ * Specifies a region node with child nodes. A Boolean OR operation SHOULD be applied to the left and right
+ * child nodes specified by an EmfPlusRegionNodeChildNodes object.
+ */
+ OR(0X00000002, EmfPlusRegionNode::new),
+ /**
+ * Specifies a region node with child nodes. A Boolean XOR operation SHOULD be applied to the left and right
+ * child nodes specified by an EmfPlusRegionNodeChildNodes object.
+ */
+ XOR(0X00000003, EmfPlusRegionNode::new),
+ /**
+ * Specifies a region node with child nodes. A Boolean operation, defined as "the part of region 1 that is excluded
+ * from region 2", SHOULD be applied to the left and right child nodes specified by an EmfPlusRegionNodeChildNodes object.
+ */
+ EXCLUDE(0X00000004, EmfPlusRegionNode::new),
+ /**
+ * Specifies a region node with child nodes. A Boolean operation, defined as "the part of region 2 that is excluded
+ * from region 1", SHOULD be applied to the left and right child nodes specified by an EmfPlusRegionNodeChildNodes object.
+ */
+ COMPLEMENT(0X00000005, EmfPlusRegionNode::new),
+ /**
+ * Specifies a region node with no child nodes.
+ * The RegionNodeData field SHOULD specify a boundary with an EmfPlusRectF object.
+ */
+ RECT(0X10000000, EmfPlusRegionRect::new),
+ /**
+ * Specifies a region node with no child nodes.
+ * The RegionNodeData field SHOULD specify a boundary with an EmfPlusRegionNodePath object
+ */
+ PATH(0X10000001, EmfPlusRegionPath::new),
+ /** Specifies a region node with no child nodes. The RegionNodeData field SHOULD NOT be present. */
+ EMPTY(0X10000002, EmfPlusRegionEmpty::new),
+ /** Specifies a region node with no child nodes, and its bounds are not defined. */
+ INFINITE(0X10000003, EmfPlusRegionInfinite::new)
+ ;
+
+ public final int id;
+ public final Supplier<EmfPlusRegionNodeData> constructor;
+
+ EmfPlusRegionNodeDataType(int id, Supplier<EmfPlusRegionNodeData> constructor) {
+ this.id = id;
+ this.constructor = constructor;
+ }
+
+ public static EmfPlusRegionNodeDataType valueOf(int id) {
+ for (EmfPlusRegionNodeDataType wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+ }
+
+ public static class EmfPlusRegion implements EmfPlusObjectData {
+
+ private final EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
+ private EmfPlusRegionNodeData regionNode;
+
+ @Override
+ public long init(LittleEndianInputStream leis, long dataSize, EmfPlusObjectType objectType, int flags) throws IOException {
+ long size = version.init(leis);
+
+ // A 32-bit unsigned integer that specifies the number of child nodes in the RegionNode field.
+ int nodeCount = leis.readInt();
+ size += LittleEndianConsts.INT_SIZE;
+
+ // An array of RegionNodeCount+1 EmfPlusRegionNode objects. Regions are specified as a binary tree of
+ // region nodes, and each node MUST either be a terminal node or specify one or two child nodes.
+ // RegionNode MUST contain at least one element.
+ size += readNode(leis, d -> regionNode = d);
+
+ return size;
+ }
+
+
+ }
+
+
+ public interface EmfPlusRegionNodeData {
+ long init(LittleEndianInputStream leis) throws IOException;
+ }
+
+ public static class EmfPlusRegionPath extends EmfPlusPath implements EmfPlusRegionNodeData {
+ public long init(LittleEndianInputStream leis) throws IOException {
+ int dataSize = leis.readInt();
+ return super.init(leis, dataSize, EmfPlusObjectType.PATH, 0) + LittleEndianConsts.INT_SIZE;
+ }
+ }
+
+ public static class EmfPlusRegionInfinite implements EmfPlusRegionNodeData {
+ @Override
+ public long init(LittleEndianInputStream leis) throws IOException {
+ return 0;
+ }
+ }
+
+ public static class EmfPlusRegionEmpty implements EmfPlusRegionNodeData {
+ @Override
+ public long init(LittleEndianInputStream leis) throws IOException {
+ return 0;
+ }
+ }
+
+ public static class EmfPlusRegionRect implements EmfPlusRegionNodeData {
+ private final Rectangle2D rect = new Rectangle2D.Double();
+
+ @Override
+ public long init(LittleEndianInputStream leis) {
+ return readRectF(leis, rect);
+ }
+ }
+
+ public static class EmfPlusRegionNode implements EmfPlusRegionNodeData {
+ private EmfPlusRegionNodeData left, right;
+
+ @Override
+ public long init(LittleEndianInputStream leis) throws IOException {
+ long size = readNode(leis, n -> left = n);
+ size += readNode(leis, n -> right = n);
+ return size;
+ }
+ }
+
+
+ private static long readNode(LittleEndianInputStream leis, Consumer<EmfPlusRegionNodeData> con) throws IOException {
+ // A 32-bit unsigned integer that specifies the type of data in the RegionNodeData field.
+ // This value MUST be defined in the RegionNodeDataType enumeration
+ EmfPlusRegionNodeDataType type = EmfPlusRegionNodeDataType.valueOf(leis.readInt());
+ assert(type != null);
+ EmfPlusRegionNodeData nd = type.constructor.get();
+ con.accept(nd);
+ return LittleEndianConsts.INT_SIZE + nd.init(leis);
+ }
+}
Propchange: poi/trunk/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRegion.java
------------------------------------------------------------------------------
svn:eol-style = native
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=1859159&r1=1859158&r2=1859159&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 Sun May 12 19:50:04 2019
@@ -36,7 +36,11 @@ import javax.imageio.ImageIO;
import org.apache.poi.hemf.record.emf.HemfComment;
import org.apache.poi.hemf.record.emf.HemfRecord;
+import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusBitmapDataType;
+import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusImage;
+import org.apache.poi.hemf.record.emfplus.HemfPlusImage.EmfPlusPixelFormat;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject;
+import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObject;
import org.apache.poi.hwmf.record.HwmfBitmapDib;
import org.apache.poi.hwmf.record.HwmfFill;
import org.apache.poi.hwmf.usermodel.HwmfEmbedded;
@@ -105,7 +109,7 @@ public class HemfEmbeddedIterator implem
return true;
}
- if (obj instanceof HemfPlusObject.EmfPlusObject && ((HemfPlusObject.EmfPlusObject)obj).getObjectType() == HemfPlusObject.EmfPlusObjectType.IMAGE) {
+ if (obj instanceof EmfPlusObject && ((EmfPlusObject)obj).getObjectType() == HemfPlusObject.EmfPlusObjectType.IMAGE) {
current = obj;
return true;
}
@@ -196,13 +200,13 @@ public class HemfEmbeddedIterator implem
}
private HwmfEmbedded checkEmfPlusObject() {
- if (!(current instanceof HemfPlusObject.EmfPlusObject)) {
+ if (!(current instanceof EmfPlusObject)) {
return null;
}
- HemfPlusObject.EmfPlusObject epo = (HemfPlusObject.EmfPlusObject)current;
+ EmfPlusObject epo = (EmfPlusObject)current;
assert(epo.getObjectType() == HemfPlusObject.EmfPlusObjectType.IMAGE);
- HemfPlusObject.EmfPlusImage img = epo.getObjectData();
+ EmfPlusImage img = epo.getObjectData();
assert(img.getImageDataType() != null);
HwmfEmbedded emb = getEmfPlusImageData();
@@ -210,7 +214,7 @@ public class HemfEmbeddedIterator implem
HwmfEmbeddedType et;
switch (img.getImageDataType()) {
case BITMAP:
- if (img.getBitmapType() == HemfPlusObject.EmfPlusBitmapDataType.COMPRESSED) {
+ if (img.getBitmapType() == EmfPlusBitmapDataType.COMPRESSED) {
switch (FileMagic.valueOf(emb.getRawData())) {
case JPEG:
et = HwmfEmbeddedType.JPEG;
@@ -262,11 +266,11 @@ public class HemfEmbeddedIterator implem
/**
* Compress GDIs internal format to something useful
*/
- private void compressGDIBitmap(HemfPlusObject.EmfPlusImage img, HwmfEmbedded emb, HwmfEmbeddedType et) {
+ 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 HemfPlusObject.EmfPlusPixelFormat pf = img.getPixelFormat();
+ final EmfPlusPixelFormat pf = img.getPixelFormat();
int[] nBits, bOffs;
switch (pf) {
@@ -306,14 +310,14 @@ public class HemfEmbeddedIterator implem
private HwmfEmbedded getEmfPlusImageData() {
- HemfPlusObject.EmfPlusObject epo = (HemfPlusObject.EmfPlusObject)current;
+ EmfPlusObject epo = (EmfPlusObject)current;
assert(epo.getObjectType() == HemfPlusObject.EmfPlusObjectType.IMAGE);
final int objectId = epo.getObjectId();
HwmfEmbedded emb = new HwmfEmbedded();
- HemfPlusObject.EmfPlusImage img = (HemfPlusObject.EmfPlusImage)epo.getObjectData();
+ EmfPlusImage img = (EmfPlusImage)epo.getObjectData();
assert(img.getImageDataType() != null);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -324,10 +328,10 @@ public class HemfEmbeddedIterator implem
current = null;
//noinspection ConstantConditions
if (hasNext() &&
- (current instanceof HemfPlusObject.EmfPlusObject) &&
- ((epo = (HemfPlusObject.EmfPlusObject) current).getObjectId() == objectId)
+ (current instanceof EmfPlusObject) &&
+ ((epo = (EmfPlusObject) current).getObjectId() == objectId)
) {
- img = (HemfPlusObject.EmfPlusImage)epo.getObjectData();
+ img = (EmfPlusImage)epo.getObjectData();
} else {
return emb;
}
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=1859159&r1=1859158&r2=1859159&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 Sun May 12 19:50:04 2019
@@ -94,7 +94,7 @@ public class HemfPictureTest {
if (entry.isDirectory() || !etName.endsWith(".emf") || passed.contains(etName)) continue;
- if (!etName.equals("emfs/commoncrawl2/2S/2SYMYPLNJURGCXJKLNZCJQGIBHVMQTRS_0.emf")) continue;
+ // if (!etName.equals("emfs/commoncrawl2/2S/2SYMYPLNJURGCXJKLNZCJQGIBHVMQTRS_0.emf")) continue;
// emfs/commoncrawl2/ZJ/ZJT2BZPLQR7DKSKYLYL6GRDEUM2KIO5F_4.emf
// emfs/govdocs1/005/005203.ppt_3.emf
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org