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 2018/09/14 21:37:38 UTC
svn commit: r1840956 [1/5] - in /poi/branches/hemf/src:
java/org/apache/poi/util/ ooxml/java/org/apache/poi/xdgf/geom/
ooxml/java/org/apache/poi/xdgf/usermodel/
ooxml/java/org/apache/poi/xdgf/util/
scratchpad/src/org/apache/poi/hemf/draw/ scratchpad/sr...
Author: kiwiwings
Date: Fri Sep 14 21:37:37 2018
New Revision: 1840956
URL: http://svn.apache.org/viewvc?rev=1840956&view=rev
Log:
#60656 - Support export file that contains emf and render it correctly
Added:
poi/branches/hemf/src/java/org/apache/poi/util/Dimension2DDouble.java
- copied, changed from r1840955, poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/geom/Dimension2dDouble.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/UnimplementedHemfRecord.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusHeader.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusHeader.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecord.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordIterator.java (with props)
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusRecordType.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecordType.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emfplus/UnimplementedHemfPlusRecord.java
- copied, changed from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/UnimplementedHemfPlusRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/
- copied from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/extractor/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
- copied, changed from r1840385, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/extractor/HemfExtractor.java
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/
- copied from r1840955, poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/extractor/
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java
- copied, changed from r1840385, poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/extractor/HemfExtractorTest.java
Removed:
poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/geom/Dimension2dDouble.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/extractor/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/hemfplus/
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/AbstractHemfComment.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFSpool.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfExtractor.java
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/extractor/
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfExtractorTest.java
Modified:
poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFPage.java
poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/util/VsdxToPng.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecordType.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java
poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
Copied: poi/branches/hemf/src/java/org/apache/poi/util/Dimension2DDouble.java (from r1840955, poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/geom/Dimension2dDouble.java)
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/java/org/apache/poi/util/Dimension2DDouble.java?p2=poi/branches/hemf/src/java/org/apache/poi/util/Dimension2DDouble.java&p1=poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/geom/Dimension2dDouble.java&r1=1840955&r2=1840956&rev=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/geom/Dimension2dDouble.java (original)
+++ poi/branches/hemf/src/java/org/apache/poi/util/Dimension2DDouble.java Fri Sep 14 21:37:37 2018
@@ -15,21 +15,21 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.xdgf.geom;
+package org.apache.poi.util;
import java.awt.geom.Dimension2D;
-public class Dimension2dDouble extends Dimension2D {
+public class Dimension2DDouble extends Dimension2D {
double width;
double height;
- public Dimension2dDouble() {
+ public Dimension2DDouble() {
width = 0d;
height = 0d;
}
- public Dimension2dDouble(double width, double height) {
+ public Dimension2DDouble(double width, double height) {
this.width = width;
this.height = height;
}
@@ -52,8 +52,8 @@ public class Dimension2dDouble extends D
@Override
public boolean equals(Object obj) {
- if (obj instanceof Dimension2dDouble) {
- Dimension2dDouble other = (Dimension2dDouble) obj;
+ if (obj instanceof Dimension2DDouble) {
+ Dimension2DDouble other = (Dimension2DDouble) obj;
return width == other.width && height == other.height;
}
@@ -68,6 +68,6 @@ public class Dimension2dDouble extends D
@Override
public String toString() {
- return "Dimension2dDouble[" + width + ", " + height + "]";
+ return "Dimension2DDouble[" + width + ", " + height + "]";
}
}
Modified: poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFPage.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFPage.java?rev=1840956&r1=1840955&r2=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFPage.java (original)
+++ poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/usermodel/XDGFPage.java Fri Sep 14 21:37:37 2018
@@ -22,7 +22,7 @@ import java.awt.geom.Rectangle2D;
import org.apache.poi.ooxml.POIXMLException;
import org.apache.poi.util.Internal;
-import org.apache.poi.xdgf.geom.Dimension2dDouble;
+import org.apache.poi.util.Dimension2DDouble;
import com.microsoft.schemas.office.visio.x2012.main.PageType;
@@ -75,14 +75,14 @@ public class XDGFPage {
/**
* @return width/height of page
*/
- public Dimension2dDouble getPageSize() {
+ public Dimension2DDouble getPageSize() {
XDGFCell w = _pageSheet.getCell("PageWidth");
XDGFCell h = _pageSheet.getCell("PageHeight");
if (w == null || h == null)
throw new POIXMLException("Cannot determine page size");
- return new Dimension2dDouble(Double.parseDouble(w.getValue()),
+ return new Dimension2DDouble(Double.parseDouble(w.getValue()),
Double.parseDouble(h.getValue()));
}
@@ -109,7 +109,7 @@ public class XDGFPage {
* @return bounding box of page
*/
public Rectangle2D getBoundingBox() {
- Dimension2dDouble sz = getPageSize();
+ Dimension2DDouble sz = getPageSize();
Point2D.Double offset = getPageOffset();
return new Rectangle2D.Double(-offset.getX(), -offset.getY(),
Modified: poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/util/VsdxToPng.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/util/VsdxToPng.java?rev=1840956&r1=1840955&r2=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/util/VsdxToPng.java (original)
+++ poi/branches/hemf/src/ooxml/java/org/apache/poi/xdgf/util/VsdxToPng.java Fri Sep 14 21:37:37 2018
@@ -25,7 +25,7 @@ import java.io.*;
import javax.imageio.ImageIO;
-import org.apache.poi.xdgf.geom.Dimension2dDouble;
+import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.xdgf.usermodel.XDGFPage;
import org.apache.poi.xdgf.usermodel.XmlVisioDocument;
import org.apache.poi.xdgf.usermodel.shape.ShapeDebuggerRenderer;
@@ -58,7 +58,7 @@ public class VsdxToPng {
public static void renderToPng(XDGFPage page, File outFile, double scale,
ShapeRenderer renderer) throws IOException {
- Dimension2dDouble sz = page.getPageSize();
+ Dimension2DDouble sz = page.getPageSize();
int width = (int) (scale * sz.getWidth());
int height = (int) (scale * sz.getHeight());
Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,30 @@
+/* ====================================================================
+ 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.draw;
+
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
+
+public class HemfDrawProperties extends HwmfDrawProperties {
+
+ public HemfDrawProperties() {
+ }
+
+ public HemfDrawProperties(HemfDrawProperties other) {
+ super(other);
+ }
+}
Propchange: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,29 @@
+/* ====================================================================
+ 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.draw;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.poi.hwmf.draw.HwmfGraphics;
+
+public class HemfGraphics extends HwmfGraphics {
+ public HemfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
+ super(graphicsCtx,bbox);
+ }
+}
Propchange: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java (from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java)
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java?p2=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java&p1=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java&r1=1840955&r2=1840956&rev=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java Fri Sep 14 21:37:37 2018
@@ -15,17 +15,430 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hemf.record;
+package org.apache.poi.hemf.record.emf;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.apache.poi.hemf.record.emfplus.HemfPlusRecord;
+import org.apache.poi.hemf.record.emfplus.HemfPlusRecordIterator;
+import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.RecordFormatException;
/**
* Contains arbitrary data
*/
@Internal
-public class HemfComment extends AbstractHemfComment {
+public class HemfComment {
+ private static final int MAX_RECORD_LENGTH = 1_000_000;
+
+ public enum HemfCommentRecordType {
+ emfGeneric(-1, EmfCommentDataGeneric::new, false),
+ emfSpool(0x00000000, EmfCommentDataGeneric::new, false),
+ emfPlus(0x2B464D45, EmfCommentDataPlus::new, false),
+ emfPublic(0x43494447, null, false),
+ emfBeginGroup(0x00000002, EmfCommentDataBeginGroup::new, true),
+ emfEndGroup(0x00000003, EmfCommentDataEndGroup::new, true),
+ emfMultiFormats(0x40000004, EmfCommentDataMultiformats::new, true),
+ emfWMF(0x80000001, EmfCommentDataWMF::new, true),
+ emfUnicodeString(0x00000040, EmfCommentDataUnicode::new, true),
+ emfUnicodeEnd(0x00000080, EmfCommentDataUnicode::new, true)
+ ;
+
+
+ public final long id;
+ public final Supplier<? extends EmfCommentData> constructor;
+ public final boolean isEmfPublic;
+
+ HemfCommentRecordType(long id, Supplier<? extends EmfCommentData> constructor, boolean isEmfPublic) {
+ this.id = id;
+ this.constructor = constructor;
+ this.isEmfPublic = isEmfPublic;
+ }
+
+ public static HemfCommentRecordType getById(long id, boolean isEmfPublic) {
+ for (HemfCommentRecordType wrt : values()) {
+ if (wrt.id == id && wrt.isEmfPublic == isEmfPublic) return wrt;
+ }
+ return emfGeneric;
+ }
+ }
+
+ public interface EmfCommentData {
+ HemfCommentRecordType getCommentRecordType();
+
+ long init(LittleEndianInputStream leis, long dataSize) throws IOException;
+ }
+
+ public static class EmfComment implements HemfRecord {
+ private EmfCommentData data;
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.comment;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ int startIdx = leis.getReadIndex();
+ data = new EmfCommentDataIterator(leis, (int)recordSize, true).next();
+ return leis.getReadIndex()-startIdx;
+ }
+
+ public EmfCommentData getCommentData() {
+ return data;
+ }
+ }
+
+ public static class EmfCommentDataIterator implements Iterator<EmfCommentData> {
+
+ private final LittleEndianInputStream leis;
+ private final int startIdx;
+ private final int limit;
+ private EmfCommentData currentRecord;
+ /** is the caller the EmfComment */
+ private final boolean emfParent;
+
+ public EmfCommentDataIterator(LittleEndianInputStream leis, int limit, boolean emfParent) {
+ this.leis = leis;
+ this.limit = limit;
+ this.emfParent = emfParent;
+ startIdx = leis.getReadIndex();
+ //queue the first non-header record
+ currentRecord = _next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currentRecord != null;
+ }
+
+ @Override
+ public EmfCommentData next() {
+ EmfCommentData toReturn = currentRecord;
+ final boolean isEOF = (limit == -1 || leis.getReadIndex() >= startIdx+limit);
+ // (currentRecord instanceof HemfPlusMisc.EmfEof)
+ currentRecord = isEOF ? null : _next();
+ return toReturn;
+ }
+
+ private EmfCommentData _next() {
+ long type, recordSize;
+ if (currentRecord == null && emfParent) {
+ type = HemfRecordType.comment.id;
+ recordSize = limit;
+ } else {
+ // A 32-bit unsigned integer from the RecordType enumeration that identifies this record
+ // as a comment record. This value MUST be 0x00000046.
+ type = leis.readUInt();
+ assert(type == HemfRecordType.comment.id);
+ // A 32-bit unsigned integer that specifies the size in bytes of this record in the
+ // metafile. This value MUST be a multiple of 4 bytes.
+ recordSize = leis.readUInt();
+ }
+
+ // A 32-bit unsigned integer that specifies the size, in bytes, of the CommentIdentifier and
+ // CommentRecordParm fields in the RecordBuffer field that follows.
+ // It MUST NOT include the size of itself or the size of the AlignmentPadding field, if present.
+ long dataSize = leis.readUInt();
+
+ try {
+ leis.mark(2*LittleEndianConsts.INT_SIZE);
+ // An optional, 32-bit unsigned integer that identifies the type of comment record.
+ // See the preceding table for descriptions of these record types.
+ // Valid comment identifier values are listed in the following table.
+ //
+ // If this field contains any other value, the comment record MUST be an EMR_COMMENT record
+ final int commentIdentifier = (int)leis.readUInt();
+ // A 32-bit unsigned integer that identifies the type of public comment record.
+ final int publicCommentIdentifier = (int)leis.readUInt();
+
+ final boolean isEmfPublic = (commentIdentifier == HemfCommentRecordType.emfPublic.id);
+ leis.reset();
+
+ final HemfCommentRecordType commentType = HemfCommentRecordType.getById
+ (isEmfPublic ? publicCommentIdentifier : commentIdentifier, isEmfPublic);
+ assert(commentType != null);
+ final EmfCommentData record = commentType.constructor.get();
+
+ long readBytes = record.init(leis, dataSize);
+ final int skipBytes = (int)(recordSize-4-readBytes);
+ assert (skipBytes >= 0);
+ leis.skipFully(skipBytes);
+
+ return record;
+ } catch (IOException e) {
+ throw new RecordFormatException(e);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+
+ }
+
+
+
+ /**
+ * Private data is unknown to EMF; it is meaningful only to applications that know the format of the
+ * data and how to use it. EMR_COMMENT private data records MAY be ignored.
+ */
+ public static class EmfCommentDataGeneric implements EmfCommentData {
+ private byte[] privateData;
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfGeneric;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long dataSize) throws IOException {
+ privateData = IOUtils.safelyAllocate(dataSize, MAX_RECORD_LENGTH);
+ leis.readFully(privateData);
+ return privateData.length;
+ }
+ }
+
+ /** The EMR_COMMENT_EMFPLUS record contains embedded EMF+ records. */
+ public static class EmfCommentDataPlus implements EmfCommentData {
+ private final List<HemfPlusRecord> records = new ArrayList<>();
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfPlus;
+ }
+
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ long startIdx = leis.getReadIndex();
+ int commentIdentifier = leis.readInt();
+ assert (commentIdentifier == HemfCommentRecordType.emfPlus.id);
+ new HemfPlusRecordIterator(leis, (int)dataSize-LittleEndianConsts.INT_SIZE).forEachRemaining(records::add);
+ return leis.getReadIndex()-startIdx;
+ }
+
+ public List<HemfPlusRecord> getRecords() {
+ return Collections.unmodifiableList(records);
+ }
+ }
+
+ public static class EmfCommentDataBeginGroup implements EmfCommentData {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+ private String description;
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfBeginGroup;
+ }
+
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ final int startIdx = leis.getReadIndex();
+ final int commentIdentifier = (int)leis.readUInt();
+ assert(commentIdentifier == HemfCommentRecordType.emfPublic.id);
+ final int publicCommentIdentifier = (int)leis.readUInt();
+ assert(publicCommentIdentifier == HemfCommentRecordType.emfBeginGroup.id);
+ HemfDraw.readRectL(leis, bounds);
+
+ // The number of Unicode characters in the optional description string that follows.
+ int nDescription = (int)leis.readUInt();
+
+ byte[] buf = IOUtils.safelyAllocate(nDescription*2, MAX_RECORD_LENGTH);
+ leis.readFully(buf);
+ description = new String(buf, StandardCharsets.UTF_16LE);
+
+ return leis.getReadIndex()-startIdx;
+ }
+ }
+
+ public static class EmfCommentDataEndGroup implements EmfCommentData {
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfEndGroup;
+ }
+
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ final int startIdx = leis.getReadIndex();
+ final int commentIdentifier = (int)leis.readUInt();
+ assert(commentIdentifier == HemfCommentRecordType.emfPublic.id);
+ final int publicCommentIdentifier = (int)leis.readUInt();
+ assert(publicCommentIdentifier == HemfCommentRecordType.emfEndGroup.id);
+ return leis.getReadIndex()-startIdx;
+ }
+ }
+
+ public static class EmfCommentDataMultiformats implements EmfCommentData {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+ private final List<EmfCommentDataFormat> formats = new ArrayList<>();
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfMultiFormats;
+ }
+
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ final int startIdx = leis.getReadIndex();
+ final int commentIdentifier = (int)leis.readUInt();
+ assert(commentIdentifier == HemfCommentRecordType.emfPublic.id);
+ final int publicCommentIdentifier = (int)leis.readUInt();
+ assert(publicCommentIdentifier == HemfCommentRecordType.emfMultiFormats.id);
+ HemfDraw.readRectL(leis, bounds);
+
+ // A 32-bit unsigned integer that specifies the number of graphics formats contained in this record.
+ int countFormats = (int)leis.readUInt();
+ for (int i=0; i<countFormats; i++) {
+ EmfCommentDataFormat fmt = new EmfCommentDataFormat();
+ long readBytes = fmt.init(leis, dataSize, startIdx);
+ formats.add(fmt);
+ if (readBytes == 0) {
+ // binary data is appended without DataFormat header
+ break;
+ }
+ }
+
+ for (EmfCommentDataFormat fmt : formats) {
+ int skip = fmt.offData-(leis.getReadIndex()-startIdx);
+ leis.skipFully(skip);
+ fmt.rawData = new byte[fmt.sizeData];
+ leis.readFully(fmt.rawData);
+ }
+
+ return leis.getReadIndex()-startIdx;
+ }
+
+ public List<EmfCommentDataFormat> getFormats() {
+ return Collections.unmodifiableList(formats);
+ }
+ }
+
+ public enum EmfFormatSignature {
+ ENHMETA_SIGNATURE(0x464D4520),
+ EPS_SIGNATURE(0x46535045);
+
+ int id;
+
+ EmfFormatSignature(int flag) {
+ this.id = id;
+ }
+
+ public static EmfFormatSignature getById(int id) {
+ for (EmfFormatSignature wrt : values()) {
+ if (wrt.id == id) return wrt;
+ }
+ return null;
+ }
+
+ }
+
+ public static class EmfCommentDataFormat {
+ private EmfFormatSignature signature;
+ private int version;
+ private int sizeData;
+ private int offData;
+ private byte[] rawData;
+
+ public long init(final LittleEndianInputStream leis, final long dataSize, long startIdx) throws IOException {
+ // A 32-bit unsigned integer that specifies the format of the image data.
+ signature = EmfFormatSignature.getById(leis.readInt());
+
+ // A 32-bit unsigned integer that specifies the format version number.
+ // If the Signature field specifies encapsulated PostScript (EPS), this value MUST be 0x00000001;
+ // otherwise, this value MUST be ignored.
+ version = leis.readInt();
+
+ // A 32-bit unsigned integer that specifies the size of the data in bytes.
+ sizeData = leis.readInt();
+
+ // A 32-bit unsigned integer that specifies the offset to the data from the start
+ // of the identifier field in an EMR_COMMENT_PUBLIC record. The offset MUST be 32-bit aligned.
+ offData = leis.readInt();
+ if (sizeData < 0) {
+ throw new RecordFormatException("size for emrformat must be > 0");
+ }
+ if (offData < 0) {
+ throw new RecordFormatException("offset for emrformat must be > 0");
+ }
+
+ return 4*LittleEndianConsts.INT_SIZE;
+ }
+
+ public byte[] getRawData() {
+ return rawData;
+ }
+ }
+
+ public static class EmfCommentDataWMF implements EmfCommentData {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+ private final List<EmfCommentDataFormat> formats = new ArrayList<>();
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfWMF;
+ }
+
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ final int startIdx = leis.getReadIndex();
+ final int commentIdentifier = (int)leis.readUInt();
+ assert(commentIdentifier == HemfCommentRecordType.emfPublic.id);
+ final int publicCommentIdentifier = (int)leis.readUInt();
+ assert(publicCommentIdentifier == HemfCommentRecordType.emfWMF.id);
+
+ // A 16-bit unsigned integer that specifies the WMF metafile version in terms
+ //of support for device-independent bitmaps (DIBs)
+ int version = leis.readUShort();
+
+ // A 16-bit value that MUST be 0x0000 and MUST be ignored.
+ leis.skipFully(LittleEndianConsts.SHORT_SIZE);
+
+ // A 32-bit unsigned integer that specifies the checksum for this record.
+ int checksum = leis.readInt();
+
+ // A 32-bit value that MUST be 0x00000000 and MUST be ignored.
+ int flags = leis.readInt();
+
+ // A 32-bit unsigned integer that specifies the size, in bytes, of the
+ // WMF metafile in the WinMetafile field.
+ int winMetafileSize = (int)leis.readUInt();
+
+ byte[] winMetafile = IOUtils.safelyAllocate(winMetafileSize, MAX_RECORD_LENGTH);
+ leis.readFully(winMetafile);
+
+ return leis.getReadIndex()-startIdx;
+ }
+ }
+
+ public static class EmfCommentDataUnicode implements EmfCommentData {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+ private final List<EmfCommentDataFormat> formats = new ArrayList<>();
+
+ @Override
+ public HemfCommentRecordType getCommentRecordType() {
+ return HemfCommentRecordType.emfUnicodeString;
+ }
- public HemfComment(byte[] rawBytes) {
- super(rawBytes);
+ @Override
+ public long init(final LittleEndianInputStream leis, final long dataSize)
+ throws IOException {
+ throw new RecordFormatException("UNICODE_STRING/UNICODE_END values are reserved in CommentPublic records");
+ }
}
}
Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,783 @@
+/* ====================================================================
+ 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.emf;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import org.apache.poi.hemf.draw.HemfGraphics;
+import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.hwmf.record.HwmfDraw;
+import org.apache.poi.hwmf.record.HwmfDraw.WmfSelectObject;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfDraw {
+ /**
+ * The EMR_SELECTOBJECT record adds a graphics object to the current metafile playback device
+ * context. The object is specified either by its index in the EMF Object Table or by its
+ * value from the StockObject enumeration.
+ */
+ public static class EmfSelectObject extends WmfSelectObject implements HemfRecord {
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.selectObject;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ // A 32-bit unsigned integer that specifies either the index of a graphics object in the
+ // EMF Object Table or the index of a stock object from the StockObject enumeration.
+ objectIndex = leis.readInt();
+ return LittleEndianConsts.INT_SIZE;
+ }
+ }
+
+
+ /** The EMR_POLYBEZIER record specifies one or more Bezier curves. */
+ public static class EmfPolyBezier extends HwmfDraw.WmfPolygon implements HemfRecord {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyBezier;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointL(leis, point);
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+
+ /* A 32-bit unsigned integer that specifies the number of points in the points
+ * array. This value MUST be one more than three times the number of curves to
+ * be drawn, because each Bezier curve requires two control points and an
+ * endpoint, and the initial curve requires an additional starting point.
+ *
+ * Line width | Device supports wideline | Maximum points allowed
+ * 1 | n/a | 16K
+ * > 1 | yes | 16K
+ * > 1 | no | 1360
+ *
+ * Any extra points MUST be ignored.
+ */
+ final int count = (int)leis.readUInt();
+ final int points = Math.min(count, 16384);
+ size += LittleEndianConsts.INT_SIZE;
+
+ poly.reset();
+
+ /* Cubic Bezier curves are defined using the endpoints and control points
+ * specified by the points field. The first curve is drawn from the first
+ * point to the fourth point, using the second and third points as control
+ * points. Each subsequent curve in the sequence needs exactly three more points:
+ * the ending point of the previous curve is used as the starting point,
+ * the next two points in the sequence are control points,
+ * and the third is the ending point.
+ * The cubic Bezier curves SHOULD be drawn using the current pen.
+ */
+
+ Point2D pnt[] = { new Point2D.Double(), new Point2D.Double(), new Point2D.Double() };
+
+ // points-1 because of the first point
+ final int pointCnt = hasStartPoint() ? points-1 : points;
+ for (int i=0; i+3<pointCnt; i+=3) {
+ // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
+ // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
+ if (i==0 && hasStartPoint()) {
+ size += readPoint(leis, pnt[0]);
+ poly.moveTo(pnt[0].getX(),pnt[0].getY());
+ }
+
+ size += readPoint(leis, pnt[0]);
+ size += readPoint(leis, pnt[1]);
+ size += readPoint(leis, pnt[2]);
+
+ poly.curveTo(
+ pnt[0].getX(),pnt[0].getY(),
+ pnt[1].getX(),pnt[1].getY(),
+ pnt[2].getX(),pnt[2].getY()
+ );
+ }
+
+ return size;
+ }
+
+ /**
+ * @return true, if start point is in the list of points. false, if start point is taken from the context
+ */
+ protected boolean hasStartPoint() {
+ return true;
+ }
+ }
+
+ /**
+ * The EMR_POLYBEZIER16 record specifies one or more Bezier curves.
+ * The curves are drawn using the current pen.
+ */
+ public static class EmfPolyBezier16 extends EmfPolyBezier {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyBezier16;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+
+ /**
+ * The EMR_POLYGON record specifies a polygon consisting of two or more vertexes connected by
+ * straight lines.
+ */
+ public static class EmfPolygon extends HwmfDraw.WmfPolygon implements HemfRecord {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polygon;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointL(leis, point);
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+
+ // see PolyBezier about limits
+ final int count = (int)leis.readUInt();
+ final int points = Math.min(count, 16384);
+ size += LittleEndianConsts.INT_SIZE;
+
+ Point2D pnt = new Point2D.Double();
+ for (int i=0; i<points; i++) {
+ size += readPoint(leis, pnt);
+ if (i==0) {
+ poly.moveTo(pnt.getX(), pnt.getY());
+
+ if (hasStartPoint()) {
+ continue;
+ }
+
+ // if this path is connected to the current position (= has no start point)
+ // the first entry is a dummy entry and will be skipped later
+ }
+ poly.lineTo(pnt.getX(), pnt.getY());
+ }
+
+ return size;
+ }
+
+ /**
+ * @return true, if start point is in the list of points. false, if start point is taken from the context
+ */
+ protected boolean hasStartPoint() {
+ return true;
+ }
+ }
+
+ /**
+ * The EMR_POLYGON16 record specifies a polygon consisting of two or more vertexes connected by straight lines.
+ * The polygon is outlined by using the current pen and filled by using the current brush and polygon fill mode.
+ * The polygon is closed automatically by drawing a line from the last vertex to the first
+ */
+ public static class EmfPolygon16 extends EmfPolygon {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polygon16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_POLYLINE record specifies a series of line segments by connecting the points in the
+ * specified array.
+ */
+ public static class EmfPolyline extends EmfPolygon {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyline;
+ }
+
+ @Override
+ protected boolean isFill() {
+ return false;
+ }
+ }
+
+ /**
+ * The EMR_POLYLINE16 record specifies a series of line segments by connecting the points in the
+ * specified array.
+ */
+ public static class EmfPolyline16 extends EmfPolyline {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyline16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_POLYBEZIERTO record specifies one or more Bezier curves based upon the current
+ * position.
+ */
+ public static class EmfPolyBezierTo extends EmfPolyBezier {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyBezierTo;
+ }
+
+ @Override
+ protected boolean hasStartPoint() {
+ return false;
+ }
+
+ @Override
+ protected Path2D getShape(HwmfGraphics ctx) {
+ return polyTo(ctx, poly);
+ }
+ }
+
+ /**
+ * The EMR_POLYBEZIERTO16 record specifies one or more Bezier curves based on the current
+ * position.
+ */
+ public static class EmfPolyBezierTo16 extends EmfPolyBezierTo {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyBezierTo16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /** The EMR_POLYLINETO record specifies one or more straight lines based upon the current position. */
+ public static class EmfPolylineTo extends EmfPolyline {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polylineTo;
+ }
+
+ @Override
+ protected boolean hasStartPoint() {
+ return false;
+ }
+
+ @Override
+ protected Path2D getShape(HwmfGraphics ctx) {
+ return polyTo(ctx, poly);
+ }
+ }
+
+ /**
+ * The EMR_POLYLINETO16 record specifies one or more straight lines based upon the current position.
+ * A line is drawn from the current position to the first point specified by the points field by using the
+ * current pen. For each additional line, drawing is performed from the ending point of the previous
+ * line to the next point specified by points.
+ */
+ public static class EmfPolylineTo16 extends EmfPolylineTo {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polylineTo16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_POLYPOLYGON record specifies a series of closed polygons.
+ */
+ public static class EmfPolyPolygon extends HwmfDraw.WmfPolyPolygon implements HemfRecord {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyPolygon;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointL(leis, point);
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+
+ // A 32-bit unsigned integer that specifies the number of polygons.
+ long numberOfPolygons = leis.readUInt();
+ // A 32-bit unsigned integer that specifies the total number of points in all polygons.
+ long count = Math.min(16384, leis.readUInt());
+
+ size += 2 * LittleEndianConsts.INT_SIZE;
+
+ // An array of 32-bit unsigned integers that specifies the point count for each polygon.
+ long[] polygonPointCount = new long[(int)numberOfPolygons];
+
+ size += numberOfPolygons * LittleEndianConsts.INT_SIZE;
+
+ for (int i=0; i<numberOfPolygons; i++) {
+ polygonPointCount[i] = leis.readUInt();
+ }
+
+ Point2D pnt = new Point2D.Double();
+ for (long nPoints : polygonPointCount) {
+ /**
+ * An array of WMF PointL objects that specifies the points for all polygons in logical units.
+ * The number of points is specified by the Count field value.
+ */
+ Path2D poly = new Path2D.Double();
+ for (int i=0; i<nPoints; i++) {
+ size += readPoint(leis, pnt);
+ if (i == 0) {
+ poly.moveTo(pnt.getX(), pnt.getY());
+ } else {
+ poly.lineTo(pnt.getX(), pnt.getY());
+ }
+ }
+ if (isClosed()) {
+ poly.closePath();
+ }
+ polyList.add(poly);
+ }
+ return size;
+ }
+
+ /**
+ * @return true, if a polyline should be closed, i.e. is a polygon
+ */
+ protected boolean isClosed() {
+ return true;
+ }
+ }
+
+ /**
+ * The EMR_POLYPOLYGON16 record specifies a series of closed polygons. Each polygon is outlined
+ * using the current pen, and filled using the current brush and polygon fill mode.
+ * The polygons drawn by this record can overlap.
+ */
+ public static class EmfPolyPolygon16 extends EmfPolyPolygon {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyPolygon16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_POLYPOLYLINE record specifies multiple series of connected line segments.
+ */
+ public static class EmfPolyPolyline extends EmfPolyPolygon {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyPolyline;
+ }
+
+ @Override
+ protected boolean isClosed() {
+ return false;
+ }
+
+ @Override
+ protected boolean isFill() {
+ return false;
+ }
+ }
+
+ /** The EMR_POLYPOLYLINE16 record specifies multiple series of connected line segments. */
+ public static class EmfPolyPolyline16 extends EmfPolyPolyline {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyPolyline16;
+ }
+
+ @Override
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_SETPIXELV record defines the color of the pixel at the specified logical coordinates.
+ */
+ public static class EmfSetPixelV extends HwmfDraw.WmfSetPixel implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.setPixelV;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readPointL(leis, point);
+ size += colorRef.init(leis);
+ return size;
+ }
+ }
+
+ /**
+ * The EMR_MOVETOEX record specifies coordinates of the new current position, in logical units.
+ */
+ public static class EmfSetMoveToEx extends HwmfDraw.WmfMoveTo implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.setMoveToEx;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ return readPointL(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_ARCTO record specifies an elliptical arc.
+ * It resets the current position to the end point of the arc.
+ */
+ public static class EmfArc extends HwmfDraw.WmfArc implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.arc;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+ size += readPointL(leis, startPoint);
+ size += readPointL(leis, endPoint);
+ return size;
+ }
+
+ @Override
+ public void draw(HemfGraphics ctx) {
+ super.draw(ctx);
+ ctx.getProperties().setLocation(endPoint);
+ }
+ }
+
+ /**
+ * The EMR_CHORD record specifies a chord, which is a region bounded by the intersection of an
+ * ellipse and a line segment, called a secant. The chord is outlined by using the current pen
+ * and filled by using the current brush.
+ */
+ public static class EmfChord extends HwmfDraw.WmfChord implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.chord;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+ size += readPointL(leis, startPoint);
+ size += readPointL(leis, endPoint);
+ return size;
+ }
+ }
+
+ /**
+ * The EMR_PIE record specifies a pie-shaped wedge bounded by the intersection of an ellipse and two
+ * radials. The pie is outlined by using the current pen and filled by using the current brush.
+ */
+ public static class EmfPie extends HwmfDraw.WmfPie implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.pie;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+ size += readPointL(leis, startPoint);
+ size += readPointL(leis, endPoint);
+ return size;
+ }
+ }
+
+ /**
+ * The EMR_ELLIPSE record specifies an ellipse. The center of the ellipse is the center of the specified
+ * bounding rectangle. The ellipse is outlined by using the current pen and is filled by using the current
+ * brush.
+ */
+ public static class EmfEllipse extends HwmfDraw.WmfEllipse implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.ellipse;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ return readRectL(leis, bounds);
+ }
+ }
+
+ /**
+ * The EMR_RECTANGLE record draws a rectangle. The rectangle is outlined by using the current pen
+ * and filled by using the current brush.
+ */
+ public static class EmfRectangle extends HwmfDraw.WmfRectangle implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.rectangle;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ return readRectL(leis, bounds);
+ }
+ }
+
+ /**
+ * The EMR_ROUNDRECT record specifies a rectangle with rounded corners. The rectangle is outlined
+ * by using the current pen and filled by using the current brush.
+ */
+ public static class EmfRoundRect extends HwmfDraw.WmfRoundRect implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.roundRect;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+
+ // A 32-bit unsigned integer that defines the x-coordinate of the point.
+ width = (int)leis.readUInt();
+ height = (int)leis.readUInt();
+
+ return size + 2*LittleEndianConsts.INT_SIZE;
+ }
+ }
+
+ /**
+ * The EMR_LINETO record specifies a line from the current position up to, but not including, the
+ * specified point. It resets the current position to the specified point.
+ */
+ public static class EmfLineTo extends HwmfDraw.WmfLineTo implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.lineTo;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ return readPointL(leis, point);
+ }
+ }
+
+ /**
+ * The EMR_ARCTO record specifies an elliptical arc.
+ * It resets the current position to the end point of the arc.
+ */
+ public static class EmfArcTo extends HwmfDraw.WmfArc implements HemfRecord {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.arcTo;
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+ size += readPointL(leis, startPoint);
+ size += readPointL(leis, endPoint);
+ return size;
+ }
+
+ @Override
+ public void draw(HemfGraphics ctx) {
+ super.draw(ctx);
+ ctx.getProperties().setLocation(endPoint);
+ }
+ }
+
+ /** The EMR_POLYDRAW record specifies a set of line segments and Bezier curves. */
+ public static class EmfPolyDraw extends HwmfDraw.WmfPolygon implements HemfRecord {
+ private final Rectangle2D bounds = new Rectangle2D.Double();
+
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyDraw;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointL(leis, point);
+ }
+
+ @Override
+ public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+ long size = readRectL(leis, bounds);
+ int count = (int)leis.readUInt();
+ size += LittleEndianConsts.INT_SIZE;
+ Point2D points[] = new Point2D[count];
+ for (int i=0; i<count; i++) {
+ size += readPoint(leis, points[i]);
+ }
+
+ poly.reset();
+
+ for (int i=0; i<count; i++) {
+ int mode = leis.readUByte();
+ switch (mode & 0x06) {
+ // PT_LINETO
+ // Specifies that a line is to be drawn from the current position to this point, which
+ // then becomes the new current position.
+ case 0x02:
+ poly.lineTo(points[i].getX(), points[i].getY());
+ break;
+ // PT_BEZIERTO
+ // Specifies that this point is a control point or ending point for a Bezier curve.
+ // PT_BEZIERTO types always occur in sets of three.
+ // The current position defines the starting point for the Bezier curve.
+ // The first two PT_BEZIERTO points are the control points,
+ // and the third PT_BEZIERTO point is the ending point.
+ // The ending point becomes the new current position.
+ // If there are not three consecutive PT_BEZIERTO points, an error results.
+ case 0x04:
+ int mode2 = leis.readUByte();
+ int mode3 = leis.readUByte();
+ assert(mode2 == 0x04 && mode3 == 0x04);
+ poly.curveTo(
+ points[i].getX(), points[i].getY(),
+ points[i+1].getX(), points[i+1].getY(),
+ points[i+2].getX(), points[i+2].getY()
+ );
+ i+=2;
+ break;
+ // PT_MOVETO
+ // Specifies that this point starts a disjoint figure. This point becomes the new current position.
+ case 0x06:
+ poly.moveTo(points[i].getX(), points[i].getY());
+ break;
+ default:
+ // TODO: log error
+ break;
+ }
+
+ // PT_CLOSEFIGURE
+ // A PT_LINETO or PT_BEZIERTO type can be combined with this value by using the bitwise operator OR
+ // to indicate that the corresponding point is the last point in a figure and the figure is closed.
+ // The current position is set to the ending point of the closing line.
+ if ((mode & 0x01) == 0x01) {
+ this.poly.closePath();
+ }
+ }
+ size += count;
+ return size;
+ }
+ }
+
+ public static class EmfPolyDraw16 extends EmfPolyDraw {
+ @Override
+ public HemfRecordType getEmfRecordType() {
+ return HemfRecordType.polyDraw16;
+ }
+
+ protected long readPoint(LittleEndianInputStream leis, Point2D point) {
+ return readPointS(leis, point);
+ }
+
+ }
+ static long readRectL(LittleEndianInputStream leis, Rectangle2D bounds) {
+ /* A 32-bit signed integer that defines the x coordinate, in logical coordinates,
+ * of the ... corner of the rectangle.
+ */
+ final int left = leis.readInt();
+ final int top = leis.readInt();
+ final int right = leis.readInt();
+ final int bottom = leis.readInt();
+ bounds.setRect(left, top, right-left, bottom-top);
+
+ return 4 * LittleEndianConsts.INT_SIZE;
+ }
+
+ static long readPointS(LittleEndianInputStream leis, Point2D point) {
+ // x (2 bytes): A 16-bit signed integer that defines the horizontal (x) coordinate of the point.
+ final int x = leis.readShort();
+ // y (2 bytes): A 16-bit signed integer that defines the vertical (y) coordinate of the point.
+ final int y = leis.readShort();
+ point.setLocation(x, y);
+
+ return 2*LittleEndianConsts.SHORT_SIZE;
+
+ }
+ static long readPointL(LittleEndianInputStream leis, Point2D point) {
+ // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
+ final int x = leis.readInt();
+ // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
+ final int y = leis.readInt();
+ point.setLocation(x, y);
+
+ return 2*LittleEndianConsts.INT_SIZE;
+
+ }
+
+ static long readDimensionFloat(LittleEndianInputStream leis, Dimension2D dimension) {
+ final double width = leis.readFloat();
+ final double height = leis.readFloat();
+ dimension.setSize(width, height);
+ return 2*LittleEndianConsts.INT_SIZE;
+ }
+
+ static long readDimensionInt(LittleEndianInputStream leis, Dimension2D dimension) {
+ final double width = leis.readUInt();
+ final double height = leis.readUInt();
+ dimension.setSize(width, height);
+ return 2*LittleEndianConsts.INT_SIZE;
+ }
+
+ private static Path2D polyTo(HwmfGraphics ctx, Path2D poly) {
+ Path2D polyCopy = new Path2D.Double();
+ Point2D start = ctx.getProperties().getLocation();
+ polyCopy.moveTo(start.getX(), start.getY());
+
+ PathIterator iter = poly.getPathIterator(null);
+ iter.next();
+
+ polyCopy.append(iter, true);
+ return polyCopy;
+ }
+
+
+}
Propchange: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org