#60656 - Support export file that contains emf and render it correctly

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1846472 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2018-11-12 23:21:18 +00:00
parent 0e68ef5f84
commit 940daf0d92
13 changed files with 286 additions and 125 deletions

View File

@ -22,6 +22,8 @@ package org.apache.poi.sl.draw;
import java.awt.Font;
import java.awt.Graphics2D;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.poi.common.usermodel.fonts.FontInfo;
import org.apache.poi.sl.draw.Drawable.DrawableHint;
@ -33,6 +35,13 @@ import org.apache.poi.sl.draw.Drawable.DrawableHint;
*/
public class DrawFontManagerDefault implements DrawFontManager {
protected final Set<String> knownSymbolFonts = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
public DrawFontManagerDefault() {
knownSymbolFonts.add("Wingdings");
knownSymbolFonts.add("Symbol");
}
@Override
public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) {
return getFontWithFallback(graphics, Drawable.FONT_MAP, fontInfo);
@ -49,25 +58,35 @@ public class DrawFontManagerDefault implements DrawFontManager {
public String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, String text) {
// TODO: find a real charset mapping solution instead of hard coding for Wingdings
String attStr = text;
if (fontInfo != null && "Wingdings".equalsIgnoreCase(fontInfo.getTypeface())) {
// wingdings doesn't contain high-surrogates, so chars are ok
boolean changed = false;
char chrs[] = attStr.toCharArray();
for (int i=0; i<chrs.length; i++) {
// only change valid chars
if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) ||
(0xa0 <= chrs[i] && chrs[i] <= 0xff)) {
chrs[i] |= 0xf000;
changed = true;
}
}
return (fontInfo != null && knownSymbolFonts.contains(fontInfo.getTypeface()))
? mapSymbolChars(text)
: text;
}
if (changed) {
attStr = new String(chrs);
/**
* Symbol fonts like "Wingdings" or "Symbol" have glyphs mapped to a Unicode private use range via the Java font loader,
* although a system font viewer might show you the glyphs in the ASCII range.
* This helper function maps the chars of the text string to the corresponding private use range chars.
*
* @param text the input string, typically consists of ASCII chars
* @return the mapped string, typically consists of chars in the range of 0xf000 to 0xf0ff
*
* @since POI 4.0.0
*/
public static String mapSymbolChars(String text) {
// wingdings doesn't contain high-surrogates, so chars are ok
boolean changed = false;
char chrs[] = text.toCharArray();
for (int i=0; i<chrs.length; i++) {
// only change valid chars
if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) ||
(0xa0 <= chrs[i] && chrs[i] <= 0xff)) {
chrs[i] |= 0xf000;
changed = true;
}
}
return attStr;
return changed ? new String(chrs) : text;
}
@Override

View File

@ -138,20 +138,18 @@ public class HemfDraw {
Point2D pnt[] = { new Point2D.Double(), new Point2D.Double(), new Point2D.Double() };
// points-1 because of the first point
final int pointCnt = hasStartPoint() ? points-2 : points;
for (int i=0; i+2<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) {
if (hasStartPoint()) {
size += readPoint(leis, pnt[0]);
poly.moveTo(pnt[0].getX(), pnt[0].getY());
} else {
poly.moveTo(0, 0);
}
int i=0;
if (hasStartPoint()) {
if (i < points) {
size += readPoint(leis, pnt[0]);
poly.moveTo(pnt[0].getX(), pnt[0].getY());
i++;
}
} else {
poly.moveTo(0, 0);
}
for (; i+2<points; i+=3) {
size += readPoint(leis, pnt[0]);
size += readPoint(leis, pnt[1]);
size += readPoint(leis, pnt[2]);
@ -758,7 +756,8 @@ public class HemfDraw {
size += LittleEndianConsts.INT_SIZE;
Point2D points[] = new Point2D[count];
for (int i=0; i<count; i++) {
size += readPoint(leis, points[i]);
points[i] = new Point2D.Double();
size += readPoint(leis, points[i]);
}
poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, count);
@ -783,12 +782,14 @@ public class HemfDraw {
case 0x04:
int mode2 = leis.readUByte();
int mode3 = leis.readUByte();
assert(mode2 == 0x04 && mode3 == 0x04);
assert(mode2 == 0x04 && (mode3 == 0x04 || mode3 == 0x05));
poly.curveTo(
points[i].getX(), points[i].getY(),
points[i+1].getX(), points[i+1].getY(),
points[i+2].getX(), points[i+2].getY()
);
// update mode for closePath handling below
mode = mode3;
i+=2;
break;
// PT_MOVETO

View File

@ -683,33 +683,27 @@ public class HemfFill {
}
static int readXForm(LittleEndianInputStream leis, AffineTransform xform) {
// mapping <java AffineTransform> = <xform>:
// mapping <java AffineTransform> = <xform>
// m00 (scaleX) = eM11 (Horizontal scaling component)
// m11 (scaleY) = eM22 (Vertical scaling component)
double m00 = leis.readFloat();
// m01 (shearX) = eM12 (Horizontal proportionality constant)
double m01 = leis.readFloat();
// m10 (shearY) = eM21 (Vertical proportionality constant)
double m10 = leis.readFloat();
// m11 (scaleY) = eM22 (Vertical scaling component)
double m11 = leis.readFloat();
// m02 (translateX) = eDx (The horizontal translation component, in logical units.)
double m02 = leis.readFloat();
// m12 (translateY) = eDy (The vertical translation component, in logical units.)
double m12 = leis.readFloat();
// A 32-bit floating-point value of the transform matrix.
double eM11 = leis.readFloat();
// A 32-bit floating-point value of the transform matrix.
double eM12 = leis.readFloat();
// A 32-bit floating-point value of the transform matrix.
double eM21 = leis.readFloat();
// A 32-bit floating-point value of the transform matrix.
double eM22 = leis.readFloat();
// A 32-bit floating-point value that contains a horizontal translation component, in logical units.
double eDx = leis.readFloat();
// A 32-bit floating-point value that contains a vertical translation component, in logical units.
double eDy = leis.readFloat();
xform.setTransform(eM11, eM21, eM12, eM22, eDx, eDy);
xform.setTransform(m00, m10, m01, m11, m02, m12);
return 6 * LittleEndian.INT_SIZE;
}

View File

@ -273,15 +273,15 @@ public class HemfFont extends HwmfFont {
// An 8-bit unsigned integer that specifies an italic font if set to 0x01;
// otherwise, it MUST be set to 0x00.
italic = (leis.readUByte() == 0x01);
italic = (leis.readUByte() != 0x00);
// An 8-bit unsigned integer that specifies an underlined font if set to 0x01;
// otherwise, it MUST be set to 0x00.
underline = (leis.readUByte() == 0x01);
underline = (leis.readUByte() != 0x00);
// An 8-bit unsigned integer that specifies a strikeout font if set to 0x01;
// otherwise, it MUST be set to 0x00.
strikeOut = (leis.readUByte() == 0x01);
strikeOut = (leis.readUByte() != 0x00);
// An 8-bit unsigned integer that specifies the set of character glyphs.
// It MUST be a value in the WMF CharacterSet enumeration.
@ -441,7 +441,8 @@ public class HemfFont extends HwmfFont {
// A 32-bit unsigned integer that MUST be set to the value 0x08007664.
int signature = leis.readInt();
assert (signature == 0x08007664);
// some non-conformant applications don't write the magic code in
// assert (signature == 0x08007664);
// A 32-bit unsigned integer that specifies the number of elements in the
// Values array. It MUST be in the range 0 to 16, inclusive.

View File

@ -27,7 +27,9 @@ import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
@ -443,8 +445,6 @@ public class HemfMisc {
protected HwmfBrushStyle brushStyle;
protected HwmfHatchStyle hatchStyle;
protected int[] styleEntry;
protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
@ -477,7 +477,8 @@ public class HemfMisc {
// A 32-bit unsigned integer that specifies the PenStyle.
// The value MUST be defined from the PenStyle enumeration table
penStyle = HwmfPenStyle.valueOf((int) leis.readUInt());
final HemfPenStyle emfPS = HemfPenStyle.valueOf((int) leis.readUInt());
penStyle = emfPS;
// A 32-bit unsigned integer that specifies the width of the line drawn by the pen.
// If the pen type in the PenStyle field is PS_GEOMETRIC, this value is the width in logical
@ -517,10 +518,14 @@ public class HemfMisc {
// If the pen type in the PenStyle field is PS_GEOMETRIC, the lengths are specified in logical
// units; otherwise, the lengths are specified in device units.
styleEntry = new int[numStyleEntries];
float[] dashPattern = new float[numStyleEntries];
for (int i = 0; i < numStyleEntries; i++) {
styleEntry[i] = (int) leis.readUInt();
dashPattern[i] = (int) leis.readUInt();
}
if (penStyle.getLineDash() == HwmfLineDash.USERSTYLE) {
emfPS.setLineDashes(dashPattern);
}
size += numStyleEntries * LittleEndianConsts.INT_SIZE;
@ -533,8 +538,11 @@ public class HemfMisc {
@Override
public String toString() {
// TODO: add style entries + bmp
return super.toString().replaceFirst("\\{",
"{ brushStyle: '"+brushStyle+"', hatchStyle: '"+hatchStyle+"', ");
return
"{ brushStyle: '"+brushStyle+"'"+
", hatchStyle: '"+hatchStyle+"'"+
", dashPattern: "+ Arrays.toString(penStyle.getLineDashes())+
", "+super.toString().substring(1);
}
}
@ -602,7 +610,8 @@ public class HemfMisc {
@Override
public void draw(HemfGraphics ctx) {
AffineTransform tx = ctx.getInitTransform();
ctx.updateWindowMapMode();
AffineTransform tx = ctx.getTransform();
tx.concatenate(xForm);
ctx.setTransform(tx);
}
@ -649,30 +658,46 @@ public class HemfMisc {
return;
}
final AffineTransform tx;
switch (modifyWorldTransformMode) {
case MWT_LEFTMULTIPLY:
tx = ctx.getTransform();
tx.concatenate(adaptXForm(tx));
break;
case MWT_RIGHTMULTIPLY:
tx = ctx.getTransform();
tx.preConcatenate(adaptXForm(tx));
break;
case MWT_IDENTITY:
ctx.setTransform(ctx.getInitTransform());
ctx.updateWindowMapMode();
tx = ctx.getTransform();
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);
case MWT_SET:
ctx.updateWindowMapMode();
tx = ctx.getTransform();
tx.concatenate(adaptXForm(tx));
break;
}
}
ctx.setTransform(tx);
}
/**
* adapt xform depending on the base transformation (... experimental ...)
*/
private AffineTransform adaptXForm(AffineTransform other) {
// normalize signed zero
Function<Double,Double> nn = (d) -> (d == 0. ? 0. : d);
double yDiff = Math.signum(nn.apply(xForm.getTranslateY())) == Math.signum(nn.apply(other.getTranslateY())) ? 1. : -1.;
double xDiff = Math.signum(nn.apply(xForm.getTranslateX())) == Math.signum(nn.apply(other.getTranslateX())) ? 1. : -1.;
return new AffineTransform(
xForm.getScaleX() == 0 ? 1. : xForm.getScaleX(),
yDiff * xForm.getShearY(),
xDiff * xForm.getShearX(),
xForm.getScaleY() == 0. ? 1. : xForm.getScaleY(),
xForm.getTranslateX(),
xForm.getTranslateY()
);
}
@Override

View File

@ -0,0 +1,45 @@
/* ====================================================================
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 org.apache.poi.hwmf.record.HwmfPenStyle;
public class HemfPenStyle extends HwmfPenStyle {
private float[] dashPattern;
public static HemfPenStyle valueOf(int flag) {
HemfPenStyle ps = new HemfPenStyle();
ps.flag = flag;
return ps;
}
@Override
public float[] getLineDashes() {
return (getLineDash() == HwmfLineDash.USERSTYLE) ? dashPattern : super.getLineDashes();
}
public void setLineDashes(float[] dashPattern) {
this.dashPattern = (dashPattern == null) ? null : dashPattern.clone();
}
@Override
public HemfPenStyle clone() {
return (HemfPenStyle)super.clone();
}
}

View File

@ -43,6 +43,10 @@ public interface HemfRecord {
*/
long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException;
/**
* Draws the record, the default redirects to the parent WMF record drawing
* @param ctx the drawing context
*/
default void draw(HemfGraphics ctx) {
if (this instanceof HwmfRecord) {
((HwmfRecord) this).draw(ctx);

View File

@ -54,6 +54,8 @@ public class HemfRecordIterator implements Iterator<HemfRecord> {
return null;
}
final int readIndex = stream.getReadIndex();
final long recordId, recordSize;
try {
recordId = stream.readUInt();
@ -65,7 +67,7 @@ public class HemfRecordIterator implements Iterator<HemfRecord> {
HemfRecordType type = HemfRecordType.getById(recordId);
if (type == null) {
throw new RecordFormatException("Undefined record of type:"+recordId);
throw new RecordFormatException("Undefined record of type: "+recordId+" at "+Integer.toHexString(readIndex));
}
final HemfRecord record = type.constructor.get();

View File

@ -141,14 +141,12 @@ public class HemfText {
dx.add((int) leis.readUInt());
size += LittleEndianConsts.INT_SIZE;
}
} else {
// if there are no dx entries, reset the string end
strEnd = (int)recordSize;
}
if (dx.size() < stringLength) {
// invalid dx array
dx.clear();
}
strEnd = (int)recordSize;
break;
}
default:

View File

@ -31,6 +31,7 @@ import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Dimension2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
@ -43,6 +44,7 @@ import java.util.NoSuchElementException;
import java.util.TreeMap;
import org.apache.commons.codec.Charsets;
import org.apache.poi.common.usermodel.fonts.FontCharset;
import org.apache.poi.common.usermodel.fonts.FontInfo;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfFont;
@ -57,6 +59,7 @@ import org.apache.poi.hwmf.record.HwmfText;
import org.apache.poi.hwmf.record.HwmfText.WmfExtTextOutOptions;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawFontManager;
import org.apache.poi.sl.draw.DrawFontManagerDefault;
import org.apache.poi.util.LocaleUtil;
public class HwmfGraphics {
@ -152,7 +155,7 @@ public class HwmfGraphics {
int cap = ps.getLineCap().awtFlag;
int join = ps.getLineJoin().awtFlag;
float miterLimit = (float)getProperties().getPenMiterLimit();
float dashes[] = ps.getLineDash().dashes;
float dashes[] = ps.getLineDashes();
boolean dashAlt = ps.isAlternateDash();
// This value is not an integer index into the dash pattern array.
// Instead, it is a floating-point value that specifies a linear distance.
@ -370,6 +373,17 @@ public class HwmfGraphics {
public void drawString(byte[] text, int length, Point2D reference, Dimension2D scale, Rectangle2D clip, WmfExtTextOutOptions opts, List<Integer> dx, boolean isUnicode) {
final HwmfDrawProperties prop = getProperties();
final AffineTransform at = graphicsCtx.getTransform();
if (at.getScaleX() == 0. || at.getScaleY() == 0.) {
return;
}
try {
at.createInverse();
} catch (NoninvertibleTransformException e) {
return;
}
HwmfFont font = prop.getFont();
if (font == null || text == null || text.length == 0) {
return;
@ -390,11 +404,19 @@ public class HwmfGraphics {
}
String textString = new String(text, charset).substring(0,length).trim();
if (textString.isEmpty()) {
return;
}
DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx);
FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font);
if (fontInfo.getCharset() == FontCharset.SYMBOL) {
textString = DrawFontManagerDefault.mapSymbolChars(textString);
}
AttributedString as = new AttributedString(textString);
addAttributes(as, font);
addAttributes(as, font, fontInfo.getTypeface());
// disabled for the time being, as the results aren't promising
/*
@ -473,7 +495,6 @@ public class HwmfGraphics {
tx.transform(src, dst);
final Shape clipShape = graphicsCtx.getClip();
final AffineTransform at = graphicsCtx.getTransform();
try {
if (clip != null) {
graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY());
@ -503,11 +524,8 @@ public class HwmfGraphics {
}
}
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());
private void addAttributes(AttributedString as, HwmfFont font, String typeface) {
as.addAttribute(TextAttribute.FAMILY, typeface);
as.addAttribute(TextAttribute.SIZE, getFontHeight(font));
if (font.isStrikeOut()) {
as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
@ -669,4 +687,11 @@ public class HwmfGraphics {
graphicsCtx.setTransform(at);
}
}
/**
* @return the bounding box
*/
public Rectangle2D getBbox() {
return (Rectangle2D)bbox.clone();
}
}

View File

@ -499,8 +499,8 @@ public class HwmfFill {
if (bitmap.isValid()) {
ctx.drawImage(getImage(), srcBounds, dstBounds);
} else if (!dstBounds.isEmpty()) {
BufferedImage bi = new BufferedImage((int)dstBounds.getWidth(), (int)dstBounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
ctx.drawImage(bi, dstBounds, dstBounds);
BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
ctx.drawImage(bi, new Rectangle2D.Double(0,0,100,100), dstBounds);
}
}

View File

@ -142,7 +142,7 @@ public class HwmfPenStyle implements Cloneable {
private static final BitField SUBSECTION_JOIN = BitFieldFactory.getInstance(0x03000);
private static final BitField SUBSECTION_GEOMETRIC = BitFieldFactory.getInstance(0x10000);
private int flag;
protected int flag;
public static HwmfPenStyle valueOf(int flag) {
HwmfPenStyle ps = new HwmfPenStyle();
@ -161,7 +161,16 @@ public class HwmfPenStyle implements Cloneable {
public HwmfLineDash getLineDash() {
return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag));
}
/**
* Convienence method which should be used instead of accessing {@link HwmfLineDash#dashes}
* directly, so an subclass can provide user-style dashes
*
* @return the dash pattern
*/
public float[] getLineDashes() {
return getLineDash().dashes;
}
/**
* The pen sets every other pixel (this style is applicable only for cosmetic pens).

View File

@ -18,6 +18,7 @@
package org.apache.poi.hwmf.record;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.dimToString;
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
@ -30,6 +31,7 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.LittleEndianConsts;
@ -56,8 +58,14 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
ctx.getProperties().setViewportOrg(origin.getX(), origin.getY());
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D old = prop.getViewport();
double oldX = (old == null ? 0 : old.getX());
double oldY = (old == null ? 0 : old.getY());
if (oldX != origin.getX() || oldY != origin.getY()) {
prop.setViewportOrg(origin.getX(), origin.getY());
ctx.updateWindowMapMode();
}
}
@Override
@ -91,13 +99,19 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
ctx.getProperties().setViewportExt(extents.getWidth(), extents.getHeight());
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D old = prop.getViewport();
double oldW = (old == null ? 0 : old.getWidth());
double oldH = (old == null ? 0 : old.getHeight());
if (oldW != extents.getWidth() || oldH != extents.getHeight()) {
prop.setViewportExt(extents.getWidth(), extents.getHeight());
ctx.updateWindowMapMode();
}
}
@Override
public String toString() {
return "{ width: "+extents.getWidth()+", height: "+extents.getHeight()+" }";
return dimToString(extents);
}
}
@ -121,10 +135,14 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
Rectangle2D viewport = ctx.getProperties().getViewport();
double x = (viewport == null) ? 0 : viewport.getX();
double y = (viewport == null) ? 0 : viewport.getY();
ctx.getProperties().setViewportOrg(x+offset.getX(), y+offset.getY());
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D viewport = prop.getViewport();
if (offset.getX() != 0 || offset.getY() != 0) {
double x = (viewport == null) ? 0 : viewport.getX();
double y = (viewport == null) ? 0 : viewport.getY();
prop.setViewportOrg(x + offset.getX(), y + offset.getY());
ctx.updateWindowMapMode();
}
}
@Override
@ -152,8 +170,14 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
ctx.getProperties().setWindowOrg(getX(), getY());
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
final Rectangle2D old = prop.getWindow();
double oldX = (old == null ? 0 : old.getX());
double oldY = (old == null ? 0 : old.getY());
if (oldX != getX() || oldY != getY()) {
prop.setWindowOrg(getX(), getY());
ctx.updateWindowMapMode();
}
}
public double getY() {
@ -195,8 +219,14 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
ctx.getProperties().setWindowExt(size.getWidth(), size.getHeight());
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D old = prop.getWindow();
double oldW = (old == null ? 0 : old.getWidth());
double oldH = (old == null ? 0 : old.getHeight());
if (oldW != size.getWidth() || oldH != size.getHeight()) {
prop.setWindowExt(size.getWidth(), size.getHeight());
ctx.updateWindowMapMode();
}
}
public Dimension2D getSize() {
@ -205,7 +235,7 @@ public class HwmfWindowing {
@Override
public String toString() {
return "{ width: "+size.getWidth()+", height: "+size.getHeight()+" }";
return dimToString(size);
}
}
@ -229,9 +259,12 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
Rectangle2D window = ctx.getProperties().getWindow();
ctx.getProperties().setWindowOrg(window.getX()+offset.getX(), window.getY()+offset.getY());
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D old = prop.getWindow();
if (offset.getX() != 0 || offset.getY() != 0) {
prop.setWindowOrg(old.getX() + offset.getX(), old.getY() + offset.getY());
ctx.updateWindowMapMode();
}
}
@Override
@ -275,11 +308,14 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
Rectangle2D window = ctx.getProperties().getWindow();
double width = window.getWidth() * scale.getWidth();
double height = window.getHeight() * scale.getHeight();
ctx.getProperties().setWindowExt(width, height);
ctx.updateWindowMapMode();
final HwmfDrawProperties prop = ctx.getProperties();
Rectangle2D old = prop.getWindow();
if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) {
double width = old.getWidth() * scale.getWidth();
double height = old.getHeight() * scale.getHeight();
ctx.getProperties().setWindowExt(width, height);
ctx.updateWindowMapMode();
}
}
@Override
@ -325,13 +361,15 @@ public class HwmfWindowing {
@Override
public void draw(HwmfGraphics ctx) {
Rectangle2D viewport = ctx.getProperties().getViewport();
if (viewport == null) {
viewport = ctx.getProperties().getWindow();
final HwmfDrawProperties prop = ctx.getProperties();
final Rectangle2D old = prop.getViewport() == null ? prop.getWindow() : prop.getViewport();
if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) {
double width = old.getWidth() * scale.getWidth();
double height = old.getHeight() * scale.getHeight();
prop.setViewportExt(width, height);
ctx.updateWindowMapMode();
}
double width = viewport.getWidth() * scale.getWidth();
double height = viewport.getHeight() * scale.getHeight();
ctx.getProperties().setViewportExt(width, height);
}
@Override