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.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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue