git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1846472 13f79535-47bb-0310-9956-ffa450edef68tags/REL_4_1_0
@@ -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>: | |||
// m00 (scaleX) = eM11 (Horizontal scaling component) | |||
// m11 (scaleY) = eM22 (Vertical scaling component) | |||
// m01 (shearX) = eM12 (Horizontal proportionality constant) | |||
// m10 (shearY) = eM21 (Vertical proportionality constant) | |||
// m02 (translateX) = eDx (The horizontal translation component, in logical units.) | |||
// m12 (translateY) = eDy (The vertical translation component, in logical units.) | |||
// mapping <java AffineTransform> = <xform> | |||
// A 32-bit floating-point value of the transform matrix. | |||
double eM11 = leis.readFloat(); | |||
// m00 (scaleX) = eM11 (Horizontal scaling component) | |||
double m00 = leis.readFloat(); | |||
// A 32-bit floating-point value of the transform matrix. | |||
double eM12 = leis.readFloat(); | |||
// m01 (shearX) = eM12 (Horizontal proportionality constant) | |||
double m01 = leis.readFloat(); | |||
// A 32-bit floating-point value of the transform matrix. | |||
double eM21 = leis.readFloat(); | |||
// m10 (shearY) = eM21 (Vertical proportionality constant) | |||
double m10 = leis.readFloat(); | |||
// A 32-bit floating-point value of the transform matrix. | |||
double eM22 = leis.readFloat(); | |||
// m11 (scaleY) = eM22 (Vertical scaling component) | |||
double m11 = leis.readFloat(); | |||
// A 32-bit floating-point value that contains a horizontal translation component, in logical units. | |||
double eDx = leis.readFloat(); | |||
// m02 (translateX) = eDx (The horizontal translation component, in logical units.) | |||
double m02 = leis.readFloat(); | |||
// A 32-bit floating-point value that contains a vertical translation component, in logical units. | |||
double eDy = leis.readFloat(); | |||
// m12 (translateY) = eDy (The vertical translation component, in logical units.) | |||
double m12 = 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_IDENTITY: | |||
ctx.setTransform(ctx.getInitTransform()); | |||
case MWT_LEFTMULTIPLY: | |||
tx = ctx.getTransform(); | |||
tx.concatenate(adaptXForm(tx)); | |||
break; | |||
case MWT_LEFTMULTIPLY: { | |||
AffineTransform tx = new AffineTransform(xForm); | |||
tx.concatenate(ctx.getTransform()); | |||
ctx.setTransform(tx); | |||
case MWT_RIGHTMULTIPLY: | |||
tx = ctx.getTransform(); | |||
tx.preConcatenate(adaptXForm(tx)); | |||
break; | |||
} | |||
case MWT_RIGHTMULTIPLY: { | |||
AffineTransform tx = new AffineTransform(xForm); | |||
tx.preConcatenate(ctx.getTransform()); | |||
ctx.setTransform(tx); | |||
case MWT_IDENTITY: | |||
ctx.updateWindowMapMode(); | |||
tx = ctx.getTransform(); | |||
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 |