From: Andreas Beeker Date: Sun, 21 Oct 2018 20:49:03 +0000 (+0000) Subject: #60656 - Support export file that contains emf and render it correctly X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b0c48d163f9e008dde1508c83612c298d9bbced1;p=poi.git #60656 - Support export file that contains emf and render it correctly git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1844522 13f79535-47bb-0310-9956-ffa450edef68 --- 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 8b18be82f9..e32c451e2a 100644 --- a/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java @@ -53,6 +53,7 @@ public class HemfGraphics extends HwmfGraphics { super(graphicsCtx,bbox); // add dummy entry for object index 0, as emf is 1-based objectIndexes.set(0); + saveTransform(); } @Override @@ -82,10 +83,10 @@ public class HemfGraphics extends HwmfGraphics { if (tgt != null && !tgt.isEmpty()) { final Rectangle2D src = bounded.getShapeBounds(this); if (src != null && !src.isEmpty()) { - graphicsCtx.translate(tgt.getCenterX() - src.getCenterX(), tgt.getCenterY() - src.getCenterY()); - graphicsCtx.translate(src.getCenterX(), src.getCenterY()); - graphicsCtx.scale(tgt.getWidth() / src.getWidth(), tgt.getHeight() / src.getHeight()); - graphicsCtx.translate(-src.getCenterX(), -src.getCenterY()); +// graphicsCtx.translate(tgt.getCenterX() - src.getCenterX(), tgt.getCenterY() - src.getCenterY()); +// graphicsCtx.translate(src.getCenterX(), src.getCenterY()); +// graphicsCtx.scale(tgt.getWidth() / src.getWidth(), tgt.getHeight() / src.getHeight()); +// graphicsCtx.translate(-src.getCenterX(), -src.getCenterY()); } } } @@ -266,7 +267,27 @@ public class HemfGraphics extends HwmfGraphics { } } + /** + * @return the initial AffineTransform, when this graphics context was created + */ + public AffineTransform getInitTransform() { + return new AffineTransform(transforms.peekFirst()); + } + + /** + * @return the current AffineTransform + */ + public AffineTransform getTransform() { + return new AffineTransform(graphicsCtx.getTransform()); + } + /** + * Set the current AffineTransform + * @param tx the current AffineTransform + */ + public void setTransform(AffineTransform tx) { + graphicsCtx.setTransform(tx); + } /** saves the current affine transform on the stack */ private void saveTransform() { 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 3596462364..459a0b2ee3 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 @@ -860,6 +860,11 @@ public class HemfDraw { final HemfDrawProperties prop = ctx.getProperties(); prop.setPath(new Path2D.Double()); } + + @Override + public String toString() { + return "{}"; + } } /** @@ -876,6 +881,11 @@ public class HemfDraw { public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { return 0; } + + @Override + public String toString() { + return "{}"; + } } /** @@ -897,6 +907,11 @@ public class HemfDraw { final HemfDrawProperties prop = ctx.getProperties(); prop.setPath(null); } + + @Override + public String toString() { + return "{}"; + } } /** @@ -929,7 +944,6 @@ public class HemfDraw { return 0; } - @Override public void draw(HemfGraphics ctx) { final HemfDrawProperties prop = ctx.getProperties(); @@ -940,6 +954,11 @@ public class HemfDraw { } } + + @Override + public String toString() { + return "{}"; + } } /** @@ -972,12 +991,17 @@ public class HemfDraw { public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { return 0; } + + @Override + public String toString() { + return "{}"; + } } /** * The EMR_STROKEPATH record renders the specified path by using the current pen. */ - public static class EmfStrokePath implements HemfRecord { + public static class EmfStrokePath implements HemfRecord, HemfBounded { protected final Rectangle2D bounds = new Rectangle2D.Double(); @Override @@ -990,6 +1014,28 @@ public class HemfDraw { // A 128-bit WMF RectL object, which specifies bounding rectangle, in device units return readRectL(leis, bounds); } + + @Override + public void draw(HemfGraphics ctx) { + HemfDrawProperties props = ctx.getProperties(); + ctx.draw(props.getPath()); + } + + @Override + public Rectangle2D getRecordBounds() { + return bounds; + } + + @Override + public Rectangle2D getShapeBounds(HemfGraphics ctx) { + HemfDrawProperties props = ctx.getProperties(); + return props.getPath().getBounds2D(); + } + + @Override + public String toString() { + return "{ bounds: { x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }"; + } } static long readRectL(LittleEndianInputStream leis, Rectangle2D bounds) { 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 2b814336f2..90a91a0bd1 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 @@ -358,14 +358,12 @@ public class HemfFill { } protected Area getShape() { - final Area frame = new Area(); - rgnRects.forEach((rct) -> frame.add(new Area(rct))); - return frame; + return getRgnShape(rgnRects); } } /** The EMR_INVERTRGN record inverts the colors in the specified region. */ - public static class EmfInvertRgn implements HemfRecord { + public static class EmfInvertRgn implements HemfRecord, HemfBounded { protected final Rectangle2D bounds = new Rectangle2D.Double(); protected final List rgnRects = new ArrayList<>(); @@ -383,6 +381,20 @@ public class HemfFill { size += readRgnData(leis, rgnRects); return size; } + + @Override + public Rectangle2D getRecordBounds() { + return bounds; + } + + @Override + public Rectangle2D getShapeBounds(HemfGraphics ctx) { + return getShape().getBounds2D(); + } + + protected Area getShape() { + return getRgnShape(rgnRects); + } } /** @@ -397,7 +409,7 @@ public class HemfFill { } /** The EMR_FILLRGN record fills the specified region by using the specified brush. */ - public static class EmfFillRgn extends HwmfFill.WmfFillRegion implements HemfRecord { + public static class EmfFillRgn extends HwmfFill.WmfFillRegion implements HemfRecord, HemfBounded { protected final Rectangle2D bounds = new Rectangle2D.Double(); protected final List rgnRects = new ArrayList<>(); @@ -416,6 +428,20 @@ public class HemfFill { size += readRgnData(leis, rgnRects); return size; } + + @Override + public Rectangle2D getRecordBounds() { + return bounds; + } + + @Override + public Rectangle2D getShapeBounds(HemfGraphics ctx) { + return getShape().getBounds2D(); + } + + protected Area getShape() { + return getRgnShape(rgnRects); + } } public static class EmfExtSelectClipRgn implements HemfRecord { @@ -442,9 +468,13 @@ public class HemfFill { } return size; } + + protected Area getShape() { + return getRgnShape(rgnRects); + } } - public static class EmfAlphaBlend implements HemfRecord { + public static class EmfAlphaBlend implements HemfRecord, HemfBounded { /** the destination bounding rectangle in device units */ protected final Rectangle2D bounds = new Rectangle2D.Double(); /** the destination rectangle */ @@ -553,9 +583,24 @@ public class HemfFill { return size; } + + + @Override + public Rectangle2D getRecordBounds() { + return bounds; + } + + @Override + public Rectangle2D getShapeBounds(HemfGraphics ctx) { + return destRect; + } } - public static class EmfSetDiBitsToDevice implements HemfRecord { + /** + * The EMR_SETDIBITSTODEVICE record specifies a block transfer of pixels from specified scanlines of + * a source bitmap to a destination rectangle. + */ + public static class EmfSetDiBitsToDevice implements HemfRecord, HemfBounded { protected final Rectangle2D bounds = new Rectangle2D.Double(); protected final Point2D dest = new Point2D.Double(); protected final Rectangle2D src = new Rectangle2D.Double(); @@ -600,6 +645,16 @@ public class HemfFill { return size; } + + @Override + public Rectangle2D getRecordBounds() { + return bounds; + } + + @Override + public Rectangle2D getShapeBounds(HemfGraphics ctx) { + return new Rectangle2D.Double(dest.getX(), dest.getY(), src.getWidth(), src.getHeight()); + } } static long readBitmap(final LittleEndianInputStream leis, final HwmfBitmapDib bitmap, @@ -759,4 +814,10 @@ public class HemfFill { } } } + + protected static Area getRgnShape(List rgnRects) { + final Area frame = new Area(); + rgnRects.forEach((rct) -> frame.add(new Area(rct))); + return frame; + } } 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 ade921d200..e9ca805fd3 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 @@ -29,6 +29,8 @@ import java.util.ArrayList; import java.util.List; import org.apache.poi.hemf.draw.HemfGraphics; +import org.apache.poi.hwmf.draw.HwmfDrawProperties; +import org.apache.poi.hwmf.draw.HwmfGraphics; import org.apache.poi.hwmf.record.HwmfBinaryRasterOp; import org.apache.poi.hwmf.record.HwmfBitmapDib; import org.apache.poi.hwmf.record.HwmfBrushStyle; @@ -45,6 +47,44 @@ import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianInputStream; public class HemfMisc { + + public enum HemfModifyWorldTransformMode { + /** + * Reset the current transform using the identity matrix. + * In this mode, the specified transform data is ignored. + */ + MWT_IDENTITY(1), + /** + * Multiply the current transform. In this mode, the specified transform data is the left multiplicand, + * and the transform that is currently defined in the playback device context is the right multiplicand. + */ + MWT_LEFTMULTIPLY(2), + /** + * Multiply the current transform. In this mode, the specified transform data is the right multiplicand, + * and the transform that is currently defined in the playback device context is the left multiplicand. + */ + MWT_RIGHTMULTIPLY(3), + /** + * Perform the function of an EMR_SETWORLDTRANSFORM record + */ + MWT_SET(4) + ; + + public final int id; + + HemfModifyWorldTransformMode(int id) { + this.id = id; + } + + public static HemfModifyWorldTransformMode valueOf(int id) { + for (HemfModifyWorldTransformMode wrt : values()) { + if (wrt.id == id) return wrt; + } + return null; + } + } + + public static class EmfEof implements HemfRecord { protected final List palette = new ArrayList<>(); @@ -518,6 +558,11 @@ public class HemfMisc { public void draw(HemfGraphics ctx) { ctx.getProperties().setPenMiterLimit(miterLimit); } + + @Override + public String toString() { + return "{ miterLimit: "+miterLimit+" }"; + } } @@ -552,11 +597,30 @@ public class HemfMisc { public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException { return readXForm(leis, xForm); } + + @Override + public void draw(HemfGraphics ctx) { + AffineTransform tx = ctx.getInitTransform(); + tx.concatenate(xForm); + ctx.setTransform(tx); + } + + @Override + public String toString() { + return + "{ xForm: " + + "{ scaleX: "+xForm.getScaleX()+ + ", shearX: "+xForm.getShearX()+ + ", transX: "+xForm.getTranslateX()+ + ", scaleY: "+xForm.getScaleY()+ + ", shearY: "+xForm.getShearY()+ + ", transY: "+xForm.getTranslateY()+" } }"; + } } public static class EmfModifyWorldTransform implements HemfRecord { protected final AffineTransform xForm = new AffineTransform(); - protected int modifyWorldTransformMode; + protected HemfModifyWorldTransformMode modifyWorldTransformMode; @Override public HemfRecordType getEmfRecordType() { @@ -572,16 +636,54 @@ public class HemfMisc { // A 32-bit unsigned integer that specifies how the transform specified in Xform is used. // This value MUST be in the ModifyWorldTransformMode enumeration - modifyWorldTransformMode = (int)leis.readUInt(); + modifyWorldTransformMode = HemfModifyWorldTransformMode.valueOf((int)leis.readUInt()); return size + LittleEndianConsts.INT_SIZE; } + @Override + public void draw(HemfGraphics ctx) { + if (modifyWorldTransformMode == null) { + return; + } + + switch (modifyWorldTransformMode) { + case MWT_IDENTITY: + ctx.setTransform(ctx.getInitTransform()); + break; + case MWT_LEFTMULTIPLY: { + AffineTransform tx = new AffineTransform(xForm); + tx.concatenate(ctx.getTransform()); + ctx.setTransform(tx); + break; + } + case MWT_RIGHTMULTIPLY: { + AffineTransform tx = new AffineTransform(xForm); + tx.preConcatenate(ctx.getTransform()); + ctx.setTransform(tx); + break; + } + default: + case MWT_SET: { + AffineTransform tx = ctx.getInitTransform(); + tx.concatenate(xForm); + ctx.setTransform(tx); + break; + } + } + } + @Override public String toString() { return - "{ xForm: { scaleX: "+xForm.getScaleX()+", shearX: "+xForm.getShearX()+", transX: "+xForm.getTranslateX()+", scaleY: "+xForm.getScaleY()+", shearY: "+xForm.getShearY()+", transY: "+xForm.getTranslateY()+" }"+ - ", modifyWorldTransformMode: "+modifyWorldTransformMode+" }"; + "{ xForm: " + + "{ scaleX: "+xForm.getScaleX()+ + ", shearX: "+xForm.getShearX()+ + ", transX: "+xForm.getTranslateX()+ + ", scaleY: "+xForm.getScaleY()+ + ", shearY: "+xForm.getShearY()+ + ", transY: "+xForm.getTranslateY()+" }"+ + ", modifyWorldTransformMode: '"+modifyWorldTransformMode+"' }"; } } @@ -626,5 +728,13 @@ public class HemfMisc { return size; } + + @Override + public void applyObject(HwmfGraphics ctx) { + super.applyObject(ctx); + HwmfDrawProperties props = ctx.getProperties(); + props.setBrushStyle(HwmfBrushStyle.BS_PATTERN); + props.setBrushBitmap(bitmap.getImage()); + } } } 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 6b2f9a6d26..97a81d9102 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 @@ -57,6 +57,7 @@ public class HemfText { public static class EmfExtTextOutA extends HwmfText.WmfExtTextOut implements HemfRecord { + protected Rectangle2D boundsIgnored = new Rectangle2D.Double(); protected EmfGraphicsMode graphicsMode; /** @@ -81,7 +82,7 @@ public class HemfText { } // A WMF RectL object. It is not used and MUST be ignored on receipt. - long size = readRectL(leis, bounds); + long size = readRectL(leis, boundsIgnored); // A 32-bit unsigned integer that specifies the graphics mode from the GraphicsMode enumeration graphicsMode = EmfGraphicsMode.values()[leis.readInt()-1]; @@ -192,8 +193,7 @@ public class HemfText { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D bounds = new Rectangle2D.Double(reference.getX(), reference.getY(), 0, 0); - ctx.drawString(rawTextBytes, bounds, dx, isUnicode()); + ctx.drawString(rawTextBytes, reference, bounds, dx, isUnicode()); } @Override 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 dff46ce863..7a325dc0a0 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java @@ -25,8 +25,11 @@ import java.awt.Paint; import java.awt.Rectangle; import java.awt.Shape; import java.awt.TexturePaint; +import java.awt.font.FontRenderContext; import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.nio.charset.Charset; @@ -47,6 +50,7 @@ import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode; import org.apache.poi.hwmf.record.HwmfObjectTableEntry; import org.apache.poi.hwmf.record.HwmfPenStyle; import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash; +import org.apache.poi.hwmf.record.HwmfText; import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFontManager; import org.apache.poi.util.LocaleUtil; @@ -327,11 +331,11 @@ public class HwmfGraphics { } } - public void drawString(byte[] text, Rectangle2D bounds) { - drawString(text, bounds, null, false); + public void drawString(byte[] text, Point2D reference, Rectangle2D clip) { + drawString(text, reference, clip, null, false); } - public void drawString(byte[] text, Rectangle2D bounds, List dx, boolean isUnicode) { + public void drawString(byte[] text, Point2D reference, Rectangle2D clip, List dx, boolean isUnicode) { HwmfFont font = getProperties().getFont(); if (font == null || text == null || text.length == 0) { @@ -396,18 +400,55 @@ public class HwmfGraphics { } } */ - + double angle = Math.toRadians(-font.getEscapement()/10.); + final HwmfText.HwmfTextAlignment align = prop.getTextAlignLatin(); + final HwmfText.HwmfTextVerticalAlignment valign = prop.getTextVAlignLatin(); + final FontRenderContext frc = graphicsCtx.getFontRenderContext(); + final TextLayout layout = new TextLayout(as.getIterator(), frc); + + final Rectangle2D pixelBounds = layout.getBounds(); + + AffineTransform tx = new AffineTransform(); + switch (align) { + default: + case LEFT: + break; + case CENTER: + tx.translate(-pixelBounds.getWidth() / 2., 0); + break; + case RIGHT: + tx.translate(-pixelBounds.getWidth(), 0); + break; + } + + // TODO: check min/max orientation + switch (valign) { + case TOP: + tx.translate(0, layout.getAscent()); + default: + case BASELINE: + break; + case BOTTOM: + tx.translate(0, pixelBounds.getHeight()); + break; + } + tx.rotate(angle); + Point2D src = new Point2D.Double(); + Point2D dst = new Point2D.Double(); + tx.transform(src, dst); + + // TODO: implement clipping on bounds final AffineTransform at = graphicsCtx.getTransform(); try { - graphicsCtx.translate(bounds.getX(), bounds.getY()); + graphicsCtx.translate(reference.getX(), reference.getY()); graphicsCtx.rotate(angle); - graphicsCtx.translate(0, fontH); - if (getProperties().getBkMode() == HwmfBkMode.OPAQUE) { + graphicsCtx.translate(dst.getX(), dst.getY()); + if (getProperties().getBkMode() == HwmfBkMode.OPAQUE && clip != null) { // TODO: validate bounds graphicsCtx.setBackground(getProperties().getBackgroundColor().getColor()); - graphicsCtx.fill(new Rectangle2D.Double(0, 0, bounds.getWidth(), bounds.getHeight())); + graphicsCtx.fill(new Rectangle2D.Double(0, 0, clip.getWidth(), clip.getHeight())); } graphicsCtx.setColor(getProperties().getTextColor().getColor()); graphicsCtx.drawString(as.getIterator(), 0, 0); @@ -415,11 +456,11 @@ public class HwmfGraphics { graphicsCtx.setTransform(at); } } - + private void addAttributes(AttributedString as, HwmfFont font) { DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx); FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font); - + as.addAttribute(TextAttribute.FAMILY, fontInfo.getTypeface()); as.addAttribute(TextAttribute.SIZE, getFontHeight(font)); if (font.isStrikeOut()) { 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 64f2dae8c9..b4e7ba73ed 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java @@ -374,6 +374,16 @@ public class HwmfDraw { public void draw(HwmfGraphics ctx) { ctx.fill(bounds); } + + @Override + public String toString() { + return + "{ bounds: " + + "{ x: "+bounds.getX()+ + ", y: "+bounds.getY()+ + ", w: "+bounds.getWidth()+ + ", h: "+bounds.getHeight()+" } }"; + } } /** 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 7bc46795bb..7197674ffa 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java @@ -302,6 +302,11 @@ public class HwmfMisc { public void draw(HwmfGraphics ctx) { } + + @Override + public String toString() { + return "{ drawMode: '"+drawMode+"' }"; + } } /** diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java index fb45170d22..a0b240d048 100644 --- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java @@ -164,17 +164,9 @@ public class HwmfText { * The string is written at the location specified by the XStart and YStart fields. */ private byte[] rawTextBytes; - /** - * A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical - * units, of the point where drawing is to start. - */ - private int yStart; - /** - * A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in - * logical units, of the point where drawing is to start. - */ - private int xStart; - + + protected Point2D reference = new Point2D.Double(); + @Override public HwmfRecordType getWmfRecordType() { return HwmfRecordType.textOut; @@ -185,15 +177,19 @@ public class HwmfText { stringLength = leis.readShort(); rawTextBytes = IOUtils.safelyAllocate(stringLength+(stringLength&1), MAX_RECORD_LENGTH); leis.readFully(rawTextBytes); - yStart = leis.readShort(); - xStart = leis.readShort(); + // A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical + // units, of the point where drawing is to start. + int yStart = leis.readShort(); + // A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in + // logical units, of the point where drawing is to start. + int xStart = leis.readShort(); + reference.setLocation(xStart, yStart); return 3*LittleEndianConsts.SHORT_SIZE+rawTextBytes.length; } @Override public void draw(HwmfGraphics ctx) { - Rectangle2D bounds = new Rectangle2D.Double(xStart, yStart, 0, 0); - ctx.drawString(getTextBytes(), bounds); + ctx.drawString(getTextBytes(), reference, null); } public String getText(Charset charset) { @@ -398,8 +394,7 @@ public class HwmfText { @Override public void draw(HwmfGraphics ctx) { - Rectangle2D bounds = new Rectangle2D.Double(reference.getX(), reference.getY(), 0, 0); - ctx.drawString(rawTextBytes, bounds, dx, false); + ctx.drawString(rawTextBytes, reference, bounds, dx, false); } public String getText(Charset charset) throws IOException { diff --git a/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java b/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java index 94be4712e5..cabe627f66 100644 --- a/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java +++ b/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java @@ -63,7 +63,8 @@ public class HemfPictureTest { public void paint() throws IOException { byte buf[] = new byte[50_000_000]; - final boolean writeLog = true; + final boolean writeLog = false; + final boolean dumpRecords = false; final boolean savePng = true; Set passed = new HashSet<>(); @@ -101,6 +102,10 @@ public class HemfPictureTest { } } + if (dumpRecords) { + dumpRecords(emf); + } + Graphics2D g = null; try { Dimension2D dim = emf.getSize(); @@ -112,17 +117,23 @@ public class HemfPictureTest { width *= 1500. / max; height *= 1500. / max; } + width = Math.ceil(width); + height = Math.ceil(height); - BufferedImage bufImg = new BufferedImage((int)Math.ceil(width), (int)Math.ceil(height), BufferedImage.TYPE_INT_ARGB); + BufferedImage bufImg = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB); g = bufImg.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + g.setComposite(AlphaComposite.Clear); + g.fillRect(0, 0, (int)width, (int)height); + g.setComposite(AlphaComposite.Src); + emf.draw(g, new Rectangle2D.Double(0, 0, width, height)); - final File pngName = new File("build/tmp", etName.replaceFirst(".*"+"/", "").replace(".emf", ".png")); + final File pngName = new File("build/tmp", etName.replaceFirst(".+/", "").replace(".emf", ".png")); if (savePng) { ImageIO.write(bufImg, "PNG", pngName); }