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
5d79479dcf
commit
afb36678f5
@ -20,6 +20,7 @@ package org.apache.poi.hwmf.draw;
|
|||||||
import java.awt.BasicStroke;
|
import java.awt.BasicStroke;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Shape;
|
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.HwmfBrushStyle;
|
||||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||||
|
import org.apache.poi.hwmf.record.HwmfMapMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
|
||||||
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
|
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
|
||||||
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||||
@ -49,6 +51,7 @@ public class HwmfGraphics {
|
|||||||
private List<HwmfObjectTableEntry> objectTable = new ArrayList<HwmfObjectTableEntry>();
|
private List<HwmfObjectTableEntry> objectTable = new ArrayList<HwmfObjectTableEntry>();
|
||||||
/** Bounding box from the placeable header */
|
/** Bounding box from the placeable header */
|
||||||
private final Rectangle2D bbox;
|
private final Rectangle2D bbox;
|
||||||
|
private final AffineTransform initialAT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a graphics context for wmf rendering
|
* Initialize a graphics context for wmf rendering
|
||||||
@ -59,6 +62,7 @@ public class HwmfGraphics {
|
|||||||
public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
|
public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
|
||||||
this.graphicsCtx = graphicsCtx;
|
this.graphicsCtx = graphicsCtx;
|
||||||
this.bbox = (Rectangle2D)bbox.clone();
|
this.bbox = (Rectangle2D)bbox.clone();
|
||||||
|
this.initialAT = graphicsCtx.getTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HwmfDrawProperties getProperties() {
|
public HwmfDrawProperties getProperties() {
|
||||||
@ -72,7 +76,6 @@ public class HwmfGraphics {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shape tshape = fitShapeToView(shape);
|
|
||||||
BasicStroke stroke = getStroke();
|
BasicStroke stroke = getStroke();
|
||||||
|
|
||||||
// first draw a solid background line (depending on bkmode)
|
// 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)) {
|
if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {
|
||||||
graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));
|
graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));
|
||||||
graphicsCtx.setColor(prop.getBackgroundColor().getColor());
|
graphicsCtx.setColor(prop.getBackgroundColor().getColor());
|
||||||
graphicsCtx.draw(tshape);
|
graphicsCtx.draw(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then draw the (dashed) line
|
// then draw the (dashed) line
|
||||||
graphicsCtx.setStroke(stroke);
|
graphicsCtx.setStroke(stroke);
|
||||||
graphicsCtx.setColor(prop.getPenColor().getColor());
|
graphicsCtx.setColor(prop.getPenColor().getColor());
|
||||||
graphicsCtx.draw(tshape);
|
graphicsCtx.draw(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fill(Shape shape) {
|
public void fill(Shape shape) {
|
||||||
if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
|
if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
|
||||||
GeneralPath gp = new GeneralPath(shape);
|
GeneralPath gp = new GeneralPath(shape);
|
||||||
gp.setWindingRule(prop.getPolyfillMode().awtFlag);
|
gp.setWindingRule(prop.getPolyfillMode().awtFlag);
|
||||||
Shape tshape = fitShapeToView(gp);
|
|
||||||
graphicsCtx.setPaint(getFill());
|
graphicsCtx.setPaint(getFill());
|
||||||
graphicsCtx.fill(tshape);
|
graphicsCtx.fill(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(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() {
|
protected BasicStroke getStroke() {
|
||||||
Rectangle2D view = prop.getViewport();
|
Rectangle2D view = prop.getViewport();
|
||||||
Rectangle2D win = prop.getWindow();
|
Rectangle2D win = prop.getWindow();
|
||||||
@ -285,4 +258,47 @@ public class HwmfGraphics {
|
|||||||
}
|
}
|
||||||
prop = propStack.remove(stackIndex);
|
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
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
|
ctx.applyObjectTableEntry(objectIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,6 +221,7 @@ public class HwmfMisc {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setMapMode(mapMode);
|
ctx.getProperties().setMapMode(mapMode);
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package org.apache.poi.hwmf.record;
|
package org.apache.poi.hwmf.record;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
import org.apache.poi.hwmf.draw.HwmfGraphics;
|
||||||
@ -26,18 +27,58 @@ import org.apache.poi.util.LittleEndianInputStream;
|
|||||||
public class HwmfPalette {
|
public class HwmfPalette {
|
||||||
|
|
||||||
public static class PaletteEntry {
|
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.
|
// 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.
|
// 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.
|
// 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.
|
// 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.
|
// 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 {
|
public int init(LittleEndianInputStream leis) throws IOException {
|
||||||
values = leis.readUByte();
|
values = PaletteEntryFlag.valueOf(leis.readUByte());
|
||||||
blue = leis.readUByte();
|
int blue = leis.readUByte();
|
||||||
green = leis.readUByte();
|
int green = leis.readUByte();
|
||||||
red = leis.readUByte();
|
int red = leis.readUByte();
|
||||||
|
colorRef = new Color(red, green, blue);
|
||||||
|
|
||||||
return 4*LittleEndianConsts.BYTE_SIZE;
|
return 4*LittleEndianConsts.BYTE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +98,7 @@ public class HwmfPalette {
|
|||||||
*/
|
*/
|
||||||
private int numberOfEntries;
|
private int numberOfEntries;
|
||||||
|
|
||||||
PaletteEntry entries[];
|
private PaletteEntry entries[];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
|
||||||
|
@ -167,6 +167,7 @@ public class HwmfWindowing {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowOrg(x, y);
|
ctx.getProperties().setWindowOrg(x, y);
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getY() {
|
public int getY() {
|
||||||
@ -211,6 +212,7 @@ public class HwmfWindowing {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
ctx.getProperties().setWindowExt(width, height);
|
ctx.getProperties().setWindowExt(width, height);
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
@ -254,6 +256,7 @@ public class HwmfWindowing {
|
|||||||
public void draw(HwmfGraphics ctx) {
|
public void draw(HwmfGraphics ctx) {
|
||||||
Rectangle2D window = ctx.getProperties().getWindow();
|
Rectangle2D window = ctx.getProperties().getWindow();
|
||||||
ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);
|
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 width = window.getWidth() * xNum / xDenom;
|
||||||
double height = window.getHeight() * yNum / yDenom;
|
double height = window.getHeight() * yNum / yDenom;
|
||||||
ctx.getProperties().setWindowExt(width, height);
|
ctx.getProperties().setWindowExt(width, height);
|
||||||
|
ctx.updateWindowMapMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.apache.poi.hwmf.usermodel;
|
package org.apache.poi.hwmf.usermodel;
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -84,9 +85,14 @@ public class HwmfPicture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Graphics2D ctx) {
|
public void draw(Graphics2D ctx) {
|
||||||
HwmfGraphics g = new HwmfGraphics(ctx, getBounds());
|
AffineTransform at = ctx.getTransform();
|
||||||
for (HwmfRecord r : records) {
|
try {
|
||||||
r.draw(g);
|
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_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||||
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
|
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);
|
wmf.draw(g);
|
||||||
|
|
||||||
g.dispose();
|
g.dispose();
|
||||||
|
Loading…
Reference in New Issue
Block a user