From b3fc9f49572cb79ffa25f82d45987adb33b09e93 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Mon, 24 Sep 2018 23:55:52 +0000 Subject: [PATCH] #60656 - Support export file that contains emf and render it correctly git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1841897 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/sl/draw/DrawPictureShape.java | 39 +++++++-- .../org.apache.poi.sl.draw.ImageRenderer | 1 - .../org.apache.poi.sl.draw.ImageRenderer | 2 - .../poi/hemf/draw/HemfDrawProperties.java | 22 ++++- .../apache/poi/hemf/draw/HemfGraphics.java | 58 +++++++++++++ .../poi/hemf/record/emf/HemfComment.java | 11 +++ .../apache/poi/hemf/record/emf/HemfDraw.java | 86 ++++++++++++------- .../apache/poi/hemf/record/emf/HemfFill.java | 3 + .../apache/poi/hemf/record/emf/HemfMisc.java | 44 ++++------ .../poi/hemf/record/emf/HemfPalette.java | 16 ++++ .../poi/hemf/record/emf/HemfRecordType.java | 6 +- .../apache/poi/hemf/record/emf/HemfText.java | 48 ++++++++--- .../apache/poi/hwmf/draw/HwmfGraphics.java | 4 +- .../apache/poi/hwmf/record/HwmfColorRef.java | 5 ++ .../org/apache/poi/hwmf/record/HwmfDraw.java | 56 +++++++++++- .../org/apache/poi/hwmf/record/HwmfFont.java | 33 +++++++ .../org/apache/poi/hwmf/record/HwmfMisc.java | 25 +++++- .../org/apache/poi/hwmf/record/HwmfText.java | 13 ++- .../apache/poi/hwmf/record/HwmfWindowing.java | 27 +++--- .../poi/hemf/usermodel/HemfPictureTest.java | 15 +++- 20 files changed, 396 insertions(+), 118 deletions(-) delete mode 100644 src/resources/main/META-INF/services/org.apache.poi.sl.draw.ImageRenderer delete mode 100644 src/resources/scratchpad/META-INF/services/org.apache.poi.sl.draw.ImageRenderer diff --git a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java index 5c42d6fd13..3ccbc9f219 100644 --- a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java @@ -33,7 +33,10 @@ import org.apache.poi.util.POILogger; public class DrawPictureShape extends DrawSimpleShape { private static final POILogger LOG = POILogFactory.getLogger(DrawPictureShape.class); - private static final ServiceLoader rendererLoader = ServiceLoader.load(ImageRenderer.class); + private static final String[] KNOWN_RENDERER = { + "org.apache.poi.hwmf.draw.HwmfImageRenderer", + "org.apache.poi.hemf.draw.HemfImageRenderer" + }; public DrawPictureShape(PictureShape shape) { super(shape); @@ -62,24 +65,44 @@ public class DrawPictureShape extends DrawSimpleShape { * @param graphics the graphics context * @return the image renderer */ - @SuppressWarnings("WeakerAccess") + @SuppressWarnings({"WeakerAccess", "unchecked"}) public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) { - ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER); - if (renderer != null) { + final ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER); + if (renderer != null && renderer.canRender(contentType)) { return renderer; } - for (ImageRenderer ir : rendererLoader) { + // first try with our default image renderer + final BitmapImageRenderer bir = new BitmapImageRenderer(); + if (bir.canRender(contentType)) { + return bir; + } + + // then iterate through the scratchpad renderers + // + // this could be nicely implemented via a j.u.ServiceLoader, but OSGi makes things complicated ... + // https://blog.osgi.org/2013/02/javautilserviceloader-in-osgi.html + // ... therefore falling back to classloading attempts + ClassLoader cl = ImageRenderer.class.getClassLoader(); + for (String kr : KNOWN_RENDERER) { + final ImageRenderer ir; + try { + ir = ((Class)cl.loadClass(kr)).newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + // scratchpad was not on the path, ignore and continue + LOG.log(POILogger.INFO, "Known image renderer '"+kr+" not found/loaded - include poi-scratchpad jar!", e); + continue; + } if (ir.canRender(contentType)) { return ir; } } - LOG.log(POILogger.ERROR, "No suiteable image renderer found for content-type '"+ + LOG.log(POILogger.WARN, "No suiteable image renderer found for content-type '"+ contentType+"' - include poi-scratchpad jar!"); - // falling back to BitmapImageRenderer although this doesn't make much sense ... - return new BitmapImageRenderer(); + // falling back to BitmapImageRenderer, at least it gracefully handles invalid images + return bir; } @Override diff --git a/src/resources/main/META-INF/services/org.apache.poi.sl.draw.ImageRenderer b/src/resources/main/META-INF/services/org.apache.poi.sl.draw.ImageRenderer deleted file mode 100644 index 1e7699fe57..0000000000 --- a/src/resources/main/META-INF/services/org.apache.poi.sl.draw.ImageRenderer +++ /dev/null @@ -1 +0,0 @@ -org.apache.poi.sl.draw.BitmapImageRenderer \ No newline at end of file diff --git a/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.draw.ImageRenderer b/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.draw.ImageRenderer deleted file mode 100644 index b23f654157..0000000000 --- a/src/resources/scratchpad/META-INF/services/org.apache.poi.sl.draw.ImageRenderer +++ /dev/null @@ -1,2 +0,0 @@ -org.apache.poi.hwmf.draw.HwmfImageRenderer -org.apache.poi.hemf.draw.HemfImageRenderer \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java b/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java index 8bb8af33bf..b12a4caa6c 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java +++ b/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java @@ -24,16 +24,15 @@ import org.apache.poi.hwmf.draw.HwmfDrawProperties; public class HemfDrawProperties extends HwmfDrawProperties { /** Path for path bracket operations */ - protected final Path2D path; + protected Path2D path = null; public HemfDrawProperties() { - path = new Path2D.Double(); } public HemfDrawProperties(HemfDrawProperties other) { super(other); - path = (Path2D)other.path.clone(); + path = (other.path != null) ? (Path2D)other.path.clone() : null; } /** @@ -42,4 +41,21 @@ public class HemfDrawProperties extends HwmfDrawProperties { public Path2D getPath() { return path; } + + /** + * Un-/Sets the bracket path + * @param path the bracket path + */ + public void setPath(Path2D path) { + this.path = path; + } + + /** + * Use path (bracket) or graphics context for drawing operations + * @return {@code true}, if the drawing should go to the path bracket, + * if {@code false} draw directly to the graphics context + */ + public boolean usePathBracket() { + return path != null; + } } diff --git a/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java b/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java index 05701ef823..c4783950a6 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java @@ -19,13 +19,18 @@ package org.apache.poi.hemf.draw; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayDeque; import java.util.Deque; +import java.util.function.Consumer; import org.apache.poi.hemf.record.emf.HemfBounded; import org.apache.poi.hemf.record.emf.HemfRecord; import org.apache.poi.hwmf.draw.HwmfGraphics; +import org.apache.poi.hwmf.record.HwmfObjectTableEntry; +import org.apache.poi.util.Internal; public class HemfGraphics extends HwmfGraphics { @@ -80,6 +85,59 @@ public class HemfGraphics extends HwmfGraphics { } } + @Internal + public void draw(Consumer pathConsumer) { + final HemfDrawProperties prop = getProperties(); + final boolean useBracket = prop.usePathBracket(); + + final Path2D path; + if (useBracket) { + path = prop.getPath(); + } else { + path = new Path2D.Double(); + Point2D pnt = prop.getLocation(); + path.moveTo(pnt.getX(),pnt.getY()); + } + + pathConsumer.accept(path); + + prop.setLocation(path.getCurrentPoint()); + if (!useBracket) { + // TODO: when to use draw vs. fill? + graphicsCtx.draw(path); + } + + } + + /** + * Adds or sets an record of type {@link HwmfObjectTableEntry} to the object table. + * If the {@code index} is less than 1, the method acts the same as + * {@link HwmfGraphics#addObjectTableEntry(HwmfObjectTableEntry)}, otherwise the + * index is used to access the object table. + * As the table is filled successively, the index must be between 1 and size+1 + * + * @param entry the record to be stored + * @param index the index to be overwritten, regardless if its content was unset before + * + * @see HwmfGraphics#addObjectTableEntry(HwmfObjectTableEntry) + */ + public void addObjectTableEntry(HwmfObjectTableEntry entry, int index) { + if (index < 1) { + super.addObjectTableEntry(entry); + return; + } + + if (index > objectTable.size()) { + throw new IllegalStateException("object table hasn't grown to this index yet"); + } + + if (index == objectTable.size()) { + objectTable.add(entry); + } else { + objectTable.set(index, entry); + } + } + /** saves the current affine transform on the stack */ private void saveTransform() { diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java index 0a459e3cd0..fe098f2794 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java @@ -32,6 +32,7 @@ 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.LocaleUtil; import org.apache.poi.util.RecordFormatException; /** @@ -97,6 +98,11 @@ public class HemfComment { public EmfCommentData getCommentData() { return data; } + + @Override + public String toString() { + return "{ data: "+data+" }"; + } } public static class EmfCommentDataIterator implements Iterator { @@ -208,6 +214,11 @@ public class HemfComment { leis.readFully(privateData); return privateData.length; } + + @Override + public String toString() { + return "\""+new String(privateData, LocaleUtil.CHARSET_1252)+"\""; + } } /** The EMR_COMMENT_EMFPLUS record contains embedded EMF+ records. */ diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java index c2cc9c3de2..f9c6e975a2 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java @@ -53,6 +53,28 @@ public class HemfDraw { private static final HwmfColorRef DKGRAY = new HwmfColorRef(new Color(0x00404040)); private static final HwmfColorRef BLACK = new HwmfColorRef(Color.BLACK); + private static final String[] STOCK_IDS = { + "0x80000000 /* WHITE_BRUSH */", + "0x80000001 /* LTGRAY_BRUSH */", + "0x80000002 /* GRAY_BRUSH */", + "0x80000003 /* DKGRAY_BRUSH */", + "0x80000004 /* BLACK_BRUSH */", + "0x80000005 /* NULL_BRUSH */", + "0x80000006 /* WHITE_PEN */", + "0x80000007 /* BLACK_PEN */", + "0x80000008 /* NULL_PEN */", + "0x8000000A /* OEM_FIXED_FONT */", + "0x8000000B /* ANSI_FIXED_FONT */", + "0x8000000C /* ANSI_VAR_FONT */", + "0x8000000D /* SYSTEM_FONT */", + "0x8000000E /* DEVICE_DEFAULT_FONT */", + "0x8000000F /* DEFAULT_PALETTE */", + "0x80000010 /* SYSTEM_FIXED_FONT */", + "0x80000011 /* DEFAULT_GUI_FONT */", + "0x80000012 /* DC_BRUSH */", + "0x80000013 /* DC_PEN */" + }; + @Override public HemfRecordType getEmfRecordType() { return HemfRecordType.selectObject; @@ -184,6 +206,14 @@ public class HemfDraw { } } + @Override + public String toString() { + return "{ index: "+ + (((objectIndex & 0x80000000) != 0 && (objectIndex & 0x3FFFFFFF) <= 13 ) + ? STOCK_IDS[objectIndex & 0x3FFFFFFF] + : objectIndex)+" }"; + } + } @@ -220,7 +250,7 @@ public class HemfDraw { final int points = Math.min(count, 16384); size += LittleEndianConsts.INT_SIZE; - poly.reset(); + poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, points); /* Cubic Bezier curves are defined using the endpoints and control points * specified by the points field. The first curve is drawn from the first @@ -324,6 +354,8 @@ public class HemfDraw { final int points = Math.min(count, 16384); size += LittleEndianConsts.INT_SIZE; + poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, points); + Point2D pnt = new Point2D.Double(); for (int i=0; i path.moveTo(point.getX(), point.getY())); } } @@ -802,11 +831,8 @@ public class HemfDraw { } @Override - public void draw(HemfGraphics ctx) { - final HemfDrawProperties prop = ctx.getProperties(); - final Path2D path = prop.getPath(); - path.lineTo(point.getX(), point.getY()); - prop.setLocation(point); + public void draw(final HemfGraphics ctx) { + ctx.draw((path) -> path.lineTo(point.getX(), point.getY())); } } @@ -829,11 +855,9 @@ public class HemfDraw { } @Override - public void draw(HemfGraphics ctx) { - final Path2D path = ctx.getProperties().getPath(); - Arc2D arc = getShape(); - path.append(arc, true); - ctx.getProperties().setLocation(endPoint); + public void draw(final HemfGraphics ctx) { + final Arc2D arc = getShape(); + ctx.draw((path) -> path.append(arc, true)); } } @@ -860,7 +884,7 @@ public class HemfDraw { size += readPoint(leis, points[i]); } - poly.reset(); + poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, count); for (int i=0; i path.append(pi, true)); + } } diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java index e28a355f0c..5dca14537f 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java @@ -655,6 +655,9 @@ public class HemfFill { @Override public void draw(HemfGraphics ctx) { final HemfDrawProperties prop = ctx.getProperties(); + if (!prop.usePathBracket()) { + return; + } final Path2D path = (Path2D)prop.getPath().clone(); path.setWindingRule(ctx.getProperties().getWindingRule()); if (prop.getBrushStyle() == HwmfBrushStyle.BS_NULL) { diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java index f3424d08d0..291c83d630 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java @@ -98,7 +98,7 @@ public class HemfMisc { /** * The EMF_SAVEDC record saves the playback device context for later retrieval. */ - public static class EmfSaveDc implements HemfRecord { + public static class EmfSaveDc extends HwmfMisc.WmfSaveDc implements HemfRecord { @Override public HemfRecordType getEmfRecordType() { return HemfRecordType.saveDc; @@ -108,25 +108,13 @@ public class HemfMisc { public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { return 0; } - - @Override - public void draw(HemfGraphics ctx) { - ctx.saveProperties(); - } } /** * The EMF_RESTOREDC record restores the playback device context from a previously saved device * context. */ - public static class EmfRestoreDc implements HemfRecord { - - /** - * SavedDC (4 bytes): A 32-bit signed integer that specifies the saved state to restore relative to - * the current state. This value MUST be negative; –1 represents the state that was most - * recently saved on the stack, –2 the one before that, etc. - */ - private int nSavedDC; + public static class EmfRestoreDc extends HwmfMisc.WmfRestoreDc implements HemfRecord { @Override public HemfRecordType getEmfRecordType() { @@ -135,23 +123,19 @@ public class HemfMisc { @Override public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { + // A 32-bit signed integer that specifies the saved state to restore relative to + // the current state. This value MUST be negative; –1 represents the state that was most + // recently saved on the stack, –2 the one before that, etc. nSavedDC = leis.readInt(); return LittleEndianConsts.INT_SIZE; } - - @Override - public void draw(HemfGraphics ctx) { - ctx.restoreProperties(nSavedDC); - } } /** * The META_SETBKCOLOR record sets the background color in the playback device context to a * specified color, or to the nearest physical color if the device cannot represent the specified color. */ - public static class EmfSetBkColor implements HemfRecord { - - private HwmfColorRef colorRef; + public static class EmfSetBkColor extends HwmfMisc.WmfSetBkColor implements HemfRecord { @Override public HemfRecordType getEmfRecordType() { @@ -160,14 +144,8 @@ public class HemfMisc { @Override public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { - colorRef = new HwmfColorRef(); return colorRef.init(leis); } - - @Override - public void draw(HemfGraphics ctx) { - ctx.getProperties().setBackgroundColor(colorRef); - } } @@ -287,8 +265,13 @@ public class HemfMisc { int size = colorRef.init(leis); brushHatch = HwmfHatchStyle.valueOf((int) leis.readUInt()); return size + 3 * LittleEndianConsts.INT_SIZE; + } + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, brushIdx); } + } /** @@ -341,6 +324,11 @@ public class HemfMisc { return size + 4 * LittleEndianConsts.INT_SIZE; } + + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, penIndex); + } } public static class EmfExtCreatePen extends EmfCreatePen { diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java index b9a909991e..9811cb2c3d 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java @@ -19,6 +19,7 @@ package org.apache.poi.hemf.record.emf; import java.io.IOException; +import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hwmf.record.HwmfPalette; import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianInputStream; @@ -67,6 +68,11 @@ public class HemfPalette { int size = readPaletteEntries(leis, -1); return size + LittleEndianConsts.INT_SIZE + LittleEndianConsts.SHORT_SIZE; } + + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, paletteIndex); + } } /** @@ -93,6 +99,11 @@ public class HemfPalette { int size = readPaletteEntries(leis, nbrOfEntries); return size + 3*LittleEndianConsts.INT_SIZE; } + + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, paletteIndex); + } } /** @@ -118,6 +129,11 @@ public class HemfPalette { return 2*LittleEndianConsts.INT_SIZE; } + + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, paletteIndex); + } } /** diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java index 6c858ccc53..f6584443a1 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java @@ -47,7 +47,7 @@ public enum HemfRecordType { setStretchBltMode(0x00000015, HemfMisc.EmfSetStretchBltMode::new), setTextAlign(0x00000016, HemfText.EmfSetTextAlign::new), setcoloradjustment(0x00000017, UnimplementedHemfRecord::new), - setTextColor(0x00000018, HemfText.SetTextColor::new), + setTextColor(0x00000018, HemfText.EmfSetTextColor::new), setBkColor(0x00000019, HemfMisc.EmfSetBkColor::new), setOffsetClipRgn(0x0000001A, HemfWindowing.EmfSetOffsetClipRgn::new), setMoveToEx(0x0000001B, HemfDraw.EmfSetMoveToEx::new), @@ -106,8 +106,8 @@ public enum HemfRecordType { setDiBitsToDevice(0x00000050, HemfFill.EmfSetDiBitsToDevice::new), stretchdibits(0x00000051, UnimplementedHemfRecord::new), extCreateFontIndirectW(0x00000052, HemfText.ExtCreateFontIndirectW::new), - exttextouta(0x00000053, HemfText.ExtTextOutA::new), - exttextoutw(0x00000054, HemfText.ExtTextOutW::new), + exttextouta(0x00000053, HemfText.EmfExtTextOutA::new), + exttextoutw(0x00000054, HemfText.EmfExtTextOutW::new), polyBezier16(0x00000055, HemfDraw.EmfPolyBezier16::new), polygon16(0x00000056, HemfDraw.EmfPolygon16::new), polyline16(0x00000057, HemfDraw.EmfPolyline16::new), diff --git a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java index 95c110df10..2305aeced8 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java +++ b/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java @@ -29,7 +29,7 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import org.apache.poi.hwmf.record.HwmfColorRef; +import org.apache.poi.hemf.draw.HemfGraphics; import org.apache.poi.hwmf.record.HwmfText; import org.apache.poi.hwmf.record.HwmfText.WmfSetTextAlign; import org.apache.poi.util.Dimension2DDouble; @@ -53,9 +53,9 @@ public class HemfText { GM_COMPATIBLE, GM_ADVANCED } - public static class ExtTextOutA implements HemfRecord { + public static class EmfExtTextOutA implements HemfRecord { - protected final Rectangle2D boundsIgnored = new Rectangle2D.Double(); + protected final Rectangle2D bounds = new Rectangle2D.Double(); protected EmfGraphicsMode graphicsMode; @@ -67,11 +67,11 @@ public class HemfText { protected final EmrTextObject textObject; - public ExtTextOutA() { + public EmfExtTextOutA() { this(false); } - protected ExtTextOutA(boolean isUnicode) { + protected EmfExtTextOutA(boolean isUnicode) { textObject = new EmrTextObject(isUnicode); } @@ -87,7 +87,7 @@ public class HemfText { } // A WMF RectL object. It is not used and MUST be ignored on receipt. - long size = readRectL(leis, boundsIgnored); + long size = readRectL(leis, bounds); // A 32-bit unsigned integer that specifies the graphics mode from the GraphicsMode enumeration graphicsMode = EmfGraphicsMode.values()[leis.readInt()-1]; @@ -104,10 +104,10 @@ public class HemfText { /** * * To be implemented! We need to get the current character set - * from the current font for {@link ExtTextOutA}, + * from the current font for {@link EmfExtTextOutA}, * which has to be tracked in the playback device. * - * For {@link ExtTextOutW}, the charset is "UTF-16LE" + * For {@link EmfExtTextOutW}, the charset is "UTF-16LE" * * @param charset the charset to be used to decode the character bytes * @return text from this text element @@ -132,11 +132,24 @@ public class HemfText { public Dimension2D getScale() { return scale; } + + @Override + public String toString() { + return + "{ bounds: { x: "+bounds.getX()+ + ", y: "+bounds.getY()+ + ", w: "+bounds.getWidth()+ + ", h: "+bounds.getHeight()+ + "}, graphicsMode: '"+graphicsMode+"'"+ + ", scale: { w: "+scale.getWidth()+", h: "+scale.getHeight()+" }"+ + ", textObject: "+textObject+ + "}"; + } } - public static class ExtTextOutW extends ExtTextOutA { + public static class EmfExtTextOutW extends EmfExtTextOutA { - public ExtTextOutW() { + public EmfExtTextOutW() { super(true); } @@ -175,10 +188,7 @@ public class HemfText { /** * The EMR_SETTEXTCOLOR record defines the current text color. */ - public static class SetTextColor implements HemfRecord { - /** A WMF ColorRef object that specifies the text color value. */ - private final HwmfColorRef colorRef = new HwmfColorRef(); - + public static class EmfSetTextColor extends HwmfText.WmfSetTextColor implements HemfRecord { @Override public HemfRecordType getEmfRecordType() { return HemfRecordType.setTextColor; @@ -284,6 +294,16 @@ public class HemfText { int size = font.init(leis, (int)(recordSize-LittleEndianConsts.INT_SIZE)); return size+LittleEndianConsts.INT_SIZE; } + + @Override + public void draw(HemfGraphics ctx) { + ctx.addObjectTableEntry(this, fontIdx); + } + + @Override + public String toString() { + return "{ index: "+fontIdx+", font: "+font+" } "; + } } public static class EmfExtTextOutOptions extends HwmfText.WmfExtTextOutOptions { diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java index de348480ad..b29c1187e9 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java @@ -55,10 +55,10 @@ public class HwmfGraphics { protected final List propStack = new LinkedList<>(); protected HwmfDrawProperties prop; protected final Graphics2D graphicsCtx; + protected final List objectTable = new ArrayList<>(); private static final Charset DEFAULT_CHARSET = LocaleUtil.CHARSET_1252; - private final List objectTable = new ArrayList<>(); - /** Bounding box from the placeable header */ + /** Bounding box from the placeable header */ private final Rectangle2D bbox; private final AffineTransform initialAT; diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java index 5b24fbc7e9..12204d61ec 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java @@ -69,4 +69,9 @@ public class HwmfColorRef implements Cloneable { throw new InternalError(); } } + + @Override + public String toString() { + return String.format("%#8X", colorRef.getRGB()); + } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java index 2f052075b5..64f2dae8c9 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java @@ -23,6 +23,7 @@ import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; @@ -57,6 +58,11 @@ public class HwmfDraw { public void draw(HwmfGraphics ctx) { ctx.getProperties().setLocation(point); } + + @Override + public String toString() { + return "{ x: "+point.getX()+", y: "+point.getY()+" }"; + } } /** @@ -84,6 +90,11 @@ public class HwmfDraw { ctx.draw(line); ctx.getProperties().setLocation(point); } + + @Override + public String toString() { + return "{ x: "+point.getX()+", y: "+point.getY()+" }"; + } } /** @@ -93,7 +104,7 @@ public class HwmfDraw { */ public static class WmfPolygon implements HwmfRecord { - protected Path2D poly = new Path2D.Double(); + protected Path2D poly; @Override public HwmfRecordType getWmfRecordType() { @@ -107,6 +118,7 @@ public class HwmfDraw { */ int numberofPoints = leis.readShort(); + poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, numberofPoints); for (int i=0; i -1 && lastY != reference.getY()) { sb.append("\n"); @@ -194,7 +203,7 @@ public class HemfPictureTest { int foundExpected = 0; for (HemfRecord record : pic) { if (record.getEmfRecordType().equals(HemfRecordType.exttextoutw)) { - HemfText.ExtTextOutW extTextOutW = (HemfText.ExtTextOutW) record; + HemfText.EmfExtTextOutW extTextOutW = (HemfText.EmfExtTextOutW) record; Point2D reference = extTextOutW.getTextObject().getReference(); if (lastY > -1 && lastY != reference.getY()) { sb.append("\n"); -- 2.39.5