aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2016-01-10 01:12:16 +0000
committerAndreas Beeker <kiwiwings@apache.org>2016-01-10 01:12:16 +0000
commit2962d7e1ba9491b63aeee48f2b8755af90e1aeb3 (patch)
tree307c63d849ad8a9e51f125f5a27a0fe5c7a2f256 /src
parent7de587053e34bd5863b117826289655b23d87472 (diff)
downloadpoi-2962d7e1ba9491b63aeee48f2b8755af90e1aeb3.tar.gz
poi-2962d7e1ba9491b63aeee48f2b8755af90e1aeb3.zip
WMF fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723898 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java96
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java73
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java138
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java52
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java60
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java10
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java221
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java8
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java7
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java174
-rw-r--r--src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java34
-rw-r--r--src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java44
12 files changed, 682 insertions, 235 deletions
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
index aa8a2f3cbd..8c112169f1 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
@@ -25,14 +25,19 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
+import java.util.List;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfColorRef;
+import org.apache.poi.hwmf.record.HwmfFont;
import org.apache.poi.hwmf.record.HwmfFill.WmfSetPolyfillMode.HwmfPolyfillMode;
import org.apache.poi.hwmf.record.HwmfHatchStyle;
import org.apache.poi.hwmf.record.HwmfMapMode;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
+import org.apache.poi.hwmf.record.HwmfPalette.PaletteEntry;
import org.apache.poi.hwmf.record.HwmfPenStyle;
+import org.apache.poi.hwmf.record.HwmfText.HwmfTextAlignment;
+import org.apache.poi.hwmf.record.HwmfText.HwmfTextVerticalAlignment;
public class HwmfDrawProperties {
private final Rectangle2D window;
@@ -51,6 +56,14 @@ public class HwmfDrawProperties {
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;
private Shape region = null;
+ private List<PaletteEntry> palette = null;
+ private int paletteOffset = 0;
+ private HwmfFont font = null;
+ private HwmfColorRef textColor = new HwmfColorRef(Color.BLACK);
+ private HwmfTextAlignment textAlignLatin = HwmfTextAlignment.LEFT;
+ private HwmfTextVerticalAlignment textVAlignLatin = HwmfTextVerticalAlignment.TOP;
+ private HwmfTextAlignment textAlignAsian = HwmfTextAlignment.RIGHT;
+ private HwmfTextVerticalAlignment textVAlignAsian = HwmfTextVerticalAlignment.TOP;
public HwmfDrawProperties() {
window = new Rectangle2D.Double(0, 0, 1, 1);
@@ -84,9 +97,16 @@ public class HwmfDrawProperties {
} else if (other.region instanceof Area) {
this.region = new Area(other.region);
}
+ this.palette = other.palette;
+ this.paletteOffset = other.paletteOffset;
+ this.font = other.font;
+ this.textColor = (other.textColor == null) ? null : other.textColor.clone();
}
public void setViewportExt(double width, double height) {
+ if (viewport == null) {
+ viewport = (Rectangle2D)window.clone();
+ }
double x = viewport.getX();
double y = viewport.getY();
double w = (width != 0) ? width : viewport.getWidth();
@@ -244,4 +264,80 @@ public class HwmfDrawProperties {
public void setRegion(Shape region) {
this.region = region;
}
+
+ /**
+ * Returns the current palette.
+ * Callers may modify the palette.
+ *
+ * @return the current palette or null, if it hasn't been set
+ */
+ public List<PaletteEntry> getPalette() {
+ return palette;
+ }
+
+ /**
+ * Sets the current palette.
+ * It's the callers duty to set a modifiable copy of the palette.
+ *
+ * @param palette
+ */
+ public void setPalette(List<PaletteEntry> palette) {
+ this.palette = palette;
+ }
+
+ public int getPaletteOffset() {
+ return paletteOffset;
+ }
+
+ public void setPaletteOffset(int paletteOffset) {
+ this.paletteOffset = paletteOffset;
+ }
+
+ public HwmfColorRef getTextColor() {
+ return textColor;
+ }
+
+ public void setTextColor(HwmfColorRef textColor) {
+ this.textColor = textColor;
+ }
+
+ public HwmfFont getFont() {
+ return font;
+ }
+
+ public void setFont(HwmfFont font) {
+ this.font = font;
+ }
+
+ public HwmfTextAlignment getTextAlignLatin() {
+ return textAlignLatin;
+ }
+
+ public void setTextAlignLatin(HwmfTextAlignment textAlignLatin) {
+ this.textAlignLatin = textAlignLatin;
+ }
+
+ public HwmfTextVerticalAlignment getTextVAlignLatin() {
+ return textVAlignLatin;
+ }
+
+ public void setTextVAlignLatin(HwmfTextVerticalAlignment textVAlignLatin) {
+ this.textVAlignLatin = textVAlignLatin;
+ }
+
+ public HwmfTextAlignment getTextAlignAsian() {
+ return textAlignAsian;
+ }
+
+ public void setTextAlignAsian(HwmfTextAlignment textAlignAsian) {
+ this.textAlignAsian = textAlignAsian;
+ }
+
+ public HwmfTextVerticalAlignment getTextVAlignAsian() {
+ return textVAlignAsian;
+ }
+
+ public void setTextVAlignAsian(HwmfTextVerticalAlignment textVAlignAsian) {
+ this.textVAlignAsian = textVAlignAsian;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
index a61390704a..75e815f70b 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
@@ -25,10 +25,12 @@ import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.TexturePaint;
+import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
+import java.text.AttributedString;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -36,13 +38,13 @@ import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
+import org.apache.poi.hwmf.record.HwmfFont;
import org.apache.poi.hwmf.record.HwmfHatchStyle;
import org.apache.poi.hwmf.record.HwmfMapMode;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
import org.apache.poi.hwmf.record.HwmfPenStyle;
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
-import org.apache.poi.util.Units;
public class HwmfGraphics {
private final Graphics2D graphicsCtx;
@@ -118,7 +120,7 @@ public class HwmfGraphics {
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.
- float dashStart = (dashAlt && dashes.length > 1) ? dashes[0] : 0;
+ float dashStart = (dashAlt && dashes != null && dashes.length > 1) ? dashes[0] : 0;
return new BasicStroke(width, cap, join, miterLimit, dashes, dashStart);
}
@@ -243,8 +245,8 @@ public class HwmfGraphics {
/**
* Restores the properties from the stack
*
- * @param index if the index is positive, the n-th element from the start is removed and activated.
- * If the index is negative, the n-th previous element relative to the current properties element is removed and activated.
+ * @param index if the index is positive, the n-th element from the start is activated.
+ * If the index is negative, the n-th previous element relative to the current properties element is activated.
*/
public void restoreProperties(int index) {
if (index == 0) {
@@ -253,12 +255,20 @@ public class HwmfGraphics {
int stackIndex = index;
if (stackIndex < 0) {
int curIdx = propStack.indexOf(prop);
- assert (curIdx != -1);
+ if (curIdx == -1) {
+ // the current element is not pushed to the stacked, i.e. it's the last
+ curIdx = propStack.size();
+ }
stackIndex = curIdx + index;
}
- prop = propStack.remove(stackIndex);
+ prop = propStack.get(stackIndex);
}
+ /**
+ * After setting various window and viewport related properties,
+ * the underlying graphics context needs to be adapted.
+ * This methods gathers and sets the corresponding graphics transformations.
+ */
public void updateWindowMapMode() {
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
Rectangle2D win = prop.getWindow();
@@ -268,23 +278,15 @@ public class HwmfGraphics {
switch (mapMode) {
default:
case MM_ANISOTROPIC:
- // scale output bounds to image bounds
- graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getHeight()/bbox.getHeight());
- graphicsCtx.translate(-bbox.getX(), -bbox.getY());
-
// scale window bounds to output bounds
- graphicsCtx.translate(win.getCenterX(), win.getCenterY());
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
- graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
+ graphicsCtx.translate(-win.getX(), -win.getY());
break;
case MM_ISOTROPIC:
// TODO: to be validated ...
// like anisotropic, but use x-axis as reference
- graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getWidth()/bbox.getWidth());
- graphicsCtx.translate(-bbox.getX(), -bbox.getY());
- graphicsCtx.translate(win.getCenterX(), win.getCenterY());
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth());
- graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
+ graphicsCtx.translate(-win.getX(), -win.getY());
break;
case MM_LOMETRIC:
case MM_HIMETRIC:
@@ -294,11 +296,48 @@ public class HwmfGraphics {
// TODO: to be validated ...
graphicsCtx.transform(gc.getNormalizingTransform());
graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);
- graphicsCtx.translate(-bbox.getX(), -bbox.getY());
+ graphicsCtx.translate(-win.getX(), -win.getY());
break;
case MM_TEXT:
// TODO: to be validated ...
break;
}
}
+
+ public void drawString(String text, Rectangle2D bounds) {
+ HwmfFont font = prop.getFont();
+ if (font == null) {
+ return;
+ }
+ AttributedString as = new AttributedString(text);
+ as.addAttribute(TextAttribute.FAMILY, font.getFacename());
+ // TODO: fix font height calculation
+ as.addAttribute(TextAttribute.SIZE, Math.abs(font.getHeight()));
+ as.addAttribute(TextAttribute.STRIKETHROUGH, font.isStrikeOut());
+ if (font.isUnderline()) {
+ as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
+ }
+ if (font.isItalic()) {
+ as.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+ }
+ as.addAttribute(TextAttribute.WEIGHT, font.getWeight());
+
+ double angle = Math.toRadians(-font.getEscapement()/10.);
+
+
+ final AffineTransform at = graphicsCtx.getTransform();
+ try {
+ graphicsCtx.translate(bounds.getX(), bounds.getY());
+ graphicsCtx.rotate(angle);
+ if (prop.getBkMode() == HwmfBkMode.OPAQUE) {
+ // TODO: validate bounds
+ graphicsCtx.setBackground(prop.getBackgroundColor().getColor());
+ graphicsCtx.fill(bounds);
+ }
+ graphicsCtx.setColor(prop.getTextColor().getColor());
+ graphicsCtx.drawString(as.getIterator(), 0, 0); // (float)bounds.getX(), (float)bounds.getY());
+ } finally {
+ graphicsCtx.setTransform(at);
+ }
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
index 4ed79ceb49..b167d0236a 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
@@ -17,17 +17,18 @@
package org.apache.poi.hwmf.record;
-import java.awt.Polygon;
-import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.util.LittleEndianConsts;
@@ -114,13 +115,8 @@ public class HwmfDraw {
*/
public static class WmfPolygon implements HwmfRecord {
- /**
- * A 16-bit signed integer that defines the number of points in the array.
- */
- private int numberofPoints;
-
- short xPoints[], yPoints[];
-
+ private Path2D poly = new Path2D.Double();
+
@Override
public HwmfRecordType getRecordType() {
return HwmfRecordType.polygon;
@@ -128,15 +124,21 @@ public class HwmfDraw {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- numberofPoints = leis.readShort();
- xPoints = new short[numberofPoints];
- yPoints = new short[numberofPoints];
+ /**
+ * A 16-bit signed integer that defines the number of points in the array.
+ */
+ int numberofPoints = leis.readShort();
for (int i=0; i<numberofPoints; i++) {
// A 16-bit signed integer that defines the horizontal (x) coordinate of the point.
- xPoints[i] = leis.readShort();
+ int x = leis.readShort();
// A 16-bit signed integer that defines the vertical (y) coordinate of the point.
- yPoints[i] = leis.readShort();
+ int y = leis.readShort();
+ if (i==0) {
+ poly.moveTo(x, y);
+ } else {
+ poly.lineTo(x, y);
+ }
}
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;
@@ -144,15 +146,14 @@ public class HwmfDraw {
@Override
public void draw(HwmfGraphics ctx) {
- ctx.fill(getShape());
+ Path2D p = getShape();
+ p.closePath();
+ p.setWindingRule(ctx.getProperties().getPolyfillMode().awtFlag);
+ ctx.fill(p);
}
- protected Polygon getShape() {
- Polygon polygon = new Polygon();
- for(int i = 0; i < numberofPoints; i++) {
- polygon.addPoint(xPoints[i], yPoints[i]);
- }
- return polygon;
+ protected Path2D getShape() {
+ return (Path2D)poly.clone();
}
}
@@ -169,7 +170,9 @@ public class HwmfDraw {
@Override
public void draw(HwmfGraphics ctx) {
- ctx.draw(getShape());
+ Path2D p = getShape();
+ p.setWindingRule(ctx.getProperties().getPolyfillMode().awtFlag);
+ ctx.draw(p);
}
}
@@ -234,12 +237,12 @@ public class HwmfDraw {
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be framed.
*/
- private int region;
+ private int regionIndex;
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get the
* Brush to use for filling the region.
*/
- private int brush;
+ private int brushIndex;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* region frame.
@@ -258,8 +261,8 @@ public class HwmfDraw {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- region = leis.readUShort();
- brush = leis.readUShort();
+ regionIndex = leis.readUShort();
+ brushIndex = leis.readUShort();
height = leis.readShort();
width = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
@@ -267,7 +270,17 @@ public class HwmfDraw {
@Override
public void draw(HwmfGraphics ctx) {
-
+ ctx.applyObjectTableEntry(brushIndex);
+ ctx.applyObjectTableEntry(regionIndex);
+ Rectangle2D inner = ctx.getProperties().getRegion().getBounds();
+ double x = inner.getX()-width;
+ double y = inner.getY()-height;
+ double w = inner.getWidth()+2*width;
+ double h = inner.getHeight()+2*height;
+ Rectangle2D outer = new Rectangle2D.Double(x,y,w,h);
+ Area frame = new Area(outer);
+ frame.subtract(new Area(inner));
+ ctx.fill(frame);
}
}
@@ -278,28 +291,8 @@ public class HwmfDraw {
*/
public static class WmfPolyPolygon implements HwmfRecord {
- /**
- * A 16-bit unsigned integer that defines the number of polygons in the object.
- */
- private int numberOfPolygons;
-
- /**
- * A NumberOfPolygons array of 16-bit unsigned integers that define the number of
- * points for each polygon in the object.
- */
- private int pointsPerPolygon[];
-
- /**
- * An array of 16-bit unsigned integers that define the coordinates of the polygons.
- */
- private int xPoints[][];
-
- /**
- * An array of 16-bit unsigned integers that define the coordinates of the polygons.
- */
- private int yPoints[][];
-
-
+ private List<Path2D> polyList = new ArrayList<Path2D>();
+
@Override
public HwmfRecordType getRecordType() {
return HwmfRecordType.polyPolygon;
@@ -308,10 +301,15 @@ public class HwmfDraw {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
// see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
- numberOfPolygons = leis.readUShort();
- pointsPerPolygon = new int[numberOfPolygons];
- xPoints = new int[numberOfPolygons][];
- yPoints = new int[numberOfPolygons][];
+ /**
+ * A 16-bit unsigned integer that defines the number of polygons in the object.
+ */
+ int numberOfPolygons = leis.readUShort();
+ /**
+ * A NumberOfPolygons array of 16-bit unsigned integers that define the number of
+ * points for each polygon in the object.
+ */
+ int[] pointsPerPolygon = new int[numberOfPolygons];
int size = LittleEndianConsts.SHORT_SIZE;
@@ -320,16 +318,23 @@ public class HwmfDraw {
size += LittleEndianConsts.SHORT_SIZE;
}
- for (int i=0; i<numberOfPolygons; i++) {
-
- xPoints[i] = new int[pointsPerPolygon[i]];
- yPoints[i] = new int[pointsPerPolygon[i]];
-
- for (int j=0; j<pointsPerPolygon[i]; j++) {
- xPoints[i][j] = leis.readUShort();
- yPoints[i][j] = leis.readUShort();
+ for (int nPoints : pointsPerPolygon) {
+ /**
+ * An array of 16-bit unsigned integers that define the coordinates of the polygons.
+ */
+ Path2D poly = new Path2D.Double();
+ for (int i=0; i<nPoints; i++) {
+ int x = leis.readUShort();
+ int y = leis.readUShort();
size += 2*LittleEndianConsts.SHORT_SIZE;
+ if (i == 0) {
+ poly.moveTo(x, y);
+ } else {
+ poly.lineTo(x, y);
+ }
}
+ poly.closePath();
+ polyList.add(poly);
}
return size;
@@ -337,7 +342,14 @@ public class HwmfDraw {
@Override
public void draw(HwmfGraphics ctx) {
-
+ int windingRule = ctx.getProperties().getPolyfillMode().awtFlag;
+ Area area = new Area();
+ for (Path2D poly : polyList) {
+ Path2D p = (Path2D)poly.clone();
+ p.setWindingRule(windingRule);
+ area.add(new Area(p));
+ }
+ ctx.draw(area);
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
index 32d34d76aa..d77aa49323 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
@@ -38,6 +38,42 @@ public class HwmfFill {
BufferedImage getImage();
}
+ /**
+ * The ColorUsage Enumeration (a 16-bit unsigned integer) specifies whether a color table
+ * exists in a device-independent bitmap (DIB) and how to interpret its values,
+ * i.e. if contains explicit RGB values or indexes into a palette.
+ */
+ public enum ColorUsage {
+ /**
+ * The color table contains RGB values
+ */
+ DIB_RGB_COLORS(0x0000),
+ /**
+ * The color table contains 16-bit indices into the current logical palette in
+ * the playback device context.
+ */
+ DIB_PAL_COLORS(0x0001),
+ /**
+ * No color table exists. The pixels in the DIB are indices into the current
+ * logical palette in the playback device context.
+ */
+ DIB_PAL_INDICES(0x0002)
+ ;
+
+
+ int flag;
+ ColorUsage(int flag) {
+ this.flag = flag;
+ }
+
+ static ColorUsage valueOf(int flag) {
+ for (ColorUsage bs : values()) {
+ if (bs.flag == flag) return bs;
+ }
+ return null;
+ }
+ }
+
/**
* The META_FILLREGION record fills a region using a specified brush.
@@ -482,12 +518,8 @@ public class HwmfFill {
/**
* A 16-bit unsigned integer that defines whether the Colors field of the
* DIB contains explicit RGB values or indexes into a palette.
- * This value MUST be in the ColorUsage Enumeration:
- * DIB_RGB_COLORS = 0x0000,
- * DIB_PAL_COLORS = 0x0001,
- * DIB_PAL_INDICES = 0x0002
*/
- private int colorUsage;
+ private ColorUsage colorUsage;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* source rectangle.
@@ -548,7 +580,7 @@ public class HwmfFill {
rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
- colorUsage = leis.readUShort();
+ colorUsage = ColorUsage.valueOf(leis.readUShort());
srcHeight = leis.readShort();
srcWidth = leis.readShort();
ySrc = leis.readShort();
@@ -679,12 +711,8 @@ public class HwmfFill {
/**
* A 16-bit unsigned integer that defines whether the Colors field of the
* DIB contains explicit RGB values or indexes into a palette.
- * This MUST be one of the values in the ColorUsage Enumeration:
- * DIB_RGB_COLORS = 0x0000,
- * DIB_PAL_COLORS = 0x0001,
- * DIB_PAL_INDICES = 0x0002
*/
- private int colorUsage;
+ private ColorUsage colorUsage;
/**
* A 16-bit unsigned integer that defines the number of scan lines in the source.
*/
@@ -736,7 +764,7 @@ public class HwmfFill {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- colorUsage = leis.readUShort();
+ colorUsage = ColorUsage.valueOf(leis.readUShort());
scanCount = leis.readUShort();
startScan = leis.readUShort();
yDib = leis.readUShort();
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
index d1a99e641a..d23b2381b6 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
@@ -497,4 +497,64 @@ public class HwmfFont {
return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;
}
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getEscapement() {
+ return escapement;
+ }
+
+ public int getOrientation() {
+ return orientation;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public boolean isItalic() {
+ return italic;
+ }
+
+ public boolean isUnderline() {
+ return underline;
+ }
+
+ public boolean isStrikeOut() {
+ return strikeOut;
+ }
+
+ public WmfCharset getCharSet() {
+ return charSet;
+ }
+
+ public WmfOutPrecision getOutPrecision() {
+ return outPrecision;
+ }
+
+ public WmfClipPrecision getClipPrecision() {
+ return clipPrecision;
+ }
+
+ public WmfFontQuality getQuality() {
+ return quality;
+ }
+
+ public WmfFontFamilyClass getFamily() {
+ return family;
+ }
+
+ public WmfFontPitch getPitch() {
+ return pitch;
+ }
+
+ public String getFacename() {
+ return facename;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
index 749faa29bd..90fd70dced 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.hwmf.record.HwmfFill.ColorUsage;
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@@ -349,12 +350,9 @@ public class HwmfMisc {
* If the Style field specifies BS_PATTERN, a ColorUsage value of DIB_RGB_COLORS MUST be
* used regardless of the contents of this field.
*
- * If the Style field specified anything but BS_PATTERN, this field MUST be one of the values:
- * DIB_RGB_COLORS = 0x0000,
- * DIB_PAL_COLORS = 0x0001,
- * DIB_PAL_INDICES = 0x0002
+ * If the Style field specified anything but BS_PATTERN, this field MUST be one of the ColorUsage values.
*/
- private int colorUsage;
+ private ColorUsage colorUsage;
private HwmfBitmapDib patternDib;
private HwmfBitmap16 pattern16;
@@ -367,7 +365,7 @@ public class HwmfMisc {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
style = HwmfBrushStyle.valueOf(leis.readUShort());
- colorUsage = leis.readUShort();
+ colorUsage = ColorUsage.valueOf(leis.readUShort());
int size = 2*LittleEndianConsts.SHORT_SIZE;
switch (style) {
case BS_SOLID:
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
index ae403d5f13..42e661b17e 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
@@ -19,106 +19,121 @@ package org.apache.poi.hwmf.record;
import java.awt.Color;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfPalette {
-
+
public static class PaletteEntry {
- enum PaletteEntryFlag {
- /**
- * Specifies that the logical palette entry be used for palette animation. This value
- * prevents other windows from matching colors to the palette entry because the color frequently
- * changes. If an unused system-palette entry is available, the color is placed in that entry.
- * Otherwise, the color is not available for animation.
- */
- PC_RESERVED(0x01),
- /**
- * Specifies that the low-order word of the logical palette entry designates a hardware
- * palette index. This value allows the application to show the contents of the display device palette.
- */
- PC_EXPLICIT(0x02),
- /**
- * Specifies that the color be placed in an unused entry in the system palette
- * instead of being matched to an existing color in the system palette. If there are no unused entries
- * in the system palette, the color is matched normally. Once this color is in the system palette,
- * colors in other logical palettes can be matched to this color.
- */
- PC_NOCOLLAPSE(0x04)
- ;
-
- int flag;
-
- PaletteEntryFlag(int flag) {
- this.flag = flag;
- }
+ private static final BitField PC_RESERVED = BitFieldFactory.getInstance(0x01);
+ private static final BitField PC_EXPLICIT = BitFieldFactory.getInstance(0x02);
+ private static final BitField PC_NOCOLLAPSE = BitFieldFactory.getInstance(0x04);
- static PaletteEntryFlag valueOf(int flag) {
- for (PaletteEntryFlag pef : values()) {
- if (pef.flag == flag) return pef;
- }
- return null;
- }
+ private int values;
+ private Color colorRef;
+ private PaletteEntry() {
+ this.values = PC_RESERVED.set(0);
+ this.colorRef = Color.BLACK;
}
-
- // Values (1 byte): An 8-bit unsigned integer that defines how the palette entry is to be used.
- // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.
- // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.
- // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.
- // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.
- private PaletteEntryFlag values;
- private Color colorRef;
-
+
+ private PaletteEntry(PaletteEntry other) {
+ this.values = other.values;
+ this.colorRef = other.colorRef;
+ }
+
public int init(LittleEndianInputStream leis) throws IOException {
- values = PaletteEntryFlag.valueOf(leis.readUByte());
+ // Values (1 byte): An 8-bit unsigned integer that defines how the palette entry is to be used.
+ // The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.
+ values = leis.readUByte();
+ // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.
int blue = leis.readUByte();
+ // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.
int green = leis.readUByte();
+ // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.
int red = leis.readUByte();
colorRef = new Color(red, green, blue);
-
+
return 4*LittleEndianConsts.BYTE_SIZE;
}
+
+ /**
+ * Specifies that the logical palette entry be used for palette animation. This value
+ * prevents other windows from matching colors to the palette entry because the color frequently
+ * changes. If an unused system-palette entry is available, the color is placed in that entry.
+ * Otherwise, the color is not available for animation.
+ */
+ public boolean isReserved() {
+ return PC_RESERVED.isSet(values);
+ }
+
+ /**
+ * Specifies that the low-order word of the logical palette entry designates a hardware
+ * palette index. This value allows the application to show the contents of the display device palette.
+ */
+ public boolean isExplicit() {
+ return PC_EXPLICIT.isSet(values);
+ }
+
+ /**
+ * Specifies that the color be placed in an unused entry in the system palette
+ * instead of being matched to an existing color in the system palette. If there are no unused entries
+ * in the system palette, the color is matched normally. Once this color is in the system palette,
+ * colors in other logical palettes can be matched to this color.
+ */
+ public boolean isNoCollapse() {
+ return PC_NOCOLLAPSE.isSet(values);
+ }
}
-
+
public static abstract class WmfPaletteParent implements HwmfRecord {
-
+
/**
* Start (2 bytes): A 16-bit unsigned integer that defines the offset into the Palette Object when
* used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.
* When used with META_CREATEPALETTE, it MUST be 0x0300
*/
private int start;
-
- /**
- * NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
- * aPaletteEntries.
- */
- private int numberOfEntries;
-
- private PaletteEntry entries[];
-
+
+ private List<PaletteEntry> palette = new ArrayList<PaletteEntry>();
+
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
start = leis.readUShort();
- numberOfEntries = leis.readUShort();
+ /**
+ * NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
+ * aPaletteEntries.
+ */
+ int numberOfEntries = leis.readUShort();
int size = 2*LittleEndianConsts.SHORT_SIZE;
- entries = new PaletteEntry[numberOfEntries];
for (int i=0; i<numberOfEntries; i++) {
- entries[i] = new PaletteEntry();
- size += entries[i].init(leis);
+ PaletteEntry pe = new PaletteEntry();
+ size += pe.init(leis);
+ palette.add(pe);
}
return size;
}
- @Override
- public void draw(HwmfGraphics ctx) {
+ protected List<PaletteEntry> getPaletteCopy() {
+ List<PaletteEntry> newPalette = new ArrayList<PaletteEntry>();
+ for (PaletteEntry et : palette) {
+ newPalette.add(new PaletteEntry(et));
+ }
+ return newPalette;
+ }
+ protected int getPaletteStart() {
+ return start;
}
}
-
+
/**
* The META_CREATEPALETTE record creates a Palette Object
*/
@@ -132,10 +147,10 @@ public class HwmfPalette {
public void draw(HwmfGraphics ctx) {
ctx.addObjectTableEntry(this);
}
-
+
@Override
public void applyObject(HwmfGraphics ctx) {
-
+ ctx.getProperties().setPalette(getPaletteCopy());
}
}
@@ -151,35 +166,62 @@ public class HwmfPalette {
@Override
public void draw(HwmfGraphics ctx) {
-
+ HwmfDrawProperties props = ctx.getProperties();
+ List<PaletteEntry> palette = props.getPalette();
+ if (palette == null) {
+ palette = new ArrayList<PaletteEntry>();
+ }
+ int start = getPaletteStart();
+ for (int i=palette.size(); i<start; i++) {
+ palette.add(new PaletteEntry());
+ }
+ int index = start;
+ for (PaletteEntry palCopy : getPaletteCopy()) {
+ if (palette.size() <= index) {
+ palette.add(palCopy);
+ } else {
+ palette.set(index, palCopy);
+ }
+ index++;
+ }
+ props.setPalette(palette);
}
}
-
+
/**
* The META_RESIZEPALETTE record redefines the size of the logical palette that is defined in the
* playback device context.
*/
public static class WmfResizePalette implements HwmfRecord {
/**
- * A 16-bit unsigned integer that defines the number of entries in
+ * A 16-bit unsigned integer that defines the number of entries in
* the logical palette.
*/
int numberOfEntries;
-
+
@Override
public HwmfRecordType getRecordType() {
return HwmfRecordType.resizePalette;
}
-
+
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
numberOfEntries = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
- }
+ }
@Override
public void draw(HwmfGraphics ctx) {
-
+ HwmfDrawProperties props = ctx.getProperties();
+ List<PaletteEntry> palette = props.getPalette();
+ if (palette == null) {
+ palette = new ArrayList<PaletteEntry>();
+ }
+ for (int i=palette.size(); i<numberOfEntries; i++) {
+ palette.add(new PaletteEntry());
+ }
+ palette = palette.subList(0, numberOfEntries);
+ props.setPalette(palette);
}
}
@@ -191,22 +233,22 @@ public class HwmfPalette {
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the Palette Object to be selected.
*/
- private int palette;
+ private int paletteIndex;
@Override
public HwmfRecordType getRecordType() {
return HwmfRecordType.selectPalette;
}
-
+
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- palette = leis.readUShort();
+ paletteIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
- }
+ }
@Override
public void draw(HwmfGraphics ctx) {
-
+ ctx.applyObjectTableEntry(paletteIndex);
}
}
@@ -234,7 +276,7 @@ public class HwmfPalette {
/**
* The META_ANIMATEPALETTE record redefines entries in the logical palette that
* is defined in the playback device context with the specified Palette object
- *
+ *
* The logical palette that is specified by the Palette object in this record is the
* source of the palette changes, and the logical palette that is currently selected
* into the playback device context is the destination. Entries in the destination
@@ -251,7 +293,28 @@ public class HwmfPalette {
@Override
public void draw(HwmfGraphics ctx) {
-
+ HwmfDrawProperties props = ctx.getProperties();
+ List<PaletteEntry> dest = props.getPalette();
+ List<PaletteEntry> src = getPaletteCopy();
+ int start = getPaletteStart();
+ if (dest == null) {
+ dest = new ArrayList<PaletteEntry>();
+ }
+ for (int i=dest.size(); i<start; i++) {
+ dest.add(new PaletteEntry());
+ }
+ for (int i=0; i<src.size(); i++) {
+ PaletteEntry pe = src.get(i);
+ if (dest.size() <= start+i) {
+ dest.add(pe);
+ } else {
+ PaletteEntry peDst = dest.get(start+i);
+ if (peDst.isReserved()) {
+ dest.set(start+i, pe);
+ }
+ }
+ }
+ props.setPalette(dest);
}
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
index 075a0a3c91..fb2ce122e1 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
@@ -86,7 +86,7 @@ public class HwmfPenStyle implements Cloneable {
/**
* The pen is solid.
*/
- SOLID(0x0000, 10),
+ SOLID(0x0000, null),
/**
* The pen is dashed. (-----)
*/
@@ -106,19 +106,19 @@ public class HwmfPenStyle implements Cloneable {
/**
* The pen is invisible.
*/
- NULL(0x0005),
+ NULL(0x0005, null),
/**
* The pen is solid. When this pen is used in any drawing record that takes a
* bounding rectangle, the dimensions of the figure are shrunk so that it fits
* entirely in the bounding rectangle, taking into account the width of the pen.
*/
- INSIDEFRAME(0x0006, 10),
+ INSIDEFRAME(0x0006, null),
/**
* The pen uses a styling array supplied by the user.
* (this is currently not supported and drawn as solid ... no idea where the user
* styling is supposed to come from ...)
*/
- USERSTYLE(0x0007, 10);
+ USERSTYLE(0x0007, null);
public int wmfFlag;
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java
index 4518921320..ea22350135 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPlaceableHeader.java
@@ -27,6 +27,7 @@ public class HwmfPlaceableHeader {
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
final Rectangle2D bounds;
+ final int unitsPerInch;
protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
/*
@@ -53,7 +54,7 @@ public class HwmfPlaceableHeader {
* Thus, a value of 720 specifies that the image SHOULD be rendered at twice its normal size,
* and a value of 2880 specifies that the image SHOULD be rendered at half its normal size.
*/
- int inch = leis.readShort();
+ unitsPerInch = leis.readShort();
/*
* Reserved (4 bytes): A field that is not used and MUST be set to 0x00000000.
@@ -82,4 +83,8 @@ public class HwmfPlaceableHeader {
public Rectangle2D getBounds() {
return bounds;
}
+
+ public int getUnitsPerInch() {
+ return unitsPerInch;
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
index 167e446bef..8c6c41549b 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
@@ -17,10 +17,15 @@
package org.apache.poi.hwmf.record;
+import java.awt.geom.Rectangle2D;
import java.io.IOException;
+import java.text.AttributedString;
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LocaleUtil;
@@ -80,7 +85,7 @@ public class HwmfText {
@Override
public void draw(HwmfGraphics ctx) {
-
+ ctx.getProperties().setTextColor(colorRef);
}
}
@@ -168,7 +173,8 @@ public class HwmfText {
@Override
public void draw(HwmfGraphics ctx) {
-
+ Rectangle2D bounds = new Rectangle2D.Double(xStart, yStart, 0, 0);
+ ctx.drawString(text, bounds);
}
}
@@ -304,74 +310,125 @@ public class HwmfText {
}
}
-
+ public enum HwmfTextAlignment {
+ LEFT,
+ RIGHT,
+ CENTER;
+ }
+ public enum HwmfTextVerticalAlignment {
+ TOP,
+ BOTTOM,
+ BASELINE;
+ }
/**
* The META_SETTEXTALIGN record defines text-alignment values in the playback device context.
*/
public static class WmfSetTextAlign implements HwmfRecord {
- /**
- * A 16-bit unsigned integer that defines text alignment.
- * This value MUST be a combination of one or more TextAlignmentMode Flags
- * for text with a horizontal baseline, and VerticalTextAlignmentMode Flags
- * for text with a vertical baseline.
- *
- * TextAlignmentMode Flags:
- * TA_NOUPDATECP (0x0000):
+ // ***********************************************************************************
+ // TextAlignmentMode Flags:
+ // ***********************************************************************************
+
+ /**
* The drawing position in the playback device context MUST NOT be updated after each
* text output call. The reference point MUST be passed to the text output function.
- *
- * TA_LEFT (0x0000):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField TA_NOUPDATECP = BitFieldFactory.getInstance(0x0000);
+
+ /**
* The reference point MUST be on the left edge of the bounding rectangle.
- *
- * TA_TOP (0x0000):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField TA_LEFT = BitFieldFactory.getInstance(0x0000);
+
+ /**
* The reference point MUST be on the top edge of the bounding rectangle.
- *
- * TA_UPDATECP (0x0001):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField TA_TOP = BitFieldFactory.getInstance(0x0000);
+
+ /**
* The drawing position in the playback device context MUST be updated after each text
* output call. It MUST be used as the reference point.
- *
- * TA_RIGHT (0x0002):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField TA_UPDATECP = BitFieldFactory.getInstance(0x0001);
+
+ /**
* The reference point MUST be on the right edge of the bounding rectangle.
- *
- * TA_CENTER (0x0006):
+ */
+ private static final BitField TA_RIGHT = BitFieldFactory.getInstance(0x0002);
+
+ /**
* The reference point MUST be aligned horizontally with the center of the bounding
* rectangle.
- *
- * TA_BOTTOM (0x0008):
+ */
+ private static final BitField TA_CENTER = BitFieldFactory.getInstance(0x0006);
+
+ /**
* The reference point MUST be on the bottom edge of the bounding rectangle.
- *
- * TA_BASELINE (0x0018):
+ */
+ private static final BitField TA_BOTTOM = BitFieldFactory.getInstance(0x0008);
+
+ /**
* The reference point MUST be on the baseline of the text.
- *
- * TA_RTLREADING (0x0100):
+ */
+ private static final BitField TA_BASELINE = BitFieldFactory.getInstance(0x0018);
+
+ /**
* The text MUST be laid out in right-to-left reading order, instead of the default
- * left-toright order. This SHOULD be applied only when the font that is defined in the
+ * left-to-right order. This SHOULD be applied only when the font that is defined in the
* playback device context is either Hebrew or Arabic.
- *
- *
- * VerticalTextAlignmentMode Flags (e.g. for Kanji fonts)
- * VTA_TOP (0x0000):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField TA_RTLREADING = BitFieldFactory.getInstance(0x0100);
+
+ // ***********************************************************************************
+ // VerticalTextAlignmentMode Flags (e.g. for Kanji fonts)
+ // ***********************************************************************************
+
+ /**
* The reference point MUST be on the top edge of the bounding rectangle.
- *
- * VTA_RIGHT (0x0000):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField VTA_TOP = BitFieldFactory.getInstance(0x0000);
+
+ /**
* The reference point MUST be on the right edge of the bounding rectangle.
- *
- * VTA_BOTTOM (0x0002):
+ */
+ @SuppressWarnings("unused")
+ private static final BitField VTA_RIGHT = BitFieldFactory.getInstance(0x0000);
+
+ /**
* The reference point MUST be on the bottom edge of the bounding rectangle.
- *
- * VTA_CENTER (0x0006):
+ */
+ private static final BitField VTA_BOTTOM = BitFieldFactory.getInstance(0x0002);
+
+ /**
* The reference point MUST be aligned vertically with the center of the bounding
* rectangle.
- *
- * VTA_LEFT (0x0008):
+ */
+ private static final BitField VTA_CENTER = BitFieldFactory.getInstance(0x0006);
+
+ /**
* The reference point MUST be on the left edge of the bounding rectangle.
- *
- * VTA_BASELINE (0x0018):
+ */
+ private static final BitField VTA_LEFT = BitFieldFactory.getInstance(0x0008);
+
+ /**
* The reference point MUST be on the baseline of the text.
*/
+ private static final BitField VTA_BASELINE = BitFieldFactory.getInstance(0x0018);
+
+ /**
+ * A 16-bit unsigned integer that defines text alignment.
+ * This value MUST be a combination of one or more TextAlignmentMode Flags
+ * for text with a horizontal baseline, and VerticalTextAlignmentMode Flags
+ * for text with a vertical baseline.
+ */
private int textAlignmentMode;
@Override
@@ -387,7 +444,38 @@ public class HwmfText {
@Override
public void draw(HwmfGraphics ctx) {
+ HwmfDrawProperties props = ctx.getProperties();
+ if (TA_CENTER.isSet(textAlignmentMode)) {
+ props.setTextAlignLatin(HwmfTextAlignment.CENTER);
+ } else if (TA_RIGHT.isSet(textAlignmentMode)) {
+ props.setTextAlignLatin(HwmfTextAlignment.RIGHT);
+ } else {
+ props.setTextAlignLatin(HwmfTextAlignment.LEFT);
+ }
+
+ if (VTA_CENTER.isSet(textAlignmentMode)) {
+ props.setTextAlignAsian(HwmfTextAlignment.CENTER);
+ } else if (VTA_LEFT.isSet(textAlignmentMode)) {
+ props.setTextAlignAsian(HwmfTextAlignment.LEFT);
+ } else {
+ props.setTextAlignAsian(HwmfTextAlignment.RIGHT);
+ }
+
+ if (TA_BASELINE.isSet(textAlignmentMode)) {
+ props.setTextVAlignLatin(HwmfTextVerticalAlignment.BASELINE);
+ } else if (TA_BOTTOM.isSet(textAlignmentMode)) {
+ props.setTextVAlignLatin(HwmfTextVerticalAlignment.BOTTOM);
+ } else {
+ props.setTextVAlignLatin(HwmfTextVerticalAlignment.TOP);
+ }
+ if (VTA_BASELINE.isSet(textAlignmentMode)) {
+ props.setTextVAlignAsian(HwmfTextVerticalAlignment.BASELINE);
+ } else if (VTA_BOTTOM.isSet(textAlignmentMode)) {
+ props.setTextVAlignAsian(HwmfTextVerticalAlignment.BOTTOM);
+ } else {
+ props.setTextVAlignAsian(HwmfTextVerticalAlignment.TOP);
+ }
}
}
@@ -412,7 +500,7 @@ public class HwmfText {
@Override
public void applyObject(HwmfGraphics ctx) {
-
+ ctx.getProperties().setFont(font);
}
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
index 19385d4fee..39a05e6600 100644
--- a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
+++ b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
@@ -17,9 +17,12 @@
package org.apache.poi.hwmf.usermodel;
+import java.awt.Dimension;
import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
+import java.awt.geom.Rectangle2D.Double;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -35,6 +38,7 @@ import org.apache.poi.hwmf.record.HwmfRecordType;
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowExt;
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg;
import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.Units;
public class HwmfPicture {
final List<HwmfRecord> records = new ArrayList<HwmfRecord>();
@@ -85,9 +89,23 @@ public class HwmfPicture {
}
public void draw(Graphics2D ctx) {
+ Dimension dim = getSize();
+ int width = Units.pointsToPixel(dim.getWidth());
+ // keep aspect ratio for height
+ int height = Units.pointsToPixel(dim.getHeight());
+ Rectangle2D bounds = new Rectangle2D.Double(0,0,width,height);
+ draw(ctx, bounds);
+ }
+
+ public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
AffineTransform at = ctx.getTransform();
try {
- HwmfGraphics g = new HwmfGraphics(ctx, getBounds());
+ Rectangle2D wmfBounds = getBounds();
+ // scale output bounds to image bounds
+ ctx.scale(graphicsBounds.getWidth()/wmfBounds.getWidth(), graphicsBounds.getHeight()/wmfBounds.getHeight());
+ ctx.translate(-wmfBounds.getX(), -wmfBounds.getY());
+
+ HwmfGraphics g = new HwmfGraphics(ctx, wmfBounds);
for (HwmfRecord r : records) {
r.draw(g);
}
@@ -131,4 +149,18 @@ public class HwmfPicture {
public HwmfHeader getHeader() {
return header;
}
+
+ /**
+ * Return the image size in points
+ *
+ * @return the image size in points
+ */
+ public Dimension getSize() {
+ double inch = (placeableHeader == null) ? 1440 : placeableHeader.getUnitsPerInch();
+ Rectangle2D bounds = getBounds();
+
+ //coefficient to translate from WMF dpi to 72dpi
+ double coeff = Units.POINT_DPI/inch;
+ return new Dimension((int)Math.round(bounds.getWidth()*coeff), (int)Math.round(bounds.getHeight()*coeff));
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
index 8d14f0c7dc..7ddacf475a 100644
--- a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
+++ b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
@@ -19,9 +19,9 @@ package org.apache.poi.hwmf;
import static org.junit.Assert.assertEquals;
+import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
-import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
@@ -45,6 +45,7 @@ import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
+import org.apache.poi.util.Units;
import org.junit.Ignore;
import org.junit.Test;
@@ -60,17 +61,18 @@ public class TestHwmfParsing {
}
@Test
- @Ignore
+ @Ignore("This is work-in-progress and not a real unit test ...")
public void paint() throws IOException {
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
+// File f = new File("E:\\project\\poi\\misc\\govdocs-ppt", "000133-0001.wmf");
FileInputStream fis = new FileInputStream(f);
HwmfPicture wmf = new HwmfPicture(fis);
fis.close();
- Rectangle2D bounds = wmf.getBounds();
- int width = 300;
+ Dimension dim = wmf.getSize();
+ int width = Units.pointsToPixel(dim.getWidth());
// keep aspect ratio for height
- int height = (int)(width*bounds.getHeight()/bounds.getWidth());
+ int height = Units.pointsToPixel(dim.getHeight());
BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bufImg.createGraphics();
@@ -87,7 +89,7 @@ public class TestHwmfParsing {
}
@Test
- @Ignore
+ @Ignore("This is work-in-progress and not a real unit test ...")
public void fetchWmfFromGovdocs() throws IOException {
URL url = new URL("http://digitalcorpora.org/corpora/files/govdocs1/by_type/ppt.zip");
File outdir = new File("build/ppt");
@@ -117,12 +119,16 @@ public class TestHwmfParsing {
}
}
}
-
+
@Test
- @Ignore
+ @Ignore("This is work-in-progress and not a real unit test ...")
public void parseWmfs() throws IOException {
+ // parse and render the extracted wmfs from the fetchWmfFromGovdocs step
boolean outputFiles = false;
- File indir = new File("build/ppt"), outdir = indir;
+ boolean renderWmf = true;
+ File indir = new File("E:\\project\\poi\\misc\\govdocs-ppt");
+ File outdir = new File("build/wmf");
+ outdir.mkdirs();
final String startFile = "";
File files[] = indir.listFiles(new FileFilter() {
boolean foundStartFile = false;
@@ -149,6 +155,26 @@ public class TestHwmfParsing {
bmpIndex++;
}
}
+
+ if (renderWmf) {
+ Dimension dim = wmf.getSize();
+ int width = Units.pointsToPixel(dim.getWidth());
+ // keep aspect ratio for height
+ int height = Units.pointsToPixel(dim.getHeight());
+
+ BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = bufImg.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+ wmf.draw(g);
+
+ g.dispose();
+
+ ImageIO.write(bufImg, "PNG", new File(outdir, basename+".png"));
+ }
} catch (Exception e) {
System.out.println(f.getName()+" ignored.");
}