git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1844522 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_1_0
@@ -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() { |
@@ -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) { |
@@ -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<Rectangle2D> 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<Rectangle2D> 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<Rectangle2D> rgnRects) { | |||
final Area frame = new Area(); | |||
rgnRects.forEach((rct) -> frame.add(new Area(rct))); | |||
return frame; | |||
} | |||
} |
@@ -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<PaletteEntry> 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()); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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<Integer> dx, boolean isUnicode) { | |||
public void drawString(byte[] text, Point2D reference, Rectangle2D clip, List<Integer> 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()) { |
@@ -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()+" } }"; | |||
} | |||
} | |||
/** |
@@ -302,6 +302,11 @@ public class HwmfMisc { | |||
public void draw(HwmfGraphics ctx) { | |||
} | |||
@Override | |||
public String toString() { | |||
return "{ drawMode: '"+drawMode+"' }"; | |||
} | |||
} | |||
/** |
@@ -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 { |
@@ -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<String> 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); | |||
} |