WMF fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723898 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f065bf6e00
commit
22a9bade84
@ -25,14 +25,19 @@ import java.awt.geom.Rectangle2D;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.ColorModel;
|
import java.awt.image.ColorModel;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfColorRef;
|
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.HwmfFill.WmfSetPolyfillMode.HwmfPolyfillMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfMapMode;
|
import org.apache.poi.hwmf.record.HwmfMapMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
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.HwmfPenStyle;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfText.HwmfTextAlignment;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfText.HwmfTextVerticalAlignment;
|
||||||
|
|
||||||
public class HwmfDrawProperties {
|
public class HwmfDrawProperties {
|
||||||
private final Rectangle2D window;
|
private final Rectangle2D window;
|
||||||
@ -51,6 +56,14 @@ public class HwmfDrawProperties {
|
|||||||
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
|
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
|
||||||
private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;
|
private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;
|
||||||
private Shape region = null;
|
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() {
|
public HwmfDrawProperties() {
|
||||||
window = new Rectangle2D.Double(0, 0, 1, 1);
|
window = new Rectangle2D.Double(0, 0, 1, 1);
|
||||||
@ -84,9 +97,16 @@ public class HwmfDrawProperties {
|
|||||||
} else if (other.region instanceof Area) {
|
} else if (other.region instanceof Area) {
|
||||||
this.region = new Area(other.region);
|
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) {
|
public void setViewportExt(double width, double height) {
|
||||||
|
if (viewport == null) {
|
||||||
|
viewport = (Rectangle2D)window.clone();
|
||||||
|
}
|
||||||
double x = viewport.getX();
|
double x = viewport.getX();
|
||||||
double y = viewport.getY();
|
double y = viewport.getY();
|
||||||
double w = (width != 0) ? width : viewport.getWidth();
|
double w = (width != 0) ? width : viewport.getWidth();
|
||||||
@ -244,4 +264,80 @@ public class HwmfDrawProperties {
|
|||||||
public void setRegion(Shape region) {
|
public void setRegion(Shape region) {
|
||||||
this.region = 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,12 @@ import java.awt.Paint;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.TexturePaint;
|
import java.awt.TexturePaint;
|
||||||
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.GeneralPath;
|
import java.awt.geom.GeneralPath;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.text.AttributedString;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -36,13 +38,13 @@ import java.util.ListIterator;
|
|||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfFont;
|
||||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfMapMode;
|
import org.apache.poi.hwmf.record.HwmfMapMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
|
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
|
||||||
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
|
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
|
||||||
import org.apache.poi.util.Units;
|
|
||||||
|
|
||||||
public class HwmfGraphics {
|
public class HwmfGraphics {
|
||||||
private final Graphics2D graphicsCtx;
|
private final Graphics2D graphicsCtx;
|
||||||
@ -118,7 +120,7 @@ public class HwmfGraphics {
|
|||||||
boolean dashAlt = ps.isAlternateDash();
|
boolean dashAlt = ps.isAlternateDash();
|
||||||
// This value is not an integer index into the dash pattern array.
|
// This value is not an integer index into the dash pattern array.
|
||||||
// Instead, it is a floating-point value that specifies a linear distance.
|
// Instead, it is a floating-point value that specifies a linear distance.
|
||||||
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);
|
return new BasicStroke(width, cap, join, miterLimit, dashes, dashStart);
|
||||||
}
|
}
|
||||||
@ -243,8 +245,8 @@ public class HwmfGraphics {
|
|||||||
/**
|
/**
|
||||||
* Restores the properties from the stack
|
* Restores the properties from the stack
|
||||||
*
|
*
|
||||||
* @param index if the index is positive, the n-th element from the start 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 removed and activated.
|
* If the index is negative, the n-th previous element relative to the current properties element is activated.
|
||||||
*/
|
*/
|
||||||
public void restoreProperties(int index) {
|
public void restoreProperties(int index) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
@ -253,12 +255,20 @@ public class HwmfGraphics {
|
|||||||
int stackIndex = index;
|
int stackIndex = index;
|
||||||
if (stackIndex < 0) {
|
if (stackIndex < 0) {
|
||||||
int curIdx = propStack.indexOf(prop);
|
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;
|
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() {
|
public void updateWindowMapMode() {
|
||||||
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
|
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
|
||||||
Rectangle2D win = prop.getWindow();
|
Rectangle2D win = prop.getWindow();
|
||||||
@ -268,23 +278,15 @@ public class HwmfGraphics {
|
|||||||
switch (mapMode) {
|
switch (mapMode) {
|
||||||
default:
|
default:
|
||||||
case MM_ANISOTROPIC:
|
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
|
// scale window bounds to output bounds
|
||||||
graphicsCtx.translate(win.getCenterX(), win.getCenterY());
|
|
||||||
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
|
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
|
||||||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
|
graphicsCtx.translate(-win.getX(), -win.getY());
|
||||||
break;
|
break;
|
||||||
case MM_ISOTROPIC:
|
case MM_ISOTROPIC:
|
||||||
// TODO: to be validated ...
|
// TODO: to be validated ...
|
||||||
// like anisotropic, but use x-axis as reference
|
// 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.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth());
|
||||||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
|
graphicsCtx.translate(-win.getX(), -win.getY());
|
||||||
break;
|
break;
|
||||||
case MM_LOMETRIC:
|
case MM_LOMETRIC:
|
||||||
case MM_HIMETRIC:
|
case MM_HIMETRIC:
|
||||||
@ -294,11 +296,48 @@ public class HwmfGraphics {
|
|||||||
// TODO: to be validated ...
|
// TODO: to be validated ...
|
||||||
graphicsCtx.transform(gc.getNormalizingTransform());
|
graphicsCtx.transform(gc.getNormalizingTransform());
|
||||||
graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);
|
graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);
|
||||||
graphicsCtx.translate(-bbox.getX(), -bbox.getY());
|
graphicsCtx.translate(-win.getX(), -win.getY());
|
||||||
break;
|
break;
|
||||||
case MM_TEXT:
|
case MM_TEXT:
|
||||||
// TODO: to be validated ...
|
// TODO: to be validated ...
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.record;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
import java.awt.Polygon;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Arc2D;
|
import java.awt.geom.Arc2D;
|
||||||
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.GeneralPath;
|
|
||||||
import java.awt.geom.Line2D;
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.geom.RoundRectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
@ -114,12 +115,7 @@ public class HwmfDraw {
|
|||||||
*/
|
*/
|
||||||
public static class WmfPolygon implements HwmfRecord {
|
public static class WmfPolygon implements HwmfRecord {
|
||||||
|
|
||||||
/**
|
private Path2D poly = new Path2D.Double();
|
||||||
* A 16-bit signed integer that defines the number of points in the array.
|
|
||||||
*/
|
|
||||||
private int numberofPoints;
|
|
||||||
|
|
||||||
short xPoints[], yPoints[];
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
@ -128,15 +124,21 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
numberofPoints = leis.readShort();
|
/**
|
||||||
xPoints = new short[numberofPoints];
|
* A 16-bit signed integer that defines the number of points in the array.
|
||||||
yPoints = new short[numberofPoints];
|
*/
|
||||||
|
int numberofPoints = leis.readShort();
|
||||||
|
|
||||||
for (int i=0; i<numberofPoints; i++) {
|
for (int i=0; i<numberofPoints; i++) {
|
||||||
// A 16-bit signed integer that defines the horizontal (x) coordinate of the point.
|
// 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.
|
// 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;
|
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;
|
||||||
@ -144,15 +146,14 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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() {
|
protected Path2D getShape() {
|
||||||
Polygon polygon = new Polygon();
|
return (Path2D)poly.clone();
|
||||||
for(int i = 0; i < numberofPoints; i++) {
|
|
||||||
polygon.addPoint(xPoints[i], yPoints[i]);
|
|
||||||
}
|
|
||||||
return polygon;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +170,9 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||||
* the region to be framed.
|
* 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
|
* A 16-bit unsigned integer used to index into the WMF Object Table to get the
|
||||||
* Brush to use for filling the region.
|
* 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
|
* A 16-bit signed integer that defines the height, in logical units, of the
|
||||||
* region frame.
|
* region frame.
|
||||||
@ -258,8 +261,8 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
region = leis.readUShort();
|
regionIndex = leis.readUShort();
|
||||||
brush = leis.readUShort();
|
brushIndex = leis.readUShort();
|
||||||
height = leis.readShort();
|
height = leis.readShort();
|
||||||
width = leis.readShort();
|
width = leis.readShort();
|
||||||
return 4*LittleEndianConsts.SHORT_SIZE;
|
return 4*LittleEndianConsts.SHORT_SIZE;
|
||||||
@ -267,7 +270,17 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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,27 +291,7 @@ public class HwmfDraw {
|
|||||||
*/
|
*/
|
||||||
public static class WmfPolyPolygon implements HwmfRecord {
|
public static class WmfPolyPolygon implements HwmfRecord {
|
||||||
|
|
||||||
/**
|
private List<Path2D> polyList = new ArrayList<Path2D>();
|
||||||
* 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[][];
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
@ -308,10 +301,15 @@ public class HwmfDraw {
|
|||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
// see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
|
// see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
|
||||||
numberOfPolygons = leis.readUShort();
|
/**
|
||||||
pointsPerPolygon = new int[numberOfPolygons];
|
* A 16-bit unsigned integer that defines the number of polygons in the object.
|
||||||
xPoints = new int[numberOfPolygons][];
|
*/
|
||||||
yPoints = new int[numberOfPolygons][];
|
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;
|
int size = LittleEndianConsts.SHORT_SIZE;
|
||||||
|
|
||||||
@ -320,24 +318,38 @@ public class HwmfDraw {
|
|||||||
size += LittleEndianConsts.SHORT_SIZE;
|
size += LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<numberOfPolygons; i++) {
|
for (int nPoints : pointsPerPolygon) {
|
||||||
|
/**
|
||||||
xPoints[i] = new int[pointsPerPolygon[i]];
|
* An array of 16-bit unsigned integers that define the coordinates of the polygons.
|
||||||
yPoints[i] = new int[pointsPerPolygon[i]];
|
*/
|
||||||
|
Path2D poly = new Path2D.Double();
|
||||||
for (int j=0; j<pointsPerPolygon[i]; j++) {
|
for (int i=0; i<nPoints; i++) {
|
||||||
xPoints[i][j] = leis.readUShort();
|
int x = leis.readUShort();
|
||||||
yPoints[i][j] = leis.readUShort();
|
int y = leis.readUShort();
|
||||||
size += 2*LittleEndianConsts.SHORT_SIZE;
|
size += 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
|
if (i == 0) {
|
||||||
|
poly.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
poly.lineTo(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
poly.closePath();
|
||||||
|
polyList.add(poly);
|
||||||
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,42 @@ public class HwmfFill {
|
|||||||
BufferedImage getImage();
|
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.
|
* 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
|
* A 16-bit unsigned integer that defines whether the Colors field of the
|
||||||
* DIB contains explicit RGB values or indexes into a palette.
|
* 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
|
* A 16-bit signed integer that defines the height, in logical units, of the
|
||||||
* source rectangle.
|
* source rectangle.
|
||||||
@ -548,7 +580,7 @@ public class HwmfFill {
|
|||||||
rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
|
rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
|
||||||
assert(rasterOpCode == rasterOperation.opCode);
|
assert(rasterOpCode == rasterOperation.opCode);
|
||||||
|
|
||||||
colorUsage = leis.readUShort();
|
colorUsage = ColorUsage.valueOf(leis.readUShort());
|
||||||
srcHeight = leis.readShort();
|
srcHeight = leis.readShort();
|
||||||
srcWidth = leis.readShort();
|
srcWidth = leis.readShort();
|
||||||
ySrc = 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
|
* A 16-bit unsigned integer that defines whether the Colors field of the
|
||||||
* DIB contains explicit RGB values or indexes into a palette.
|
* 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.
|
* A 16-bit unsigned integer that defines the number of scan lines in the source.
|
||||||
*/
|
*/
|
||||||
@ -736,7 +764,7 @@ public class HwmfFill {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
colorUsage = leis.readUShort();
|
colorUsage = ColorUsage.valueOf(leis.readUShort());
|
||||||
scanCount = leis.readUShort();
|
scanCount = leis.readUShort();
|
||||||
startScan = leis.readUShort();
|
startScan = leis.readUShort();
|
||||||
yDib = leis.readUShort();
|
yDib = leis.readUShort();
|
||||||
|
@ -497,4 +497,64 @@ public class HwmfFont {
|
|||||||
|
|
||||||
return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfFill.ColorUsage;
|
||||||
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
|
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
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
|
* If the Style field specifies BS_PATTERN, a ColorUsage value of DIB_RGB_COLORS MUST be
|
||||||
* used regardless of the contents of this field.
|
* 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:
|
* If the Style field specified anything but BS_PATTERN, this field MUST be one of the ColorUsage values.
|
||||||
* DIB_RGB_COLORS = 0x0000,
|
|
||||||
* DIB_PAL_COLORS = 0x0001,
|
|
||||||
* DIB_PAL_INDICES = 0x0002
|
|
||||||
*/
|
*/
|
||||||
private int colorUsage;
|
private ColorUsage colorUsage;
|
||||||
|
|
||||||
private HwmfBitmapDib patternDib;
|
private HwmfBitmapDib patternDib;
|
||||||
private HwmfBitmap16 pattern16;
|
private HwmfBitmap16 pattern16;
|
||||||
@ -367,7 +365,7 @@ public class HwmfMisc {
|
|||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
style = HwmfBrushStyle.valueOf(leis.readUShort());
|
style = HwmfBrushStyle.valueOf(leis.readUShort());
|
||||||
colorUsage = leis.readUShort();
|
colorUsage = ColorUsage.valueOf(leis.readUShort());
|
||||||
int size = 2*LittleEndianConsts.SHORT_SIZE;
|
int size = 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case BS_SOLID:
|
case BS_SOLID:
|
||||||
|
@ -19,67 +19,77 @@ package org.apache.poi.hwmf.record;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.io.IOException;
|
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.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.LittleEndianConsts;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
|
|
||||||
public class HwmfPalette {
|
public class HwmfPalette {
|
||||||
|
|
||||||
public static class PaletteEntry {
|
public static class PaletteEntry {
|
||||||
enum PaletteEntryFlag {
|
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);
|
||||||
|
|
||||||
|
private int values;
|
||||||
|
private Color colorRef;
|
||||||
|
|
||||||
|
private PaletteEntry() {
|
||||||
|
this.values = PC_RESERVED.set(0);
|
||||||
|
this.colorRef = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PaletteEntry(PaletteEntry other) {
|
||||||
|
this.values = other.values;
|
||||||
|
this.colorRef = other.colorRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int init(LittleEndianInputStream leis) throws IOException {
|
||||||
|
// 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
|
* 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
|
* 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.
|
* changes. If an unused system-palette entry is available, the color is placed in that entry.
|
||||||
* Otherwise, the color is not available for animation.
|
* Otherwise, the color is not available for animation.
|
||||||
*/
|
*/
|
||||||
PC_RESERVED(0x01),
|
public boolean isReserved() {
|
||||||
|
return PC_RESERVED.isSet(values);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that the low-order word of the logical palette entry designates a hardware
|
* 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.
|
* palette index. This value allows the application to show the contents of the display device palette.
|
||||||
*/
|
*/
|
||||||
PC_EXPLICIT(0x02),
|
public boolean isExplicit() {
|
||||||
|
return PC_EXPLICIT.isSet(values);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that the color be placed in an unused entry in the system palette
|
* 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
|
* 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,
|
* 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.
|
* colors in other logical palettes can be matched to this color.
|
||||||
*/
|
*/
|
||||||
PC_NOCOLLAPSE(0x04)
|
public boolean isNoCollapse() {
|
||||||
;
|
return PC_NOCOLLAPSE.isSet(values);
|
||||||
|
|
||||||
int flag;
|
|
||||||
|
|
||||||
PaletteEntryFlag(int flag) {
|
|
||||||
this.flag = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PaletteEntryFlag valueOf(int flag) {
|
|
||||||
for (PaletteEntryFlag pef : values()) {
|
|
||||||
if (pef.flag == flag) return pef;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
public int init(LittleEndianInputStream leis) throws IOException {
|
|
||||||
values = PaletteEntryFlag.valueOf(leis.readUByte());
|
|
||||||
int blue = leis.readUByte();
|
|
||||||
int green = leis.readUByte();
|
|
||||||
int red = leis.readUByte();
|
|
||||||
colorRef = new Color(red, green, blue);
|
|
||||||
|
|
||||||
return 4*LittleEndianConsts.BYTE_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,30 +102,35 @@ public class HwmfPalette {
|
|||||||
*/
|
*/
|
||||||
private int start;
|
private int start;
|
||||||
|
|
||||||
/**
|
private List<PaletteEntry> palette = new ArrayList<PaletteEntry>();
|
||||||
* NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
|
|
||||||
* aPaletteEntries.
|
|
||||||
*/
|
|
||||||
private int numberOfEntries;
|
|
||||||
|
|
||||||
private PaletteEntry entries[];
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
start = leis.readUShort();
|
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;
|
int size = 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
entries = new PaletteEntry[numberOfEntries];
|
|
||||||
for (int i=0; i<numberOfEntries; i++) {
|
for (int i=0; i<numberOfEntries; i++) {
|
||||||
entries[i] = new PaletteEntry();
|
PaletteEntry pe = new PaletteEntry();
|
||||||
size += entries[i].init(leis);
|
size += pe.init(leis);
|
||||||
|
palette.add(pe);
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected List<PaletteEntry> getPaletteCopy() {
|
||||||
public void draw(HwmfGraphics ctx) {
|
List<PaletteEntry> newPalette = new ArrayList<PaletteEntry>();
|
||||||
|
for (PaletteEntry et : palette) {
|
||||||
|
newPalette.add(new PaletteEntry(et));
|
||||||
|
}
|
||||||
|
return newPalette;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getPaletteStart() {
|
||||||
|
return start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +150,7 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyObject(HwmfGraphics ctx) {
|
public void applyObject(HwmfGraphics ctx) {
|
||||||
|
ctx.getProperties().setPalette(getPaletteCopy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +166,25 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +212,16 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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,7 +233,7 @@ public class HwmfPalette {
|
|||||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||||
* the Palette Object to be selected.
|
* the Palette Object to be selected.
|
||||||
*/
|
*/
|
||||||
private int palette;
|
private int paletteIndex;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
@ -200,13 +242,13 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
palette = leis.readUShort();
|
paletteIndex = leis.readUShort();
|
||||||
return LittleEndianConsts.SHORT_SIZE;
|
return LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.applyObjectTableEntry(paletteIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +293,28 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public class HwmfPenStyle implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* The pen is solid.
|
* The pen is solid.
|
||||||
*/
|
*/
|
||||||
SOLID(0x0000, 10),
|
SOLID(0x0000, null),
|
||||||
/**
|
/**
|
||||||
* The pen is dashed. (-----)
|
* The pen is dashed. (-----)
|
||||||
*/
|
*/
|
||||||
@ -106,19 +106,19 @@ public class HwmfPenStyle implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* The pen is invisible.
|
* 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
|
* 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
|
* 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.
|
* 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.
|
* The pen uses a styling array supplied by the user.
|
||||||
* (this is currently not supported and drawn as solid ... no idea where the user
|
* (this is currently not supported and drawn as solid ... no idea where the user
|
||||||
* styling is supposed to come from ...)
|
* styling is supposed to come from ...)
|
||||||
*/
|
*/
|
||||||
USERSTYLE(0x0007, 10);
|
USERSTYLE(0x0007, null);
|
||||||
|
|
||||||
|
|
||||||
public int wmfFlag;
|
public int wmfFlag;
|
||||||
|
@ -27,6 +27,7 @@ public class HwmfPlaceableHeader {
|
|||||||
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
|
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
|
||||||
|
|
||||||
final Rectangle2D bounds;
|
final Rectangle2D bounds;
|
||||||
|
final int unitsPerInch;
|
||||||
|
|
||||||
protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
|
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,
|
* 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.
|
* 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.
|
* 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() {
|
public Rectangle2D getBounds() {
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getUnitsPerInch() {
|
||||||
|
return unitsPerInch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,15 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.record;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.IOException;
|
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.draw.HwmfGraphics;
|
||||||
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
|
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.LittleEndianConsts;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
@ -80,7 +85,7 @@ public class HwmfText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.getProperties().setTextColor(colorRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +173,8 @@ public class HwmfText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
Rectangle2D bounds = new Rectangle2D.Double(xStart, yStart, 0, 0);
|
||||||
|
ctx.drawString(text, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,73 +310,124 @@ 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.
|
* The META_SETTEXTALIGN record defines text-alignment values in the playback device context.
|
||||||
*/
|
*/
|
||||||
public static class WmfSetTextAlign implements HwmfRecord {
|
public static class WmfSetTextAlign implements HwmfRecord {
|
||||||
|
|
||||||
|
// ***********************************************************************************
|
||||||
|
// 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.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final BitField TA_NOUPDATECP = BitFieldFactory.getInstance(0x0000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the left edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final BitField TA_LEFT = BitFieldFactory.getInstance(0x0000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the top edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final BitField TA_UPDATECP = BitFieldFactory.getInstance(0x0001);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the right edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
private static final BitField TA_RIGHT = BitFieldFactory.getInstance(0x0002);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be aligned horizontally with the center of the bounding
|
||||||
|
* rectangle.
|
||||||
|
*/
|
||||||
|
private static final BitField TA_CENTER = BitFieldFactory.getInstance(0x0006);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the bottom edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
private static final BitField TA_BOTTOM = BitFieldFactory.getInstance(0x0008);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the baseline of the text.
|
||||||
|
*/
|
||||||
|
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-to-right order. This SHOULD be applied only when the font that is defined in the
|
||||||
|
* playback device context is either Hebrew or Arabic.
|
||||||
|
*/
|
||||||
|
@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.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final BitField VTA_TOP = BitFieldFactory.getInstance(0x0000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the right edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final BitField VTA_RIGHT = BitFieldFactory.getInstance(0x0000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the bottom edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
private static final BitField VTA_BOTTOM = BitFieldFactory.getInstance(0x0002);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be aligned vertically with the center of the bounding
|
||||||
|
* rectangle.
|
||||||
|
*/
|
||||||
|
private static final BitField VTA_CENTER = BitFieldFactory.getInstance(0x0006);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference point MUST be on the left edge of the bounding rectangle.
|
||||||
|
*/
|
||||||
|
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.
|
* A 16-bit unsigned integer that defines text alignment.
|
||||||
* This value MUST be a combination of one or more TextAlignmentMode Flags
|
* 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 horizontal baseline, and VerticalTextAlignmentMode Flags
|
||||||
* for text with a vertical baseline.
|
* for text with a vertical baseline.
|
||||||
*
|
|
||||||
* TextAlignmentMode Flags:
|
|
||||||
* TA_NOUPDATECP (0x0000):
|
|
||||||
* 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):
|
|
||||||
* The reference point MUST be on the left edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* TA_TOP (0x0000):
|
|
||||||
* The reference point MUST be on the top edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* TA_UPDATECP (0x0001):
|
|
||||||
* 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):
|
|
||||||
* The reference point MUST be on the right edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* TA_CENTER (0x0006):
|
|
||||||
* The reference point MUST be aligned horizontally with the center of the bounding
|
|
||||||
* rectangle.
|
|
||||||
*
|
|
||||||
* TA_BOTTOM (0x0008):
|
|
||||||
* The reference point MUST be on the bottom edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* TA_BASELINE (0x0018):
|
|
||||||
* The reference point MUST be on the baseline of the text.
|
|
||||||
*
|
|
||||||
* TA_RTLREADING (0x0100):
|
|
||||||
* 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
|
|
||||||
* playback device context is either Hebrew or Arabic.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* VerticalTextAlignmentMode Flags (e.g. for Kanji fonts)
|
|
||||||
* VTA_TOP (0x0000):
|
|
||||||
* The reference point MUST be on the top edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* VTA_RIGHT (0x0000):
|
|
||||||
* The reference point MUST be on the right edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* VTA_BOTTOM (0x0002):
|
|
||||||
* The reference point MUST be on the bottom edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* VTA_CENTER (0x0006):
|
|
||||||
* The reference point MUST be aligned vertically with the center of the bounding
|
|
||||||
* rectangle.
|
|
||||||
*
|
|
||||||
* VTA_LEFT (0x0008):
|
|
||||||
* The reference point MUST be on the left edge of the bounding rectangle.
|
|
||||||
*
|
|
||||||
* VTA_BASELINE (0x0018):
|
|
||||||
* The reference point MUST be on the baseline of the text.
|
|
||||||
*/
|
*/
|
||||||
private int textAlignmentMode;
|
private int textAlignmentMode;
|
||||||
|
|
||||||
@ -387,7 +444,38 @@ public class HwmfText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
@Override
|
||||||
public void applyObject(HwmfGraphics ctx) {
|
public void applyObject(HwmfGraphics ctx) {
|
||||||
|
ctx.getProperties().setFont(font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.usermodel;
|
package org.apache.poi.hwmf.usermodel;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.geom.Rectangle2D.Double;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
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.WmfSetWindowExt;
|
||||||
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg;
|
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
|
import org.apache.poi.util.Units;
|
||||||
|
|
||||||
public class HwmfPicture {
|
public class HwmfPicture {
|
||||||
final List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
final List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
||||||
@ -85,9 +89,23 @@ public class HwmfPicture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Graphics2D ctx) {
|
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();
|
AffineTransform at = ctx.getTransform();
|
||||||
try {
|
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) {
|
for (HwmfRecord r : records) {
|
||||||
r.draw(g);
|
r.draw(g);
|
||||||
}
|
}
|
||||||
@ -131,4 +149,18 @@ public class HwmfPicture {
|
|||||||
public HwmfHeader getHeader() {
|
public HwmfHeader getHeader() {
|
||||||
return header;
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ package org.apache.poi.hwmf;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.RenderingHints;
|
import java.awt.RenderingHints;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
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.PictureData.PictureType;
|
||||||
import org.apache.poi.sl.usermodel.SlideShow;
|
import org.apache.poi.sl.usermodel.SlideShow;
|
||||||
import org.apache.poi.sl.usermodel.SlideShowFactory;
|
import org.apache.poi.sl.usermodel.SlideShowFactory;
|
||||||
|
import org.apache.poi.util.Units;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -60,17 +61,18 @@ public class TestHwmfParsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore("This is work-in-progress and not a real unit test ...")
|
||||||
public void paint() throws IOException {
|
public void paint() throws IOException {
|
||||||
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
|
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);
|
FileInputStream fis = new FileInputStream(f);
|
||||||
HwmfPicture wmf = new HwmfPicture(fis);
|
HwmfPicture wmf = new HwmfPicture(fis);
|
||||||
fis.close();
|
fis.close();
|
||||||
|
|
||||||
Rectangle2D bounds = wmf.getBounds();
|
Dimension dim = wmf.getSize();
|
||||||
int width = 300;
|
int width = Units.pointsToPixel(dim.getWidth());
|
||||||
// keep aspect ratio for height
|
// 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);
|
BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
Graphics2D g = bufImg.createGraphics();
|
Graphics2D g = bufImg.createGraphics();
|
||||||
@ -87,7 +89,7 @@ public class TestHwmfParsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore("This is work-in-progress and not a real unit test ...")
|
||||||
public void fetchWmfFromGovdocs() throws IOException {
|
public void fetchWmfFromGovdocs() throws IOException {
|
||||||
URL url = new URL("http://digitalcorpora.org/corpora/files/govdocs1/by_type/ppt.zip");
|
URL url = new URL("http://digitalcorpora.org/corpora/files/govdocs1/by_type/ppt.zip");
|
||||||
File outdir = new File("build/ppt");
|
File outdir = new File("build/ppt");
|
||||||
@ -119,10 +121,14 @@ public class TestHwmfParsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore("This is work-in-progress and not a real unit test ...")
|
||||||
public void parseWmfs() throws IOException {
|
public void parseWmfs() throws IOException {
|
||||||
|
// parse and render the extracted wmfs from the fetchWmfFromGovdocs step
|
||||||
boolean outputFiles = false;
|
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 = "";
|
final String startFile = "";
|
||||||
File files[] = indir.listFiles(new FileFilter() {
|
File files[] = indir.listFiles(new FileFilter() {
|
||||||
boolean foundStartFile = false;
|
boolean foundStartFile = false;
|
||||||
@ -149,6 +155,26 @@ public class TestHwmfParsing {
|
|||||||
bmpIndex++;
|
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) {
|
} catch (Exception e) {
|
||||||
System.out.println(f.getName()+" ignored.");
|
System.out.println(f.getName()+" ignored.");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user