git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1723198 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_14_FINAL
@@ -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,9 +85,14 @@ public class HwmfPicture { | |||
} | |||
public void draw(Graphics2D ctx) { | |||
HwmfGraphics g = new HwmfGraphics(ctx, getBounds()); | |||
for (HwmfRecord r : records) { | |||
r.draw(g); | |||
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(); |