WMF fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1722771 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0fe35af294
commit
6ec54a0177
@ -18,9 +18,13 @@
|
||||
package org.apache.poi.hwmf.draw;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfColorRef;
|
||||
@ -31,9 +35,9 @@ import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
||||
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||
|
||||
public class HwmfDrawProperties {
|
||||
private Rectangle2D window = new Rectangle2D.Double(0, 0, 1, 1);
|
||||
private Rectangle2D viewport = new Rectangle2D.Double(0, 0, 1, 1);
|
||||
private Point2D location = new Point2D.Double(0,0);
|
||||
private final Rectangle2D window;
|
||||
private Rectangle2D viewport = null;
|
||||
private final Point2D location;
|
||||
private HwmfMapMode mapMode = HwmfMapMode.MM_ANISOTROPIC;
|
||||
private HwmfColorRef backgroundColor = new HwmfColorRef(Color.BLACK);
|
||||
private HwmfBrushStyle brushStyle = HwmfBrushStyle.BS_SOLID;
|
||||
@ -46,6 +50,41 @@ public class HwmfDrawProperties {
|
||||
private double penMiterLimit = 10;
|
||||
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
|
||||
private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;
|
||||
private Shape region = null;
|
||||
|
||||
public HwmfDrawProperties() {
|
||||
window = new Rectangle2D.Double(0, 0, 1, 1);
|
||||
viewport = null;
|
||||
location = new Point2D.Double(0,0);
|
||||
}
|
||||
|
||||
public HwmfDrawProperties(HwmfDrawProperties other) {
|
||||
this.window = (Rectangle2D)other.window.clone();
|
||||
this.viewport = (other.viewport == null) ? null : (Rectangle2D)other.viewport.clone();
|
||||
this.location = (Point2D)other.location.clone();
|
||||
this.mapMode = other.mapMode;
|
||||
this.backgroundColor = (other.backgroundColor == null) ? null : other.backgroundColor.clone();
|
||||
this.brushStyle = other.brushStyle;
|
||||
this.brushColor = other.brushColor.clone();
|
||||
this.brushHatch = other.brushHatch;
|
||||
if (other.brushBitmap != null) {
|
||||
ColorModel cm = other.brushBitmap.getColorModel();
|
||||
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
|
||||
WritableRaster raster = other.brushBitmap.copyData(null);
|
||||
this.brushBitmap = new BufferedImage(cm, raster, isAlphaPremultiplied, null);
|
||||
}
|
||||
this.penWidth = 1;
|
||||
this.penStyle = (other.penStyle == null) ? null : other.penStyle.clone();
|
||||
this.penColor = (other.penColor == null) ? null : other.penColor.clone();
|
||||
this.penMiterLimit = other.penMiterLimit;
|
||||
this.bkMode = other.bkMode;
|
||||
this.polyfillMode = other.polyfillMode;
|
||||
if (other.region instanceof Rectangle2D) {
|
||||
this.region = ((Rectangle2D)other.region).getBounds2D();
|
||||
} else if (other.region instanceof Area) {
|
||||
this.region = new Area(other.region);
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewportExt(double width, double height) {
|
||||
double x = viewport.getX();
|
||||
@ -62,7 +101,7 @@ public class HwmfDrawProperties {
|
||||
}
|
||||
|
||||
public Rectangle2D getViewport() {
|
||||
return (Rectangle2D)viewport.clone();
|
||||
return (viewport == null) ? null : (Rectangle2D)viewport.clone();
|
||||
}
|
||||
|
||||
public void setWindowExt(double width, double height) {
|
||||
@ -186,4 +225,23 @@ public class HwmfDrawProperties {
|
||||
public void setBrushBitmap(BufferedImage brushBitmap) {
|
||||
this.brushBitmap = brushBitmap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the last stored region
|
||||
*
|
||||
* @return the last stored region
|
||||
*/
|
||||
public Shape getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a region for further usage
|
||||
*
|
||||
* @param region a region object which is usually a rectangle
|
||||
*/
|
||||
public void setRegion(Shape region) {
|
||||
this.region = region;
|
||||
}
|
||||
}
|
||||
|
@ -28,25 +28,37 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||
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;
|
||||
private final Deque<HwmfDrawProperties> propStack = new ArrayDeque<HwmfDrawProperties>();
|
||||
HwmfDrawProperties prop;
|
||||
private final List<HwmfDrawProperties> propStack = new LinkedList<HwmfDrawProperties>();
|
||||
private HwmfDrawProperties prop = new HwmfDrawProperties();
|
||||
private List<HwmfObjectTableEntry> objectTable = new ArrayList<HwmfObjectTableEntry>();
|
||||
/** Bounding box from the placeable header */
|
||||
private final Rectangle2D bbox;
|
||||
|
||||
public HwmfGraphics(Graphics2D graphicsCtx) {
|
||||
/**
|
||||
* Initialize a graphics context for wmf rendering
|
||||
*
|
||||
* @param graphicsCtx the graphics context to delegate drawing calls
|
||||
* @param bbox the bounding box of the wmf (taken from the placeable header)
|
||||
*/
|
||||
public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
|
||||
this.graphicsCtx = graphicsCtx;
|
||||
prop = new HwmfDrawProperties();
|
||||
propStack.push(prop);
|
||||
this.bbox = (Rectangle2D)bbox.clone();
|
||||
}
|
||||
|
||||
public HwmfDrawProperties getProperties() {
|
||||
@ -91,7 +103,11 @@ public class HwmfGraphics {
|
||||
|
||||
protected Shape fitShapeToView(Shape shape) {
|
||||
int scaleUnits = prop.getMapMode().scale;
|
||||
Rectangle2D view = prop.getViewport(), win = prop.getWindow();
|
||||
Rectangle2D view = prop.getViewport();
|
||||
Rectangle2D win = prop.getWindow();
|
||||
if (view == null) {
|
||||
view = win;
|
||||
}
|
||||
double scaleX, scaleY;
|
||||
switch (scaleUnits) {
|
||||
case -1:
|
||||
@ -106,16 +122,20 @@ public class HwmfGraphics {
|
||||
}
|
||||
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.translate(view.getX(), view.getY());
|
||||
at.scale(scaleX, scaleY);
|
||||
at.translate(-win.getX(), -win.getY());
|
||||
at.translate(-view.getX(), -view.getY());
|
||||
// at.translate(-view.getX(), -view.getY());
|
||||
at.translate(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
|
||||
|
||||
return at.createTransformedShape(shape);
|
||||
Shape tshape = at.createTransformedShape(shape);
|
||||
return tshape;
|
||||
}
|
||||
|
||||
protected BasicStroke getStroke() {
|
||||
Rectangle2D view = prop.getViewport(), win = prop.getWindow();
|
||||
Rectangle2D view = prop.getViewport();
|
||||
Rectangle2D win = prop.getWindow();
|
||||
if (view == null) {
|
||||
view = win;
|
||||
}
|
||||
float width = (float)(prop.getPenWidth() * view.getWidth() / win.getWidth());
|
||||
HwmfPenStyle ps = prop.getPenStyle();
|
||||
int cap = ps.getLineCap().awtFlag;
|
||||
@ -182,4 +202,87 @@ public class HwmfGraphics {
|
||||
return (bi == null) ? null
|
||||
: new TexturePaint(bi, new Rectangle(0,0,bi.getWidth(),bi.getHeight()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an record of type {@link HwmfObjectTableEntry} to the object table.
|
||||
*
|
||||
* Every object is assigned the lowest available index-that is, the smallest
|
||||
* numerical value-in the WMF Object Table. This binding happens at object creation,
|
||||
* not when the object is used.
|
||||
* Moreover, each object table index uniquely refers to an object.
|
||||
* Indexes in the WMF Object Table always start at 0.
|
||||
*
|
||||
* @param entry
|
||||
*/
|
||||
public void addObjectTableEntry(HwmfObjectTableEntry entry) {
|
||||
ListIterator<HwmfObjectTableEntry> oIter = objectTable.listIterator();
|
||||
while (oIter.hasNext()) {
|
||||
HwmfObjectTableEntry tableEntry = oIter.next();
|
||||
if (tableEntry == null) {
|
||||
oIter.set(entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
objectTable.add(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the object table entry
|
||||
*
|
||||
* @param index the index of the object table entry (0-based)
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
* @throws NoSuchElementException if the entry was deleted before
|
||||
*/
|
||||
public void applyObjectTableEntry(int index) {
|
||||
HwmfObjectTableEntry ote = objectTable.get(index);
|
||||
if (ote == null) {
|
||||
throw new NoSuchElementException("WMF reference exception - object table entry on index "+index+" was deleted before.");
|
||||
}
|
||||
ote.applyObject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets (deletes) the object table entry for further usage
|
||||
*
|
||||
* When a META_DELETEOBJECT record (section 2.3.4.7) is received that specifies this
|
||||
* object's particular index, the object's resources are released, the binding to its
|
||||
* WMF Object Table index is ended, and the index value is returned to the pool of
|
||||
* available indexes. The index will be reused, if needed, by a subsequent object
|
||||
* created by another Object Record Type record.
|
||||
*
|
||||
* @param index the index (0-based)
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if the index is out of range
|
||||
*/
|
||||
public void unsetObjectTableEntry(int index) {
|
||||
objectTable.set(index, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current properties to the stack
|
||||
*/
|
||||
public void saveProperties() {
|
||||
propStack.add(prop);
|
||||
prop = new HwmfDrawProperties(prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void restoreProperties(int index) {
|
||||
if (index == 0) {
|
||||
return;
|
||||
}
|
||||
int stackIndex = index;
|
||||
if (stackIndex < 0) {
|
||||
int curIdx = propStack.indexOf(prop);
|
||||
assert (curIdx != -1);
|
||||
stackIndex = curIdx + index;
|
||||
}
|
||||
prop = propStack.remove(stackIndex);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import org.apache.poi.util.LittleEndianInputStream;
|
||||
* Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.
|
||||
* Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.
|
||||
*/
|
||||
public class HwmfColorRef {
|
||||
public class HwmfColorRef implements Cloneable {
|
||||
private Color colorRef = Color.BLACK;
|
||||
|
||||
public HwmfColorRef() {}
|
||||
@ -53,4 +53,21 @@ public class HwmfColorRef {
|
||||
public Color getColor() {
|
||||
return colorRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object of the same class and with the
|
||||
* same contents as this object.
|
||||
* @return a clone of this instance.
|
||||
* @exception OutOfMemoryError if there is not enough memory.
|
||||
* @see java.lang.Cloneable
|
||||
*/
|
||||
@Override
|
||||
public HwmfColorRef clone() {
|
||||
try {
|
||||
return (HwmfColorRef)super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// this shouldn't happen, since we are Cloneable
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,15 @@
|
||||
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.Ellipse2D;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
@ -210,7 +216,12 @@ public class HwmfDraw {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
int x = Math.min(leftRect, rightRect);
|
||||
int y = Math.min(topRect, bottomRect);
|
||||
int w = Math.abs(leftRect - rightRect - 1);
|
||||
int h = Math.abs(topRect - bottomRect - 1);
|
||||
Shape s = new Ellipse2D.Double(x, y, w, h);
|
||||
ctx.fill(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -372,7 +383,12 @@ public class HwmfDraw {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
int x = Math.min(leftRect, rightRect);
|
||||
int y = Math.min(topRect, bottomRect);
|
||||
int w = Math.abs(leftRect - rightRect - 1);
|
||||
int h = Math.abs(topRect - bottomRect - 1);
|
||||
Shape s = new Rectangle2D.Double(x, y, w, h);
|
||||
ctx.fill(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,7 +431,8 @@ public class HwmfDraw {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
Shape s = new Rectangle2D.Double(x, y, 1, 1);
|
||||
ctx.fill(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,84 +496,16 @@ public class HwmfDraw {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
int x = Math.min(leftRect, rightRect);
|
||||
int y = Math.min(topRect, bottomRect);
|
||||
int w = Math.abs(leftRect - rightRect - 1);
|
||||
int h = Math.abs(topRect - bottomRect - 1);
|
||||
Shape s = new RoundRectangle2D.Double(x, y, w, h, width, height);
|
||||
ctx.fill(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The META_PIE record draws a pie-shaped wedge bounded by the intersection of an ellipse and two
|
||||
* radials. The pie is outlined by using the pen and filled by using the brush that are defined in the
|
||||
* playback device context.
|
||||
*/
|
||||
public static class WmfPie implements HwmfRecord {
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical
|
||||
* coordinates, of the endpoint of the second radial.
|
||||
*/
|
||||
private int yRadial2;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical
|
||||
* coordinates, of the endpoint of the second radial.
|
||||
*/
|
||||
private int xRadial2;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical
|
||||
* coordinates, of the endpoint of the first radial.
|
||||
*/
|
||||
private int yRadial1;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical
|
||||
* coordinates, of the endpoint of the first radial.
|
||||
*/
|
||||
private int xRadial1;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
|
||||
* the lower-right corner of the bounding rectangle.
|
||||
*/
|
||||
private int bottomRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
|
||||
* the lower-right corner of the bounding rectangle.
|
||||
*/
|
||||
private int rightRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
|
||||
* upper-left corner of the bounding rectangle.
|
||||
*/
|
||||
private int topRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
|
||||
* the upper-left corner of the bounding rectangle.
|
||||
*/
|
||||
private int leftRect;
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getRecordType() {
|
||||
return HwmfRecordType.pie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
yRadial2 = leis.readShort();
|
||||
xRadial2 = leis.readShort();
|
||||
yRadial1 = leis.readShort();
|
||||
xRadial1 = leis.readShort();
|
||||
bottomRect = leis.readShort();
|
||||
rightRect = leis.readShort();
|
||||
topRect = leis.readShort();
|
||||
leftRect = leis.readShort();
|
||||
return 8*LittleEndianConsts.SHORT_SIZE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The META_ARC record draws an elliptical arc.
|
||||
*/
|
||||
@ -622,7 +571,54 @@ public class HwmfDraw {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
int x = Math.min(leftRect, rightRect);
|
||||
int y = Math.min(topRect, bottomRect);
|
||||
int w = Math.abs(leftRect - rightRect - 1);
|
||||
int h = Math.abs(topRect - bottomRect - 1);
|
||||
double startAngle = Math.toDegrees(Math.atan2(-(yStartArc - (topRect + h / 2.)), xStartArc - (leftRect + w / 2.)));
|
||||
double endAngle = Math.toDegrees(Math.atan2(-(yEndArc - (topRect + h / 2.)), xEndArc - (leftRect + w / 2.)));
|
||||
double arcAngle = (endAngle - startAngle) + (endAngle - startAngle > 0 ? 0 : 360);
|
||||
if (startAngle < 0) {
|
||||
startAngle += 360;
|
||||
}
|
||||
|
||||
boolean fillShape;
|
||||
int arcClosure;
|
||||
switch (getRecordType()) {
|
||||
default:
|
||||
case arc:
|
||||
arcClosure = Arc2D.OPEN;
|
||||
fillShape = false;
|
||||
break;
|
||||
case chord:
|
||||
arcClosure = Arc2D.CHORD;
|
||||
fillShape = true;
|
||||
break;
|
||||
case pie:
|
||||
arcClosure = Arc2D.PIE;
|
||||
fillShape = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Shape s = new Arc2D.Double(x, y, w, h, startAngle, arcAngle, arcClosure);
|
||||
if (fillShape) {
|
||||
ctx.fill(s);
|
||||
} else {
|
||||
ctx.draw(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The META_PIE record draws a pie-shaped wedge bounded by the intersection of an ellipse and two
|
||||
* radials. The pie is outlined by using the pen and filled by using the brush that are defined in the
|
||||
* playback device context.
|
||||
*/
|
||||
public static class WmfPie extends WmfArc {
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getRecordType() {
|
||||
return HwmfRecordType.pie;
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,73 +627,14 @@ public class HwmfDraw {
|
||||
* an ellipse with a line segment. The chord is outlined using the pen and filled using the brush
|
||||
* that are defined in the playback device context.
|
||||
*/
|
||||
public static class WmfChord implements HwmfRecord {
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical
|
||||
* coordinates, of the endpoint of the second radial.
|
||||
*/
|
||||
private int yRadial2;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical
|
||||
* coordinates, of the endpoint of the second radial.
|
||||
*/
|
||||
private int xRadial2;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical
|
||||
* coordinates, of the endpoint of the first radial.
|
||||
*/
|
||||
private int yRadial1;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical
|
||||
* coordinates, of the endpoint of the first radial.
|
||||
*/
|
||||
private int xRadial1;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
|
||||
* the lower-right corner of the bounding rectangle.
|
||||
*/
|
||||
private int bottomRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
|
||||
* the lower-right corner of the bounding rectangle.
|
||||
*/
|
||||
private int rightRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
|
||||
* upper-left corner of the bounding rectangle.
|
||||
*/
|
||||
private int topRect;
|
||||
/**
|
||||
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
|
||||
* the upper-left corner of the bounding rectangle.
|
||||
*/
|
||||
private int leftRect;
|
||||
|
||||
public static class WmfChord extends WmfArc {
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getRecordType() {
|
||||
return HwmfRecordType.chord;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
yRadial2 = leis.readShort();
|
||||
xRadial2 = leis.readShort();
|
||||
yRadial1 = leis.readShort();
|
||||
xRadial1 = leis.readShort();
|
||||
bottomRect = leis.readShort();
|
||||
rightRect = leis.readShort();
|
||||
topRect = leis.readShort();
|
||||
leftRect = leis.readShort();
|
||||
return 8*LittleEndianConsts.SHORT_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The META_SELECTOBJECT record specifies a graphics object for the playback device context. The
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
@ -25,6 +26,7 @@ import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
import org.apache.poi.hwmf.record.HwmfWindowing.WmfCreateRegion;
|
||||
import org.apache.poi.util.LittleEndianConsts;
|
||||
import org.apache.poi.util.LittleEndianInputStream;
|
||||
|
||||
@ -46,13 +48,13 @@ public class HwmfFill {
|
||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||
* the region to be filled.
|
||||
*/
|
||||
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;
|
||||
|
||||
@Override
|
||||
public HwmfRecordType getRecordType() {
|
||||
@ -61,13 +63,20 @@ public class HwmfFill {
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
region = leis.readUShort();
|
||||
brush = leis.readUShort();
|
||||
regionIndex = leis.readUShort();
|
||||
brushIndex = leis.readUShort();
|
||||
return 2*LittleEndianConsts.SHORT_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.applyObjectTableEntry(regionIndex);
|
||||
ctx.applyObjectTableEntry(brushIndex);
|
||||
|
||||
Shape region = ctx.getProperties().getRegion();
|
||||
if (region != null) {
|
||||
ctx.fill(region);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -82,20 +91,25 @@ public class HwmfFill {
|
||||
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||
* the region to be painted.
|
||||
*/
|
||||
int region;
|
||||
int regionIndex;
|
||||
|
||||
public HwmfRecordType getRecordType() {
|
||||
return HwmfRecordType.paintRegion;
|
||||
}
|
||||
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
region = leis.readUShort();
|
||||
regionIndex = leis.readUShort();
|
||||
return LittleEndianConsts.SHORT_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.applyObjectTableEntry(regionIndex);
|
||||
|
||||
Shape region = ctx.getProperties().getRegion();
|
||||
if (region != null) {
|
||||
ctx.fill(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
ctx.saveProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
ctx.restoreProperties(nSavedDC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,11 +431,11 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
ctx.unsetObjectTableEntry(objectIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WmfCreatePatternBrush implements HwmfRecord {
|
||||
public static class WmfCreatePatternBrush implements HwmfRecord, HwmfObjectTableEntry {
|
||||
|
||||
private HwmfBitmap16 pattern;
|
||||
|
||||
@ -452,16 +452,23 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
HwmfDrawProperties dp = ctx.getProperties();
|
||||
dp.setBrushBitmap(pattern.getImage());
|
||||
dp.setBrushStyle(HwmfBrushStyle.BS_PATTERN);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WmfCreatePenIndirect implements HwmfRecord {
|
||||
public static class WmfCreatePenIndirect implements HwmfRecord, HwmfObjectTableEntry {
|
||||
|
||||
private HwmfPenStyle penStyle;
|
||||
/**
|
||||
* A 32-bit PointS Object that specifies a point for the object dimensions.
|
||||
* The xcoordinate is the pen width. The y-coordinate is ignored.
|
||||
* The x-coordinate is the pen width. The y-coordinate is ignored.
|
||||
*/
|
||||
private int xWidth;
|
||||
@SuppressWarnings("unused")
|
||||
@ -488,6 +495,11 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
HwmfDrawProperties p = ctx.getProperties();
|
||||
p.setPenStyle(penStyle);
|
||||
p.setPenColor(colorRef);
|
||||
@ -540,7 +552,7 @@ public class HwmfMisc {
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
public static class WmfCreateBrushIndirect implements HwmfRecord {
|
||||
public static class WmfCreateBrushIndirect implements HwmfRecord, HwmfObjectTableEntry {
|
||||
private HwmfBrushStyle brushStyle;
|
||||
|
||||
private HwmfColorRef colorRef;
|
||||
@ -568,6 +580,11 @@ public class HwmfMisc {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
HwmfDrawProperties p = ctx.getProperties();
|
||||
p.setBrushStyle(brushStyle);
|
||||
p.setBrushColor(colorRef);
|
||||
|
@ -0,0 +1,28 @@
|
||||
/* ====================================================================
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
|
||||
/**
|
||||
* Marker interface for Records, which should be added to the
|
||||
* WMF object table for further selection
|
||||
*/
|
||||
public interface HwmfObjectTableEntry {
|
||||
public void applyObject(HwmfGraphics ctx);
|
||||
}
|
@ -81,7 +81,7 @@ public class HwmfPalette {
|
||||
/**
|
||||
* The META_CREATEPALETTE record creates a Palette Object
|
||||
*/
|
||||
public static class WmfCreatePalette extends WmfPaletteParent {
|
||||
public static class WmfCreatePalette extends WmfPaletteParent implements HwmfObjectTableEntry {
|
||||
@Override
|
||||
public HwmfRecordType getRecordType() {
|
||||
return HwmfRecordType.createPalette;
|
||||
@ -89,6 +89,11 @@ public class HwmfPalette {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import org.apache.poi.util.BitFieldFactory;
|
||||
* The defaults in case the other values of the subsection aren't set are
|
||||
* solid, round end caps, round joins and cosmetic type.
|
||||
*/
|
||||
public class HwmfPenStyle {
|
||||
public class HwmfPenStyle implements Cloneable {
|
||||
public enum HwmfLineCap {
|
||||
/** Rounded ends */
|
||||
ROUND(0, BasicStroke.CAP_ROUND),
|
||||
@ -168,4 +168,22 @@ public class HwmfPenStyle {
|
||||
public boolean isAlternateDash() {
|
||||
return SUBSECTION_ALTERNATE.isSet(flag);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object of the same class and with the
|
||||
* same contents as this object.
|
||||
* @return a clone of this instance.
|
||||
* @exception OutOfMemoryError if there is not enough memory.
|
||||
* @see java.lang.Cloneable
|
||||
*/
|
||||
@Override
|
||||
public HwmfPenStyle clone() {
|
||||
try {
|
||||
return (HwmfPenStyle)super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// this shouldn't happen, since we are Cloneable
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.util.LittleEndianConsts;
|
||||
@ -25,6 +26,8 @@ import org.apache.poi.util.LittleEndianInputStream;
|
||||
public class HwmfPlaceableHeader {
|
||||
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
|
||||
|
||||
final Rectangle2D bounds;
|
||||
|
||||
protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
|
||||
/*
|
||||
* HWmf (2 bytes): The resource handle to the metafile, when the metafile is in memory. When
|
||||
@ -41,6 +44,7 @@ public class HwmfPlaceableHeader {
|
||||
int y1 = leis.readShort();
|
||||
int x2 = leis.readShort();
|
||||
int y2 = leis.readShort();
|
||||
bounds = new Rectangle2D.Double(x1, y1, x2-x1, y2-y1);
|
||||
|
||||
/*
|
||||
* Inch (2 bytes): The number of logical units per inch used to represent the image.
|
||||
@ -74,4 +78,8 @@ public class HwmfPlaceableHeader {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
@ -23,76 +23,77 @@ package org.apache.poi.hwmf.record;
|
||||
* @see <a href="http://www.symantec.com/avcenter/reference/inside.the.windows.meta.file.format.pdf">Inside the Windows Meta File Format</a>
|
||||
*/
|
||||
public enum HwmfRecordType {
|
||||
eof(0x0000, null),
|
||||
realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class),
|
||||
setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class),
|
||||
setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class),
|
||||
setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class),
|
||||
setRop2(0x0104, HwmfMisc.WmfSetRop2.class),
|
||||
setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class),
|
||||
setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class),
|
||||
setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class),
|
||||
setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class),
|
||||
restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class),
|
||||
resizePalette(0x0139, HwmfPalette.WmfResizePalette.class),
|
||||
dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class),
|
||||
setLayout(0x0149, HwmfMisc.WmfSetLayout.class),
|
||||
setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class),
|
||||
setTextColor(0x0209, HwmfText.WmfSetTextColor.class),
|
||||
offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class),
|
||||
lineTo(0x0213, HwmfDraw.WmfLineTo.class),
|
||||
moveTo(0x0214, HwmfDraw.WmfMoveTo.class),
|
||||
offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class),
|
||||
fillRegion(0x0228, HwmfFill.WmfFillRegion.class),
|
||||
setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class),
|
||||
selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class),
|
||||
polygon(0x0324, HwmfDraw.WmfPolygon.class),
|
||||
polyline(0x0325, HwmfDraw.WmfPolyline.class),
|
||||
setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class),
|
||||
setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class),
|
||||
setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class),
|
||||
setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class),
|
||||
setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class),
|
||||
offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class),
|
||||
scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class),
|
||||
scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class),
|
||||
excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class),
|
||||
intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class),
|
||||
ellipse(0x0418, HwmfDraw.WmfEllipse.class),
|
||||
floodFill(0x0419, HwmfFill.WmfFloodFill.class),
|
||||
frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class),
|
||||
animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class),
|
||||
textOut(0x0521, HwmfText.WmfTextOut.class),
|
||||
polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class),
|
||||
extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class),
|
||||
rectangle(0x041b, HwmfDraw.WmfRectangle.class),
|
||||
setPixel(0x041f, HwmfDraw.WmfSetPixel.class),
|
||||
roundRect(0x061c, HwmfDraw.WmfRoundRect.class),
|
||||
patBlt(0x061d, HwmfFill.WmfPatBlt.class),
|
||||
saveDc(0x001e, HwmfMisc.WmfSaveDc.class),
|
||||
pie(0x081a, HwmfDraw.WmfPie.class),
|
||||
stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class),
|
||||
escape(0x0626, HwmfEscape.class),
|
||||
invertRegion(0x012a, HwmfFill.WmfInvertRegion.class),
|
||||
paintRegion(0x012b, HwmfFill.WmfPaintRegion.class),
|
||||
selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class),
|
||||
selectObject(0x012d, HwmfDraw.WmfSelectObject.class),
|
||||
setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class),
|
||||
arc(0x0817, HwmfDraw.WmfArc.class),
|
||||
chord(0x0830, HwmfDraw.WmfChord.class),
|
||||
bitBlt(0x0922, HwmfFill.WmfBitBlt.class),
|
||||
extTextOut(0x0a32, HwmfText.WmfExtTextOut.class),
|
||||
setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class),
|
||||
dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class),
|
||||
dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class),
|
||||
stretchDib(0x0f43, HwmfFill.WmfStretchDib.class),
|
||||
deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class),
|
||||
createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class),
|
||||
createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class),
|
||||
createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class),
|
||||
createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class),
|
||||
createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class),
|
||||
createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class);
|
||||
eof(0x0000, null)
|
||||
,animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class)
|
||||
,arc(0x0817, HwmfDraw.WmfArc.class)
|
||||
,bitBlt(0x0922, HwmfFill.WmfBitBlt.class)
|
||||
,chord(0x0830, HwmfDraw.WmfChord.class)
|
||||
,createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class)
|
||||
,createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class)
|
||||
,createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class)
|
||||
,createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class)
|
||||
,createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class)
|
||||
,createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class)
|
||||
,deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class)
|
||||
,dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class)
|
||||
,dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class)
|
||||
,dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class)
|
||||
,ellipse(0x0418, HwmfDraw.WmfEllipse.class)
|
||||
,escape(0x0626, HwmfEscape.class)
|
||||
,excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class)
|
||||
,extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class)
|
||||
,extTextOut(0x0a32, HwmfText.WmfExtTextOut.class)
|
||||
,fillRegion(0x0228, HwmfFill.WmfFillRegion.class)
|
||||
,floodFill(0x0419, HwmfFill.WmfFloodFill.class)
|
||||
,frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class)
|
||||
,intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class)
|
||||
,invertRegion(0x012a, HwmfFill.WmfInvertRegion.class)
|
||||
,lineTo(0x0213, HwmfDraw.WmfLineTo.class)
|
||||
,moveTo(0x0214, HwmfDraw.WmfMoveTo.class)
|
||||
,offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class)
|
||||
,offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class)
|
||||
,offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class)
|
||||
,paintRegion(0x012b, HwmfFill.WmfPaintRegion.class)
|
||||
,patBlt(0x061d, HwmfFill.WmfPatBlt.class)
|
||||
,pie(0x081a, HwmfDraw.WmfPie.class)
|
||||
,polygon(0x0324, HwmfDraw.WmfPolygon.class)
|
||||
,polyline(0x0325, HwmfDraw.WmfPolyline.class)
|
||||
,polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class)
|
||||
,realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class)
|
||||
,rectangle(0x041b, HwmfDraw.WmfRectangle.class)
|
||||
,resizePalette(0x0139, HwmfPalette.WmfResizePalette.class)
|
||||
,restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class)
|
||||
,roundRect(0x061c, HwmfDraw.WmfRoundRect.class)
|
||||
,saveDc(0x001e, HwmfMisc.WmfSaveDc.class)
|
||||
,scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class)
|
||||
,scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class)
|
||||
,selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class)
|
||||
,selectObject(0x012d, HwmfDraw.WmfSelectObject.class)
|
||||
,selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class)
|
||||
,setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class)
|
||||
,setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class)
|
||||
,setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class)
|
||||
,setLayout(0x0149, HwmfMisc.WmfSetLayout.class)
|
||||
,setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class)
|
||||
,setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class)
|
||||
,setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class)
|
||||
,setPixel(0x041f, HwmfDraw.WmfSetPixel.class)
|
||||
,setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class)
|
||||
,setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class)
|
||||
,setRop2(0x0104, HwmfMisc.WmfSetRop2.class)
|
||||
,setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class)
|
||||
,setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class)
|
||||
,setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class)
|
||||
,setTextColor(0x0209, HwmfText.WmfSetTextColor.class)
|
||||
,setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class)
|
||||
,setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class)
|
||||
,setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class)
|
||||
,setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class)
|
||||
,setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class)
|
||||
,stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class)
|
||||
,stretchDib(0x0f43, HwmfFill.WmfStretchDib.class)
|
||||
,textOut(0x0521, HwmfText.WmfTextOut.class)
|
||||
;
|
||||
|
||||
public int id;
|
||||
public Class<? extends HwmfRecord> clazz;
|
||||
|
@ -391,7 +391,7 @@ public class HwmfText {
|
||||
}
|
||||
}
|
||||
|
||||
public static class WmfCreateFontIndirect implements HwmfRecord {
|
||||
public static class WmfCreateFontIndirect implements HwmfRecord, HwmfObjectTableEntry {
|
||||
private HwmfFont font;
|
||||
|
||||
@Override
|
||||
@ -407,6 +407,11 @@ public class HwmfText {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,10 @@
|
||||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.Rectangle2D.Double;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -128,7 +131,9 @@ public class HwmfWindowing {
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
||||
ctx.getProperties().setViewportOrg(viewport.getX()+xOffset, viewport.getY()+yOffset);
|
||||
double x = (viewport == null) ? 0 : viewport.getX();
|
||||
double y = (viewport == null) ? 0 : viewport.getY();
|
||||
ctx.getProperties().setViewportOrg(x+xOffset, y+yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,6 +168,14 @@ public class HwmfWindowing {
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.getProperties().setWindowOrg(x, y);
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,6 +212,14 @@ public class HwmfWindowing {
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.getProperties().setWindowExt(width, height);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,6 +359,9 @@ public class HwmfWindowing {
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
||||
if (viewport == null) {
|
||||
viewport = ctx.getProperties().getWindow();
|
||||
}
|
||||
double width = viewport.getWidth() * xNum / xDenom;
|
||||
double height = viewport.getHeight() * yNum / yDenom;
|
||||
ctx.getProperties().setViewportExt(width, height);
|
||||
@ -556,7 +580,7 @@ public class HwmfWindowing {
|
||||
}
|
||||
}
|
||||
|
||||
public static class WmfCreateRegion implements HwmfRecord {
|
||||
public static class WmfCreateRegion implements HwmfRecord, HwmfObjectTableEntry {
|
||||
/**
|
||||
* A 16-bit signed integer. A value that MUST be ignored.
|
||||
*/
|
||||
@ -642,7 +666,32 @@ public class HwmfWindowing {
|
||||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.addObjectTableEntry(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyObject(HwmfGraphics ctx) {
|
||||
Rectangle2D lastRect = null;
|
||||
Area scanLines = new Area();
|
||||
int count = 0;
|
||||
for (WmfScanObject so : scanObjects) {
|
||||
int y = Math.min(so.top, so.bottom);
|
||||
int h = Math.abs(so.top - so.bottom - 1);
|
||||
for (int i=0; i<so.count/2; i++) {
|
||||
int x = Math.min(so.left_scanline[i], so.right_scanline[i]);
|
||||
int w = Math.abs(so.right_scanline[i] - so.left_scanline[i] - 1);
|
||||
lastRect = new Rectangle2D.Double(x,y,w,h);
|
||||
scanLines.add(new Area(lastRect));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Shape region = null;
|
||||
if (count > 0) {
|
||||
region = (count == 1) ? lastRect : scanLines;
|
||||
}
|
||||
|
||||
ctx.getProperties().setRegion(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
package org.apache.poi.hwmf.usermodel;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -24,24 +26,25 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
import org.apache.poi.hwmf.record.HwmfHeader;
|
||||
import org.apache.poi.hwmf.record.HwmfPlaceableHeader;
|
||||
import org.apache.poi.hwmf.record.HwmfRecord;
|
||||
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;
|
||||
|
||||
public class HwmfPicture {
|
||||
List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
||||
|
||||
public List<HwmfRecord> getRecords() {
|
||||
return Collections.unmodifiableList(records);
|
||||
}
|
||||
final List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
||||
final HwmfPlaceableHeader placeableHeader;
|
||||
final HwmfHeader header;
|
||||
|
||||
public HwmfPicture(InputStream inputStream) throws IOException {
|
||||
BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);
|
||||
LittleEndianInputStream leis = new LittleEndianInputStream(bis);
|
||||
HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
||||
HwmfHeader header = new HwmfHeader(leis);
|
||||
placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
||||
header = new HwmfHeader(leis);
|
||||
|
||||
for (;;) {
|
||||
// recordSize in DWORDs
|
||||
@ -76,5 +79,50 @@ public class HwmfPicture {
|
||||
}
|
||||
}
|
||||
|
||||
public List<HwmfRecord> getRecords() {
|
||||
return Collections.unmodifiableList(records);
|
||||
}
|
||||
|
||||
public void draw(Graphics2D ctx) {
|
||||
HwmfGraphics g = new HwmfGraphics(ctx, getBounds());
|
||||
for (HwmfRecord r : records) {
|
||||
r.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounding box in device-independent units. Usually this is taken from the placeable header.
|
||||
*
|
||||
* @return the bounding box
|
||||
*/
|
||||
public Rectangle2D getBounds() {
|
||||
if (placeableHeader != null) {
|
||||
return placeableHeader.getBounds();
|
||||
} else {
|
||||
WmfSetWindowOrg wOrg = null;
|
||||
WmfSetWindowExt wExt = null;
|
||||
for (HwmfRecord r : getRecords()) {
|
||||
if (wOrg != null && wExt != null) {
|
||||
break;
|
||||
}
|
||||
if (r instanceof WmfSetWindowOrg) {
|
||||
wOrg = (WmfSetWindowOrg)r;
|
||||
} else if (r instanceof WmfSetWindowExt) {
|
||||
wExt = (WmfSetWindowExt)r;
|
||||
}
|
||||
}
|
||||
if (wOrg == null || wExt == null) {
|
||||
throw new RuntimeException("invalid wmf file - window records are incomplete.");
|
||||
}
|
||||
return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getWidth(), wExt.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
public HwmfPlaceableHeader getPlaceableHeader() {
|
||||
return placeableHeader;
|
||||
}
|
||||
|
||||
public HwmfHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ package org.apache.poi.hwmf;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
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;
|
||||
@ -56,6 +59,36 @@ public class TestHwmfParsing {
|
||||
assertEquals(581, records.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void paint() throws IOException {
|
||||
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
HwmfPicture wmf = new HwmfPicture(fis);
|
||||
fis.close();
|
||||
|
||||
Rectangle2D bounds = wmf.getBounds();
|
||||
int width = 300;
|
||||
// keep aspect ratio for height
|
||||
int height = (int)(width*bounds.getHeight()/bounds.getWidth());
|
||||
|
||||
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);
|
||||
|
||||
g.scale(width/bounds.getWidth(), height/bounds.getHeight());
|
||||
g.translate(-bounds.getX(), -bounds.getY());
|
||||
|
||||
wmf.draw(g);
|
||||
|
||||
g.dispose();
|
||||
|
||||
ImageIO.write(bufImg, "PNG", new File("bla.png"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void fetchWmfFromGovdocs() throws IOException {
|
||||
|
Loading…
Reference in New Issue
Block a user