/******************************************************************************* * Copyright (c) 2009, Adobe Systems Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * · Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * · Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * · Neither the name of Adobe Systems Incorporated nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ package com.adobe.dp.office.metafile; // WMF doc: http://wvware.sourceforge.net/caolan/support.html // wxwidgets import java.io.EOFException; import java.io.IOException; import java.io.InputStream; public class WMFParser extends MetafileParser { public static final int META_MAGIC = 0x9AC6CDD7; public static final int META_MAGIC1 = 0x00090001; public static final int META_MAGIC2 = 0x00090002; private static final int META_SAVEDC = 0x1E; // private static final int META_REALIZEPALETTE = 0x35; // private static final int META_SETPALENTRIES = 0x37; // private static final int META_CREATEPALETTE = 0xf7; private static final int META_SETBKMODE = 0x102; private static final int META_SETMAPMODE = 0x103; private static final int META_SETROP2 = 0x104; private static final int META_SETRELABS = 0x105; private static final int META_SETPOLYFILLMODE = 0x106; // private static final int META_SETSTRETCHBLTMODE = 0x107; // private static final int META_SETTEXTCHAREXTRA = 0x108; private static final int META_RESTOREDC = 0x127; // private static final int META_INVERTREGION = 0x12A; // private static final int META_PAINTREGION = 0x12B; // private static final int META_SELECTCLIPREGION = 0x12C; private static final int META_SELECTOBJECT = 0x12D; private static final int META_SETTEXTALIGN = 0x12E; // private static final int META_RESIZEPALETTE = 0x139; // private static final int META_DIBCREATEPATTERNBRUSH = 0x142; // private static final int META_SETLAYOUT = 0x149; private static final int META_DELETEOBJECT = 0x1F0; // private static final int META_CREATEPATTERNBRUSH = 0x1F9; private static final int META_SETBKCOLOR = 0x201; private static final int META_SETTEXTCOLOR = 0x209; // private static final int META_SETTEXTJUSTIFICATION = 0x20A; private static final int META_SETWINDOWORG = 0x20B; private static final int META_SETWINDOWEXT = 0x20C; // private static final int META_SETVIEWPORTORG = 0x20D; // private static final int META_SETVIEWPORTEXT = 0x20E; // private static final int META_OFFSETWINDOWORG = 0x20F; // private static final int META_OFFSETVIEWPORTORG = 0x211; private static final int META_LINETO = 0x213; private static final int META_MOVETO = 0x214; // private static final int META_OFFSETCLIPRGN = 0x220; // private static final int META_FILLREGION = 0x228; // private static final int META_SETMAPPERFLAGS = 0x231; // private static final int META_SELECTPALETTE = 0x234; private static final int META_CREATEPENINDIRECT = 0x2FA; private static final int META_CREATEFONTINDIRECT = 0x2FB; private static final int META_CREATEBRUSHINDIRECT = 0x2FC; private static final int META_POLYGON = 0x324; private static final int META_POLYLINE = 0x325; // private static final int META_SCALEWINDOWEXT = 0x410; // private static final int META_SCALEVIEWPORTEXT = 0x412; // private static final int META_EXCLUDECLIPRECT = 0x415; // private static final int META_INTERSECTCLIPRECT = 0x416; private static final int META_ELLIPSE = 0x418; // private static final int META_FLOODFILL = 0x419; private static final int META_RECTANGLE = 0x41B; // private static final int META_SETPIXEL = 0x41F; // private static final int META_FRAMEREGION = 0x429; // private static final int META_ANIMATEPALETTE = 0x436; // private static final int META_TEXTOUT = 0x521; private static final int META_POLYPOLYGON = 0x538; // private static final int META_EXTFLOODFILL = 0x548; // private static final int META_ROUNDRECT = 0x61C; // private static final int META_PATBLT = 0x61D; // private static final int META_ESCAPE = 0x626; // private static final int META_CREATEREGION = 0x6FF; // private static final int META_ARC = 0x817; // private static final int META_PIE = 0x81A; // private static final int META_CHORD = 0x830; // private static final int META_BITBLT = 0x922; // private static final int META_DIBBITBLT = 0x940; private static final int META_EXTTEXTOUT = 0xA32; //private static final int META_STRETCHBLT = 0xB23; private static final int META_DIBSTRETCHBLT = 0xB41; //private static final int META_SETDIBTODEV = 0xD33; private static final int META_STRETCHDIB = 0xF43; public WMFParser(InputStream in, GDISurface handler) throws IOException { super(in, handler); readFileHeader(); } private int readRecordHeader() throws IOException { int remainsInRecord = readInt(); // size in shorts int opcode = readShort() & 0xFFFF; setRemainsShorts(remainsInRecord - 3); return opcode; } private void readFileHeader() throws IOException { int magic = readInt(); if (magic == META_MAGIC) { readShort(); short left = readShort(); short top = readShort(); short right = readShort(); short bottom = readShort(); handler.setBounds(left, top, right, bottom); skipShorts(13); } else if (magic == META_MAGIC1 || magic == META_MAGIC2) { skipShorts(7); } else throw new IOException("Invalid file format"); } public void readAll() throws IOException { while (readNext()) { } close(); } public boolean readNext() throws IOException { try { int opcode = readRecordHeader(); switch (opcode) { case 0: // end return false; case META_SAVEDC: { handler.saveDC(); break; } case META_RESTOREDC: { handler.restoreDC(); break; } case META_STRETCHDIB: { skipShorts(3); int srcHeight = readShort(); int srcWidth = readShort(); int srcY = readShort(); int srcX = readShort(); int destHeight = readShort(); int destWidth = readShort(); int destY = readShort(); int destX = readShort(); GDIBitmap bitmap = readDIB(); handler.stretchDIB(bitmap, destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight); break; } case META_DIBSTRETCHBLT: { readInt(); // rop; not supported int srcY = readShort(); int srcX = readShort(); int srcHeight = readShort(); int srcWidth = readShort(); int destHeight = readShort(); int destWidth = readShort(); int destY = readShort(); int destX = readShort(); GDIBitmap bitmap = readDIB(); handler.stretchDIB(bitmap, destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight); break; } case META_SETMAPMODE: { if (remainsBytes() <= 0) throw new IOException("Problem in SETMAPMODE"); int mode = readShort(); handler.setMapMode(mode); break; } case META_SETROP2: { if (remainsBytes() <= 0) throw new IOException("Problem in SETROP2"); int mode = readShort(); handler.setROP2(mode); break; } case META_SETPOLYFILLMODE: { if (remainsBytes() <= 0) throw new IOException("Problem in SETPOLYFILLMODE"); short mode = readShort(); handler.setPolyFillMode(mode); break; } case META_SETBKMODE: { if (remainsBytes() <= 0) throw new IOException("Problem in SETBKMODE"); short mode = readShort(); handler.setBkMode(mode); break; } case META_SETTEXTALIGN: { if (remainsBytes() <= 0) throw new IOException("Problem in SETTEXTALIGN"); short mode = readShort(); handler.setTextAlign(mode); break; } case META_SELECTOBJECT: { if (remainsBytes() <= 0) throw new IOException("Problem in SELECTOBJECT"); short handle = readShort(); GDIObject gdi = (GDIObject) objects.get(handle); handler.selectObject(gdi); break; } case META_DELETEOBJECT: { if (remainsBytes() <= 0) throw new IOException("Problem in DELETEOBJECT"); short handle = readShort(); GDIObject gdi = (GDIObject) objects.get(handle); handler.deleteObject(gdi); gdi.dispose(); objects.set(handle, null); break; } case META_SETWINDOWEXT: { if (remainsShorts() < 2) throw new IOException("Problem in SETWINDOWEXT"); short h = readShort(); short w = readShort(); handler.setWindowExt(w, h); break; } case META_SETWINDOWORG: { if (remainsShorts() < 2) throw new IOException("Problem in SETWINDOWORG"); short y = readShort(); short x = readShort(); handler.setWindowOrg(x, y); break; } case META_SETBKCOLOR: { if (remainsShorts() < 2) throw new IOException("Problem in SETBKCOLOR"); handler.setBkColor(readRGB()); break; } case META_SETTEXTCOLOR: { if (remainsShorts() < 2) throw new IOException("Problem in SETTEXTCOLOR"); handler.setTextColor(readRGB()); break; } case META_CREATEPENINDIRECT: { if (remainsShorts() < 5) throw new IOException("Problem in CREATEPENINDIRECT"); short style = readShort(); short widthX = readShort(); short widthY = readShort(); int width = (widthX > widthY ? widthX : widthY); int rgb = readRGB(); Object pen = handler.createPenIndirect(style, width, rgb); storeObject(pen, 0); break; } case META_CREATEBRUSHINDIRECT: { if (remainsShorts() < 4) throw new IOException("Problem in CREATEBRUSHINDIRECT"); short style = readShort(); int rgb = readRGB(); short hatch = readShort(); Object brush = handler.createBrushIndirect(style, rgb, hatch); storeObject(brush, 0); break; } case META_CREATEFONTINDIRECT: { if (remainsShorts() < 10) throw new IOException("Problem in CREATEFONTINDIRECT"); int fontHeight = readShort(); int width = readShort(); // width int esc = readShort(); // esc int orientation = readShort(); // orientation int weight = readShort(); // weight int dl = 2 * remainsShorts(); byte[] data = new byte[dl]; readBytes(data); int l = 8; while (l < dl && data[l] != 0) l++; String name = new String(data, 8, l - 8); boolean italic = data[0] != 0; boolean underline = data[1] != 0; boolean strikeout = data[2] != 0; int charset = data[3] & 0xFF; int quality = data[6] & 0xFF; int pitchAndFamily = data[7] & 0xFF; Object font = handler.createFontIndirect(fontHeight, width, esc, orientation, weight, name, italic, underline, strikeout, charset, quality, pitchAndFamily); storeObject(font, 0); break; } case META_EXTTEXTOUT: { if (remainsShorts() < 4) throw new IOException("Problem in EXTTEXTOUT"); short y = readShort(); short x = readShort(); short count = readShort(); short flags = readShort(); int[] clipRect = null; int[] adj = null; if ((flags & 4) != 0) { // ETO_CLIPPED clipRect = new int[4]; clipRect[0] = readShort(); // x1 clipRect[1] = readShort(); // y1 clipRect[2] = readShort(); // x2 clipRect[3] = readShort(); // y2 } byte[] data = new byte[2 * remainsShorts()]; readBytes(data); String text = new String(data, 0, count); handler.extTextOut(x, y, text, flags, clipRect, adj); break; } case META_MOVETO: { if (remainsShorts() < 2) throw new IOException("Problem in MOVETO"); short y = readShort(); short x = readShort(); handler.moveTo(x, y); break; } case META_LINETO: { if (remainsShorts() < 2) throw new IOException("Problem in LINETO"); short y = readShort(); short x = readShort(); handler.lineTo(x, y); break; } case META_RECTANGLE: { if (remainsShorts() < 4) throw new IOException("Problem in RECTANGLE"); short bottom = readShort(); short right = readShort(); short top = readShort(); short left = readShort(); handler.rectangle(left, top, right, bottom); break; } case META_ELLIPSE: { if (remainsShorts() < 4) throw new IOException("Problem in ELLIPSE"); short bottom = readShort(); short right = readShort(); short top = readShort(); short left = readShort(); handler.ellipse(left, top, right, bottom); break; } case META_POLYGON: { if (remainsShorts() < 2) throw new IOException("Problem in POLYGON"); int count = readShort() * 2; int[] points = new int[count]; for (int i = 0; i < count; i++) { points[i] = readShort(); } handler.polygon(points, 0, count); break; } case META_POLYLINE: { if (remainsShorts() < 2) throw new IOException("Problem in POLYLINE"); int count = readShort() * 2; int[] points = new int[count]; for (int i = 0; i < count; i++) { points[i] = readShort(); } handler.polyline(points, 0, count); break; } case META_POLYPOLYGON: { if (remainsShorts() < 2) throw new IOException("Problem in POLYPOLYLINE"); int polyCount = readShort(); int[] pointCounts = new int[polyCount]; int total = 0; for (int i = 0; i < polyCount; i++) { int n = readShort(); total += n; pointCounts[i] = n; } total *= 2; int[] points = new int[total]; for (int i = 0; i < total; i++) { points[i] = readShort(); } handler.polyPolygon(pointCounts, points); break; } case META_SETRELABS: // undocumented API default: System.out.println("UNKNOWN " + Integer.toHexString(opcode) + " " + remainsShorts()); break; } finishRecord(); return true; } catch (EOFException e) { return false; } } }