mirror of https://github.com/apache/poi.git
WMF fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723198 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0190e79270
commit
799eced5bb
|
@ -20,6 +20,7 @@ package org.apache.poi.hwmf.draw;
|
|||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
|
@ -36,6 +37,7 @@ import java.util.NoSuchElementException;
|
|||
|
||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfMapMode;
|
||||
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
||||
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
|
||||
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||
|
@ -49,6 +51,7 @@ public class HwmfGraphics {
|
|||
private List<HwmfObjectTableEntry> objectTable = new ArrayList<HwmfObjectTableEntry>();
|
||||
/** Bounding box from the placeable header */
|
||||
private final Rectangle2D bbox;
|
||||
private final AffineTransform initialAT;
|
||||
|
||||
/**
|
||||
* Initialize a graphics context for wmf rendering
|
||||
|
@ -59,6 +62,7 @@ public class HwmfGraphics {
|
|||
public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
|
||||
this.graphicsCtx = graphicsCtx;
|
||||
this.bbox = (Rectangle2D)bbox.clone();
|
||||
this.initialAT = graphicsCtx.getTransform();
|
||||
}
|
||||
|
||||
public HwmfDrawProperties getProperties() {
|
||||
|
@ -72,7 +76,6 @@ public class HwmfGraphics {
|
|||
return;
|
||||
}
|
||||
|
||||
Shape tshape = fitShapeToView(shape);
|
||||
BasicStroke stroke = getStroke();
|
||||
|
||||
// first draw a solid background line (depending on bkmode)
|
||||
|
@ -80,56 +83,26 @@ public class HwmfGraphics {
|
|||
if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {
|
||||
graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));
|
||||
graphicsCtx.setColor(prop.getBackgroundColor().getColor());
|
||||
graphicsCtx.draw(tshape);
|
||||
graphicsCtx.draw(shape);
|
||||
}
|
||||
|
||||
// then draw the (dashed) line
|
||||
graphicsCtx.setStroke(stroke);
|
||||
graphicsCtx.setColor(prop.getPenColor().getColor());
|
||||
graphicsCtx.draw(tshape);
|
||||
graphicsCtx.draw(shape);
|
||||
}
|
||||
|
||||
public void fill(Shape shape) {
|
||||
if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
|
||||
GeneralPath gp = new GeneralPath(shape);
|
||||
gp.setWindingRule(prop.getPolyfillMode().awtFlag);
|
||||
Shape tshape = fitShapeToView(gp);
|
||||
graphicsCtx.setPaint(getFill());
|
||||
graphicsCtx.fill(tshape);
|
||||
graphicsCtx.fill(shape);
|
||||
}
|
||||
|
||||
draw(shape);
|
||||
}
|
||||
|
||||
protected Shape fitShapeToView(Shape shape) {
|
||||
int scaleUnits = prop.getMapMode().scale;
|
||||
Rectangle2D view = prop.getViewport();
|
||||
Rectangle2D win = prop.getWindow();
|
||||
if (view == null) {
|
||||
view = win;
|
||||
}
|
||||
double scaleX, scaleY;
|
||||
switch (scaleUnits) {
|
||||
case -1:
|
||||
scaleX = view.getWidth() / win.getWidth();
|
||||
scaleY = view.getHeight() / win.getHeight();
|
||||
break;
|
||||
case 0:
|
||||
scaleX = scaleY = 1;
|
||||
break;
|
||||
default:
|
||||
scaleX = scaleY = scaleUnits / (double)Units.POINT_DPI;
|
||||
}
|
||||
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.scale(scaleX, scaleY);
|
||||
// at.translate(-view.getX(), -view.getY());
|
||||
at.translate(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
|
||||
|
||||
Shape tshape = at.createTransformedShape(shape);
|
||||
return tshape;
|
||||
}
|
||||
|
||||
protected BasicStroke getStroke() {
|
||||
Rectangle2D view = prop.getViewport();
|
||||
Rectangle2D win = prop.getWindow();
|
||||
|
@ -285,4 +258,47 @@ public class HwmfGraphics {
|
|||
}
|
||||
prop = propStack.remove(stackIndex);
|
||||
}
|
||||
|
||||
public void updateWindowMapMode() {
|
||||
GraphicsConfiguration gc = graphicsCtx.getDeviceConfiguration();
|
||||
Rectangle2D win = prop.getWindow();
|
||||
HwmfMapMode mapMode = prop.getMapMode();
|
||||
graphicsCtx.setTransform(initialAT);
|
||||
|
||||
switch (mapMode) {
|
||||
default:
|
||||
case MM_ANISOTROPIC:
|
||||
// scale output bounds to image bounds
|
||||
graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getHeight()/bbox.getHeight());
|
||||
graphicsCtx.translate(-bbox.getX(), -bbox.getY());
|
||||
|
||||
// scale window bounds to output bounds
|
||||
graphicsCtx.translate(win.getCenterX(), win.getCenterY());
|
||||
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
|
||||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
|
||||
break;
|
||||
case MM_ISOTROPIC:
|
||||
// TODO: to be validated ...
|
||||
// like anisotropic, but use x-axis as reference
|
||||
graphicsCtx.scale(gc.getBounds().getWidth()/bbox.getWidth(), gc.getBounds().getWidth()/bbox.getWidth());
|
||||
graphicsCtx.translate(-bbox.getX(), -bbox.getY());
|
||||
graphicsCtx.translate(win.getCenterX(), win.getCenterY());
|
||||
graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getWidth()/win.getWidth());
|
||||
graphicsCtx.translate(-win.getCenterX(), -win.getCenterY());
|
||||
break;
|
||||
case MM_LOMETRIC:
|
||||
case MM_HIMETRIC:
|
||||
case MM_LOENGLISH:
|
||||
case MM_HIENGLISH:
|
||||
case MM_TWIPS:
|
||||
// TODO: to be validated ...
|
||||
graphicsCtx.transform(gc.getNormalizingTransform());
|
||||
graphicsCtx.scale(1./mapMode.scale, -1./mapMode.scale);
|
||||
graphicsCtx.translate(-bbox.getX(), -bbox.getY());
|
||||
break;
|
||||
case MM_TEXT:
|
||||
// TODO: to be validated ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,7 +664,7 @@ public class HwmfDraw {
|
|||
|
||||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
|
||||
ctx.applyObjectTableEntry(objectIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,6 +221,7 @@ public class HwmfMisc {
|
|||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.getProperties().setMapMode(mapMode);
|
||||
ctx.updateWindowMapMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||
|
@ -26,18 +27,58 @@ import org.apache.poi.util.LittleEndianInputStream;
|
|||
public class HwmfPalette {
|
||||
|
||||
public static class PaletteEntry {
|
||||
enum PaletteEntryFlag {
|
||||
/**
|
||||
* Specifies that the logical palette entry be used for palette animation. This value
|
||||
* prevents other windows from matching colors to the palette entry because the color frequently
|
||||
* changes. If an unused system-palette entry is available, the color is placed in that entry.
|
||||
* Otherwise, the color is not available for animation.
|
||||
*/
|
||||
PC_RESERVED(0x01),
|
||||
/**
|
||||
* Specifies that the low-order word of the logical palette entry designates a hardware
|
||||
* palette index. This value allows the application to show the contents of the display device palette.
|
||||
*/
|
||||
PC_EXPLICIT(0x02),
|
||||
/**
|
||||
* Specifies that the color be placed in an unused entry in the system palette
|
||||
* instead of being matched to an existing color in the system palette. If there are no unused entries
|
||||
* in the system palette, the color is matched normally. Once this color is in the system palette,
|
||||
* colors in other logical palettes can be matched to this color.
|
||||
*/
|
||||
PC_NOCOLLAPSE(0x04)
|
||||
;
|
||||
|
||||
int flag;
|
||||
|
||||
PaletteEntryFlag(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
static PaletteEntryFlag valueOf(int flag) {
|
||||
for (PaletteEntryFlag pef : values()) {
|
||||
if (pef.flag == flag) return pef;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Values (1 byte): An 8-bit unsigned integer that defines how the palette entry is to be used.
|
||||
// The Values field MUST be 0x00 or one of the values in the PaletteEntryFlag Enumeration table.
|
||||
// Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.
|
||||
// Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.
|
||||
// Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.
|
||||
private int values, blue, green, red;
|
||||
private PaletteEntryFlag values;
|
||||
private Color colorRef;
|
||||
|
||||
public int init(LittleEndianInputStream leis) throws IOException {
|
||||
values = leis.readUByte();
|
||||
blue = leis.readUByte();
|
||||
green = leis.readUByte();
|
||||
red = leis.readUByte();
|
||||
values = PaletteEntryFlag.valueOf(leis.readUByte());
|
||||
int blue = leis.readUByte();
|
||||
int green = leis.readUByte();
|
||||
int red = leis.readUByte();
|
||||
colorRef = new Color(red, green, blue);
|
||||
|
||||
return 4*LittleEndianConsts.BYTE_SIZE;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +98,7 @@ public class HwmfPalette {
|
|||
*/
|
||||
private int numberOfEntries;
|
||||
|
||||
PaletteEntry entries[];
|
||||
private PaletteEntry entries[];
|
||||
|
||||
@Override
|
||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||
|
|
|
@ -167,6 +167,7 @@ public class HwmfWindowing {
|
|||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.getProperties().setWindowOrg(x, y);
|
||||
ctx.updateWindowMapMode();
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
|
@ -211,6 +212,7 @@ public class HwmfWindowing {
|
|||
@Override
|
||||
public void draw(HwmfGraphics ctx) {
|
||||
ctx.getProperties().setWindowExt(width, height);
|
||||
ctx.updateWindowMapMode();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
|
@ -254,6 +256,7 @@ public class HwmfWindowing {
|
|||
public void draw(HwmfGraphics ctx) {
|
||||
Rectangle2D window = ctx.getProperties().getWindow();
|
||||
ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);
|
||||
ctx.updateWindowMapMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,6 +310,7 @@ public class HwmfWindowing {
|
|||
double width = window.getWidth() * xNum / xDenom;
|
||||
double height = window.getHeight() * yNum / yDenom;
|
||||
ctx.getProperties().setWindowExt(width, height);
|
||||
ctx.updateWindowMapMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.poi.hwmf.usermodel;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -84,10 +85,15 @@ public class HwmfPicture {
|
|||
}
|
||||
|
||||
public void draw(Graphics2D ctx) {
|
||||
AffineTransform at = ctx.getTransform();
|
||||
try {
|
||||
HwmfGraphics g = new HwmfGraphics(ctx, getBounds());
|
||||
for (HwmfRecord r : records) {
|
||||
r.draw(g);
|
||||
}
|
||||
} finally {
|
||||
ctx.setTransform(at);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,9 +79,6 @@ public class TestHwmfParsing {
|
|||
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();
|
||||
|
|
Loading…
Reference in New Issue