From 799eced5bb93dfbb1e750bbf496f8413db70ae36 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Tue, 5 Jan 2016 23:40:47 +0000 Subject: [PATCH] WMF fixes git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723198 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/poi/hwmf/draw/HwmfGraphics.java | 84 +++++++++++-------- .../org/apache/poi/hwmf/record/HwmfDraw.java | 2 +- .../org/apache/poi/hwmf/record/HwmfMisc.java | 1 + .../apache/poi/hwmf/record/HwmfPalette.java | 53 ++++++++++-- .../apache/poi/hwmf/record/HwmfWindowing.java | 4 + .../poi/hwmf/usermodel/HwmfPicture.java | 12 ++- .../org/apache/poi/hwmf/TestHwmfParsing.java | 3 - 7 files changed, 112 insertions(+), 47 deletions(-) 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 2ef64a8ed9..a61390704a 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java @@ -20,6 +20,7 @@ package org.apache.poi.hwmf.draw; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; import java.awt.Paint; import java.awt.Rectangle; import java.awt.Shape; @@ -36,6 +37,7 @@ import java.util.NoSuchElementException; import org.apache.poi.hwmf.record.HwmfBrushStyle; import org.apache.poi.hwmf.record.HwmfHatchStyle; +import org.apache.poi.hwmf.record.HwmfMapMode; import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode; import org.apache.poi.hwmf.record.HwmfObjectTableEntry; import org.apache.poi.hwmf.record.HwmfPenStyle; @@ -49,6 +51,7 @@ public class HwmfGraphics { private List objectTable = new ArrayList(); /** Bounding box from the placeable header */ private final Rectangle2D bbox; + private final AffineTransform initialAT; /** * Initialize a graphics context for wmf rendering @@ -59,6 +62,7 @@ public class HwmfGraphics { public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) { this.graphicsCtx = graphicsCtx; this.bbox = (Rectangle2D)bbox.clone(); + this.initialAT = graphicsCtx.getTransform(); } public HwmfDrawProperties getProperties() { @@ -72,7 +76,6 @@ public class HwmfGraphics { return; } - Shape tshape = fitShapeToView(shape); BasicStroke stroke = getStroke(); // first draw a solid background line (depending on bkmode) @@ -80,56 +83,26 @@ public class HwmfGraphics { if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) { graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth())); graphicsCtx.setColor(prop.getBackgroundColor().getColor()); - graphicsCtx.draw(tshape); + graphicsCtx.draw(shape); } // then draw the (dashed) line graphicsCtx.setStroke(stroke); graphicsCtx.setColor(prop.getPenColor().getColor()); - graphicsCtx.draw(tshape); + graphicsCtx.draw(shape); } public void fill(Shape shape) { if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) { GeneralPath gp = new GeneralPath(shape); gp.setWindingRule(prop.getPolyfillMode().awtFlag); - Shape tshape = fitShapeToView(gp); graphicsCtx.setPaint(getFill()); - graphicsCtx.fill(tshape); + graphicsCtx.fill(shape); } draw(shape); } - protected Shape fitShapeToView(Shape shape) { - int scaleUnits = prop.getMapMode().scale; - Rectangle2D view = prop.getViewport(); - Rectangle2D win = prop.getWindow(); - if (view == null) { - view = win; - } - double scaleX, scaleY; - switch (scaleUnits) { - case -1: - scaleX = view.getWidth() / win.getWidth(); - scaleY = view.getHeight() / win.getHeight(); - break; - case 0: - scaleX = scaleY = 1; - break; - default: - scaleX = scaleY = scaleUnits / (double)Units.POINT_DPI; - } - - AffineTransform at = new AffineTransform(); - at.scale(scaleX, scaleY); -// at.translate(-view.getX(), -view.getY()); - at.translate(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight()); - - Shape tshape = at.createTransformedShape(shape); - return tshape; - } - protected BasicStroke getStroke() { Rectangle2D view = prop.getViewport(); Rectangle2D win = prop.getWindow(); @@ -285,4 +258,47 @@ public class HwmfGraphics { } prop = propStack.remove(stackIndex); } + + public void updateWindowMapMode() { + GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration(); + Rectangle2D win = prop.getWindow(); + HwmfMapMode mapMode = prop.getMapMode(); + graphicsCtx.setTransform(initialAT); + + switch (mapMode) { + default: + case MM_ANISOTROPIC: + // scale output bounds to image bounds + graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getHeight()/bbox.getHeight()); + graphicsCtx.translate(-bbox.getX(), -bbox.getY()); + + // scale window bounds to output bounds + graphicsCtx.translate(win.getCenterX(), win.getCenterY()); + graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight()); + graphicsCtx.translate(-win.getCenterX(), -win.getCenterY()); + break; + case MM_ISOTROPIC: + // TODO: to be validated ... + // like anisotropic, but use x-axis as reference + graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getWidth()/bbox.getWidth()); + graphicsCtx.translate(-bbox.getX(), -bbox.getY()); + graphicsCtx.translate(win.getCenterX(), win.getCenterY()); + graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth()); + graphicsCtx.translate(-win.getCenterX(), -win.getCenterY()); + break; + case MM_LOMETRIC: + case MM_HIMETRIC: + case MM_LOENGLISH: + case MM_HIENGLISH: + case MM_TWIPS: + // TODO: to be validated ... + graphicsCtx.transform(gc.getNormalizingTransform()); + graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale); + graphicsCtx.translate(-bbox.getX(), -bbox.getY()); + break; + case MM_TEXT: + // TODO: to be validated ... + break; + } + } } 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 06f9b03af0..4ed79ceb49 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java @@ -664,7 +664,7 @@ public class HwmfDraw { @Override public void draw(HwmfGraphics ctx) { - + ctx.applyObjectTableEntry(objectIndex); } } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java index adaf91cc44..749faa29bd 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java @@ -221,6 +221,7 @@ public class HwmfMisc { @Override public void draw(HwmfGraphics ctx) { ctx.getProperties().setMapMode(mapMode); + ctx.updateWindowMapMode(); } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java index 0823e807c6..ae403d5f13 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java @@ -17,6 +17,7 @@ package org.apache.poi.hwmf.record; +import java.awt.Color; import java.io.IOException; import org.apache.poi.hwmf.draw.HwmfGraphics; @@ -26,18 +27,58 @@ import org.apache.poi.util.LittleEndianInputStream; public class HwmfPalette { public static class PaletteEntry { + enum PaletteEntryFlag { + /** + * Specifies that the logical palette entry be used for palette animation. This value + * prevents other windows from matching colors to the palette entry because the color frequently + * changes. If an unused system-palette entry is available, the color is placed in that entry. + * Otherwise, the color is not available for animation. + */ + PC_RESERVED(0x01), + /** + * Specifies that the low-order word of the logical palette entry designates a hardware + * palette index. This value allows the application to show the contents of the display device palette. + */ + PC_EXPLICIT(0x02), + /** + * Specifies that the color be placed in an unused entry in the system palette + * instead of being matched to an existing color in the system palette. If there are no unused entries + * in the system palette, the color is matched normally. Once this color is in the system palette, + * colors in other logical palettes can be matched to this color. + */ + PC_NOCOLLAPSE(0x04) + ; + + int flag; + + PaletteEntryFlag(int flag) { + this.flag = flag; + } + + static PaletteEntryFlag valueOf(int flag) { + for (PaletteEntryFlag pef : values()) { + if (pef.flag == flag) return pef; + } + return null; + } + + } + // Values (1 byte): An 8-bit unsigned integer that defines how the palette entry is to be used. // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table. // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry. // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry. // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry. - private int values, blue, green, red; + private PaletteEntryFlag values; + private Color colorRef; public int init(LittleEndianInputStream leis) throws IOException { - values = leis.readUByte(); - blue = leis.readUByte(); - green = leis.readUByte(); - red = leis.readUByte(); + values = PaletteEntryFlag.valueOf(leis.readUByte()); + int blue = leis.readUByte(); + int green = leis.readUByte(); + int red = leis.readUByte(); + colorRef = new Color(red, green, blue); + return 4*LittleEndianConsts.BYTE_SIZE; } } @@ -57,7 +98,7 @@ public class HwmfPalette { */ private int numberOfEntries; - PaletteEntry entries[]; + private PaletteEntry entries[]; @Override public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException { diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java index 5af1ab826c..6dbde2bc4f 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java @@ -167,6 +167,7 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { ctx.getProperties().setWindowOrg(x, y); + ctx.updateWindowMapMode(); } public int getY() { @@ -211,6 +212,7 @@ public class HwmfWindowing { @Override public void draw(HwmfGraphics ctx) { ctx.getProperties().setWindowExt(width, height); + ctx.updateWindowMapMode(); } public int getHeight() { @@ -254,6 +256,7 @@ public class HwmfWindowing { public void draw(HwmfGraphics ctx) { Rectangle2D window = ctx.getProperties().getWindow(); ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset); + ctx.updateWindowMapMode(); } } @@ -307,6 +310,7 @@ public class HwmfWindowing { double width = window.getWidth() * xNum / xDenom; double height = window.getHeight() * yNum / yDenom; ctx.getProperties().setWindowExt(width, height); + ctx.updateWindowMapMode(); } } diff --git a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java index 7d953aa03a..19385d4fee 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java @@ -18,6 +18,7 @@ package org.apache.poi.hwmf.usermodel; import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.io.BufferedInputStream; import java.io.IOException; @@ -84,9 +85,14 @@ public class HwmfPicture { } public void draw(Graphics2D ctx) { - HwmfGraphics g = new HwmfGraphics(ctx, getBounds()); - for (HwmfRecord r : records) { - r.draw(g); + AffineTransform at = ctx.getTransform(); + try { + HwmfGraphics g = new HwmfGraphics(ctx, getBounds()); + for (HwmfRecord r : records) { + r.draw(g); + } + } finally { + ctx.setTransform(at); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java index 1c9f4c1a12..8d14f0c7dc 100644 --- a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java +++ b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java @@ -79,9 +79,6 @@ public class TestHwmfParsing { g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - g.scale(width/bounds.getWidth(), height/bounds.getHeight()); - g.translate(-bounds.getX(), -bounds.getY()); - wmf.draw(g); g.dispose();