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;
|
package org.apache.poi.hwmf.draw;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Shape;
|
||||||
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
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.HwmfBrushStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfColorRef;
|
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;
|
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||||
|
|
||||||
public class HwmfDrawProperties {
|
public class HwmfDrawProperties {
|
||||||
private Rectangle2D window = new Rectangle2D.Double(0, 0, 1, 1);
|
private final Rectangle2D window;
|
||||||
private Rectangle2D viewport = new Rectangle2D.Double(0, 0, 1, 1);
|
private Rectangle2D viewport = null;
|
||||||
private Point2D location = new Point2D.Double(0,0);
|
private final Point2D location;
|
||||||
private HwmfMapMode mapMode = HwmfMapMode.MM_ANISOTROPIC;
|
private HwmfMapMode mapMode = HwmfMapMode.MM_ANISOTROPIC;
|
||||||
private HwmfColorRef backgroundColor = new HwmfColorRef(Color.BLACK);
|
private HwmfColorRef backgroundColor = new HwmfColorRef(Color.BLACK);
|
||||||
private HwmfBrushStyle brushStyle = HwmfBrushStyle.BS_SOLID;
|
private HwmfBrushStyle brushStyle = HwmfBrushStyle.BS_SOLID;
|
||||||
@ -46,7 +50,42 @@ public class HwmfDrawProperties {
|
|||||||
private double penMiterLimit = 10;
|
private double penMiterLimit = 10;
|
||||||
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
|
private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;
|
||||||
private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;
|
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) {
|
public void setViewportExt(double width, double height) {
|
||||||
double x = viewport.getX();
|
double x = viewport.getX();
|
||||||
double y = viewport.getY();
|
double y = viewport.getY();
|
||||||
@ -62,7 +101,7 @@ public class HwmfDrawProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Rectangle2D getViewport() {
|
public Rectangle2D getViewport() {
|
||||||
return (Rectangle2D)viewport.clone();
|
return (viewport == null) ? null : (Rectangle2D)viewport.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWindowExt(double width, double height) {
|
public void setWindowExt(double width, double height) {
|
||||||
@ -186,4 +225,23 @@ public class HwmfDrawProperties {
|
|||||||
public void setBrushBitmap(BufferedImage brushBitmap) {
|
public void setBrushBitmap(BufferedImage brushBitmap) {
|
||||||
this.brushBitmap = 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.GeneralPath;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayList;
|
||||||
import java.util.Deque;
|
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.HwmfBrushStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||||
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.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;
|
import org.apache.poi.util.Units;
|
||||||
|
|
||||||
public class HwmfGraphics {
|
public class HwmfGraphics {
|
||||||
private final Graphics2D graphicsCtx;
|
private final Graphics2D graphicsCtx;
|
||||||
private final Deque<HwmfDrawProperties> propStack = new ArrayDeque<HwmfDrawProperties>();
|
private final List<HwmfDrawProperties> propStack = new LinkedList<HwmfDrawProperties>();
|
||||||
HwmfDrawProperties prop;
|
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;
|
this.graphicsCtx = graphicsCtx;
|
||||||
prop = new HwmfDrawProperties();
|
this.bbox = (Rectangle2D)bbox.clone();
|
||||||
propStack.push(prop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HwmfDrawProperties getProperties() {
|
public HwmfDrawProperties getProperties() {
|
||||||
@ -91,7 +103,11 @@ public class HwmfGraphics {
|
|||||||
|
|
||||||
protected Shape fitShapeToView(Shape shape) {
|
protected Shape fitShapeToView(Shape shape) {
|
||||||
int scaleUnits = prop.getMapMode().scale;
|
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;
|
double scaleX, scaleY;
|
||||||
switch (scaleUnits) {
|
switch (scaleUnits) {
|
||||||
case -1:
|
case -1:
|
||||||
@ -106,16 +122,20 @@ public class HwmfGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AffineTransform at = new AffineTransform();
|
AffineTransform at = new AffineTransform();
|
||||||
at.translate(view.getX(), view.getY());
|
|
||||||
at.scale(scaleX, scaleY);
|
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() {
|
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());
|
float width = (float)(prop.getPenWidth() * view.getWidth() / win.getWidth());
|
||||||
HwmfPenStyle ps = prop.getPenStyle();
|
HwmfPenStyle ps = prop.getPenStyle();
|
||||||
int cap = ps.getLineCap().awtFlag;
|
int cap = ps.getLineCap().awtFlag;
|
||||||
@ -182,4 +202,87 @@ public class HwmfGraphics {
|
|||||||
return (bi == null) ? null
|
return (bi == null) ? null
|
||||||
: new TexturePaint(bi, new Rectangle(0,0,bi.getWidth(),bi.getHeight()));
|
: 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.
|
* 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.
|
* 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;
|
private Color colorRef = Color.BLACK;
|
||||||
|
|
||||||
public HwmfColorRef() {}
|
public HwmfColorRef() {}
|
||||||
@ -53,4 +53,21 @@ public class HwmfColorRef {
|
|||||||
public Color getColor() {
|
public Color getColor() {
|
||||||
return colorRef;
|
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;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
import java.awt.Polygon;
|
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.GeneralPath;
|
||||||
import java.awt.geom.Line2D;
|
import java.awt.geom.Line2D;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
@ -55,7 +61,7 @@ public class HwmfDraw {
|
|||||||
x = leis.readShort();
|
x = leis.readShort();
|
||||||
return 2*LittleEndianConsts.SHORT_SIZE;
|
return 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setLocation(x, y);
|
ctx.getProperties().setLocation(x, y);
|
||||||
@ -91,7 +97,7 @@ public class HwmfDraw {
|
|||||||
x = leis.readShort();
|
x = leis.readShort();
|
||||||
return 2*LittleEndianConsts.SHORT_SIZE;
|
return 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Point2D start = ctx.getProperties().getLocation();
|
Point2D start = ctx.getProperties().getLocation();
|
||||||
@ -135,12 +141,12 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;
|
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.fill(getShape());
|
ctx.fill(getShape());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Polygon getShape() {
|
protected Polygon getShape() {
|
||||||
Polygon polygon = new Polygon();
|
Polygon polygon = new Polygon();
|
||||||
for(int i = 0; i < numberofPoints; i++) {
|
for(int i = 0; i < numberofPoints; i++) {
|
||||||
@ -207,10 +213,15 @@ public class HwmfDraw {
|
|||||||
leftRect = leis.readShort();
|
leftRect = leis.readShort();
|
||||||
return 4*LittleEndianConsts.SHORT_SIZE;
|
return 4*LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,10 +264,10 @@ public class HwmfDraw {
|
|||||||
width = leis.readShort();
|
width = leis.readShort();
|
||||||
return 4*LittleEndianConsts.SHORT_SIZE;
|
return 4*LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +383,12 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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.
|
* The META_ARC record draws an elliptical arc.
|
||||||
*/
|
*/
|
||||||
@ -622,7 +571,54 @@ public class HwmfDraw {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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,72 +627,13 @@ public class HwmfDraw {
|
|||||||
* an ellipse with a line segment. The chord is outlined using the pen and filled using the brush
|
* 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.
|
* that are defined in the playback device context.
|
||||||
*/
|
*/
|
||||||
public static class WmfChord implements HwmfRecord {
|
public static class WmfChord extends WmfArc {
|
||||||
/**
|
|
||||||
* 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
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
return HwmfRecordType.chord;
|
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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.record;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Path2D;
|
import java.awt.geom.Path2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -25,6 +26,7 @@ import java.io.IOException;
|
|||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
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.LittleEndianConsts;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
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
|
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||||
* the region to be filled.
|
* 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
|
* 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;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
@ -61,13 +63,20 @@ 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 {
|
||||||
region = leis.readUShort();
|
regionIndex = leis.readUShort();
|
||||||
brush = leis.readUShort();
|
brushIndex = leis.readUShort();
|
||||||
return 2*LittleEndianConsts.SHORT_SIZE;
|
return 2*LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
* A 16-bit unsigned integer used to index into the WMF Object Table to get
|
||||||
* the region to be painted.
|
* the region to be painted.
|
||||||
*/
|
*/
|
||||||
int region;
|
int regionIndex;
|
||||||
|
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
return HwmfRecordType.paintRegion;
|
return HwmfRecordType.paintRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
return LittleEndianConsts.SHORT_SIZE;
|
return LittleEndianConsts.SHORT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.saveProperties();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ public class HwmfMisc {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.restoreProperties(nSavedDC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,11 +431,11 @@ public class HwmfMisc {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.unsetObjectTableEntry(objectIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WmfCreatePatternBrush implements HwmfRecord {
|
public static class WmfCreatePatternBrush implements HwmfRecord, HwmfObjectTableEntry {
|
||||||
|
|
||||||
private HwmfBitmap16 pattern;
|
private HwmfBitmap16 pattern;
|
||||||
|
|
||||||
@ -452,16 +452,23 @@ public class HwmfMisc {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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;
|
private HwmfPenStyle penStyle;
|
||||||
/**
|
/**
|
||||||
* A 32-bit PointS Object that specifies a point for the object dimensions.
|
* 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;
|
private int xWidth;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@ -488,6 +495,11 @@ public class HwmfMisc {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.addObjectTableEntry(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyObject(HwmfGraphics ctx) {
|
||||||
HwmfDrawProperties p = ctx.getProperties();
|
HwmfDrawProperties p = ctx.getProperties();
|
||||||
p.setPenStyle(penStyle);
|
p.setPenStyle(penStyle);
|
||||||
p.setPenColor(colorRef);
|
p.setPenColor(colorRef);
|
||||||
@ -540,7 +552,7 @@ public class HwmfMisc {
|
|||||||
* </tr>
|
* </tr>
|
||||||
* </table>
|
* </table>
|
||||||
*/
|
*/
|
||||||
public static class WmfCreateBrushIndirect implements HwmfRecord {
|
public static class WmfCreateBrushIndirect implements HwmfRecord, HwmfObjectTableEntry {
|
||||||
private HwmfBrushStyle brushStyle;
|
private HwmfBrushStyle brushStyle;
|
||||||
|
|
||||||
private HwmfColorRef colorRef;
|
private HwmfColorRef colorRef;
|
||||||
@ -568,6 +580,11 @@ public class HwmfMisc {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.addObjectTableEntry(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyObject(HwmfGraphics ctx) {
|
||||||
HwmfDrawProperties p = ctx.getProperties();
|
HwmfDrawProperties p = ctx.getProperties();
|
||||||
p.setBrushStyle(brushStyle);
|
p.setBrushStyle(brushStyle);
|
||||||
p.setBrushColor(colorRef);
|
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
|
* The META_CREATEPALETTE record creates a Palette Object
|
||||||
*/
|
*/
|
||||||
public static class WmfCreatePalette extends WmfPaletteParent {
|
public static class WmfCreatePalette extends WmfPaletteParent implements HwmfObjectTableEntry {
|
||||||
@Override
|
@Override
|
||||||
public HwmfRecordType getRecordType() {
|
public HwmfRecordType getRecordType() {
|
||||||
return HwmfRecordType.createPalette;
|
return HwmfRecordType.createPalette;
|
||||||
@ -89,6 +89,11 @@ public class HwmfPalette {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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
|
* The defaults in case the other values of the subsection aren't set are
|
||||||
* solid, round end caps, round joins and cosmetic type.
|
* solid, round end caps, round joins and cosmetic type.
|
||||||
*/
|
*/
|
||||||
public class HwmfPenStyle {
|
public class HwmfPenStyle implements Cloneable {
|
||||||
public enum HwmfLineCap {
|
public enum HwmfLineCap {
|
||||||
/** Rounded ends */
|
/** Rounded ends */
|
||||||
ROUND(0, BasicStroke.CAP_ROUND),
|
ROUND(0, BasicStroke.CAP_ROUND),
|
||||||
@ -168,4 +168,22 @@ public class HwmfPenStyle {
|
|||||||
public boolean isAlternateDash() {
|
public boolean isAlternateDash() {
|
||||||
return SUBSECTION_ALTERNATE.isSet(flag);
|
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;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
@ -25,6 +26,8 @@ import org.apache.poi.util.LittleEndianInputStream;
|
|||||||
public class HwmfPlaceableHeader {
|
public class HwmfPlaceableHeader {
|
||||||
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
|
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
|
||||||
|
|
||||||
|
final Rectangle2D bounds;
|
||||||
|
|
||||||
protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
|
protected HwmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
|
||||||
/*
|
/*
|
||||||
* HWmf (2 bytes): The resource handle to the metafile, when the metafile is in memory. When
|
* 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 y1 = leis.readShort();
|
||||||
int x2 = leis.readShort();
|
int x2 = leis.readShort();
|
||||||
int y2 = 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.
|
* Inch (2 bytes): The number of logical units per inch used to represent the image.
|
||||||
@ -74,4 +78,8 @@ public class HwmfPlaceableHeader {
|
|||||||
return null;
|
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>
|
* @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 {
|
public enum HwmfRecordType {
|
||||||
eof(0x0000, null),
|
eof(0x0000, null)
|
||||||
realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class),
|
,animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class)
|
||||||
setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class),
|
,arc(0x0817, HwmfDraw.WmfArc.class)
|
||||||
setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class),
|
,bitBlt(0x0922, HwmfFill.WmfBitBlt.class)
|
||||||
setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class),
|
,chord(0x0830, HwmfDraw.WmfChord.class)
|
||||||
setRop2(0x0104, HwmfMisc.WmfSetRop2.class),
|
,createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class)
|
||||||
setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class),
|
,createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class)
|
||||||
setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class),
|
,createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class)
|
||||||
setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class),
|
,createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class)
|
||||||
setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class),
|
,createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class)
|
||||||
restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class),
|
,createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class)
|
||||||
resizePalette(0x0139, HwmfPalette.WmfResizePalette.class),
|
,deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class)
|
||||||
dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class),
|
,dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class)
|
||||||
setLayout(0x0149, HwmfMisc.WmfSetLayout.class),
|
,dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class)
|
||||||
setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class),
|
,dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class)
|
||||||
setTextColor(0x0209, HwmfText.WmfSetTextColor.class),
|
,ellipse(0x0418, HwmfDraw.WmfEllipse.class)
|
||||||
offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class),
|
,escape(0x0626, HwmfEscape.class)
|
||||||
lineTo(0x0213, HwmfDraw.WmfLineTo.class),
|
,excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class)
|
||||||
moveTo(0x0214, HwmfDraw.WmfMoveTo.class),
|
,extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class)
|
||||||
offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class),
|
,extTextOut(0x0a32, HwmfText.WmfExtTextOut.class)
|
||||||
fillRegion(0x0228, HwmfFill.WmfFillRegion.class),
|
,fillRegion(0x0228, HwmfFill.WmfFillRegion.class)
|
||||||
setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class),
|
,floodFill(0x0419, HwmfFill.WmfFloodFill.class)
|
||||||
selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class),
|
,frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class)
|
||||||
polygon(0x0324, HwmfDraw.WmfPolygon.class),
|
,intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class)
|
||||||
polyline(0x0325, HwmfDraw.WmfPolyline.class),
|
,invertRegion(0x012a, HwmfFill.WmfInvertRegion.class)
|
||||||
setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class),
|
,lineTo(0x0213, HwmfDraw.WmfLineTo.class)
|
||||||
setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class),
|
,moveTo(0x0214, HwmfDraw.WmfMoveTo.class)
|
||||||
setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class),
|
,offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class)
|
||||||
setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class),
|
,offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class)
|
||||||
setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class),
|
,offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class)
|
||||||
offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class),
|
,paintRegion(0x012b, HwmfFill.WmfPaintRegion.class)
|
||||||
scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class),
|
,patBlt(0x061d, HwmfFill.WmfPatBlt.class)
|
||||||
scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class),
|
,pie(0x081a, HwmfDraw.WmfPie.class)
|
||||||
excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class),
|
,polygon(0x0324, HwmfDraw.WmfPolygon.class)
|
||||||
intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class),
|
,polyline(0x0325, HwmfDraw.WmfPolyline.class)
|
||||||
ellipse(0x0418, HwmfDraw.WmfEllipse.class),
|
,polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class)
|
||||||
floodFill(0x0419, HwmfFill.WmfFloodFill.class),
|
,realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class)
|
||||||
frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class),
|
,rectangle(0x041b, HwmfDraw.WmfRectangle.class)
|
||||||
animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class),
|
,resizePalette(0x0139, HwmfPalette.WmfResizePalette.class)
|
||||||
textOut(0x0521, HwmfText.WmfTextOut.class),
|
,restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class)
|
||||||
polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class),
|
,roundRect(0x061c, HwmfDraw.WmfRoundRect.class)
|
||||||
extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class),
|
,saveDc(0x001e, HwmfMisc.WmfSaveDc.class)
|
||||||
rectangle(0x041b, HwmfDraw.WmfRectangle.class),
|
,scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class)
|
||||||
setPixel(0x041f, HwmfDraw.WmfSetPixel.class),
|
,scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class)
|
||||||
roundRect(0x061c, HwmfDraw.WmfRoundRect.class),
|
,selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class)
|
||||||
patBlt(0x061d, HwmfFill.WmfPatBlt.class),
|
,selectObject(0x012d, HwmfDraw.WmfSelectObject.class)
|
||||||
saveDc(0x001e, HwmfMisc.WmfSaveDc.class),
|
,selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class)
|
||||||
pie(0x081a, HwmfDraw.WmfPie.class),
|
,setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class)
|
||||||
stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class),
|
,setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class)
|
||||||
escape(0x0626, HwmfEscape.class),
|
,setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class)
|
||||||
invertRegion(0x012a, HwmfFill.WmfInvertRegion.class),
|
,setLayout(0x0149, HwmfMisc.WmfSetLayout.class)
|
||||||
paintRegion(0x012b, HwmfFill.WmfPaintRegion.class),
|
,setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class)
|
||||||
selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class),
|
,setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class)
|
||||||
selectObject(0x012d, HwmfDraw.WmfSelectObject.class),
|
,setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class)
|
||||||
setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class),
|
,setPixel(0x041f, HwmfDraw.WmfSetPixel.class)
|
||||||
arc(0x0817, HwmfDraw.WmfArc.class),
|
,setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class)
|
||||||
chord(0x0830, HwmfDraw.WmfChord.class),
|
,setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class)
|
||||||
bitBlt(0x0922, HwmfFill.WmfBitBlt.class),
|
,setRop2(0x0104, HwmfMisc.WmfSetRop2.class)
|
||||||
extTextOut(0x0a32, HwmfText.WmfExtTextOut.class),
|
,setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class)
|
||||||
setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class),
|
,setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class)
|
||||||
dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class),
|
,setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class)
|
||||||
dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class),
|
,setTextColor(0x0209, HwmfText.WmfSetTextColor.class)
|
||||||
stretchDib(0x0f43, HwmfFill.WmfStretchDib.class),
|
,setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class)
|
||||||
deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class),
|
,setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class)
|
||||||
createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class),
|
,setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class)
|
||||||
createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class),
|
,setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class)
|
||||||
createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class),
|
,setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class)
|
||||||
createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class),
|
,stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class)
|
||||||
createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class),
|
,stretchDib(0x0f43, HwmfFill.WmfStretchDib.class)
|
||||||
createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class);
|
,textOut(0x0521, HwmfText.WmfTextOut.class)
|
||||||
|
;
|
||||||
|
|
||||||
public int id;
|
public int id;
|
||||||
public Class<? extends HwmfRecord> clazz;
|
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;
|
private HwmfFont font;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -407,6 +407,11 @@ public class HwmfText {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.addObjectTableEntry(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyObject(HwmfGraphics ctx) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.record;
|
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;
|
||||||
|
import java.awt.geom.Rectangle2D.Double;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -128,7 +131,9 @@ public class HwmfWindowing {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
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) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowOrg(x, y);
|
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) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowExt(width, height);
|
ctx.getProperties().setWindowExt(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -338,6 +359,9 @@ public class HwmfWindowing {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D viewport = ctx.getProperties().getViewport();
|
Rectangle2D viewport = ctx.getProperties().getViewport();
|
||||||
|
if (viewport == null) {
|
||||||
|
viewport = ctx.getProperties().getWindow();
|
||||||
|
}
|
||||||
double width = viewport.getWidth() * xNum / xDenom;
|
double width = viewport.getWidth() * xNum / xDenom;
|
||||||
double height = viewport.getHeight() * yNum / yDenom;
|
double height = viewport.getHeight() * yNum / yDenom;
|
||||||
ctx.getProperties().setViewportExt(width, height);
|
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.
|
* A 16-bit signed integer. A value that MUST be ignored.
|
||||||
*/
|
*/
|
||||||
@ -642,7 +666,32 @@ public class HwmfWindowing {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
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;
|
package org.apache.poi.hwmf.usermodel;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -24,24 +26,25 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
import org.apache.poi.hwmf.record.HwmfHeader;
|
import org.apache.poi.hwmf.record.HwmfHeader;
|
||||||
import org.apache.poi.hwmf.record.HwmfPlaceableHeader;
|
import org.apache.poi.hwmf.record.HwmfPlaceableHeader;
|
||||||
import org.apache.poi.hwmf.record.HwmfRecord;
|
import org.apache.poi.hwmf.record.HwmfRecord;
|
||||||
import org.apache.poi.hwmf.record.HwmfRecordType;
|
import org.apache.poi.hwmf.record.HwmfRecordType;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowExt;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfWindowing.WmfSetWindowOrg;
|
||||||
import org.apache.poi.util.LittleEndianInputStream;
|
import org.apache.poi.util.LittleEndianInputStream;
|
||||||
|
|
||||||
public class HwmfPicture {
|
public class HwmfPicture {
|
||||||
List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
final List<HwmfRecord> records = new ArrayList<HwmfRecord>();
|
||||||
|
final HwmfPlaceableHeader placeableHeader;
|
||||||
public List<HwmfRecord> getRecords() {
|
final HwmfHeader header;
|
||||||
return Collections.unmodifiableList(records);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HwmfPicture(InputStream inputStream) throws IOException {
|
public HwmfPicture(InputStream inputStream) throws IOException {
|
||||||
BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);
|
BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);
|
||||||
LittleEndianInputStream leis = new LittleEndianInputStream(bis);
|
LittleEndianInputStream leis = new LittleEndianInputStream(bis);
|
||||||
HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
placeableHeader = HwmfPlaceableHeader.readHeader(leis);
|
||||||
HwmfHeader header = new HwmfHeader(leis);
|
header = new HwmfHeader(leis);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// recordSize in DWORDs
|
// 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 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.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
@ -55,6 +58,36 @@ public class TestHwmfParsing {
|
|||||||
List<HwmfRecord> records = wmf.getRecords();
|
List<HwmfRecord> records = wmf.getRecords();
|
||||||
assertEquals(581, records.size());
|
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
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
|
Loading…
Reference in New Issue
Block a user