mirror of https://github.com/apache/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@1846472 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0e68ef5f84
commit
940daf0d92
|
@ -22,6 +22,8 @@ package org.apache.poi.sl.draw;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||||
import org.apache.poi.sl.draw.Drawable.DrawableHint;
|
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 {
|
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
|
@Override
|
||||||
public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) {
|
public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) {
|
||||||
return getFontWithFallback(graphics, Drawable.FONT_MAP, 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) {
|
public String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, String text) {
|
||||||
// TODO: find a real charset mapping solution instead of hard coding for Wingdings
|
// TODO: find a real charset mapping solution instead of hard coding for Wingdings
|
||||||
String attStr = text;
|
return (fontInfo != null && knownSymbolFonts.contains(fontInfo.getTypeface()))
|
||||||
if (fontInfo != null && "Wingdings".equalsIgnoreCase(fontInfo.getTypeface())) {
|
? mapSymbolChars(text)
|
||||||
// wingdings doesn't contain high-surrogates, so chars are ok
|
: text;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
@Override
|
||||||
|
|
|
@ -138,20 +138,18 @@ public class HemfDraw {
|
||||||
|
|
||||||
Point2D pnt[] = { new Point2D.Double(), new Point2D.Double(), new Point2D.Double() };
|
Point2D pnt[] = { new Point2D.Double(), new Point2D.Double(), new Point2D.Double() };
|
||||||
|
|
||||||
// points-1 because of the first point
|
int i=0;
|
||||||
final int pointCnt = hasStartPoint() ? points-2 : points;
|
if (hasStartPoint()) {
|
||||||
for (int i=0; i+2<pointCnt; i+=3) {
|
if (i < points) {
|
||||||
// x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
|
size += readPoint(leis, pnt[0]);
|
||||||
// y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
|
poly.moveTo(pnt[0].getX(), pnt[0].getY());
|
||||||
if (i==0) {
|
i++;
|
||||||
if (hasStartPoint()) {
|
|
||||||
size += readPoint(leis, pnt[0]);
|
|
||||||
poly.moveTo(pnt[0].getX(), pnt[0].getY());
|
|
||||||
} else {
|
|
||||||
poly.moveTo(0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
poly.moveTo(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i+2<points; i+=3) {
|
||||||
size += readPoint(leis, pnt[0]);
|
size += readPoint(leis, pnt[0]);
|
||||||
size += readPoint(leis, pnt[1]);
|
size += readPoint(leis, pnt[1]);
|
||||||
size += readPoint(leis, pnt[2]);
|
size += readPoint(leis, pnt[2]);
|
||||||
|
@ -758,7 +756,8 @@ public class HemfDraw {
|
||||||
size += LittleEndianConsts.INT_SIZE;
|
size += LittleEndianConsts.INT_SIZE;
|
||||||
Point2D points[] = new Point2D[count];
|
Point2D points[] = new Point2D[count];
|
||||||
for (int i=0; i<count; i++) {
|
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);
|
poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, count);
|
||||||
|
@ -783,12 +782,14 @@ public class HemfDraw {
|
||||||
case 0x04:
|
case 0x04:
|
||||||
int mode2 = leis.readUByte();
|
int mode2 = leis.readUByte();
|
||||||
int mode3 = leis.readUByte();
|
int mode3 = leis.readUByte();
|
||||||
assert(mode2 == 0x04 && mode3 == 0x04);
|
assert(mode2 == 0x04 && (mode3 == 0x04 || mode3 == 0x05));
|
||||||
poly.curveTo(
|
poly.curveTo(
|
||||||
points[i].getX(), points[i].getY(),
|
points[i].getX(), points[i].getY(),
|
||||||
points[i+1].getX(), points[i+1].getY(),
|
points[i+1].getX(), points[i+1].getY(),
|
||||||
points[i+2].getX(), points[i+2].getY()
|
points[i+2].getX(), points[i+2].getY()
|
||||||
);
|
);
|
||||||
|
// update mode for closePath handling below
|
||||||
|
mode = mode3;
|
||||||
i+=2;
|
i+=2;
|
||||||
break;
|
break;
|
||||||
// PT_MOVETO
|
// PT_MOVETO
|
||||||
|
|
|
@ -683,33 +683,27 @@ public class HemfFill {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readXForm(LittleEndianInputStream leis, AffineTransform xform) {
|
static int readXForm(LittleEndianInputStream leis, AffineTransform xform) {
|
||||||
// mapping <java AffineTransform> = <xform>:
|
// mapping <java AffineTransform> = <xform>
|
||||||
|
|
||||||
// m00 (scaleX) = eM11 (Horizontal scaling component)
|
// m00 (scaleX) = eM11 (Horizontal scaling component)
|
||||||
// m11 (scaleY) = eM22 (Vertical scaling component)
|
double m00 = leis.readFloat();
|
||||||
|
|
||||||
// m01 (shearX) = eM12 (Horizontal proportionality constant)
|
// m01 (shearX) = eM12 (Horizontal proportionality constant)
|
||||||
|
double m01 = leis.readFloat();
|
||||||
|
|
||||||
// m10 (shearY) = eM21 (Vertical proportionality constant)
|
// 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.)
|
// m02 (translateX) = eDx (The horizontal translation component, in logical units.)
|
||||||
|
double m02 = leis.readFloat();
|
||||||
|
|
||||||
// m12 (translateY) = eDy (The vertical translation component, in logical units.)
|
// m12 (translateY) = eDy (The vertical translation component, in logical units.)
|
||||||
|
double m12 = leis.readFloat();
|
||||||
|
|
||||||
// A 32-bit floating-point value of the transform matrix.
|
xform.setTransform(m00, m10, m01, m11, m02, m12);
|
||||||
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);
|
|
||||||
|
|
||||||
return 6 * LittleEndian.INT_SIZE;
|
return 6 * LittleEndian.INT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,15 +273,15 @@ public class HemfFont extends HwmfFont {
|
||||||
|
|
||||||
// An 8-bit unsigned integer that specifies an italic font if set to 0x01;
|
// An 8-bit unsigned integer that specifies an italic font if set to 0x01;
|
||||||
// otherwise, it MUST be set to 0x00.
|
// 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;
|
// An 8-bit unsigned integer that specifies an underlined font if set to 0x01;
|
||||||
// otherwise, it MUST be set to 0x00.
|
// 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;
|
// An 8-bit unsigned integer that specifies a strikeout font if set to 0x01;
|
||||||
// otherwise, it MUST be set to 0x00.
|
// 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.
|
// An 8-bit unsigned integer that specifies the set of character glyphs.
|
||||||
// It MUST be a value in the WMF CharacterSet enumeration.
|
// 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.
|
// A 32-bit unsigned integer that MUST be set to the value 0x08007664.
|
||||||
int signature = leis.readInt();
|
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
|
// 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.
|
// Values array. It MUST be in the range 0 to 16, inclusive.
|
||||||
|
|
|
@ -27,7 +27,9 @@ import java.awt.geom.Point2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.apache.poi.hemf.draw.HemfGraphics;
|
import org.apache.poi.hemf.draw.HemfGraphics;
|
||||||
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
||||||
|
@ -443,8 +445,6 @@ public class HemfMisc {
|
||||||
protected HwmfBrushStyle brushStyle;
|
protected HwmfBrushStyle brushStyle;
|
||||||
protected HwmfHatchStyle hatchStyle;
|
protected HwmfHatchStyle hatchStyle;
|
||||||
|
|
||||||
protected int[] styleEntry;
|
|
||||||
|
|
||||||
protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
|
protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
|
||||||
|
|
||||||
|
|
||||||
|
@ -477,7 +477,8 @@ public class HemfMisc {
|
||||||
|
|
||||||
// A 32-bit unsigned integer that specifies the PenStyle.
|
// A 32-bit unsigned integer that specifies the PenStyle.
|
||||||
// The value MUST be defined from the PenStyle enumeration table
|
// 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.
|
// 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
|
// 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
|
// 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.
|
// 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++) {
|
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;
|
size += numStyleEntries * LittleEndianConsts.INT_SIZE;
|
||||||
|
@ -533,8 +538,11 @@ public class HemfMisc {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// TODO: add style entries + bmp
|
// TODO: add style entries + bmp
|
||||||
return super.toString().replaceFirst("\\{",
|
return
|
||||||
"{ brushStyle: '"+brushStyle+"', hatchStyle: '"+hatchStyle+"', ");
|
"{ brushStyle: '"+brushStyle+"'"+
|
||||||
|
", hatchStyle: '"+hatchStyle+"'"+
|
||||||
|
", dashPattern: "+ Arrays.toString(penStyle.getLineDashes())+
|
||||||
|
", "+super.toString().substring(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +610,8 @@ public class HemfMisc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HemfGraphics ctx) {
|
public void draw(HemfGraphics ctx) {
|
||||||
AffineTransform tx = ctx.getInitTransform();
|
ctx.updateWindowMapMode();
|
||||||
|
AffineTransform tx = ctx.getTransform();
|
||||||
tx.concatenate(xForm);
|
tx.concatenate(xForm);
|
||||||
ctx.setTransform(tx);
|
ctx.setTransform(tx);
|
||||||
}
|
}
|
||||||
|
@ -649,30 +658,46 @@ public class HemfMisc {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final AffineTransform tx;
|
||||||
switch (modifyWorldTransformMode) {
|
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:
|
case MWT_IDENTITY:
|
||||||
ctx.setTransform(ctx.getInitTransform());
|
ctx.updateWindowMapMode();
|
||||||
|
tx = ctx.getTransform();
|
||||||
break;
|
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:
|
default:
|
||||||
case MWT_SET: {
|
case MWT_SET:
|
||||||
AffineTransform tx = ctx.getInitTransform();
|
ctx.updateWindowMapMode();
|
||||||
tx.concatenate(xForm);
|
tx = ctx.getTransform();
|
||||||
ctx.setTransform(tx);
|
tx.concatenate(adaptXForm(tx));
|
||||||
break;
|
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
|
@Override
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,10 @@ public interface HemfRecord {
|
||||||
*/
|
*/
|
||||||
long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException;
|
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) {
|
default void draw(HemfGraphics ctx) {
|
||||||
if (this instanceof HwmfRecord) {
|
if (this instanceof HwmfRecord) {
|
||||||
((HwmfRecord) this).draw(ctx);
|
((HwmfRecord) this).draw(ctx);
|
||||||
|
|
|
@ -54,6 +54,8 @@ public class HemfRecordIterator implements Iterator<HemfRecord> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int readIndex = stream.getReadIndex();
|
||||||
|
|
||||||
final long recordId, recordSize;
|
final long recordId, recordSize;
|
||||||
try {
|
try {
|
||||||
recordId = stream.readUInt();
|
recordId = stream.readUInt();
|
||||||
|
@ -65,7 +67,7 @@ public class HemfRecordIterator implements Iterator<HemfRecord> {
|
||||||
|
|
||||||
HemfRecordType type = HemfRecordType.getById(recordId);
|
HemfRecordType type = HemfRecordType.getById(recordId);
|
||||||
if (type == null) {
|
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();
|
final HemfRecord record = type.constructor.get();
|
||||||
|
|
||||||
|
|
|
@ -141,14 +141,12 @@ public class HemfText {
|
||||||
dx.add((int) leis.readUInt());
|
dx.add((int) leis.readUInt());
|
||||||
size += LittleEndianConsts.INT_SIZE;
|
size += LittleEndianConsts.INT_SIZE;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if there are no dx entries, reset the string end
|
|
||||||
strEnd = (int)recordSize;
|
|
||||||
}
|
}
|
||||||
if (dx.size() < stringLength) {
|
if (dx.size() < stringLength) {
|
||||||
// invalid dx array
|
// invalid dx array
|
||||||
dx.clear();
|
dx.clear();
|
||||||
}
|
}
|
||||||
|
strEnd = (int)recordSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.awt.font.TextLayout;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Area;
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Dimension2D;
|
import java.awt.geom.Dimension2D;
|
||||||
|
import java.awt.geom.NoninvertibleTransformException;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
@ -43,6 +44,7 @@ import java.util.NoSuchElementException;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.apache.commons.codec.Charsets;
|
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.common.usermodel.fonts.FontInfo;
|
||||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfFont;
|
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.hwmf.record.HwmfText.WmfExtTextOutOptions;
|
||||||
import org.apache.poi.sl.draw.DrawFactory;
|
import org.apache.poi.sl.draw.DrawFactory;
|
||||||
import org.apache.poi.sl.draw.DrawFontManager;
|
import org.apache.poi.sl.draw.DrawFontManager;
|
||||||
|
import org.apache.poi.sl.draw.DrawFontManagerDefault;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
|
|
||||||
public class HwmfGraphics {
|
public class HwmfGraphics {
|
||||||
|
@ -152,7 +155,7 @@ public class HwmfGraphics {
|
||||||
int cap = ps.getLineCap().awtFlag;
|
int cap = ps.getLineCap().awtFlag;
|
||||||
int join = ps.getLineJoin().awtFlag;
|
int join = ps.getLineJoin().awtFlag;
|
||||||
float miterLimit = (float)getProperties().getPenMiterLimit();
|
float miterLimit = (float)getProperties().getPenMiterLimit();
|
||||||
float dashes[] = ps.getLineDash().dashes;
|
float dashes[] = ps.getLineDashes();
|
||||||
boolean dashAlt = ps.isAlternateDash();
|
boolean dashAlt = ps.isAlternateDash();
|
||||||
// This value is not an integer index into the dash pattern array.
|
// This value is not an integer index into the dash pattern array.
|
||||||
// Instead, it is a floating-point value that specifies a linear distance.
|
// 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) {
|
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 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();
|
HwmfFont font = prop.getFont();
|
||||||
if (font == null || text == null || text.length == 0) {
|
if (font == null || text == null || text.length == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -390,11 +404,19 @@ public class HwmfGraphics {
|
||||||
}
|
}
|
||||||
|
|
||||||
String textString = new String(text, charset).substring(0,length).trim();
|
String textString = new String(text, charset).substring(0,length).trim();
|
||||||
|
|
||||||
if (textString.isEmpty()) {
|
if (textString.isEmpty()) {
|
||||||
return;
|
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);
|
AttributedString as = new AttributedString(textString);
|
||||||
addAttributes(as, font);
|
addAttributes(as, font, fontInfo.getTypeface());
|
||||||
|
|
||||||
// disabled for the time being, as the results aren't promising
|
// disabled for the time being, as the results aren't promising
|
||||||
/*
|
/*
|
||||||
|
@ -473,7 +495,6 @@ public class HwmfGraphics {
|
||||||
tx.transform(src, dst);
|
tx.transform(src, dst);
|
||||||
|
|
||||||
final Shape clipShape = graphicsCtx.getClip();
|
final Shape clipShape = graphicsCtx.getClip();
|
||||||
final AffineTransform at = graphicsCtx.getTransform();
|
|
||||||
try {
|
try {
|
||||||
if (clip != null) {
|
if (clip != null) {
|
||||||
graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY());
|
graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY());
|
||||||
|
@ -503,11 +524,8 @@ public class HwmfGraphics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAttributes(AttributedString as, HwmfFont font) {
|
private void addAttributes(AttributedString as, HwmfFont font, String typeface) {
|
||||||
DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx);
|
as.addAttribute(TextAttribute.FAMILY, typeface);
|
||||||
FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font);
|
|
||||||
|
|
||||||
as.addAttribute(TextAttribute.FAMILY, fontInfo.getTypeface());
|
|
||||||
as.addAttribute(TextAttribute.SIZE, getFontHeight(font));
|
as.addAttribute(TextAttribute.SIZE, getFontHeight(font));
|
||||||
if (font.isStrikeOut()) {
|
if (font.isStrikeOut()) {
|
||||||
as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
|
as.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
|
||||||
|
@ -669,4 +687,11 @@ public class HwmfGraphics {
|
||||||
graphicsCtx.setTransform(at);
|
graphicsCtx.setTransform(at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the bounding box
|
||||||
|
*/
|
||||||
|
public Rectangle2D getBbox() {
|
||||||
|
return (Rectangle2D)bbox.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,8 +499,8 @@ public class HwmfFill {
|
||||||
if (bitmap.isValid()) {
|
if (bitmap.isValid()) {
|
||||||
ctx.drawImage(getImage(), srcBounds, dstBounds);
|
ctx.drawImage(getImage(), srcBounds, dstBounds);
|
||||||
} else if (!dstBounds.isEmpty()) {
|
} else if (!dstBounds.isEmpty()) {
|
||||||
BufferedImage bi = new BufferedImage((int)dstBounds.getWidth(), (int)dstBounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
|
BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
|
||||||
ctx.drawImage(bi, dstBounds, dstBounds);
|
ctx.drawImage(bi, new Rectangle2D.Double(0,0,100,100), dstBounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ public class HwmfPenStyle implements Cloneable {
|
||||||
private static final BitField SUBSECTION_JOIN = BitFieldFactory.getInstance(0x03000);
|
private static final BitField SUBSECTION_JOIN = BitFieldFactory.getInstance(0x03000);
|
||||||
private static final BitField SUBSECTION_GEOMETRIC = BitFieldFactory.getInstance(0x10000);
|
private static final BitField SUBSECTION_GEOMETRIC = BitFieldFactory.getInstance(0x10000);
|
||||||
|
|
||||||
private int flag;
|
protected int flag;
|
||||||
|
|
||||||
public static HwmfPenStyle valueOf(int flag) {
|
public static HwmfPenStyle valueOf(int flag) {
|
||||||
HwmfPenStyle ps = new HwmfPenStyle();
|
HwmfPenStyle ps = new HwmfPenStyle();
|
||||||
|
@ -162,6 +162,15 @@ public class HwmfPenStyle implements Cloneable {
|
||||||
return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag));
|
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).
|
* The pen sets every other pixel (this style is applicable only for cosmetic pens).
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package org.apache.poi.hwmf.record;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
|
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.normalizeBounds;
|
||||||
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
|
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
|
||||||
import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
|
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.awt.geom.Rectangle2D;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
import org.apache.poi.util.Dimension2DDouble;
|
import org.apache.poi.util.Dimension2DDouble;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
|
@ -56,8 +58,14 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setViewportOrg(origin.getX(), origin.getY());
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
ctx.updateWindowMapMode();
|
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
|
@Override
|
||||||
|
@ -91,13 +99,19 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setViewportExt(extents.getWidth(), extents.getHeight());
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
ctx.updateWindowMapMode();
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{ width: "+extents.getWidth()+", height: "+extents.getHeight()+" }";
|
return dimToString(extents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,10 +135,14 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
double x = (viewport == null) ? 0 : viewport.getX();
|
Rectangle2D viewport = prop.getViewport();
|
||||||
double y = (viewport == null) ? 0 : viewport.getY();
|
if (offset.getX() != 0 || offset.getY() != 0) {
|
||||||
ctx.getProperties().setViewportOrg(x+offset.getX(), y+offset.getY());
|
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
|
@Override
|
||||||
|
@ -152,8 +170,14 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowOrg(getX(), getY());
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
ctx.updateWindowMapMode();
|
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() {
|
public double getY() {
|
||||||
|
@ -195,8 +219,14 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowExt(size.getWidth(), size.getHeight());
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
ctx.updateWindowMapMode();
|
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() {
|
public Dimension2D getSize() {
|
||||||
|
@ -205,7 +235,7 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{ width: "+size.getWidth()+", height: "+size.getHeight()+" }";
|
return dimToString(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,9 +259,12 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D window = ctx.getProperties().getWindow();
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
ctx.getProperties().setWindowOrg(window.getX()+offset.getX(), window.getY()+offset.getY());
|
Rectangle2D old = prop.getWindow();
|
||||||
ctx.updateWindowMapMode();
|
if (offset.getX() != 0 || offset.getY() != 0) {
|
||||||
|
prop.setWindowOrg(old.getX() + offset.getX(), old.getY() + offset.getY());
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -275,11 +308,14 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D window = ctx.getProperties().getWindow();
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
double width = window.getWidth() * scale.getWidth();
|
Rectangle2D old = prop.getWindow();
|
||||||
double height = window.getHeight() * scale.getHeight();
|
if (scale.getWidth() != 1.0 || scale.getHeight() != 1.0) {
|
||||||
ctx.getProperties().setWindowExt(width, height);
|
double width = old.getWidth() * scale.getWidth();
|
||||||
ctx.updateWindowMapMode();
|
double height = old.getHeight() * scale.getHeight();
|
||||||
|
ctx.getProperties().setWindowExt(width, height);
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -325,13 +361,15 @@ public class HwmfWindowing {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
final HwmfDrawProperties prop = ctx.getProperties();
|
||||||
if (viewport == null) {
|
final Rectangle2D old = prop.getViewport() == null ? prop.getWindow() : prop.getViewport();
|
||||||
viewport = ctx.getProperties().getWindow();
|
|
||||||
|
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
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue