
com.day.cq.dam.handler.standard.msoffice.wmf.WmfDecoder Maven / Gradle / Ivy
/*
* Copyright 1997-2011 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.dam.handler.standard.msoffice.wmf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.FontMetrics;
import java.awt.image.ColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageProducer;
import java.awt.image.PixelGrabber;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.EOFException;
import java.util.Stack;
import java.util.Vector;
import java.util.Enumeration;
/**
* WMF file interpreter.
* Taken from old DAM media handler project com.day.cq.dam.media.handler.office.wmf
*/
public class WmfDecoder implements ImageProducer {
private static final Logger log = LoggerFactory.getLogger(WmfDecoder.class);
boolean drawCross_if_error = true;
private int minsize = 7;
private int top, left, siz, obj, max;
private int res;
private int inch;
private WmfDecObj gdiObj[];
private Stack DCstack;
private int rgbPixels[] = null;
private short params[];
private int width = -1, height = -1;
private InputStream in;
private ColorModel cmodel = ColorModel.getRGBdefault();
private boolean err = false;
private boolean producing = false;
private Vector consumers = new Vector();
private byte[] data;
private int factor = 1;
// constructor
public WmfDecoder(byte[] data) {
this.data = data;
}
private InputStream getStream() {
return new ByteArrayInputStream(this.data);
}
// -------- methods that implement ImageProducer -----------------------
public void addConsumer(ImageConsumer ic) {
if (log.isDebugEnabled()) {
log.debug("addConsumer:" + ic);
}
if (ic != null && !this.isConsumer(ic)) {
this.consumers.addElement(ic);
}
}
public void startProduction(ImageConsumer ic) {
if (log.isDebugEnabled()) {
log.debug("startProduction:" + ic);
}
this.addConsumer(ic);
if (this.rgbPixels == null) {
try {
this.readWmf();
} catch (Exception ex) {
this.err = true;
this.width = this.height = -1;
log.error("Error while reading wmf", ex);
}
}
if (!this.producing) {
this.producing = true;
this.sendImage();
}
}
public boolean isConsumer(ImageConsumer ic) {
return this.consumers.contains(ic);
}
public void removeConsumer(ImageConsumer ic) {
if (log.isDebugEnabled()) {
log.debug("Remove:" + ic);
}
this.consumers.removeElement(ic);
}
public void requestTopDownLeftRightResend(ImageConsumer ic) {
}
// ---- method connects the Wmf interpreter with ImageProducer methods
private void sendImage() {
Vector xconsumers = (Vector) this.consumers.clone();
// consumers will decrease while calling ic.imageComplete()
// so in xconsumers we can each all elements
for (Enumeration e = xconsumers.elements(); e.hasMoreElements();) {
if (log.isDebugEnabled()) {
log.debug("consumers.size:" + this.consumers.size());
}
ImageConsumer ic = (ImageConsumer) e.nextElement();
if (this.isConsumer(ic)) {
if (log.isDebugEnabled()) {
log.debug("setPixels:" + ic);
}
if (!this.err) {
ic.setDimensions(this.width, this.height);
ic.setColorModel(this.cmodel);
ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES
| ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);
for (int row = 0; row < this.height; row++)
ic.setPixels(0, row, this.width, 1, this.cmodel, this.rgbPixels, row
* this.width, this.width);
ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
} else {
if (log.isDebugEnabled()) {
log.debug("IMAGEERROR");
}
ic.imageComplete(ImageConsumer.IMAGEABORTED);
}
}
}
this.producing = false;
}
private static void printObserverStatus(String text, int status) {
log.info(text);
if ((status & 0x80) > 0)
log.info("ABORT ");
if ((status & 0x40) > 0)
log.info("ERROR ");
if ((status & 0x20) > 0)
log.info("ALLBITS ");
if ((status & 0x10) > 0)
log.info("FRAMEBITS ");
if ((status & 0x08) > 0)
log.info("SOMEBITS ");
if ((status & 0x04) > 0)
log.info("PROPERTIES ");
if ((status & 0x02) > 0)
log.info("HEIGHT ");
if ((status & 0x01) > 0)
log.info("WIDTH ");
log.info("");
}
public Dimension getDimension() throws IOException {
int i, rdSize, rdFunc;
this.in = this.getStream();
this.chkHeader(this.in, null);
this.params = new short[this.max]; // max space for a metafile record
boolean go = true;
while (go) {
try {
rdSize = this.readInt32(this.in);
rdFunc = this.readInt16(this.in);
for (i = 0; i < rdSize - 3; i++) {
this.params[i] = this.readInt16(this.in);
}
switch (rdFunc) {
case META_SETWINDOWEXT:
if (this.params[0] > this.params[1] && this.params[0] > 2000) {
this.factor = 4;
} else if (this.params[1] > this.params[0] && this.params[1] > 2000) {
this.factor = 4;
} else {
this.factor = 1;
}
go = false;
return new Dimension(this.params[1] / this.factor, this.params[0] / this.factor);
}
} catch (IOException ex) {
go = false;
}
}
// return default values
return new Dimension(320, 240);
}
// ---- main method for reading Wmf into a pixel array -------------------
private void readWmf() throws IOException, InterruptedException {
Dimension d = this.getDimension();
this.in = this.getStream();
Image offscreen;
Graphics g;
if (this.chkHeader(this.in, d)) {
throw new IOException("WMF file format not supported");
}
this.DCstack = new Stack();
this.gdiObj = new WmfDecObj[this.obj];
this.width = d.width;
this.height = d.height;
log.debug("Dimension:" + d);
offscreen = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_RGB);
g = offscreen.getGraphics();
// new todo
g.setColor(Color.white);
g.fillRect(0, 0, d.width, d.height);
//
this.params = new short[this.max]; // max space for a metafile record
WmfDecDC DC = new WmfDecDC(this.width, this.height, this.left, this.top);
DC.gr = g;
this.DCstack.push(DC);
while (this.readRecord(this.in))
;
this.rgbPixels = new int[d.width * d.height];
PixelGrabber pg = new PixelGrabber(offscreen.getSource(), 0, 0, d.width, d.height,
this.rgbPixels, 0, d.width);
pg.grabPixels();
if (log.isDebugEnabled()) {
printObserverStatus("PixelGrabber status: ", pg.status());
}
log.debug("PixelGrabber status:" + pg.status());
g.dispose();
}
private boolean chkHeader(InputStream in, Dimension d) throws IOException {
int i, j, wid = 0, hig = 0, sum = 0;
int hdr[] = { -12841, -25914, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 0x300 };
for (i = 0; i < 14; i++) {
j = this.readInt16(in);
sum ^= j;
if ((i < 3 || i > 7)) {
if (j != hdr[i]) {
if ((i += 11) == 11 && j == hdr[11]) { // no first header
// present
continue;
} else {
return true; // error
}
}
} else {
switch (i) {
case 3:
this.left = j;
break;
case 4:
this.top = j;
break;
case 5:
wid = j;
break;
case 6:
hig = j;
break;
case 7:
hdr[10] = sum; // store checksum
this.res = Toolkit.getDefaultToolkit().getScreenResolution();
this.inch = j;
if (log.isDebugEnabled()) {
log.debug("inch: " + this.inch);
log.debug("sres: " + this.res);
}
d.width = ((wid - this.left) * this.res) / this.inch;
d.height = ((hig - this.top) * this.res) / this.inch;
break;
}
}
}
log.debug("dimension: " + d);
this.siz = this.readInt32(in);
this.obj = this.readInt16(in);
this.max = this.readInt32(in);
this.readInt16(in); // unused
log.debug("filesize(16): " + this.siz);
log.debug("GDI-Objects : " + this.obj);
log.debug("max rec size: " + this.max);
return false;
}
private boolean readRecord(InputStream in) {
int i, j, rdSize, rdFunc;
int a, b, c, d, e, f, k, l, m, n;
Color crco;
Font fo;
Image im;
WmfDecDC DC = (WmfDecDC) this.DCstack.peek();
Graphics g = DC.gr;
boolean error;
int xpoints[], ypoints[];
byte text[];
String s;
Object ob;
Graphics g2;
try {
rdSize = this.readInt32(in);
rdFunc = this.readInt16(in);
for (i = 0; i < rdSize - 3; i++)
this.params[i] = this.readInt16(in);
} catch (IOException ex) {
return false;
}
if (log.isDebugEnabled()) {
log.debug("RFunc: " + Integer.toString(rdFunc, 16));
}
switch (rdFunc) {
case META_LINETO:
if (log.isDebugEnabled()) {
log.debug("MetaLineTo");
}
g.setColor(DC.aktpen.getColor());
a = DC.ytransfer(this.params[0]);
b = DC.xtransfer(this.params[1]);
g.drawLine(DC.aktXpos, DC.aktYpos, b, a);
DC.aktXpos = b;
DC.aktYpos = a;
break;
case META_MOVETO:
if (log.isDebugEnabled()) {
log.debug("MetaMoveTo");
}
DC.aktYpos = DC.ytransfer(this.params[0]);
DC.aktXpos = DC.xtransfer(this.params[1]);
break;
case META_ROUNDRECT:
if (log.isDebugEnabled()) {
log.debug("MetaRoundRect");
}
e = this.transform(this.params[0], this.minsize);
f = this.transform(this.params[1], this.minsize);
a = DC.ytransfer(this.params[2]);
b = DC.xtransfer(this.params[3]);
c = DC.ytransfer(this.params[4]);
d = DC.xtransfer(this.params[5]);
if (a < c && b < d) {
i = a;
a = c;
c = i;
i = b;
b = d;
d = i;
}
// FIXME: draw_round_rect_Pattern if needed
g.setColor(DC.aktbrush.getColor());
g.fillRoundRect(d, c, b - d - 1, a - c - 1, f, e);
g.setColor(DC.aktpen.getColor());
g.drawRoundRect(d, c, b - d - 1, a - c - 1, f, e);
break;
case META_RECTANGLE:
if (log.isDebugEnabled()) {
log.debug("MetaRectangle");
}
a = DC.ytransfer(this.params[0]);
b = DC.xtransfer(this.params[1]);
c = DC.ytransfer(this.params[2]);
d = DC.xtransfer(this.params[3]);
if (a < c && b < d) {
i = a;
a = c;
c = i;
i = b;
b = d;
d = i;
}
if (DC.aktbrush.getImage() != null) {
this.drawOpaqePattern(g, DC.aktbrush.getImage(), d, c, b, a, null);// fr);
// //todo
log.debug("*** drawOpaqePattern");
} else {
g.setColor(DC.aktbrush.getColor());
g.fillRect(d, c, b - d - 1, a - c - 1);
}
g.setColor(DC.aktpen.getColor());
g.drawRect(d, c, b - d - 1, a - c - 1);
break;
case META_SETPIXEL:
if (log.isDebugEnabled()) {
log.debug("MetaSetpixel");
}
crco = new Color(this.getLoByteVal(this.params[0]), this.getHiByteVal(this.params[0]),
this.getLoByteVal(this.params[1]));
g.setColor(crco);
crco = null;
a = DC.xtransfer(this.params[3]);
b = DC.ytransfer(this.params[2]);
g.drawLine(a, b, a, b);
break;
case META_POLYLINE:
case META_POLYGON:
if (log.isDebugEnabled()) {
log.debug(((rdFunc == META_POLYGON) ? "MetaPolygon: " : "MetaPolyLine: ")
+ this.params[0]);
}
xpoints = new int[this.params[0]];
ypoints = new int[this.params[0]];
for (i = 0; i < this.params[0]; i++) {
xpoints[i] = DC.xtransfer(this.params[i * 2 + 1]);
ypoints[i] = DC.ytransfer(this.params[i * 2 + 2]);
if (log.isDebugEnabled()) {
log.debug(Integer.toString(xpoints[i], 16) + " "
+ Integer.toString(ypoints[i], 16));
}
}
if (rdFunc == META_POLYGON) {
g.setColor(DC.aktbrush.getColor());
g.fillPolygon(xpoints, ypoints, this.params[0]);
g.setColor(DC.aktpen.getColor());
g.drawPolygon(xpoints, ypoints, this.params[0]);
} else {
g.setColor(DC.aktpen.getColor());
g.drawPolyline(xpoints, ypoints, this.params[0]);
}
xpoints = null;
ypoints = null;
break;
case META_POLYPOLYGON:
if (log.isDebugEnabled()) {
log.debug("MetaPolyPolygon: " + this.params[0]);
}
for (i = 0; i < this.params[0]; i++) {
xpoints = new int[this.params[i + 1]];
ypoints = new int[this.params[i + 1]];
if (log.isDebugEnabled()) {
log.debug("Polygon #" + i + " Pts=" + this.params[i + 1]);
}
b = this.params[0] + 1; // first point of first polygon
for (c = 0; c < i; c++)
b += this.params[c + 1] * 2; // add size of polygons
// before
for (a = 0; a < this.params[i + 1]; a++) {
xpoints[a] = DC.xtransfer(this.params[b + a * 2]);
ypoints[a] = DC.ytransfer(this.params[b + a * 2 + 1]);
if (log.isDebugEnabled()) {
log.debug(Integer.toString(xpoints[a], 16) + " "
+ Integer.toString(ypoints[a], 16));
}
}
g.setColor(DC.aktbrush.getColor());
g.fillPolygon(xpoints, ypoints, this.params[i + 1]);
g.drawPolygon(xpoints, ypoints, this.params[i + 1]);
}
break;
case META_ELLIPSE:
if (log.isDebugEnabled()) {
log.debug("MetaEllipse");
}
a = DC.ytransfer(this.params[0]);
b = DC.xtransfer(this.params[1]);
c = DC.ytransfer(this.params[2]);
d = DC.xtransfer(this.params[3]);
g.setColor(DC.aktpen.getColor());
g.drawOval(d, c, b - d, a - c);
g.setColor(DC.aktbrush.getColor());
g.fillOval(d, c, b - d, a - c);
break;
case META_ARC:
case META_PIE:
case META_CHORD:
if (log.isDebugEnabled())
switch (rdFunc) {
case META_ARC:
log.debug("MetaArc");
break;
case META_PIE:
log.debug("MetaPie");
break;
case META_CHORD:
log.debug("MetaChord");
break;
}
a = DC.ytransfer(this.params[0]);
b = DC.xtransfer(this.params[1]); // Yend;Xend;
c = DC.ytransfer(this.params[2]);
d = DC.xtransfer(this.params[3]); // Ystart;Xstart;
e = DC.ytransfer(this.params[4]);
f = DC.xtransfer(this.params[5]); // Ybuttom;Xright;
k = DC.ytransfer(this.params[6]);
l = DC.xtransfer(this.params[7]); // Ytop;Xleft
g.setColor(DC.aktpen.getColor());
int xm = l + (f - l) / 2;
int ym = k + (e - k) / 2;
if (rdFunc == META_PIE) {
g.drawLine(d, c, xm, ym);
g.drawLine(b, a, xm, ym);
}
if (rdFunc == META_CHORD)
g.drawLine(d, c, b, a);
int beg = this.arcus(d - xm, c - ym);
int arc = this.arcus(b - xm, a - ym) - beg;
if (arc < 0)
arc += 360;
if (log.isDebugEnabled()) {
log.debug("Beg=" + beg + " Arc=" + arc);
}
g.drawArc(l, k, f - l, e - k, beg, arc);
//
// FIXME: fill arc etc with selected brush Sat May 17 19:02:27 1997
break;
case META_DELETEOBJECT:
if (log.isDebugEnabled()) {
log.debug("MetaDeleteObject:" + this.params[0]);
}
this.gdiObj[this.params[0]] = null;
break;
case META_SELECTPALETTE:
if (log.isDebugEnabled()) {
log.debug("MetaSelectPalette:" + this.params[0] + " = "
+ this.gdiObj[this.params[0]]);
}
if (this.gdiObj[this.params[0]].getMagic() == WmfDecObj.M_PALETTE)
DC.aktpal = this.gdiObj[this.params[0]];
else
log.error(" ---- internal ERROR in MetaSelectPalette -----");
break;
case META_SELECTCLIPREGION:
if (log.isDebugEnabled()) {
log.debug("MetaSelectClipRegion:" + this.params[0] + " = "
+ this.gdiObj[this.params[0]]);
}
if (this.gdiObj[this.params[0]] != null
&& this.gdiObj[this.params[0]].getMagic() == WmfDecObj.M_CLIP) {
DC.aktclip = this.gdiObj[this.params[0]];
g.clipRect(DC.aktclip.getRect().x, DC.aktclip.getRect().y,
DC.aktclip.getRect().width, DC.aktclip.getRect().height);
} else
log.error(" ---- internal ERROR in MetaSelectClipregion -----");
break;
case META_SELECTOBJECT:
if (log.isDebugEnabled()) {
log.debug("MetaSelectObject:" + this.params[0] + " = "
+ this.gdiObj[this.params[0]]);
}
switch (this.gdiObj[this.params[0]].getMagic()) {
case WmfDecObj.M_PEN:
DC.aktpen = this.gdiObj[this.params[0]];
break;
case WmfDecObj.M_FONT:
DC.aktfont = this.gdiObj[this.params[0]];
break;
case WmfDecObj.M_BRUSH:
DC.aktbrush = this.gdiObj[this.params[0]];
break;
case WmfDecObj.M_PALETTE: // a kind of dummy
DC.aktpal = this.gdiObj[this.params[0]];
break;
case WmfDecObj.M_BITMAP: // another one...
DC.aktbmp = this.gdiObj[this.params[0]];
break;
case WmfDecObj.M_CLIP:
DC.aktclip = this.gdiObj[this.params[0]];
if (log.isDebugEnabled()) {
log.debug("Select clipping rect");
//g.drawRect(DC.aktclip.getRect().x, DC.aktclip.getRect().y,
// DC.aktclip.getRect().width, DC.aktclip.getRect().height);
}
g.clipRect(DC.aktclip.getRect().x, DC.aktclip.getRect().y,
DC.aktclip.getRect().width, DC.aktclip.getRect().height);
break;
}
break;
case META_CREATEPENINDIRECT:
if (log.isDebugEnabled()) {
log.debug("MetaCreatePenIndirect");
}
error = false;
switch (this.params[0]) {
case PS_NULL:
crco = null; // ex DC.aktbackgnd;
// FIXME: have to test all DC.akt{pen|brush}.getColor()
// if color equals null, do NOT paint,draw,fill etc!! Sat May 17
// 19:23:45 1997
log.debug("MetaCreatePenIndirect: PS_NULL");
break;
case PS_DASH:
case PS_DOT:
case PS_DASHDOT:
case PS_DASHDOTDOT:
log.debug("MetaCreatePenIndirect: line attribute " + this.params[0]
+ " ignored");
case PS_INSIDEFRAME:
case PS_SOLID:
crco = new Color(this.getLoByteVal(this.params[3]), this
.getHiByteVal(this.params[3]), this.getLoByteVal(this.params[4]));
break;
default:
crco = Color.black;
error = true;
break;
}
if (!error) {
this.add_handle(new WmfDecObj(PS_SOLID /* params[0] */, crco));
if (log.isDebugEnabled()) {
log.debug(crco.toString());
}
crco = null;
a = this.params[1];
b = this.params[2];
}
if (log.isDebugEnabled() || error) {
for (i = 0; i < rdSize - 3; i++)
if (i < 16)
log.debug(Integer.toString(this.params[i], 16) + " ");
//System.out.println();
}
break;
case META_CREATEBRUSHINDIRECT:
if (log.isDebugEnabled()) {
log.debug("MetaCreateBrushIndirect: Style=" + this.params[0]);
this.showparams(this.params, rdSize, rdFunc);
}
switch (this.params[0]) {
case 1:
crco = DC.aktbackgnd; // BS_HOLLOW
this.add_handle(new WmfDecObj(crco, WmfDecObj.M_BRUSH));
if (log.isDebugEnabled()) {
log.debug(crco.toString());
}
break;
case 0:
crco = new Color(this.getLoByteVal(this.params[1]), // BS_SOLID
this.getHiByteVal(this.params[1]), this.getLoByteVal(this.params[2]));
this.add_handle(new WmfDecObj(crco, WmfDecObj.M_BRUSH));
if (log.isDebugEnabled()) {
log.debug(crco.toString());
}
crco = null;
break;
case 2:
crco = new Color(this.getLoByteVal(this.params[1]), // BS_HATCHED
this.getHiByteVal(this.params[1]), this.getLoByteVal(this.params[2]));
this.add_handle(new WmfDecObj(this.params[3], crco, DC.aktbackgnd));// ,fr));
if (log.isDebugEnabled()) {
log.debug(crco.toString());
}
crco = null;
break;
case 3: // BS_PATTERN
case 4: // BS_INDEXED
case 5: // BS_DIBPATTERN
// FIXME: replace workaround
crco = Color.gray;
this.add_handle(new WmfDecObj(crco, WmfDecObj.M_BRUSH));
log.debug("pattern substitution used.");
break;
default:
log.warn("(bad parameter!)");
}
break;
case META_CREATEREGION:
if (log.isDebugEnabled()) {
log.debug("MetaCreateRegion");
log.debug("params[5] sub records=" + this.params[5]);
for (i = 0; i < rdSize - 3; i++)
log.debug(Integer.toString(this.params[i], 10) + " ");
//System.out.println();
}
this.add_handle(new WmfDecObj(DC.xtransfer(this.params[7]), DC
.ytransfer(this.params[8]), DC.xtransfer(this.params[9]), DC
.xtransfer(this.params[10])));
// awt supports only rectangle clipping, currently other data
// ignored
// FIXME: fake oval or other regions
break;
case META_INTERSECTCLIPRECT:
// if (debug)
log.debug("MetaIntersectClipRect is experimental");
n = DC.ytransfer(this.params[0]);
m = DC.xtransfer(this.params[1]);
l = DC.ytransfer(this.params[2]);
k = DC.xtransfer(this.params[3]);
g.clipRect(k, l, m - k, n - l);
break;
case META_CREATEFONTINDIRECT:
text = new byte[80];
for (j = i = 0; i < rdSize - 3 - 9; i++) // 9 starts FontName, 3
// for overhead
{
if ((text[2 * i] = (byte) this.getLoByteVal(this.params[i + 9])) == 0)
break;
else
j++;
if ((text[2 * i + 1] = (byte) this.getHiByteVal(this.params[i + 9])) == 0)
break;
else
j++;
}
s = new String(text, 0, 0, j);
if (log.isDebugEnabled()) {
log.debug("MetaCreateFontIndirect: " + this.params[0] + " "
+ this.params[1] + " " + s);
}
if (s.startsWith("Times")) // may be: "Times New Roman"
s = "TimesRoman";
else if (s.startsWith("Arial"))
s = "Helvetica";
else if (s.startsWith("Courier"))
s = "Courier";
else if (s.startsWith("MS")) // may be: "MS Sans Serif"
s = "Dialog";
else if (s.startsWith("WingDings"))
s = "ZapfDingbats";
b = this.params[1]; // width
c = this.params[2];
d = this.params[3]; // esc, ori
e = this.params[4];
f = this.params[5]; // weight, ita+underl
k = this.params[6];
l = this.params[7]; // str+cha, out+clip
i = this.params[8]; // pitch
a = this.transform(this.params[0], this.minsize);
fo = new Font(s, (e > 500 ? Font.BOLD : Font.PLAIN)
+ (this.getLoByteVal(f) > 0 ? Font.ITALIC : 0), a);
if (log.isDebugEnabled()) {
log.debug(fo.toString());
}
this.add_handle(new WmfDecObj(fo, this.getHiByteVal(f), d));
fo = null;
text = null;
break;
case META_CREATEPALETTE:
if (log.isDebugEnabled()) {
log.debug("MetaCreatePalette");
}
crco = Color.black;
this.add_handle(new WmfDecObj(crco, WmfDecObj.M_PALETTE));
break;
case META_REALIZEPALETTE:
if (log.isDebugEnabled()){
this.showparams(this.params, rdSize, rdFunc);
}
log.debug("MetaRealizePalette");
break;
case META_SETROP2:
if (log.isDebugEnabled()) {
log.debug("MetaSetRop2: ROP code="
+ Integer.toString((i = this.params[0]), 16));
}
break;
case META_SETPOLYFILLMODE:
if (log.isDebugEnabled()) {
log.debug("MetaSetPolyFillmode:" + this.params[0]);
}
break;
case META_SETSTRETCHBLTMODE:
if (log.isDebugEnabled()) {
log.debug("MetaSetStretchBltMode:" + this.params[0]);
}
break;
case META_INVERTREGION:
if (log.isDebugEnabled()) {
this.showparams(this.params, rdSize, rdFunc);
}
log.debug("MetaInvertRegion:" + this.params[0]);
break;
case META_SETWINDOWEXT:
DC.winextY = this.params[0];
DC.winextX = this.params[1];
if (log.isDebugEnabled()) {
log.debug("MetaSetWindowExt: X:" + DC.winextX + " Y:" + DC.winextY);
}
break;
case META_SETWINDOWORG:
DC.winorgY = this.params[0];
DC.winorgX = this.params[1];
if (log.isDebugEnabled()) {
log.debug("MetaSetWindowOrg: X:" + DC.winorgX + " Y:" + DC.winorgY);
}
break;
case META_SETTEXTCOLOR:
DC.akttextc = new Color(this.getLoByteVal(this.params[0]), this
.getHiByteVal(this.params[0]), this.getLoByteVal(this.params[1]));
if (log.isDebugEnabled()) {
log.debug("MetaSetTextColor: " + DC.akttextc);
}
break;
case META_EXTTEXTOUT:
case META_TEXTOUT:
if (rdFunc == META_EXTTEXTOUT) {
a = this.params[2]; // text length
b = DC.ytransfer(this.params[0]);
c = DC.xtransfer(this.params[1]);
d = this.params[3]; // option
if (log.isDebugEnabled()) {
log.debug("ExtTextOut:option =" + Integer.toString(d, 16));
}
k = DC.xtransfer(this.params[4]);
l = DC.ytransfer(this.params[5]);
m = DC.xtransfer(this.params[6]);
n = DC.ytransfer(this.params[7]);
log.debug("TextAlign=" + DC.akttextalign);
log.debug("x =" + c + "\ty =" + b);
log.debug("rx =" + k + "\try =" + l);
log.debug("rw =" + (m - k) + "\trh =" + (n - l));
e = d == 0 ? 3 : 7; // start of text
} else {
a = this.params[0]; // text length
b = DC.ytransfer(this.params[(a + 1) / 2 + 1]);
c = DC.xtransfer(this.params[(a + 1) / 2 + 2]);
d = e = 0;
k = l = m = n = 0;
}
// ------- handle ETO_... flags
if ((d & ETO_OPAQUE) != 0) {
g.setColor(DC.aktbackgnd); // for testing purpose: ....
// ,Color.green);
g.fillRect(k, l, m - k - 1, n - l - 1);
if (log.isDebugEnabled()) {
log.debug("ExtTextOut: using OPAQUE style");
}
}
//
if ((d & ETO_GRAYED) != 0) {
g.setColor(Color.lightGray);
} else {
g.setColor(DC.akttextc);
}
//
if ((d & ETO_CLIPPED) != 0) {
g2 = g.create();
g2.clipRect(k, l, m - k - 1, n - l - 1);
// FIXME: intersect with original clip rect
g = g2;
log.debug("ExtTextOut: using clipping rect");
} else {
g2 = null;
}
// ------------------
g.setFont(DC.aktfont.getFont());
FontMetrics fm = g.getFontMetrics();
text = new byte[a];
for (i = 0; i < a; i++) {
if (i % 2 == 0) {
text[i] = (byte) this.getLoByteVal(this.params[e + i / 2 + 1]);
} else {
text[i] = (byte) this.getHiByteVal(this.params[e + i / 2 + 1]);
}
}
s = new String(text);
// ---- draw text ---
if (DC.aktfont.getFontOrientation() != 0) {
g.drawString(s, c, b);
log.warn("non horizontal text is not supported: " + s);
} else {
if (DC.akttextalign == TA_TOP) {
b += DC.aktfont.getFont().getSize();
}
g.drawString(s, c, b);
if (DC.aktfont.isUnderlined()) {
g.drawLine(c, b + 2, c + fm.stringWidth(s), b + 2);
}
}
// ------------------
if (log.isDebugEnabled()) {
log.debug((rdFunc == META_EXTTEXTOUT ? "MetaExtTextOut: "
: "MetaTextOut: ")
+ (new String(text, 0)) + " (len=" + a + ") x=" + c + " y=" + b);
}
text = null;
if (g2 != null)
g2.dispose();
break;
case META_SETMAPMODE:
if (log.isDebugEnabled()) {
this.showparams(this.params, rdSize, rdFunc);
}
log.debug("MetaSetMapMode: " + this.params[0] + " (ignored)");
break;
case META_SETBKCOLOR:
if (log.isDebugEnabled()) {
log.debug("MetaSetBkColor");
}
DC.aktbackgnd = new Color(this.getLoByteVal(this.params[0]), this
.getHiByteVal(this.params[0]), this.getLoByteVal(this.params[1]));
break;
case META_SETTEXTJUSTIFICATION:
if (log.isDebugEnabled()) {
this.showparams(this.params, rdSize, rdFunc);
}
if (log.isDebugEnabled() || this.params[0] != 0 || this.params[1] != 0)
log.debug("MetaSetTextJustification: " + this.params[0] + " "
+ this.params[1]);
break;
case META_SETBKMODE:
if (log.isDebugEnabled()) {
log.debug("MetaSetBkMode:"
+ (this.params[0] == 1 ? "TRANSPARENT" : "OPAQUE"));
}
DC.aktbkmode = this.params[0];
break;
case META_SETTEXTALIGN:
if (log.isDebugEnabled()) {
log.debug("MetaSetTextalign: " + this.params[0]);
}
DC.akttextalign = this.params[0];
break;
case META_SAVEDC:
if (log.isDebugEnabled()) {
log.debug("MetaSaveDC");
}
try {
DC = (WmfDecDC) this.DCstack.push(DC.clone());
DC.slevel++;
DC.gr = g.create();
} catch (Exception ex) {
log.error(" ---- internal ERROR in MetaSaveDC -----");
}
break;
case META_RESTOREDC:
if (log.isDebugEnabled()) {
log.debug("MetaRestoreDC" + this.params[0]);
}
switch (this.params[0]) {
case -1:
g.dispose();
this.DCstack.pop();
DC = (WmfDecDC) this.DCstack.peek();
break;
default:
while (DC.slevel > this.params[0] && !this.DCstack.empty()) {
g.dispose();
DC = (WmfDecDC) this.DCstack.pop();
g = DC.gr;
}
break;
}
break;
case META_PATBLT:
e = (this.params[1] << 16) + this.params[0];
if (log.isDebugEnabled()) {
log.debug("MetaPatBlt: ROP code=" + Integer.toString(e, 16));
log.debug(DC.aktbrush.getImage().toString());
}
a = DC.ytransfer(this.params[2]);
b = DC.xtransfer(this.params[3]);
c = DC.ytransfer(this.params[4]);
d = DC.xtransfer(this.params[5]);
switch (e) {
case WHITENESS:
g.setColor(Color.white); // <------ not yet debugged
g.fillRect(d, c, b, a);
break;
case BLACKNESS:
g.setColor(Color.black);
g.fillRect(d, c, b, a);
break;
case PATCOPY:
if ((im = DC.aktbrush.getImage()) != null) {
this.drawOpaqePattern(g, im, d, c, d + b, c + a, null);// fr);
// todo
log.debug("*** drawOpaqePattern");
} else {
g.setColor(DC.aktbrush.getColor());
g.fillRect(d, c, b, a);
}
break;
case PATINVERT:
case DSTINVERT:// FIXME
default:
log.warn("unsupported ROP code:" + Integer.toString(e, 16));
}
break;
case META_STRETCHBLT:
if (log.isDebugEnabled()) {
log.debug("MetaStretchBlt:" + rdSize);
}
e = (this.params[1] << 16) + this.params[0];
a = DC.ytransfer(this.params[6]);
b = DC.xtransfer(this.params[7]);
c = DC.ytransfer(this.params[8]);
d = DC.xtransfer(this.params[9]);
switch (e) {
case WHITENESS:
g.setColor(Color.white); // <------ not yet debugged
g.fillRect(d, c, b, a);
break;
case BLACKNESS:
g.setColor(Color.black);
g.fillRect(d, c, b, a);
break;
case SRCCOPY:
im = this.OldBitmapImage(10, this.params);// ,fr);
if (im != null) {
g.drawImage(im, d, c, b, a, null);// fr); todo
log.debug("*** drawImage");
im = null;
} else if (this.drawCross_if_error) {
g.setColor(Color.black);
g.drawLine(0, 0, DC.xtransfer(this.params[7]), DC.ytransfer(this.params[6]));
g.drawLine(DC.xtransfer(this.params[7]), 0, 0, DC.ytransfer(this.params[6]));
}
break;
default:
log.warn("unsupported ROP code:" + Integer.toString(e, 16));
}
break;
case META_DIBCREATEPATTERNBRUSH:
if (log.isDebugEnabled()) {
log.debug("MetaDibCreatePatternBrush:" + this.params[0]);
}
im = this.DIBBitmapImage(2, this.params);// ,fr);
if (im != null)
this.add_handle(new WmfDecObj(im));
else
log.error("Error in MetaDibCreatePatternBrush");
break;
case META_DIBBITBLT:
case META_STRETCHDIB:
case META_DIBSTRETCHBLT:
k = 0;
switch (rdFunc) {
case META_DIBBITBLT:
k = -2; // 2 params less
if (log.isDebugEnabled()) {
log.debug("MetaDibBitBlt");
}
break;
case META_STRETCHDIB:
k = 1; // 1 param more
if (log.isDebugEnabled()) {
log.debug("MetaStretchDib");
}
break;
case META_DIBSTRETCHBLT:
k = 0;
if (log.isDebugEnabled()) {
log.debug("MetaDibStretchBlt");
}
break;
}
a = DC.ytransfer(this.params[6 + k]);
b = DC.xtransfer(this.params[7 + k]);
c = DC.ytransfer(this.params[8 + k]);
d = DC.xtransfer(this.params[9 + k]);
e = (this.params[1] << 16) + this.params[0];
if (log.isDebugEnabled()) {
log.debug("dest X= " + d);
log.debug("dest Y= " + c);
log.debug("width = " + b);
log.debug("height= " + a);
}
switch (e) {
case WHITENESS:
g.setColor(Color.white); // <------ not yet debugged
g.fillRect(d, c, b, a);
break;
case BLACKNESS:
g.setColor(Color.black);
g.fillRect(d, c, b, a);
break;
case SRCCOPY:
im = this.DIBBitmapImage(10 + k, this.params);// ,fr); // here
// starts bmp
if (im != null) {
g.drawImage(im, d, c, b, a, null);// fr); todo
log.debug("*** drawImage");
im = null;
} else if (this.drawCross_if_error) { // draw a cross X
g.setColor(Color.black);
g.drawLine(d, c, d + b, c + a);
g.drawLine(d + b, c, d, c + a);
}
break;
default:
log.warn("unsupported ROP code:" + Integer.toString(e, 16));
}
break;
case META_ESCAPE:
switch (this.params[0]) {
case MFCOMMENT:
if (log.isDebugEnabled()) {
text = new byte[this.params[1]];
for (i = 0; i < this.params[1]; i++) {
if (i % 2 == 0)
text[i] = (byte) this.getLoByteVal(this.params[i / 2 + 2]);
else
text[i] = (byte) this.getHiByteVal(this.params[i / 2 + 2]);
if (text[i] == 0)
break;
}
s = new String(text, 0);
log.debug("MetaEscape/MFCOMMENT: " + s);
}
break;
default:
if (log.isDebugEnabled()) {
log.debug("MetaEscape #" + this.params[0] + " "
+ ((this.params[1] + 1) >>> 2) + " Words");
}
}
break;
case 0:
return false; // EOF
default:
this.showparams(this.params, rdSize, rdFunc);
break;
}
return true;
}
private void drawOpaqePattern(Graphics g, Image im, int x1, int y1, int x2, int y2,
ImageObserver fr) {
// it's just a little bit tricky ;-)
// subsequent calls to clipRect allow only to make the clip-region
// smaller
// ... but not to set it to a different location that was not covered by
// the
// ... current clipping region. So we have to create a new graphics, g2
int width = x2 - x1;
int height = y2 - y1;
int i, j;
Graphics g2 = g.create(x1 - x1 % 8, y1 - y1 % 8, width + 8, height + 8);
g2.clipRect(x1 % 8, y1 % 8, width, height);
for (i = 0; i < width + 1; i += 8)
for (j = 0; j < height + 1; j += 8)
g2.drawImage(im, i, j, fr);
g2.dispose();
}
private int getHiByteVal(int hhh) {
byte b;
if (hhh > 0)
b = (byte) (hhh / 256);
else {
int iii = ~hhh;
b = (byte) (iii >>> 8);
b = (byte) ((byte) 255 - b);
}
return b < 0 ? b + 256 : b;
}
private int getLoByteVal(int hhh) {
byte b;
if (hhh > 0)
b = (byte) (hhh % 256);
else {
int iii = ~hhh;
b = (byte) (iii & 0xff);
b = (byte) ((byte) 255 - b);
}
return b < 0 ? b + 256 : b;
}
private int transform(int param, int minsize) {
int i = param;
if (i < 0) {
i = -i;
}
try {
i = (i * this.res) / this.inch;
if (i < minsize) {
i = minsize;
}
} catch (ArithmeticException ex) {
}
return i / this.factor;
}
private void showparams(short[] params, int recSize, int Func) {
log.debug("MetaRecord: " + Integer.toString(Func, 16) + " RecSize=" + recSize);
log.debug("Data: ");
for (int i = 0; i < recSize - 3; i++)
if (i < 16)
log.debug(Integer.toString(params[i], 16) + " ");
}
private int add_handle(WmfDecObj x) {
int i;
for (i = 0; i < this.obj; i++)
if (this.gdiObj[i] == null) {
this.gdiObj[i] = x;
if (log.isDebugEnabled()) {
log.debug("Handle: " + i + "Obj: " + x);
}
return i;
}
return -1;
}
private int readInt32(InputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
}
private short readInt16(InputStream in) throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (short) ((ch2 << 8) + (ch1 << 0));
}
private int arcus(int ank, int geg) {
int val = -(int) (Math.atan((float) (geg) / (float) (ank)) * 180 / Math.PI); // div
// 0.0
// is
// "inf"
if (ank < 0)
val += 180;
else if (geg >= 0)
val += 360;
return val;
}
// ----------- called by META_STRETCHDIB ----------- (1, 4, 8 bpp only, no
// RLE) --------
private Image DIBBitmapImage(int off, short params[])// ,Component comp)
{
int width = params[off + 2];
int height = params[off + 4];
int size = width * height;
int bpp = params[off + 7];
int colors, i, j, k, l, m, x = 0, startbitmap;
if (params[off + 0] != 40 || params[off + 1] != 0) {
log.warn("unsupported data format");
return null;
}
if (params[off + 6] != 1) {
log.warn("not supported: planes=" + params[off + 17]);
return null;
}
if (bpp != 4 && bpp != 8 && bpp != 1 && bpp != 24) {
log.warn("not supported: " + bpp + " bits per pixel");
return null;
}
if (params[off + 8] != 0 || params[off + 9] != 0) {
log.warn("not supported: RLE-compression");
return null;
}
colors = 0;
int palette[] = null;
if (bpp <= 8) {
colors = params[off + 16] != 0 ? params[off + 16] : (1 << bpp);
palette = new int[colors];
for (i = 0; i < colors; i++) { // palette data starts at
// params[off+20]
x = params[off + 21 + 2 * i]; // range = 0...255
palette[i] = x << 16;
x = this.getHiByteVal(params[off + 20 + 2 * i]);
palette[i] += x << 8;
x = this.getLoByteVal(params[off + 20 + 2 * i]);
palette[i] += x;
palette[i] -= 0x1000000; // add bit_pattern
// (unsigned)0xFF000000 (for alpha)
}
}
startbitmap = 20 + off + 2 * colors; // beginning after
// header+palette data
int pixels[] = new int[size];
if (log.isDebugEnabled()) {
log.debug("bpp = " + bpp);
}
switch (bpp) {
case 1:
for (k = height - 1, i = 0; k >= 0; k--)
for (l = 0; l < width; l += 16) {
i++;
m = params[i - 1 + startbitmap];
if (m < 0)
m += 65536;
for (j = 0, m = (m >> 8) | (m << 8); j + l < width && j < 16; j++) {
pixels[k * width + l + j] = (m & 0x8000) == 0 ? -0x1000000 : -0x1;
m <<= 1;
}
if (i % 2 != 0)
i++;
}
break;
case 4:
for (k = height - 1, i = 0; k >= 0; k--)
for (l = 0; l < width; l++) {
switch (l % 4) {
case 0:
i++;
x = this.getLoByteVal(params[i - 1 + startbitmap]) >>> 4;
break;
case 1:
x = this.getLoByteVal(params[i - 1 + startbitmap]) & 0xf;
break;
case 2:
x = this.getHiByteVal(params[i - 1 + startbitmap]) >>> 4;
break;
case 3:
x = this.getHiByteVal(params[i - 1 + startbitmap]) & 0xf;
break;
}
pixels[k * width + l] = palette[x];
}
break;
case 8:
for (k = height - 1, i = 0; k >= 0; k--) {
for (l = 0; l < width; l++) {
switch (l % 2) {
case 0:
i++;
x = this.getLoByteVal(params[i - 1 + startbitmap]);
break;
case 1:
x = this.getHiByteVal(params[i - 1 + startbitmap]);
break;
}
pixels[k * width + l] = palette[x];
}
if (i % 2 != 0) {
i++;
}
}
break;
case 24:
int ii = 4 - (size * 3) % 4;
if (ii == 4) {
ii = 0;
}
boolean low = true;
int count = 0;
for (int jj = height - 1; jj >= 0; jj--) {
for (int kk = 0; kk < width; kk++) {
int ll;
if (low) {
count++;
ll = this.getLoByteVal(params[count - 1 + startbitmap]);
low = false;
} else {
ll = this.getHiByteVal(params[count - 1 + startbitmap]);
low = true;
}
int j1;
if (low) {
count++;
j1 = this.getLoByteVal(params[count - 1 + startbitmap]);
low = false;
} else {
j1 = this.getHiByteVal(params[count - 1 + startbitmap]);
low = true;
}
int k1;
if (low) {
count++;
k1 = this.getLoByteVal(params[count - 1 + startbitmap]);
low = false;
} else {
k1 = this.getHiByteVal(params[count - 1 + startbitmap]);
low = true;
}
pixels[jj * width + kk] = k1 << 16 & 0xff0000 | j1 << 8 & 0xff00 | ll & 0xff
| 0xff000000;
}
for (int i1 = 0; i1 < ii; i1++) {
if ((i1 % 2) == 0) {
count++;
low = false;
}
}
}
break;
}
// todo
Image im = Toolkit.getDefaultToolkit().createImage(
new MemoryImageSource(width, height, pixels, 0, width));
log.info("*** Toolkit.getDefaultToolkit().createImage");
pixels = null;
return im;
}
// ----------- called by META_STRETCHBLT ----------- (here monochrome only)
// --------
private Image OldBitmapImage(int off, short params[])// ,Component comp)
{
int width = params[off];
int height = params[off + 1];
int i, j, k, l, m;
if ((params[off + 3] != 1) || (params[off + 4] != 1)) {
log.warn("sorry, the only supported format is: planes=1,bpp=1");
return null;
}
int pixels[] = new int[width * height];
for (k = 0, i = 0; k < height; k++)
for (l = 0; l < width; l += 16) {
m = params[off + 5 + i++];
if (m < 0)
m += 65536;
for (j = 0, m = (m >> 8) | (m << 8); j + l < width && j < 16; j++) {
pixels[k * width + l + j] = (m & 0x8000) == 0 ? -0x1000000 : -0x1;
m <<= 1;
}
}
// todo
Image im = Toolkit.getDefaultToolkit().createImage(
new MemoryImageSource(width, height, pixels, 0, width));
log.info("*** Toolkit.getDefaultToolkit().createImage");
pixels = null;
return im;
}
private final static int META_SETBKCOLOR = 0x0201; //
private final static int META_SETBKMODE = 0x0102; //
private final static int META_SETMAPMODE = 0x0103; //
private final static int META_SETROP2 = 0x0104; //
private final static int META_SETRELABS = 0x0105;
private final static int META_SETPOLYFILLMODE = 0x0106; //
private final static int META_SETSTRETCHBLTMODE = 0x0107;
private final static int META_SETTEXTCHAREXTRA = 0x0108;
private final static int META_SETTEXTCOLOR = 0x0209; //
private final static int META_SETTEXTJUSTIFICATION = 0x020A; //
private final static int META_SETWINDOWORG = 0x020B; //
private final static int META_SETWINDOWEXT = 0x020C; //
private final static int META_SETVIEWPORTORG = 0x020D;
private final static int META_SETVIEWPORTEXT = 0x020E;
private final static int META_OFFSETWINDOWORG = 0x020F;
private final static int META_SCALEWINDOWEXT = 0x0410;
private final static int META_OFFSETVIEWPORTORG = 0x0211;
private final static int META_SCALEVIEWPORTEXT = 0x0412;
private final static int META_LINETO = 0x0213; //
private final static int META_MOVETO = 0x0214; //
private final static int META_EXCLUDECLIPRECT = 0x0415;
private final static int META_INTERSECTCLIPRECT = 0x0416;
private final static int META_ARC = 0x0817; //
private final static int META_ELLIPSE = 0x0418; //
private final static int META_FLOODFILL = 0x0419;
private final static int META_PIE = 0x081A; //
private final static int META_RECTANGLE = 0x041B; //
private final static int META_ROUNDRECT = 0x061C; //
private final static int META_PATBLT = 0x061D; //
private final static int META_SAVEDC = 0x001E;
private final static int META_SETPIXEL = 0x041F; //
private final static int META_OFFSETCLIPRGN = 0x0220;
private final static int META_TEXTOUT = 0x0521; //
private final static int META_BITBLT = 0x0922;
private final static int META_STRETCHBLT = 0x0B23; //
private final static int META_POLYGON = 0x0324; //
private final static int META_POLYLINE = 0x0325; //
private final static int META_ESCAPE = 0x0626; //
private final static int META_RESTOREDC = 0x0127; //
private final static int META_FILLREGION = 0x0228;
private final static int META_FRAMEREGION = 0x0429;
private final static int META_INVERTREGION = 0x012A;
private final static int META_PAINTREGION = 0x012B;
private final static int META_SELECTCLIPREGION = 0x012C; //
private final static int META_SELECTOBJECT = 0x012D; //
private final static int META_SETTEXTALIGN = 0x012E; //
private final static int META_DRAWTEXT = 0x062F;
private final static int META_CHORD = 0x0830; //
private final static int META_SETMAPPERFLAGS = 0x0231;
private final static int META_EXTTEXTOUT = 0x0A32; //
private final static int META_SETDIBTODEV = 0x0D33;
private final static int META_SELECTPALETTE = 0x0234; //
private final static int META_REALIZEPALETTE = 0x0035; //
private final static int META_ANIMATEPALETTE = 0x0436;
private final static int META_SETPALENTRIES = 0x0037;
private final static int META_POLYPOLYGON = 0x0538; //
private final static int META_RESIZEPALETTE = 0x0139;
private final static int META_DIBBITBLT = 0x0940; //
private final static int META_DIBSTRETCHBLT = 0x0B41; //
private final static int META_DIBCREATEPATTERNBRUSH = 0x0142; //
private final static int META_STRETCHDIB = 0x0F43; //
private final static int META_EXTFLOODFILL = 0x0548;
private final static int META_RESETDC = 0x014C;
private final static int META_STARTDOC = 0x014D;
private final static int META_STARTPAGE = 0x004F;
private final static int META_ENDPAGE = 0x0050;
private final static int META_ABORTDOC = 0x0052;
private final static int META_ENDDOC = 0x005E;
private final static int META_DELETEOBJECT = 0x01F0; //
private final static int META_CREATEPALETTE = 0x00F7; //
private final static int META_CREATEBRUSH = 0x00F8;
private final static int META_CREATEPATTERNBRUSH = 0x01F9;
private final static int META_CREATEPENINDIRECT = 0x02FA; //
private final static int META_CREATEFONTINDIRECT = 0x02FB; //
private final static int META_CREATEBRUSHINDIRECT = 0x02FC; //
private final static int META_CREATEBITMAPINDIRECT = 0x02FD;
private final static int META_CREATEBITMAP = 0x06FE;
private final static int META_CREATEREGION = 0x06FF; //
private final static int MFCOMMENT = 15;
private final static int SRCCOPY = 0xCC0020;
private final static int PATCOPY = 0xF00021;
private final static int PATINVERT = 0x5A0049;
private final static int DSTINVERT = 0x550009;
private final static int BLACKNESS = 0x000042;
private final static int WHITENESS = 0xFF0062;
private final static int BI_RLE8 = 1;
private final static int BI_RLE4 = 2;
private final static int TA_BASELINE = 24; // TextAlign options
private final static int TA_BOTTOM = 8;
private final static int TA_CENTER = 6;
private final static int TA_UPDATECP = 1; // FIXME: update current postion
final static int TA_TOP = 0;
final static int OPAQUE = 2;
final static int TRANSPARENT = 1;
final static int ETO_GRAYED = 1;
final static int ETO_OPAQUE = 2;
final static int ETO_CLIPPED = 4;
final static int PS_SOLID = 0;
final static int PS_DASH = 1;
final static int PS_DOT = 2;
final static int PS_DASHDOT = 3;
final static int PS_DASHDOTDOT = 4;
final static int PS_NULL = 5;
final static int PS_INSIDEFRAME = 6;
}
// this an all_in_one class of GDI-objects -------------------------------------
class WmfDecObj {
/**
* the default logger
*/
private static final Logger log = LoggerFactory.getLogger(WmfDecObj.class);
final static int M_PEN = 1;// the Windows GDI uses some other magic
// words...
final static int M_BRUSH = 2;
final static int M_FONT = 3;
final static int M_BITMAP = 4;
final static int M_CLIP = 5;
final static int M_PALETTE = 6;
private Color c;
private Font f;
private boolean f_underl;
private int f_orient;
private Rectangle r;
private int magic;
private Image ibrush;
private int hatch;
private int p_style;
WmfDecObj(Color cc, int mm) {
this.c = cc;
this.magic = mm;
}
WmfDecObj(int penattr, Color cc) {
this.c = cc;
this.magic = M_PEN;
this.p_style = penattr;
}
WmfDecObj(Font ff, int underlined, int orientation) {
this.f = ff;
this.f_underl = underlined == 0 ? false : true;
this.f_orient = orientation;
this.magic = M_FONT;
}
WmfDecObj(Image ii) {
this.ibrush = ii;
this.c = null;
this.magic = M_BRUSH;
}
WmfDecObj(int hatchstyle, Color cc, Color back)// ,Component fr)
{
this.c = cc; // TRANSPARENT mode not suppd
this.hatch = hatchstyle;
this.ibrush = this.createOpaqueImage(hatchstyle, cc, back);// ,fr);
this.magic = M_BRUSH;
}
WmfDecObj(int left, int top, int right, int bottom) {
this.r = new Rectangle(left, top, right - left, bottom - top);
this.magic = M_CLIP;
}
Color getColor() {
return this.c;
}
Image getImage() {
return this.ibrush; // draw a hatch image if OPAQUE mode ?
}
Font getFont() {
return this.f;
}
boolean isUnderlined() {
return this.f_underl;
}
int getFontOrientation() {
return this.f_orient;
}
int getPenStyle() {
return this.p_style;
}
Rectangle getRect() {
return this.r;
}
// int getHatch()
// {
// return hatch;
// }
int getMagic() {
return this.magic;
}
Image createOpaqueImage(int hatchstyle, Color cc, Color back)// ,Component
// fr)
{
Image im;
int i, pixels[] = new int[64];
// from HS_HORIZONTAL=0 up to HS_DIAGCROSS=5
int set[][] = { { 32, 33, 34, 35, 36, 37, 38, 39 }, { 4, 12, 20, 28, 36, 44, 52, 60 },
{ 0, 9, 18, 27, 36, 45, 54, 63 }, { 7, 14, 21, 28, 35, 42, 49, 56 },
{ 32, 33, 34, 35, 36, 37, 38, 39, 4, 12, 20, 28, 44, 52, 60 },
{ 0, 9, 18, 27, 36, 45, 54, 63, 7, 14, 21, 28, 35, 42, 49, 56 } };
for (i = 0; i < 64; i++)
pixels[i] = /* back.getRGB(); */Color.white.getRGB();
try {
for (i = 0; i < set[hatchstyle].length; i++) {
pixels[set[hatchstyle][i]] = cc.getRGB();
}
MemoryImageSource mis = new MemoryImageSource(8, 8, ColorModel.getRGBdefault(), pixels,
0, 8);
// todo: correct?
im = Toolkit.getDefaultToolkit().createImage(mis);
log.info("*** Toolkit.getDefaultToolkit().createImage");
mis = null;
} catch (ArrayIndexOutOfBoundsException e) {
im = null;
log.warn("unknown hatchstyle found.");
}
return im;
}
}
// Consider: this is NOT really what Windows-GDI does!
class WmfDecDC implements Cloneable {
WmfDecDC(int extX, int extY, int orgX, int orgY) {
// init (some metafiles don't call META_SETWINDOWEXT/META_SETWINDOWORG
// !)
this.winextX = (short) (this.truewidth = extX);
this.winextY = (short) (this.trueheight = extY);
this.winorgX = (short) orgX;
this.winorgY = (short) orgY;
this.aktclip = new WmfDecObj(this.winorgX, this.winorgY, this.winextX, this.winextY);
this.aktpen = new WmfDecObj(WmfDecoder.PS_SOLID, Color.black);
this.aktbrush = new WmfDecObj(Color.white, WmfDecObj.M_BRUSH);
this.aktpal = new WmfDecObj(Color.white, WmfDecObj.M_PALETTE);
this.aktbmp = new WmfDecObj(Color.white, WmfDecObj.M_BITMAP);
this.aktfont = new WmfDecObj(new Font("Courier", Font.PLAIN, 12), 0, 0);
}
// this is our "device context" (DC), init'd with GDI defaults
// it has 6 selectable objects
public WmfDecObj aktpen, aktbrush, aktpal, aktbmp, aktclip, aktfont;
public Color akttextc = Color.black;
public Color aktbackgnd = Color.white; // for usage in NULL-pens and
// -brushs
public int aktYpos = 0; // current graphic cursor (MoveTo,LineTo)
public int aktXpos = 0;
public short winextX = (short) 1; // for SetWindowExt()
public short winextY = (short) 1;
public short winorgX = (short) 0; // for SetWindowOrg()
public short winorgY = (short) 0;
public int slevel = 0; // SaveDC-level
public int akttextalign = WmfDecoder.TA_TOP;
public int aktbkmode = WmfDecoder.OPAQUE;
public Graphics gr;
// --------- still missing: ROP, ViewPort,MapMode,PolyfillMode etc.
private int trueheight, truewidth; // not part of GDI device context
int ytransfer(short coo) {
int icoo = coo;
icoo -= this.winorgY;
icoo *= this.trueheight;
return icoo / this.winextY;
}
int xtransfer(short coo) {
int icoo = coo;
icoo -= this.winorgX;
icoo *= this.truewidth;
return icoo / this.winextX;
}
public Object clone() // not yet ready
{
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
} // this never happens?
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy