Compare commits

...

4 Commits

Author SHA1 Message Date
Andreas Beeker c8dee17f33 a few more wmf records ...
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/wmf_render@1568840 13f79535-47bb-0310-9956-ffa450edef68
2014-02-16 21:56:14 +00:00
Andreas Beeker 87a6135199 DIBBITBLT Record
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/wmf_render@1566465 13f79535-47bb-0310-9956-ffa450edef68
2014-02-09 23:06:22 +00:00
Andreas Beeker f0c2bda1a6 Bug 56004 - Support for WMF rendering - (working copy commit)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/wmf_render@1566181 13f79535-47bb-0310-9956-ffa450edef68
2014-02-09 01:14:54 +00:00
Andreas Beeker 393e33492f Branch opened for #56004
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/wmf_render@1566178 13f79535-47bb-0310-9956-ffa450edef68
2014-02-09 00:59:57 +00:00
19 changed files with 4097 additions and 90 deletions

View File

@ -111,7 +111,7 @@ public class LittleEndian implements LittleEndianConsts
*
* @param data
* the byte array
* @return the double (64-bit) value
* @return the float (32-bit) value
*/
public static float getFloat( byte[] data )
{
@ -127,7 +127,7 @@ public class LittleEndian implements LittleEndianConsts
* the byte array
* @param offset
* a starting offset into the byte array
* @return the double (64-bit) value
* @return the float (32-bit) value
*/
public static float getFloat( byte[] data, int offset )
{

View File

@ -30,9 +30,12 @@ import java.io.InputStream;
* @author Josh Micich
*/
public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput {
private byte _buf[] = new byte[LittleEndianConsts.LONG_SIZE];
public LittleEndianInputStream(InputStream is) {
super(is);
}
public int available() {
try {
return super.available();
@ -40,105 +43,65 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
throw new RuntimeException(e);
}
}
public byte readByte() {
return (byte)readUByte();
readFully(_buf, 0, LittleEndianConsts.BYTE_SIZE);
return _buf[0];
}
public int readUByte() {
int ch;
try {
ch = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch);
return ch;
}
public double readDouble() {
return Double.longBitsToDouble(readLong());
readFully(_buf, 0, LittleEndianConsts.BYTE_SIZE);
return LittleEndian.getUByte(_buf);
}
public short readShort() {
readFully(_buf, 0, LittleEndianConsts.SHORT_SIZE);
return LittleEndian.getShort(_buf);
}
public int readUShort() {
readFully(_buf, 0, LittleEndianConsts.SHORT_SIZE);
return LittleEndian.getUShort(_buf);
}
public int readInt() {
int ch1;
int ch2;
int ch3;
int ch4;
try {
ch1 = in.read();
ch2 = in.read();
ch3 = in.read();
ch4 = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch1 | ch2 | ch3 | ch4);
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
}
public long readLong() {
int b0;
int b1;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
try {
b0 = in.read();
b1 = in.read();
b2 = in.read();
b3 = in.read();
b4 = in.read();
b5 = in.read();
b6 = in.read();
b7 = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7);
return (((long)b7 << 56) +
((long)b6 << 48) +
((long)b5 << 40) +
((long)b4 << 32) +
((long)b3 << 24) +
(b2 << 16) +
(b1 << 8) +
(b0 << 0));
}
public short readShort() {
return (short)readUShort();
}
public int readUShort() {
int ch1;
int ch2;
try {
ch1 = in.read();
ch2 = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch1 | ch2);
return (ch2 << 8) + (ch1 << 0);
}
private static void checkEOF(int value) {
if (value <0) {
throw new RuntimeException("Unexpected end-of-file");
}
readFully(_buf, 0, LittleEndianConsts.INT_SIZE);
return LittleEndian.getInt(_buf);
}
public long readUInt() {
readFully(_buf, 0, LittleEndianConsts.INT_SIZE);
return LittleEndian.getUInt(_buf);
}
public long readLong() {
readFully(_buf, 0, LittleEndianConsts.LONG_SIZE);
return LittleEndian.getLong(_buf);
}
public double readDouble() {
readFully(_buf, 0, LittleEndianConsts.LONG_SIZE);
return LittleEndian.getDouble(_buf);
}
public void readFully(byte[] buf) {
readFully(buf, 0, buf.length);
}
public void readFully(byte[] buf, int off, int len) {
int max = off+len;
for(int i=off; i<max; i++) {
int ch;
try {
ch = in.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
checkEOF(ch);
buf[i] = (byte) ch;
}
if (buf == null || buf.length == 0) {
return;
}
int readBytes;
try {
readBytes = super.read(buf, off, len);
} catch (IOException e) {
throw new RuntimeException(e);
}
if (readBytes == -1 || readBytes < len ) {
throw new RuntimeException("Unexpected end-of-file");
}
}
}

View File

@ -0,0 +1,47 @@
package org.apache.poi.hwmf;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.hwmf.record.WmfHeader;
import org.apache.poi.hwmf.record.WmfPlaceableHeader;
import org.apache.poi.hwmf.record.WmfRecord;
import org.apache.poi.hwmf.record.WmfRecordType;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfPicture {
// http://www.symantec.com/avcenter/reference/inside.the.windows.meta.file.format.pdf
public HwmfPicture(InputStream inputStream) throws IOException {
LittleEndianInputStream leis = new LittleEndianInputStream(inputStream);
WmfPlaceableHeader placeableHeader = WmfPlaceableHeader.readHeader(leis);
WmfHeader header = new WmfHeader(leis);
for (;;) {
long recordSize = leis.readUInt();
int recordFunction = leis.readShort();
WmfRecordType wrt = WmfRecordType.getById(recordFunction);
if (wrt == null) {
throw new IOException("unexpected record type: "+recordFunction);
}
if (wrt == WmfRecordType.eof) break;
if (wrt.clazz == null) {
throw new IOException("unsupported record type: "+recordFunction);
}
WmfRecord wr;
try {
wr = wrt.clazz.newInstance();
} catch (Exception e) {
throw (IOException)new IOException("can't create wmf record").initCause(e);
}
int consumedSize = wr.init(leis, recordSize, recordFunction);
if (consumedSize < recordSize) {
leis.skip(recordSize - consumedSize);
}
}
}
}

View File

@ -0,0 +1,159 @@
package org.apache.poi.hwmf.record;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* Taken from https://code.google.com/p/javasupport/source/browse/branches/java-examples/src/main/java/deng/huffman/dukehuff/test/BitInputStream.java?r=587
*
* reads bits-at-a-time where the number of bits is between 1 and 32.
* Updated for version 2.0 to extend java.io.InputStream
* <P>
* @author Owen Astrachan
* @version 1.0, July 2000
* @version 2.0, October 2004
*/
public class BitInputStream extends InputStream
{
private InputStream myInput;
private int myBitCount;
private int myBuffer;
private File myFile;
private static final int bmask[] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
0x1ff,0x3ff,0x7ff,0xfff,0x1fff,0x3fff,0x7fff,0xffff,
0x1ffff,0x3ffff,0x7ffff,0xfffff,0x1fffff,0x3fffff,
0x7fffff,0xffffff,0x1ffffff,0x3ffffff,0x7ffffff,
0xfffffff,0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff
};
private static final int BITS_PER_BYTE = 8;
/**
* Construct a bit-at-a-time input stream from a file
*/
public BitInputStream(String filename)
{
this(new File(filename));
}
/**
* Construct a bit-at-a-time input stream from <code>file</code>
* @param file is the File that is the source of the input
*/
public BitInputStream(File file)
{
myFile = file;
try {
reset();
} catch (IOException e) {
// eat the exception
}
}
public BitInputStream(InputStream in){
myInput = in;
myFile = null;
}
/**
* This is a reset-able stream, so return true.
* @return true
*/
public boolean markSupported(){
return myFile != null;
}
/**
* reset stream to beginning. The implementation creates a new
* stream.
* @throws IOException
*/
public void reset() throws IOException
{
if (! markSupported()){
throw new IOException("not resettable");
}
try{
close();
myInput = new BufferedInputStream(new FileInputStream(myFile));
}
catch (FileNotFoundException fnf){
System.err.println("error opening " + myFile.getName() + " " + fnf);
}
myBuffer = myBitCount = 0;
}
/**
* closes the input stream
*/
public void close()
{
try{
if (myInput != null) {
myInput.close();
}
}
catch (java.io.IOException ioe){
System.err.println("error closing bit stream " + ioe);
}
}
/**
* returns the number of bits requested as rightmost bits in
* returned value, returns -1 if not enough bits available to
* satisfy the request
*
* @param howManyBits is the number of bits to read and return
* @return the value read, only rightmost <code>howManyBits</code>
* are valid, returns -1 if not enough bits left
*/
public int read(int howManyBits) throws IOException
{
int retval = 0;
if (myInput == null){
return -1;
}
while (howManyBits > myBitCount){
retval |= ( myBuffer << (howManyBits - myBitCount) );
howManyBits -= myBitCount;
try{
if ( (myBuffer = myInput.read()) == -1) {
return -1;
}
}
catch (IOException ioe) {
throw new IOException("bitreading trouble "+ioe);
}
myBitCount = BITS_PER_BYTE;
}
if (howManyBits > 0){
retval |= myBuffer >> (myBitCount - howManyBits);
myBuffer &= bmask[myBitCount - howManyBits];
myBitCount -= howManyBits;
}
return retval;
}
/**
* Required by classes extending InputStream, returns
* the next byte from this stream as an int value.
* @return the next byte from this stream
*/
public int read() throws IOException {
return read(8);
}
}

View File

@ -0,0 +1,84 @@
package org.apache.poi.hwmf.record;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfBitmap16 {
final boolean isPartial;
int type;
int width;
int height;
int widthBytes;
int planes;
int bitsPixel;
public WmfBitmap16() {
this(false);
}
public WmfBitmap16(boolean isPartial) {
this.isPartial = isPartial;
}
public int init(LittleEndianInputStream leis) throws IOException {
// A 16-bit signed integer that defines the bitmap type.
type = leis.readShort();
// A 16-bit signed integer that defines the width of the bitmap in pixels.
width = leis.readShort();
// A 16-bit signed integer that defines the height of the bitmap in scan lines.
height = leis.readShort();
// A 16-bit signed integer that defines the number of bytes per scan line.
widthBytes = leis.readShort();
// An 8-bit unsigned integer that defines the number of color planes in the
// bitmap. The value of this field MUST be 0x01.
planes = leis.readUByte();
// An 8-bit unsigned integer that defines the number of adjacent color bits on
// each plane.
bitsPixel = leis.readUByte();
int size = 2*LittleEndianConsts.BYTE_SIZE+4*LittleEndianConsts.SHORT_SIZE;
if (isPartial) {
// Bits (4 bytes): This field MUST be ignored.
long skipSize = leis.skip(LittleEndianConsts.INT_SIZE);
assert(skipSize == LittleEndianConsts.INT_SIZE);
// Reserved (18 bytes): This field MUST be ignored.
skipSize = leis.skip(18);
assert(skipSize == 18);
size += 18+LittleEndianConsts.INT_SIZE;
}
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int size2 = 0;
byte buf[] = new byte[widthBytes];
for (int h=0; h<height; h++) {
leis.read(buf);
size2 += widthBytes;
BitInputStream bis = new BitInputStream(new ByteArrayInputStream(buf));
for (int w=0; w<width; w++) {
int bitsAtPixel = bis.read(bitsPixel);
// TODO: is bitsPixel a multiple of 3 (r,g,b)
// which colortable should be used for the various bit sizes???
}
}
int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;
assert (bytes == size2);
size += size2;
return size;
}
}

View File

@ -0,0 +1,424 @@
package org.apache.poi.hwmf.record;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
/**
* The DeviceIndependentBitmap Object defines an image in device-independent bitmap (DIB) format.
*/
public class WmfBitmapDib {
public static enum BitCount {
/**
* The image SHOULD be in either JPEG or PNG format. <6> Neither of these formats includes
* a color table, so this value specifies that no color table is present. See [JFIF] and [RFC2083]
* for more information concerning JPEG and PNG compression formats.
*/
BI_BITCOUNT_0(0x0000),
/**
* Each pixel in the bitmap is represented by a single bit. If the bit is clear, the pixel is displayed
* with the color of the first entry in the color table; if the bit is set, the pixel has the color of the
* second entry in the table.
*/
BI_BITCOUNT_1(0x0001),
/**
* Each pixel in the bitmap is represented by a 4-bit index into the color table, and each byte
* contains 2 pixels.
*/
BI_BITCOUNT_2(0x0004),
/**
* Each pixel in the bitmap is represented by an 8-bit index into the color table, and each byte
* contains 1 pixel.
*/
BI_BITCOUNT_3(0x0008),
/**
* Each pixel in the bitmap is represented by a 16-bit value.
* <br/>
* If the Compression field of the BitmapInfoHeader Object is BI_RGB, the Colors field of DIB
* is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of
* red, green, and blue are represented with 5 bits for each color component. The value for blue
* is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant
* bit is not used. The color table is used for optimizing colors on palette-based devices, and
* contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader
* Object.
* <br/>
* If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field
* contains three DWORD color masks that specify the red, green, and blue components,
* respectively, of each pixel. Each WORD in the bitmap array represents a single pixel.
* <br/>
* When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be
* contiguous and SHOULD NOT overlap the bits of another mask.
*/
BI_BITCOUNT_4(0x0010),
/**
* The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is
* NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green,
* and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on
* palette-based devices, and MUST contain the number of entries specified by the ColorUsed
* field of the BitmapInfoHeader Object.
*/
BI_BITCOUNT_5(0x0018),
/**
* The bitmap has a maximum of 2^24 colors.
* <br/>
* If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field
* of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of
* blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The
* Colors color table is used for optimizing colors used on palette-based devices, and MUST
* contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader
* Object.
* <br/>
* If the Compression field of the BitmapInfoHeader Object is set to BI_BITFIELDS, the Colors
* field contains three DWORD color masks that specify the red, green, and blue components,
* respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.
* <br/>
* When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be
* contiguous and should not overlap the bits of another mask. All the bits in the pixel do not
* need to be used.
*/
BI_BITCOUNT_6(0x0020);
int flag;
BitCount(int flag) {
this.flag = flag;
}
static BitCount valueOf(int flag) {
for (BitCount bc : values()) {
if (bc.flag == flag) return bc;
}
return null;
}
}
public static enum Compression {
/**
* The bitmap is in uncompressed red green blue (RGB) format that is not compressed
* and does not use color masks.
*/
BI_RGB(0x0000),
/**
* An RGB format that uses run-length encoding (RLE) compression for bitmaps
* with 8 bits per pixel. The compression uses a 2-byte format consisting of a count byte
* followed by a byte containing a color index.
*/
BI_RLE8(0x0001),
/**
* An RGB format that uses RLE compression for bitmaps with 4 bits per pixel. The
* compression uses a 2-byte format consisting of a count byte followed by two word-length
* color indexes.
*/
BI_RLE4(0x0002),
/**
* The bitmap is not compressed and the color table consists of three DWORD
* color masks that specify the red, green, and blue components, respectively, of each pixel.
* This is valid when used with 16 and 32-bits per pixel bitmaps.
*/
BI_BITFIELDS(0x0003),
/**
* The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in
* certain bitmap operations, such as JPEG pass-through. The application MUST query for the
* pass-through support, since not all devices support JPEG pass-through. Using non-RGB
* bitmaps MAY limit the portability of the metafile to other devices. For instance, display device
* contexts generally do not support this pass-through.
*/
BI_JPEG(0x0004),
/**
* The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be
* used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query
* for the pass-through support, because not all devices support JPEG/PNG pass-through. Using
* non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance,
* display device contexts generally do not support this pass-through.
*/
BI_PNG(0x0005),
/**
* The image is an uncompressed CMYK format.
*/
BI_CMYK(0x000B),
/**
* A CMYK format that uses RLE compression for bitmaps with 8 bits per pixel.
* The compression uses a 2-byte format consisting of a count byte followed by a byte containing
* a color index.
*/
BI_CMYKRLE8(0x000C),
/**
* A CMYK format that uses RLE compression for bitmaps with 4 bits per pixel.
* The compression uses a 2-byte format consisting of a count byte followed by two word-length
* color indexes.
*/
BI_CMYKRLE4(0x000D);
int flag;
Compression(int flag) {
this.flag = flag;
}
static Compression valueOf(int flag) {
for (Compression c : values()) {
if (c.flag == flag) return c;
}
return null;
}
}
int headerSize;
int headerWidth;
int headerHeight;
int headerPlanes;
BitCount headerBitCount;
Compression headerCompression;
long headerImageSize = -1;
int headerXPelsPerMeter = -1;
int headerYPelsPerMeter = -1;
long headerColorUsed = -1;
long headerColorImportant = -1;
Color colorTable[];
int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;
public int init(LittleEndianInputStream leis) throws IOException {
int size = 0;
size += readHeader(leis);
size += readColors(leis);
int size2;
switch (headerBitCount) {
default:
case BI_BITCOUNT_0:
throw new RuntimeException("JPG and PNG formats aren't supported yet.");
case BI_BITCOUNT_1:
case BI_BITCOUNT_2:
case BI_BITCOUNT_3:
size2 = readBitmapIndexed(leis);
break;
case BI_BITCOUNT_4:
case BI_BITCOUNT_5:
case BI_BITCOUNT_6:
size2 = readBitmapDirect(leis);
break;
}
assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == size2);
assert ( headerSize == 0x0C || headerImageSize == size2 );
size += size2;
return size;
}
protected int readHeader(LittleEndianInputStream leis) throws IOException {
int size = 0;
/**
* DIBHeaderInfo (variable): Either a BitmapCoreHeader Object or a
* BitmapInfoHeader Object that specifies information about the image.
*
* The first 32 bits of this field is the HeaderSize value.
* If it is 0x0000000C, then this is a BitmapCoreHeader; otherwise, this is a BitmapInfoHeader.
*/
headerSize = leis.readInt();
size += LittleEndianConsts.INT_SIZE;
// BitmapCoreHeader
// A 16-bit unsigned integer that defines the width of the DIB, in pixels.
headerWidth = leis.readUShort();
// A 16-bit unsigned integer that defines the height of the DIB, in pixels.
headerHeight = leis.readUShort();
// A 16-bit unsigned integer that defines the number of planes for the target
// device. This value MUST be 0x0001.
headerPlanes = leis.readUShort();
// A 16-bit unsigned integer that defines the format of each pixel, and the
// maximum number of colors in the DIB.
headerBitCount = BitCount.valueOf(leis.readUShort());
size += 4*LittleEndianConsts.SHORT_SIZE;
if (headerSize > 0x0C) {
// BitmapInfoHeader
// A 32-bit unsigned integer that defines the compression mode of the
// DIB.
// This value MUST NOT specify a compressed format if the DIB is a top-down bitmap,
// as indicated by the Height value.
headerCompression = Compression.valueOf((int)leis.readUInt());
// A 32-bit unsigned integer that defines the size, in bytes, of the image.
// If the Compression value is BI_RGB, this value SHOULD be zero and MUST be ignored.
// If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG
// or PNG image buffer, respectively.
headerImageSize = leis.readUInt();
// A 32-bit signed integer that defines the horizontal resolution,
// in pixels-per-meter, of the target device for the DIB.
headerXPelsPerMeter = leis.readInt();
// A 32-bit signed integer that defines the vertical resolution,
headerYPelsPerMeter = leis.readInt();
// A 32-bit unsigned integer that specifies the number of indexes in the
// color table used by the DIB
// in pixelsper-meter, of the target device for the DIB.
headerColorUsed = leis.readUInt();
// A 32-bit unsigned integer that defines the number of color indexes that are
// required for displaying the DIB. If this value is zero, all color indexes are required.
headerColorImportant = leis.readUInt();
size += 6*LittleEndianConsts.INT_SIZE;
}
return size;
}
protected int readColors(LittleEndianInputStream leis) throws IOException {
switch (headerBitCount) {
default:
case BI_BITCOUNT_0:
// no table
return 0;
case BI_BITCOUNT_1:
// 2 colors
return readRGBQuad(leis, 2);
case BI_BITCOUNT_2:
// 16 colors
return readRGBQuad(leis, 16);
case BI_BITCOUNT_3:
// 256 colors
return readRGBQuad(leis, 256);
case BI_BITCOUNT_5:
colorMaskRed=0xFF;
colorMaskGreen=0xFF;
colorMaskBlue=0xFF;
return 0;
case BI_BITCOUNT_4:
if (headerCompression == Compression.BI_RGB) {
colorMaskBlue = 0x1F;
colorMaskGreen = 0x1F<<5;
colorMaskRed = 0x1F<<10;
return 0;
} else {
assert(headerCompression == Compression.BI_BITFIELDS);
colorMaskBlue = leis.readInt();
colorMaskGreen = leis.readInt();
colorMaskRed = leis.readInt();
return 3*LittleEndianConsts.INT_SIZE;
}
case BI_BITCOUNT_6:
if (headerCompression == Compression.BI_RGB) {
colorMaskBlue = colorMaskGreen = colorMaskRed = 0xFF;
return 0;
} else {
assert(headerCompression == Compression.BI_BITFIELDS);
colorMaskBlue = leis.readInt();
colorMaskGreen = leis.readInt();
colorMaskRed = leis.readInt();
return 3*LittleEndianConsts.INT_SIZE;
}
}
}
protected int readRGBQuad(LittleEndianInputStream leis, int count) throws IOException {
int size = 0;
List<Color> colorList = new ArrayList<Color>();
for (int i=0; i<count; i++) {
int blue = leis.readUByte();
int green = leis.readUByte();
int red = leis.readUByte();
@SuppressWarnings("unused")
int reserved = leis.readUByte();
Color c = new Color(red, green, blue);
colorList.add(c);
size += 4 * LittleEndianConsts.BYTE_SIZE;
}
colorTable = colorList.toArray(new Color[colorList.size()]);
return size;
}
protected int readBitmapIndexed(LittleEndianInputStream leis) throws IOException {
assert(colorTable != null);
byte r[] = new byte[colorTable.length];
byte g[] = new byte[colorTable.length];
byte b[] = new byte[colorTable.length];
for (int i=0; i<colorTable.length; i++) {
r[i] = (byte)colorTable[i].getRed();
g[i] = (byte)colorTable[i].getGreen();
b[i] = (byte)colorTable[i].getBlue();
}
int bits = 32-Integer.numberOfLeadingZeros(colorTable.length);
IndexColorModel cm = new IndexColorModel(bits,colorTable.length,r,g,b);
BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_BYTE_INDEXED, cm);
WritableRaster wr = bi.getRaster();
int pixelCount = headerWidth*headerHeight;
int size = 0;
for (int pixel=0; pixel<pixelCount; size++) {
int v = leis.readUByte();
switch (headerBitCount) {
default:
throw new RuntimeException("invalid bitcount for indexed image");
case BI_BITCOUNT_1:
for (int j=0; j<8 && pixel<pixelCount; j++,pixel++) {
wr.setSample(pixel/headerWidth,pixel%headerWidth,0,(v>>(7-j))&1);
}
break;
case BI_BITCOUNT_2:
wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, (v>>4)&15);
pixel++;
if (pixel<pixelCount) {
wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v&15);
pixel++;
}
break;
case BI_BITCOUNT_3:
wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v);
pixel++;
break;
}
}
return size;
}
protected int readBitmapDirect(LittleEndianInputStream leis) throws IOException {
assert(colorTable == null);
BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_RGB);
WritableRaster wr = bi.getRaster();
int bitShiftRed=0,bitShiftGreen=0,bitShiftBlue=0;
if (headerCompression == Compression.BI_BITFIELDS) {
bitShiftGreen = 32-Integer.numberOfLeadingZeros(this.colorMaskBlue);
bitShiftRed = 32-Integer.numberOfLeadingZeros(this.colorMaskGreen);
}
int pixelCount = headerWidth*headerHeight;
int size = 0;
int rgb[] = new int[3];
for (int pixel=0; pixel<pixelCount; pixel++) {
int v;
switch (headerBitCount) {
default:
throw new RuntimeException("invalid bitcount for indexed image");
case BI_BITCOUNT_4:
v = leis.readUShort();
rgb[0] = (v & colorMaskRed) >> bitShiftRed;
rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;
rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;
size += LittleEndianConsts.SHORT_SIZE;
break;
case BI_BITCOUNT_5:
rgb[2] = leis.readUByte();
rgb[1] = leis.readUByte();
rgb[0] = leis.readUByte();
size += 3*LittleEndianConsts.BYTE_SIZE;
break;
case BI_BITCOUNT_6:
v = leis.readInt();
rgb[0] = (v & colorMaskRed) >> bitShiftRed;
rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;
rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;
size += LittleEndianConsts.INT_SIZE;
break;
}
wr.setPixel(pixel/headerWidth,pixel%headerWidth,rgb);
}
return size;
}
}

View File

@ -0,0 +1,30 @@
package org.apache.poi.hwmf.record;
import java.awt.Color;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfColorRef {
/**
* A 32-bit ColorRef Object that defines the color value.
* Red (1 byte): An 8-bit unsigned integer that defines the relative intensity of red.
* Green (1 byte): An 8-bit unsigned integer that defines the relative intensity of green.
* Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.
* Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.
*/
Color colorRef;
public int init(LittleEndianInputStream leis) throws IOException {
int red = leis.readUByte();
int green = leis.readUByte();
int blue = leis.readUByte();
@SuppressWarnings("unused")
int reserved = leis.readUByte();
colorRef = new Color(red, green, blue);
return 4*LittleEndianConsts.BYTE_SIZE;
}
}

View File

@ -0,0 +1,602 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfDraw {
/**
* The META_MOVETO record sets the output position in the playback device context to a specified
* point.
*/
public static class WmfMoveTo implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units.
*/
int y;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.moveTo;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_LINETO record draws a line from the drawing position that is defined in the playback
* device context up to, but not including, the specified point.
*/
public static class WmfLineTo implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical component of the drawing
* destination position, in logical units.
*/
int y;
/**
* A 16-bit signed integer that defines the horizontal component of the drawing
* destination position, in logical units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.lineTo;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_POLYGON record paints a polygon consisting of two or more vertices connected by
* straight lines. The polygon is outlined by using the pen and filled by using the brush and polygon fill
* mode that are defined in the playback device context.
*/
public static class WmfPolygon implements WmfRecord {
/**
* A 16-bit signed integer that defines the number of points in the array.
*/
int numberofPoints;
short xPoints[], yPoints[];
public WmfRecordType getRecordType() {
return WmfRecordType.polygon;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
numberofPoints = leis.readShort();
xPoints = new short[numberofPoints];
yPoints = new short[numberofPoints];
for (int i=0; i<numberofPoints; i++) {
// A 16-bit signed integer that defines the horizontal (x) coordinate of the point.
xPoints[i] = leis.readShort();
// A 16-bit signed integer that defines the vertical (y) coordinate of the point.
yPoints[i] = leis.readShort();
}
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;
}
}
/**
* The META_POLYLINE record draws a series of line segments by connecting the points in the
* specified array.
*/
public static class WmfPolyline extends WmfPolygon {
public WmfRecordType getRecordType() {
return WmfRecordType.polyline;
}
}
/**
* The META_ELLIPSE record draws an ellipse. The center of the ellipse is the center of the specified
* bounding rectangle. The ellipse is outlined by using the pen and is filled by using the brush; these
* are defined in the playback device context.
*/
public static class WmfEllipse implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the bounding rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the bounding rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.ellipse;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_FRAMEREGION record draws a border around a specified region using a specified brush.
*/
public static class WmfFrameRegion implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be framed.
*/
int region;
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get the
* Brush to use for filling the region.
*/
int brush;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* region frame.
*/
int height;
/**
* A 16-bit signed integer that defines the width, in logical units, of the
* region frame.
*/
int width;
public WmfRecordType getRecordType() {
return WmfRecordType.frameRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readUShort();
brush = leis.readUShort();
height = leis.readShort();
width = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_POLYPOLYGON record paints a series of closed polygons. Each polygon is outlined by
* using the pen and filled by using the brush and polygon fill mode; these are defined in the playback
* device context. The polygons drawn by this function can overlap.
*/
public static class WmfPolyPolygon implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the number of polygons in the object.
*/
int numberOfPolygons;
/**
* A NumberOfPolygons array of 16-bit unsigned integers that define the number of
* points for each polygon in the object.
*/
int pointsPerPolygon[];
/**
* An array of 16-bit unsigned integers that define the coordinates of the polygons.
*/
int xPoints[][];
/**
* An array of 16-bit unsigned integers that define the coordinates of the polygons.
*/
int yPoints[][];
public WmfRecordType getRecordType() {
return WmfRecordType.polyPolygon;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
// see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
numberOfPolygons = leis.readUShort();
pointsPerPolygon = new int[numberOfPolygons];
xPoints = new int[numberOfPolygons][];
yPoints = new int[numberOfPolygons][];
int size = LittleEndianConsts.SHORT_SIZE;
for (int i=0; i<numberOfPolygons; i++) {
pointsPerPolygon[i] = leis.readUShort();
size += LittleEndianConsts.SHORT_SIZE;
}
for (int i=0; i<numberOfPolygons; i++) {
xPoints[i] = new int[pointsPerPolygon[i]];
yPoints[i] = new int[pointsPerPolygon[i]];
for (int j=0; j<pointsPerPolygon[i]; j++) {
xPoints[i][j] = leis.readUShort();
yPoints[i][j] = leis.readUShort();
size += 2*LittleEndianConsts.SHORT_SIZE;
}
}
return size;
}
}
/**
* The META_RECTANGLE record paints a rectangle. The rectangle is outlined by using the pen and
* filled by using the brush that are defined in the playback device context.
*/
public static class WmfRectangle implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.frameRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_RECTANGLE record paints a rectangle. The rectangle is outlined by using the pen and
* filled by using the brush that are defined in the playback device context.
*/
public static class WmfSetPixel implements WmfRecord {
/**
* A ColorRef Object that defines the color value.
*/
WmfColorRef colorRef;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the point
* to be set.
*/
int y;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the point
* to be set.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.setPixel;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new WmfColorRef();
int size = colorRef.init(leis);
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE+size;
}
}
/**
* The META_ROUNDRECT record paints a rectangle with rounded corners. The rectangle is outlined
* using the pen and filled using the brush, as defined in the playback device context.
*/
public static class WmfRoundRect implements WmfRecord {
/**
* A 16-bit signed integer that defines the height, in logical coordinates, of the
* ellipse used to draw the rounded corners.
*/
int height;
/**
* A 16-bit signed integer that defines the width, in logical coordinates, of the
* ellipse used to draw the rounded corners.
*/
int width;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.roundRect;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
height = leis.readShort();
width = leis.readShort();
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 6*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_PIE record draws a pie-shaped wedge bounded by the intersection of an ellipse and two
* radials. The pie is outlined by using the pen and filled by using the brush that are defined in the
* playback device context.
*/
public static class WmfPie implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical
* coordinates, of the endpoint of the second radial.
*/
int yRadial2;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical
* coordinates, of the endpoint of the second radial.
*/
int xRadial2;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical
* coordinates, of the endpoint of the first radial.
*/
int yRadial1;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical
* coordinates, of the endpoint of the first radial.
*/
int xRadial1;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the bounding rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the bounding rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.pie;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yRadial2 = leis.readShort();
xRadial2 = leis.readShort();
yRadial1 = leis.readShort();
xRadial1 = leis.readShort();
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 8*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_ARC record draws an elliptical arc.
*/
public static class WmfArc implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the ending point of the radial line defining the ending point of the arc.
*/
int yEndArc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the ending point of the radial line defining the ending point of the arc.
*/
int xEndArc;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the ending point of the radial line defining the starting point of the arc.
*/
int yStartArc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the ending point of the radial line defining the starting point of the arc.
*/
int xStartArc;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the bounding rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the bounding rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.arc;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yEndArc = leis.readShort();
xEndArc = leis.readShort();
yStartArc = leis.readShort();
xStartArc = leis.readShort();
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 8*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_CHORD record draws a chord, which is defined by a region bounded by the intersection of
* an ellipse with a line segment. The chord is outlined using the pen and filled using the brush
* that are defined in the playback device context.
*/
public static class WmfChord implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical
* coordinates, of the endpoint of the second radial.
*/
int yRadial2;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical
* coordinates, of the endpoint of the second radial.
*/
int xRadial2;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical
* coordinates, of the endpoint of the first radial.
*/
int yRadial1;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical
* coordinates, of the endpoint of the first radial.
*/
int xRadial1;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int bottomRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the lower-right corner of the bounding rectangle.
*/
int rightRect;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the bounding rectangle.
*/
int topRect;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of
* the upper-left corner of the bounding rectangle.
*/
int leftRect;
public WmfRecordType getRecordType() {
return WmfRecordType.chord;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yRadial2 = leis.readShort();
xRadial2 = leis.readShort();
yRadial1 = leis.readShort();
xRadial1 = leis.readShort();
bottomRect = leis.readShort();
rightRect = leis.readShort();
topRect = leis.readShort();
leftRect = leis.readShort();
return 8*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SELECTOBJECT record specifies a graphics object for the playback device context. The
* new object replaces the previous object of the same type, unless if the previous object is a palette
* object. If the previous object is a palette object, then the META_SELECTPALETTE record must be
* used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not
* support replacing the palette object type.
*/
public static class WmfSelectObject implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to
* get the object to be selected.
*/
int objectIndex;
public WmfRecordType getRecordType() {
return WmfRecordType.selectObject;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
objectIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
}

View File

@ -0,0 +1,36 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfEscape implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the escape function. The
* value MUST be from the MetafileEscapes enumeration.
*/
int escapeFunction;
/**
* A 16-bit unsigned integer that specifies the size, in bytes, of the
* EscapeData field.
*/
int byteCount;
/**
* An array of bytes of size ByteCount.
*/
byte escapeData[];
public WmfRecordType getRecordType() {
return WmfRecordType.escape;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
escapeFunction = leis.readUShort();
byteCount = leis.readUShort();
escapeData = new byte[byteCount];
leis.read(escapeData);
return 2*LittleEndianConsts.SHORT_SIZE+byteCount;
}
}

View File

@ -0,0 +1,777 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfFill {
/**
* The META_FILLREGION record fills a region using a specified brush.
*/
public static class WmfFillRegion implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be filled.
*/
int region;
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get the
* brush to use for filling the region.
*/
int brush;
public WmfRecordType getRecordType() {
return WmfRecordType.fillRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readUShort();
brush = leis.readUShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_PAINTREGION record paints the specified region by using the brush that is
* defined in the playback device context.
*/
public static class WmfPaintRegion implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be painted.
*/
int region;
public WmfRecordType getRecordType() {
return WmfRecordType.paintRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_FLOODFILL record fills an area of the output surface with the brush that
* is defined in the playback device context.
*/
public static class WmfFloodFill implements WmfRecord {
/**
* A 32-bit ColorRef Object that defines the color value.
*/
WmfColorRef colorRef;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* point where filling is to start.
*/
int yStart;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* point where filling is to start.
*/
int xStart;
public WmfRecordType getRecordType() {
return WmfRecordType.floodFill;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new WmfColorRef();
int size = colorRef.init(leis);
yStart = leis.readShort();
xStart = leis.readShort();
return size+2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETPOLYFILLMODE record sets polygon fill mode in the playback device context for
* graphics operations that fill polygons.
*/
public static class WmfSetPolyfillMode implements WmfRecord {
/**
* A 16-bit unsigned integer that defines polygon fill mode.
* This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
*/
int polyFillMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setPolyFillMode;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
polyFillMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_EXTFLOODFILL record fills an area with the brush that is defined in
* the playback device context.
*/
public static class WmfExtFloodFill implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the fill operation to be performed. This
* member MUST be one of the values in the FloodFill Enumeration table:
*
* FLOODFILLBORDER = 0x0000:
* The fill area is bounded by the color specified by the Color member.
* This style is identical to the filling performed by the META_FLOODFILL record.
*
* FLOODFILLSURFACE = 0x0001:
* The fill area is bounded by the color that is specified by the Color member.
* Filling continues outward in all directions as long as the color is encountered.
* This style is useful for filling areas with multicolored boundaries.
*/
int mode;
/**
* A 32-bit ColorRef Object that defines the color value.
*/
WmfColorRef colorRef;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the point
* to be set.
*/
int y;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the point
* to be set.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.extFloodFill;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
mode = leis.readUShort();
colorRef = new WmfColorRef();
int size = colorRef.init(leis);
y = leis.readShort();
x = leis.readShort();
return size+3*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_INVERTREGION record draws a region in which the colors are inverted.
*/
public static class WmfInvertRegion implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be inverted.
*/
int region;
public WmfRecordType getRecordType() {
return WmfRecordType.invertRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_PATBLT record paints a specified rectangle using the brush that is defined in the playback
* device context. The brush color and the surface color or colors are combined using the specified
* raster operation.
*/
public static class WmfPatBlt implements WmfRecord {
/**
* A 32-bit unsigned integer that defines the raster operation code.
* This code MUST be one of the values in the Ternary Raster Operation enumeration table.
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit signed integer that defines the height, in logical units, of the rectangle.
*/
int height;
/**
* A 16-bit signed integer that defines the width, in logical units, of the rectangle.
*/
int width;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the rectangle to be filled.
*/
int yLeft;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the rectangle to be filled.
*/
int xLeft;
public WmfRecordType getRecordType() {
return WmfRecordType.patBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
height = leis.readShort();
width = leis.readShort();
yLeft = leis.readShort();
xLeft = leis.readShort();
return 6*LittleEndianConsts.SHORT_SIZE;
}
}
/**
*/
public static class WmfStretchBlt implements WmfRecord {
/**
* A 32-bit unsigned integer that defines how the source pixels, the current brush
* in the playback device context, and the destination pixels are to be combined to form the new
* image. This code MUST be one of the values in the Ternary Raster Operation Enumeration
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit signed integer that defines the height, in logical units, of the source rectangle.
*/
int srcHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the source rectangle.
*/
int srcWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner
* of the source rectangle.
*/
int ySrc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner
* of the source rectangle.
*/
int xSrc;
/**
* A 16-bit signed integer that defines the height, in logical units, of the destination rectangle.
*/
int destHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the destination rectangle.
*/
int destWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left
* corner of the destination rectangle.
*/
int yDest;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left
* corner of the destination rectangle.
*/
int xDest;
/**
* A variable-sized Bitmap16 Object that defines source image content.
* This object MUST be specified, even if the raster operation does not require a source.
*/
WmfBitmap16 target;
public WmfRecordType getRecordType() {
return WmfRecordType.stretchBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
int size = 0;
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
srcHeight = leis.readShort();
srcWidth = leis.readShort();
ySrc = leis.readShort();
xSrc = leis.readShort();
size = 6*LittleEndianConsts.SHORT_SIZE;
if (!hasBitmap) {
@SuppressWarnings("unused")
int reserved = leis.readShort();
size += LittleEndianConsts.SHORT_SIZE;
}
destHeight = leis.readShort();
destWidth = leis.readShort();
yDest = leis.readShort();
xDest = leis.readShort();
size += 4*LittleEndianConsts.SHORT_SIZE;
if (hasBitmap) {
target = new WmfBitmap16();
size += target.init(leis);
}
return size;
}
}
/**
* The META_STRETCHDIB record specifies the transfer of color data from a
* block of pixels in deviceindependent format according to a raster operation,
* with possible expansion or contraction.
* The source of the color data is a DIB, and the destination of the transfer is
* the current output region in the playback device context.
*/
public static class WmfStretchDib implements WmfRecord {
/**
* A 32-bit unsigned integer that defines how the source pixels, the current brush in
* the playback device context, and the destination pixels are to be combined to
* form the new image.
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit unsigned integer that defines whether the Colors field of the
* DIB contains explicit RGB values or indexes into a palette.
* This value MUST be in the ColorUsage Enumeration:
* DIB_RGB_COLORS = 0x0000,
* DIB_PAL_COLORS = 0x0001,
* DIB_PAL_INDICES = 0x0002
*/
int colorUsage;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* source rectangle.
*/
int srcHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the
* source rectangle.
*/
int srcWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* source rectangle.
*/
int ySrc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* source rectangle.
*/
int xSrc;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* destination rectangle.
*/
int destHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the
* destination rectangle.
*/
int destWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the destination rectangle.
*/
int yDst;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the destination rectangle.
*/
int xDst;
/**
* A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the
* source of the color data.
*/
WmfBitmapDib dib;
public WmfRecordType getRecordType() {
return WmfRecordType.stretchDib;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
colorUsage = leis.readUShort();
srcHeight = leis.readShort();
srcWidth = leis.readShort();
ySrc = leis.readShort();
xSrc = leis.readShort();
destHeight = leis.readShort();
destWidth = leis.readShort();
yDst = leis.readShort();
xDst = leis.readShort();
int size = 11*LittleEndianConsts.SHORT_SIZE;
dib = new WmfBitmapDib();
size += dib.init(leis);
return size;
}
}
public static class WmfBitBlt implements WmfRecord {
/**
* A 32-bit unsigned integer that defines how the source pixels, the current brush in the playback
* device context, and the destination pixels are to be combined to form the new image.
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner
of the source rectangle.
*/
int ySrc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner
of the source rectangle.
*/
int xSrc;
/**
* A 16-bit signed integer that defines the height, in logical units, of the source and
destination rectangles.
*/
int height;
/**
* A 16-bit signed integer that defines the width, in logical units, of the source and destination
rectangles.
*/
int width;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left
corner of the destination rectangle.
*/
int yDest;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left
corner of the destination rectangle.
*/
int xDest;
/**
* A variable-sized Bitmap16 Object that defines source image content.
* This object MUST be specified, even if the raster operation does not require a source.
*/
WmfBitmap16 target;
public WmfRecordType getRecordType() {
return WmfRecordType.bitBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
int size = 0;
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
ySrc = leis.readShort();
xSrc = leis.readShort();
size = 4*LittleEndianConsts.SHORT_SIZE;
if (!hasBitmap) {
@SuppressWarnings("unused")
int reserved = leis.readShort();
size += LittleEndianConsts.SHORT_SIZE;
}
height = leis.readShort();
width = leis.readShort();
yDest = leis.readShort();
xDest = leis.readShort();
size += 4*LittleEndianConsts.SHORT_SIZE;
if (hasBitmap) {
target = new WmfBitmap16();
size += target.init(leis);
}
return size;
}
}
/**
* The META_SETDIBTODEV record sets a block of pixels in the playback device context
* using deviceindependent color data.
* The source of the color data is a DIB
*/
public static class WmfSetDibToDev implements WmfRecord {
/**
* A 16-bit unsigned integer that defines whether the Colors field of the
* DIB contains explicit RGB values or indexes into a palette.
* This MUST be one of the values in the ColorUsage Enumeration:
* DIB_RGB_COLORS = 0x0000,
* DIB_PAL_COLORS = 0x0001,
* DIB_PAL_INDICES = 0x0002
*/
int colorUsage;
/**
* A 16-bit unsigned integer that defines the number of scan lines in the source.
*/
int scanCount;
/**
* A 16-bit unsigned integer that defines the starting scan line in the source.
*/
int startScan;
/**
* A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the
* source rectangle.
*/
int yDib;
/**
* A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the
* source rectangle.
*/
int xDib;
/**
* A 16-bit unsigned integer that defines the height, in logical units, of the
* source and destination rectangles.
*/
int height;
/**
* A 16-bit unsigned integer that defines the width, in logical units, of the
* source and destination rectangles.
*/
int width;
/**
* A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the destination rectangle.
*/
int yDest;
/**
* A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the destination rectangle.
*/
int xDest;
/**
* A variable-sized DeviceIndependentBitmap Object that is the source of the color data.
*/
WmfBitmapDib dib;
public WmfRecordType getRecordType() {
return WmfRecordType.setDibToDev;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorUsage = leis.readUShort();
scanCount = leis.readUShort();
startScan = leis.readUShort();
yDib = leis.readUShort();
xDib = leis.readUShort();
height = leis.readUShort();
width = leis.readUShort();
yDest = leis.readUShort();
xDest = leis.readUShort();
int size = 9*LittleEndianConsts.SHORT_SIZE;
dib = new WmfBitmapDib();
size += dib.init(leis);
return size;
}
}
public static class WmfDibBitBlt implements WmfRecord {
/**
* A 32-bit unsigned integer that defines how the source pixels, the current brush
* in the playback device context, and the destination pixels are to be combined to form the
* new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the source rectangle.
*/
int ySrc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the source rectangle.
*/
int xSrc;
/**
* A 16-bit signed integer that defines the height, in logical units, of the source and
* destination rectangles.
*/
int height;
/**
* A 16-bit signed integer that defines the width, in logical units, of the source and destination
* rectangles.
*/
int width;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left
* corner of the destination rectangle.
*/
int yDest;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left
* corner of the destination rectangle.
*/
int xDest;
/**
* A variable-sized DeviceIndependentBitmap Object that defines image content.
* This object MUST be specified, even if the raster operation does not require a source.
*/
WmfBitmapDib target;
public WmfRecordType getRecordType() {
return WmfRecordType.dibBitBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
int size = 0;
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
ySrc = leis.readShort();
xSrc = leis.readShort();
size = 4*LittleEndianConsts.SHORT_SIZE;
if (!hasBitmap) {
@SuppressWarnings("unused")
int reserved = leis.readShort();
size += LittleEndianConsts.SHORT_SIZE;
}
height = leis.readShort();
width = leis.readShort();
yDest = leis.readShort();
xDest = leis.readShort();
size += 4*LittleEndianConsts.SHORT_SIZE;
if (hasBitmap) {
target = new WmfBitmapDib();
size += target.init(leis);
}
return size;
}
}
public static class WmfDibStretchBlt implements WmfRecord {
/**
* A 32-bit unsigned integer that defines how the source pixels, the current brush
* in the playback device context, and the destination pixels are to be combined to form the
* new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.
*/
WmfTernaryRasterOp rasterOperation;
/**
* A 16-bit signed integer that defines the height, in logical units, of the source rectangle.
*/
int srcHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the source rectangle.
*/
int srcWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the source rectangle.
*/
int ySrc;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the source rectangle.
*/
int xSrc;
/**
* A 16-bit signed integer that defines the height, in logical units, of the
* destination rectangle.
*/
int destHeight;
/**
* A 16-bit signed integer that defines the width, in logical units, of the
* destination rectangle.
*/
int destWidth;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units,
* of the upper-left corner of the destination rectangle.
*/
int yDest;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units,
* of the upper-left corner of the destination rectangle.
*/
int xDest;
/**
* A variable-sized DeviceIndependentBitmap Object that defines image content.
* This object MUST be specified, even if the raster operation does not require a source.
*/
WmfBitmapDib target;
public WmfRecordType getRecordType() {
return WmfRecordType.dibStretchBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
int size = 0;
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = WmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
assert(rasterOpCode == rasterOperation.opCode);
srcHeight = leis.readShort();
srcWidth = leis.readShort();
ySrc = leis.readShort();
xSrc = leis.readShort();
size = 6*LittleEndianConsts.SHORT_SIZE;
if (!hasBitmap) {
@SuppressWarnings("unused")
int reserved = leis.readShort();
size += LittleEndianConsts.SHORT_SIZE;
}
destHeight = leis.readShort();
destWidth = leis.readShort();
yDest = leis.readShort();
xDest = leis.readShort();
size += 4*LittleEndianConsts.SHORT_SIZE;
if (hasBitmap) {
target = new WmfBitmapDib();
size += target.init(leis);
}
return size;
}
}
}

View File

@ -0,0 +1,57 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfHeader {
private int type;
private int recordSize;
private int version;
private int filesize;
private int numberOfObjects;
private long maxRecord;
private int numberOfMembers;
public WmfHeader(LittleEndianInputStream leis) throws IOException {
// Type (2 bytes): A 16-bit unsigned integer that defines the type of metafile
// MEMORYMETAFILE = 0x0001, DISKMETAFILE = 0x0002
type = leis.readUShort();
// HeaderSize (2 bytes): A 16-bit unsigned integer that defines the number
// of 16-bit words in the header.
recordSize = leis.readUShort();
int bytesLeft = recordSize*LittleEndianConsts.SHORT_SIZE;
// Version (2 bytes): A 16-bit unsigned integer that defines the metafile version.
// METAVERSION100 = 0x0100, METAVERSION300 = 0x0300
version = leis.readUShort();
bytesLeft -= LittleEndianConsts.SHORT_SIZE;
// SizeLow (2 bytes): A 16-bit unsigned integer that defines the low-order word
// of the number of 16-bit words in the entire metafile.
// SizeHigh (2 bytes): A 16-bit unsigned integer that defines the high-order word
// of the number of 16-bit words in the entire metafile.
filesize = leis.readInt();
bytesLeft -= LittleEndianConsts.INT_SIZE;
// NumberOfObjects (2 bytes): A 16-bit unsigned integer that specifies the number
// of graphics objects that are defined in the entire metafile. These objects include
// brushes, pens, and the other objects
numberOfObjects = leis.readUShort();
bytesLeft -= LittleEndianConsts.SHORT_SIZE;
// MaxRecord (4 bytes): A 32-bit unsigned integer that specifies the size of the
// largest record used in the metafile (in 16-bit elements).
maxRecord = leis.readUInt();
bytesLeft -= LittleEndianConsts.INT_SIZE;
// NumberOfMembers (2 bytes): A 16-bit unsigned integer that is not used.
// It SHOULD be 0x0000.
numberOfMembers = leis.readUShort();
bytesLeft -= LittleEndianConsts.SHORT_SIZE;
leis.skip(bytesLeft);
}
}

View File

@ -0,0 +1,481 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfMisc {
/**
* The META_SAVEDC record saves the playback device context for later retrieval.
*/
public static class WmfSaveDc implements WmfRecord {
public WmfRecordType getRecordType() { return WmfRecordType.saveDc; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
return 0;
}
}
/**
* The META_SETRELABS record is reserved and not supported.
*/
public static class WmfSetRelabs implements WmfRecord {
public WmfRecordType getRecordType() { return WmfRecordType.setRelabs; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
return 0;
}
}
/**
* The META_RESTOREDC record restores the playback device context from a previously saved device
* context.
*/
public static class WmfRestoreDc implements WmfRecord {
/**
* nSavedDC (2 bytes): A 16-bit signed integer that defines the saved state to be restored. If this
* member is positive, nSavedDC represents a specific instance of the state to be restored. If
* this member is negative, nSavedDC represents an instance relative to the current state.
*/
int nSavedDC;
public WmfRecordType getRecordType() {
return WmfRecordType.restoreDc;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
nSavedDC = leis.readShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETBKCOLOR record sets the background color in the playback device context to a
* specified color, or to the nearest physical color if the device cannot represent the specified color.
*/
public static class WmfSetBkColor implements WmfRecord {
WmfColorRef colorRef;
public WmfRecordType getRecordType() {
return WmfRecordType.setBkColor;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
WmfColorRef colorRef = new WmfColorRef();
return colorRef.init(leis);
}
}
/**
* The META_SETBKMODE record defines the background raster operation mix mode in the playback
* device context. The background mix mode is the mode for combining pens, text, hatched brushes,
* and interiors of filled objects with background colors on the output surface.
*/
public static class WmfSetBkMode implements WmfRecord {
/**
* A 16-bit unsigned integer that defines background mix mode.
* This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002
*/
int bkMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setBkMode;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
bkMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETLAYOUT record defines the layout orientation in the playback device context.
* The layout orientation determines the direction in which text and graphics are drawn
*/
public static class WmfSetLayout implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the layout of text and graphics.
* LAYOUT_LTR = 0x0000
* LAYOUT_RTL = 0x0001
* LAYOUT_BITMAPORIENTATIONPRESERVED = 0x0008
*/
int layout;
public WmfRecordType getRecordType() {
return WmfRecordType.setLayout;
}
@SuppressWarnings("unused")
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
layout = leis.readUShort();
// A 16-bit field that MUST be ignored.
int reserved = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETMAPMODE record defines the mapping mode in the playback device context.
* The mapping mode defines the unit of measure used to transform page-space units into
* device-space units, and also defines the orientation of the device's x and y axes.
*/
public static class WmfSetMapMode implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the mapping mode.
*
* The MapMode defines how logical units are mapped to physical units;
* that is, assuming that the origins in both the logical and physical coordinate systems
* are at the same point on the drawing surface, what is the physical coordinate (x',y')
* that corresponds to logical coordinate (x,y).
*
* For example, suppose the mapping mode is MM_TEXT. Given the following definition of that
* mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical
* coordinate (4,5) would map to physical coordinate (4,5) in pixels.
*
* Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous
* example. Given the following definition of that mapping mode, logical coordinate (4,-5)
* would map to physical coordinate (0.04,0.05) in inches.
*
* This MUST be one of the following:
*
* MM_TEXT (= 0x0001):
* Each logical unit is mapped to one device pixel.
* Positive x is to the right; positive y is down.
*
* MM_LOMETRIC (= 0x0002):
* Each logical unit is mapped to 0.1 millimeter.
* Positive x is to the right; positive y is up.
*
* MM_HIMETRIC (= 0x0003):
* Each logical unit is mapped to 0.01 millimeter.
* Positive x is to the right; positive y is up.
*
* MM_LOENGLISH (= 0x0004):
* Each logical unit is mapped to 0.01 inch.
* Positive x is to the right; positive y is up.
*
* MM_HIENGLISH (= 0x0005):
* Each logical unit is mapped to 0.001 inch.
* Positive x is to the right; positive y is up.
*
* MM_TWIPS (= 0x0006):
* Each logical unit is mapped to one twentieth (1/20) of a point.
* In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.
* This unit is also known as a "twip".
* Positive x is to the right; positive y is up.
*
* MM_ISOTROPIC (= 0x0007):
* Logical units are mapped to arbitrary device units with equally scaled axes;
* that is, one unit along the x-axis is equal to one unit along the y-axis.
* The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the
* orientation of the axes.
* The processing application SHOULD make adjustments as necessary to ensure the x and y
* units remain the same size. For example, when the window extent is set, the viewport
* SHOULD be adjusted to keep the units isotropic.
*
* MM_ANISOTROPIC (= 0x0008):
* Logical units are mapped to arbitrary units with arbitrarily scaled axes.
*/
int mapMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setMapMode;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
mapMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETMAPPERFLAGS record defines the algorithm that the font mapper uses when it maps
* logical fonts to physical fonts.
*/
public static class WmfSetMapperFlags implements WmfRecord {
/**
* A 32-bit unsigned integer that defines whether the font mapper should attempt to
* match a font's aspect ratio to the current device's aspect ratio. If bit 0 is
* set, the mapper selects only matching fonts.
*/
long mapperValues;
public WmfRecordType getRecordType() {
return WmfRecordType.setMapperFlags;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
mapperValues = leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
}
/**
* The META_SETROP2 record defines the foreground raster operation mix mode in the playback device
* context. The foreground mix mode is the mode for combining pens and interiors of filled objects with
* foreground colors on the output surface.
*/
public static class WmfSetRop2 implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the foreground binary raster
* operation mixing mode. This MUST be one of the values:
* R2_BLACK = 0x0001,
* R2_NOTMERGEPEN = 0x0002,
* R2_MASKNOTPEN = 0x0003,
* R2_NOTCOPYPEN = 0x0004,
* R2_MASKPENNOT = 0x0005,
* R2_NOT = 0x0006,
* R2_XORPEN = 0x0007,
* R2_NOTMASKPEN = 0x0008,
* R2_MASKPEN = 0x0009,
* R2_NOTXORPEN = 0x000A,
* R2_NOP = 0x000B,
* R2_MERGENOTPEN = 0x000C,
* R2_COPYPEN = 0x000D,
* R2_MERGEPENNOT = 0x000E,
* R2_MERGEPEN = 0x000F,
* R2_WHITE = 0x0010
*/
int drawMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setRop2;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
drawMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETSTRETCHBLTMODE record defines the bitmap stretching mode in the playback device
* context.
*/
public static class WmfSetStretchBltMode implements WmfRecord {
/**
* A 16-bit unsigned integer that defines bitmap stretching mode.
* This MUST be one of the values:
* BLACKONWHITE = 0x0001,
* WHITEONBLACK = 0x0002,
* COLORONCOLOR = 0x0003,
* HALFTONE = 0x0004
*/
int setStretchBltMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setStretchBltMode;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
setStretchBltMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a
* pattern specified by a DeviceIndependentBitmap (DIB) Object
*/
public static class WmfDibCreatePatternBrush implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the brush style. The legal values for this
* field are defined as follows: if the value is not BS_PATTERN, BS_DIBPATTERNPT MUST be
* assumed.
*/
public static enum BrushStyle {
/**
* A brush that paints a single, constant color, either solid or dithered.
*/
BS_SOLID(0x0000),
/**
* A brush that does nothing. Using a BS_NULL brush in a graphics operation
* MUST have the same effect as using no brush at all.
*/
BS_NULL(0x0001),
/**
* A brush that paints a predefined simple pattern, or "hatch", onto a solid background.
*/
BS_HATCHED(0x0002),
/**
* A brush that paints a pattern defined by a bitmap, which MAY be a Bitmap16
* Object or a DeviceIndependentBitmap (DIB) Object.
*/
BS_PATTERN(0x0003),
/**
* Not supported
*/
BS_INDEXED(0x0004),
/**
* A pattern brush specified by a DIB.
*/
BS_DIBPATTERN(0x0005),
/**
* A pattern brush specified by a DIB.
*/
BS_DIBPATTERNPT(0x0006),
/**
* Not supported
*/
BS_PATTERN8X8(0x0007),
/**
* Not supported
*/
BS_DIBPATTERN8X8(0x0008),
/**
* Not supported
*/
BS_MONOPATTERN(0x0009);
int flag;
BrushStyle(int flag) {
this.flag = flag;
}
static BrushStyle valueOf(int flag) {
for (BrushStyle bs : values()) {
if (bs.flag == flag) return bs;
}
return null;
}
}
BrushStyle style;
/**
* A 16-bit unsigned integer that defines whether the Colors field of a DIB
* Object contains explicit RGB values, or indexes into a palette.
*
* If the Style field specifies BS_PATTERN, a ColorUsage value of DIB_RGB_COLORS MUST be
* used regardless of the contents of this field.
*
* If the Style field specified anything but BS_PATTERN, this field MUST be one of the values:
* DIB_RGB_COLORS = 0x0000,
* DIB_PAL_COLORS = 0x0001,
* DIB_PAL_INDICES = 0x0002
*/
int colorUsage;
WmfBitmapDib patternDib;
WmfBitmap16 pattern16;
public WmfRecordType getRecordType() {
return WmfRecordType.dibCreatePatternBrush;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
style = BrushStyle.valueOf(leis.readUShort());
colorUsage = leis.readUShort();
int size = 2*LittleEndianConsts.SHORT_SIZE;
switch (style) {
case BS_SOLID:
case BS_NULL:
case BS_DIBPATTERN:
case BS_DIBPATTERNPT:
case BS_HATCHED:
patternDib = new WmfBitmapDib();
size += patternDib.init(leis);
break;
case BS_PATTERN:
pattern16 = new WmfBitmap16();
size += pattern16.init(leis);
break;
case BS_INDEXED:
case BS_DIBPATTERN8X8:
case BS_MONOPATTERN:
case BS_PATTERN8X8:
throw new RuntimeException("pattern not supported");
}
return size;
}
}
/**
* The META_DELETEOBJECT record deletes an object, including Bitmap16, Brush,
* DeviceIndependentBitmap, Font, Palette, Pen, and Region. After the object is deleted,
* its index in the WMF Object Table is no longer valid but is available to be reused.
*/
public static class WmfDeleteObject implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to
get the object to be deleted.
*/
int objectIndex;
public WmfRecordType getRecordType() { return WmfRecordType.deleteObject; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
objectIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
public static class WmfCreatePatternBrush implements WmfRecord {
WmfBitmap16 pattern;
public WmfRecordType getRecordType() { return WmfRecordType.createPatternBrush; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
pattern = new WmfBitmap16(true);
return pattern.init(leis);
}
}
public static class WmfCreatePenIndirect implements WmfRecord {
/**
* A 16-bit unsigned integer that specifies the pen style.
* The value MUST be defined from the PenStyle Enumeration table.
*
* PS_COSMETIC = 0x0000,
* PS_ENDCAP_ROUND = 0x0000,
* PS_JOIN_ROUND = 0x0000,
* PS_SOLID = 0x0000,
* PS_DASH = 0x0001,
* PS_DOT = 0x0002,
* PS_DASHDOT = 0x0003,
* PS_DASHDOTDOT = 0x0004,
* PS_NULL = 0x0005,
* PS_INSIDEFRAME = 0x0006,
* PS_USERSTYLE = 0x0007,
* PS_ALTERNATE = 0x0008,
* PS_ENDCAP_SQUARE = 0x0100,
* PS_ENDCAP_FLAT = 0x0200,
* PS_JOIN_BEVEL = 0x1000,
* PS_JOIN_MITER = 0x2000
*/
int penStyle;
/**
* A 32-bit PointS Object that specifies a point for the object dimensions.
* The xcoordinate is the pen width. The y-coordinate is ignored.
*/
int xWidth, yWidth;
/**
* A 32-bit ColorRef Object that specifies the pen color value.
*/
WmfColorRef colorRef;
public WmfRecordType getRecordType() { return WmfRecordType.createPatternBrush; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
penStyle = leis.readUShort();
xWidth = leis.readShort();
yWidth = leis.readShort();
colorRef = new WmfColorRef();
int size = 3*LittleEndianConsts.SHORT_SIZE;
size += colorRef.init(leis);
return size;
}
}
}

View File

@ -0,0 +1,146 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfPalette {
public static class PaletteEntry {
// 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.
int values, blue, green, red;
public int init(LittleEndianInputStream leis) throws IOException {
values = leis.readUByte();
blue = leis.readUByte();
green = leis.readUByte();
red = leis.readUByte();
return 4*LittleEndianConsts.BYTE_SIZE;
}
}
public static abstract class WmfPaletteParent implements WmfRecord {
/**
* Start (2 bytes): A 16-bit unsigned integer that defines the offset into the Palette Object when
* used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.
* When used with META_CREATEPALETTE, it MUST be 0x0300
*/
int start;
/**
* NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
* aPaletteEntries.
*/
int numberOfEntries;
PaletteEntry entries[];
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
start = leis.readUShort();
numberOfEntries = leis.readUShort();
int size = 2*LittleEndianConsts.SHORT_SIZE;
entries = new PaletteEntry[numberOfEntries];
for (int i=0; i<numberOfEntries; i++) {
entries[i] = new PaletteEntry();
size += entries[i].init(leis);
}
return size;
}
}
/**
* The META_CREATEPALETTE record creates a Palette Object
*/
public static class WmfCreatePalette extends WmfPaletteParent {
public WmfRecordType getRecordType() {
return WmfRecordType.createPalette;
}
}
/**
* The META_SETPALENTRIES record defines RGB color values in a range of entries in the logical
* palette that is defined in the playback device context.
*/
public static class WmfSetPaletteEntries extends WmfPaletteParent {
public WmfRecordType getRecordType() {
return WmfRecordType.setPalEntries;
}
}
/**
* The META_RESIZEPALETTE record redefines the size of the logical palette that is defined in the
* playback device context.
*/
public static class WmfResizePalette implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the number of entries in
* the logical palette.
*/
int numberOfEntries;
public WmfRecordType getRecordType() {
return WmfRecordType.resizePalette;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
numberOfEntries = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SELECTPALETTE record defines the current logical palette with a specified Palette Object.
*/
public static class WmfSelectPalette implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the Palette Object to be selected.
*/
int palette;
public WmfRecordType getRecordType() {
return WmfRecordType.selectPalette;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
palette = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_REALIZEPALETTE record maps entries from the logical palette that
* is defined in the playback device context to the system palette.
*/
public static class WmfRealizePalette implements WmfRecord {
public WmfRecordType getRecordType() { return WmfRecordType.realizePalette; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
return 0;
}
}
/**
* The META_ANIMATEPALETTE record redefines entries in the logical palette that
* is defined in the playback device context with the specified Palette object
*
* The logical palette that is specified by the Palette object in this record is the
* source of the palette changes, and the logical palette that is currently selected
* into the playback device context is the destination. Entries in the destination
* palette with the PC_RESERVED PaletteEntryFlag set SHOULD be modified by this record,
* and entries with that flag clear SHOULD NOT be modified.
* If none of the entries in the destination palette have the PC_RESERVED flag set, then
* this record SHOULD have no effect.
*/
public static class WmfAnimatePalette extends WmfPaletteParent {
public WmfRecordType getRecordType() {
return WmfRecordType.animatePalette;
}
}
}

View File

@ -0,0 +1,60 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfPlaceableHeader {
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
protected WmfPlaceableHeader(LittleEndianInputStream leis) throws IOException {
/*
* HWmf (2 bytes): The resource handle to the metafile, when the metafile is in memory. When
* the metafile is on disk, this field MUST contain 0x0000. This attribute of the metafile is
* specified in the Type field of the META_HEADER record.
*/
leis.readShort(); // ignore
/*
* BoundingBox (8 bytes): The destination rectangle, measured in logical units, for displaying
* the metafile. The size of a logical unit is specified by the Inch field.
*/
int x1 = leis.readShort();
int y1 = leis.readShort();
int x2 = leis.readShort();
int y2 = leis.readShort();
/*
* Inch (2 bytes): The number of logical units per inch used to represent the image.
* This value can be used to scale an image.
* By convention, an image is considered to be recorded at 1440 logical units (twips) per inch.
* Thus, a value of 720 specifies that the image SHOULD be rendered at twice its normal size,
* and a value of 2880 specifies that the image SHOULD be rendered at half its normal size.
*/
int inch = leis.readShort();
/*
* Reserved (4 bytes): A field that is not used and MUST be set to 0x00000000.
*/
leis.readInt();
/*
* Checksum (2 bytes): A checksum for the previous 10 16-bit values in the header.
* This value can be used to determine whether the metafile has become corrupted.
*/
leis.readShort();
}
public static WmfPlaceableHeader readHeader(LittleEndianInputStream leis) throws IOException {
leis.mark(LittleEndianConsts.INT_SIZE);
int magic = leis.readInt();
if (magic == WMF_HEADER_MAGIC) {
return new WmfPlaceableHeader(leis);
} else {
leis.reset();
return null;
}
}
}

View File

@ -0,0 +1,18 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianInputStream;
public interface WmfRecord {
WmfRecordType getRecordType();
/**
* Init record from stream
*
* @param leis the little endian input stream
* @return count of processed bytes
* @throws IOException
*/
int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;
}

View File

@ -0,0 +1,89 @@
package org.apache.poi.hwmf.record;
public enum WmfRecordType {
eof(0x0000, null),
realizePalette(0x0035, WmfPalette.WmfRealizePalette.class),
setPalEntries(0x0037, WmfPalette.WmfSetPaletteEntries.class),
setBkMode(0x0102, WmfMisc.WmfSetBkMode.class),
setMapMode(0x0103, WmfMisc.WmfSetMapMode.class),
setRop2(0x0104, WmfMisc.WmfSetRop2.class),
setRelabs(0x0105, WmfMisc.WmfSetRelabs.class),
setPolyFillMode(0x0106, WmfFill.WmfSetPolyfillMode.class),
setStretchBltMode(0x0107, WmfMisc.WmfSetStretchBltMode.class),
setTextCharExtra(0x0108, WmfText.WmfSetTextCharExtra.class),
restoreDc(0x0127, WmfMisc.WmfRestoreDc.class),
resizePalette(0x0139, WmfPalette.WmfResizePalette.class),
dibCreatePatternBrush(0x0142, WmfMisc.WmfDibCreatePatternBrush.class),
setLayout(0x0149, WmfMisc.WmfSetLayout.class),
setBkColor(0x0201, WmfMisc.WmfSetBkColor.class),
setTextColor(0x0209, WmfText.WmfSetTextColor.class),
offsetViewportOrg(0x0211, WmfWindowing.WmfOffsetViewportOrg.class),
lineTo(0x0213, WmfDraw.WmfLineTo.class),
moveTo(0x0214, WmfDraw.WmfMoveTo.class),
offsetClipRgn(0x0220, WmfWindowing.WmfOffsetClipRgn.class),
fillRegion(0x0228, WmfFill.WmfFillRegion.class),
setMapperFlags(0x0231, WmfMisc.WmfSetMapperFlags.class),
selectPalette(0x0234, WmfPalette.WmfSelectPalette.class),
polygon(0x0324, WmfDraw.WmfPolygon.class),
polyline(0x0325, WmfDraw.WmfPolyline.class),
setTextJustification(0x020a, WmfText.WmfSetTextJustification.class),
setWindowOrg(0x020b, WmfWindowing.WmfSetWindowOrg.class),
setWindowExt(0x020c, WmfWindowing.WmfSetWindowExt.class),
setViewportOrg(0x020d, WmfWindowing.WmfSetViewportOrg.class),
setViewportExt(0x020e, WmfWindowing.WmfSetViewportExt.class),
offsetWindowOrg(0x020f, WmfWindowing.WmfOffsetWindowOrg.class),
scaleWindowExt(0x0410, WmfWindowing.WmfScaleWindowExt.class),
scaleViewportExt(0x0412, WmfWindowing.WmfScaleViewportExt.class),
excludeClipRect(0x0415, WmfWindowing.WmfExcludeClipRect.class),
intersectClipRect(0x0416, WmfWindowing.WmfIntersectClipRect.class),
ellipse(0x0418, WmfDraw.WmfEllipse.class),
floodFill(0x0419, WmfFill.WmfFloodFill.class),
frameRegion(0x0429, WmfDraw.WmfFrameRegion.class),
animatePalette(0x0436, WmfPalette.WmfAnimatePalette.class),
textOut(0x0521, WmfText.WmfTextOut.class),
polyPolygon(0x0538, WmfDraw.WmfPolyPolygon.class),
extFloodFill(0x0548, WmfFill.WmfExtFloodFill.class),
rectangle(0x041b, WmfDraw.WmfRectangle.class),
setPixel(0x041f, WmfDraw.WmfSetPixel.class),
roundRect(0x061c, WmfDraw.WmfRoundRect.class),
patBlt(0x061d, WmfFill.WmfPatBlt.class),
saveDc(0x001e, WmfMisc.WmfSaveDc.class),
pie(0x081a, WmfDraw.WmfPie.class),
stretchBlt(0x0b23, WmfFill.WmfStretchBlt.class),
escape(0x0626, WmfEscape.class),
invertRegion(0x012a, WmfFill.WmfInvertRegion.class),
paintRegion(0x012b, WmfFill.WmfPaintRegion.class),
selectClipRegion(0x012c, WmfWindowing.WmfSelectClipRegion.class),
selectObject(0x012d, WmfDraw.WmfSelectObject.class),
setTextAlign(0x012e, WmfText.WmfSetTextAlign.class),
arc(0x0817, WmfDraw.WmfArc.class),
chord(0x0830, WmfDraw.WmfChord.class),
bitBlt(0x0922, WmfFill.WmfBitBlt.class),
extTextOut(0x0a32, WmfText.WmfExtTextOut.class),
setDibToDev(0x0d33, WmfFill.WmfSetDibToDev.class),
dibBitBlt(0x0940, WmfFill.WmfDibBitBlt.class),
dibStretchBlt(0x0b41, WmfFill.WmfDibStretchBlt.class),
stretchDib(0x0f43, WmfFill.WmfStretchDib.class),
deleteObject(0x01f0, WmfMisc.WmfDeleteObject.class),
createPalette(0x00f7, WmfPalette.WmfCreatePalette.class),
createPatternBrush(0x01f9, WmfMisc.WmfCreatePatternBrush.class),
createPenIndirect(0x02fa, WmfMisc.WmfCreatePenIndirect.class),
createFontIndirect(0x02fb, null),
createBrushIndirect(0x02fc, null),
createRegion(0x06ff, null);
public int id;
public Class<? extends WmfRecord> clazz;
WmfRecordType(int id, Class<? extends WmfRecord> clazz) {
this.id = id;
this.clazz = clazz;
}
public static WmfRecordType getById(int id) {
for (WmfRecordType wrt : values()) {
if (wrt.id == id) return wrt;
}
return null;
}
}

View File

@ -0,0 +1,319 @@
package org.apache.poi.hwmf.record;
public enum WmfTernaryRasterOp {
BLACKNESS(0x0000,0x0042,"0"),
DPSOON(0x0001,0x0289,"DPSoon"),
DPSONA(0x0002,0x0C89,"DPSona"),
PSON(0x0003,0x00AA,"PSon"),
SDPONA(0x0004,0x0C88,"SDPona"),
DPON(0x0005,0x00A9,"DPon"),
PDSXNON(0x0006,0x0865,"PDSxnon"),
PDSAON(0x0007,0x02C5,"PDSaon"),
SDPNAA(0x0008,0x0F08,"SDPnaa"),
PDSXON(0x0009,0x0245,"PDSxon"),
DPNA(0x000A,0x0329,"DPna"),
PSDNAON(0x000B,0x0B2A,"PSDnaon"),
SPNA(0x000C,0x0324,"SPna"),
PDSNAON(0x000D,0x0B25,"PDSnaon"),
PDSONON(0x000E,0x08A5,"PDSonon"),
PN(0x000F,0x0001,"Pn"),
PDSONA(0x0010,0x0C85,"PDSona"),
NOTSRCERASE(0x0011,0x00A6,"DSon"),
SDPXNON(0x0012,0x0868,"SDPxnon"),
SDPAON(0x0013,0x02C8,"SDPaon"),
DPSXNON(0x0014,0x0869,"DPSxnon"),
DPSAON(0x0015,0x02C9,"DPSaon"),
PSDPSANAXX(0x0016,0x5CCA,"PSDPSanaxx"),
SSPXDSXAXN(0x0017,0x1D54,"SSPxDSxaxn"),
SPXPDXA(0x0018,0x0D59,"SPxPDxa"),
SDPSANAXN(0x0019,0x1CC8,"SDPSanaxn"),
PDSPAOX(0x001A,0x06C5,"PDSPaox"),
SDPSXAXN(0x001B,0x0768,"SDPSxaxn"),
PSDPAOX(0x001C,0x06CA,"PSDPaox"),
DSPDXAXN(0x001D,0x0766,"DSPDxaxn"),
PDSOX(0x001E,0x01A5,"PDSox"),
PDSOAN(0x001F,0x0385,"PDSoan"),
DPSNAA(0x0020,0x0F09,"DPSnaa"),
SDPXON(0x0021,0x0248,"SDPxon"),
DSNA(0x0022,0x0326,"DSna"),
SPDNAON(0x0023,0x0B24,"SPDnaon"),
SPXDSXA(0x0024,0x0D55,"SPxDSxa"),
PDSPANAXN(0x0025,0x1CC5,"PDSPanaxn"),
SDPSAOX(0x0026,0x06C8,"SDPSaox"),
SDPSXNOX(0x0027,0x1868,"SDPSxnox"),
DPSXA(0x0028,0x0369,"DPSxa"),
PSDPSAOXXN(0x0029,0x16CA,"PSDPSaoxxn"),
DPSANA(0x002A,0x0CC9,"DPSana"),
SSPXPDXAXN(0x002B,0x1D58,"SSPxPDxaxn"),
SPDSOAX(0x002C,0x0784,"SPDSoax"),
PSDNOX(0x002D,0x060A,"PSDnox"),
PSDPXOX(0x002E,0x064A,"PSDPxox"),
PSDNOAN(0x002F,0x0E2A,"PSDnoan"),
PSNA(0x0030,0x032A,"PSna"),
SDPNAON(0x0031,0x0B28,"SDPnaon"),
SDPSOOX(0x0032,0x0688,"SDPSoox"),
NOTSRCCOPY(0x0033,0x0008,"Sn"),
SPDSAOX(0x0034,0x06C4,"SPDSaox"),
SPDSXNOX(0x0035,0x1864,"SPDSxnox"),
SDPOX(0x0036,0x01A8,"SDPox"),
SDPOAN(0x0037,0x0388,"SDPoan"),
PSDPOAX(0x0038,0x078A,"PSDPoax"),
SPDNOX(0x0390,0x604,"SPDnox"),
SPDSXOX(0x003A,0x0644,"SPDSxox"),
SPDNOAN(0x003B,0x0E24,"SPDnoan"),
PSX(0x003C,0x004A,"PSx"),
SPDSONOX(0x003D,0x18A4,"SPDSonox"),
SPDSNAOX(0x003E,0x1B24,"SPDSnaox"),
PSAN(0x003F,0x00EA,"PSan"),
PSDNAA(0x0040,0x0F0A,"PSDnaa"),
DPSXON(0x0041,0x0249,"DPSxon"),
SDXPDXA(0x0042,0x0D5D,"SDxPDxa"),
SPDSANAXN(0x0043,0x1CC4,"SPDSanaxn"),
SRCERASE(0x0044,0x0328,"SDna"),
DPSNAON(0x0045,0x0B29,"DPSnaon"),
DSPDAOX(0x0046,0x06C6,"DSPDaox"),
PSDPXAXN(0x0047,0x076A,"PSDPxaxn"),
SDPXA(0x0048,0x0368,"SDPxa"),
PDSPDAOXXN(0x0049,0x16C5,"PDSPDaoxxn"),
DPSDOAX(0x004A,0x0789,"DPSDoax"),
PDSNOX(0x004B,0x0605,"PDSnox"),
SDPANA(0x004C,0x0CC8,"SDPana"),
SSPXDSXOXN(0x004D,0x1954,"SSPxDSxoxn"),
PDSPXOX(0x004E,0x0645,"PDSPxox"),
PDSNOAN(0x004F,0x0E25,"PDSnoan"),
PDNA(0x0050,0x0325,"PDna"),
DSPNAON(0x0051,0x0B26,"DSPnaon"),
DPSDAOX(0x0052,0x06C9,"DPSDaox"),
SPDSXAXN(0x0053,0x0764,"SPDSxaxn"),
DPSONON(0x0054,0x08A9,"DPSonon"),
DSTINVERT(0x0055,0x0009,"Dn"),
DPSOX(0x0056,0x01A9,"DPSox"),
DPSOAN(0x0005,0x70389,"DPSoan"),
PDSPOAX(0x0058,0x0785,"PDSPoax"),
DPSNOX(0x0059,0x0609,"DPSnox"),
PATINVERT(0x005A,0x0049,"DPx"),
DPSDONOX(0x005B,0x18A9,"DPSDonox"),
DPSDXOX(0x005C,0x0649,"DPSDxox"),
DPSNOAN(0x005D,0x0E29,"DPSnoan"),
DPSDNAOX(0x005E,0x1B29,"DPSDnaox"),
DPAN(0x005F,0x00E9,"DPan"),
PDSXA(0x0060,0x0365,"PDSxa"),
DSPDSAOXXN(0x0061,0x16C6,"DSPDSaoxxn"),
DSPDOAX(0x0062,0x0786,"DSPDoax"),
SDPNOX(0x0063,0x0608,"SDPnox"),
SDPSOAX(0x0064,0x0788,"SDPSoax"),
DSPNOX(0x0065,0x0606,"DSPnox"),
SRCINVERT(0x0066,0x0046,"DSx"),
SDPSONOX(0x0067,0x18A8,"SDPSonox"),
DSPDSONOXXN(0x0068,0x58A6,"DSPDSonoxxn"),
PDSXXN(0x0069,0x0145,"PDSxxn"),
DPSAX(0x006A,0x01E9,"DPSax"),
PSDPSOAXXN(0x006B,0x178A,"PSDPSoaxxn"),
SDPAX(0x006C,0x01E8,"SDPax"),
PDSPDOAXXN(0x006D,0x1785,"PDSPDoaxxn"),
SDPSNOAX(0x006E,0x1E28,"SDPSnoax"),
// PDXNAN(0x006F,0x0C65,"PDXnan"), // invalid combo
PDSANA(0x0070,0x0CC5,"PDSana"),
SSDXPDXAXN(0x0071,0x1D5C,"SSDxPDxaxn"),
SDPSXOX(0x0072,0x0648,"SDPSxox"),
SDPNOAN(0x0073,0x0E28,"SDPnoan"),
DSPDXOX(0x0074,0x0646,"DSPDxox"),
DSPNOAN(0x0075,0x0E26,"DSPnoan"),
SDPSNAOX(0x0076,0x1B28,"SDPSnaox"),
DSAN(0x0077,0x00E6,"DSan"),
PDSAX(0x0078,0x01E5,"PDSax"),
DSPDSOAXXN(0x0079,0x1786,"DSPDSoaxxn"),
DPSDNOAX(0x007A,0x1E29,"DPSDnoax"),
SDPXNAN(0x007B,0x0C68,"SDPxnan"),
SPDSNOAX(0x007C,0x1E24,"SPDSnoax"),
DPSXNAN(0x007D,0x0C69,"DPSxnan"),
SPXDSXO(0x007E,0x0955,"SPxDSxo"),
DPSAAN(0x007F,0x03C9,"DPSaan"),
DPSAA(0x0080,0x03E9,"DPSaa"),
SPXDSXON(0x0081,0x0975,"SPxDSxon"),
DPSXNA(0x0082,0x0C49,"DPSxna"),
SPDSNOAXN(0x0083,0x1E04,"SPDSnoaxn"),
SDPXNA(0x0084,0x0C48,"SDPxna"),
PDSPNOAXN(0x0085,0x1E05,"PDSPnoaxn"),
DSPDSOAXX(0x0086,0x17A6,"DSPDSoaxx"),
PDSAXN(0x0087,0x01C5,"PDSaxn"),
SRCAND(0x0088,0x00C6,"DSa"),
SDPSNAOXN(0x0089,0x1B08,"SDPSnaoxn"),
DSPNOA(0x008A,0x0E06,"DSPnoa"),
DSPDXOXN(0x008B,0x0666,"DSPDxoxn"),
SDPNOA(0x008C,0x0E08,"SDPnoa"),
SDPSXOXN(0x008D,0x0668,"SDPSxoxn"),
SSDXPDXAX(0x008E,0x1D7C,"SSDxPDxax"),
PDSANAN(0x008F,0x0CE5,"PDSanan"),
PDSXNA(0x0090,0x0C45,"PDSxna"),
SDPSNOAXN(0x0091,0x1E08,"SDPSnoaxn"),
DPSDPOAXX(0x0092,0x17A9,"DPSDPoaxx"),
SPDAXN(0x0093,0x01C4,"SPDaxn"),
PSDPSOAXX(0x0094,0x17AA,"PSDPSoaxx"),
DPSAXN(0x0095,0x01C9,"DPSaxn"),
DPSXX(0x0096,0x0169,"DPSxx"),
PSDPSONOXX(0x0097,0x588A,"PSDPSonoxx"),
SDPSONOXN(0x0098,0x1888,"SDPSonoxn"),
DSXN(0x0099,0x0066,"DSxn"),
DPSNAX(0x009A,0x0709,"DPSnax"),
SDPSOAXN(0x009B,0x07A8,"SDPSoaxn"),
SPDNAX(0x009C,0x0704,"SPDnax"),
DSPDOAXN(0x009D,0x07A6,"DSPDoaxn"),
DSPDSAOXX(0x009E,0x16E6,"DSPDSaoxx"),
PDSXAN(0x009F,0x0345,"PDSxan"),
DPA(0x00A0,0x00C9,"DPa"),
PDSPNAOXN(0x00A1,0x1B05,"PDSPnaoxn"),
DPSNOA(0x00A2,0x0E09,"DPSnoa"),
DPSDXOXN(0x00A3,0x0669,"DPSDxoxn"),
PDSPONOXN(0x00A4,0x1885,"PDSPonoxn"),
PDXN(0x00A5,0x0065,"PDxn"),
DSPNAX(0x00A6,0x0706,"DSPnax"),
PDSPOAXN(0x00A7,0x07A5,"PDSPoaxn"),
DPSOA(0x00A8,0x03A9,"DPSoa"),
DPSOXN(0x00A9,0x0189,"DPSoxn"),
D(0x00AA,0x0029,"D"),
DPSONO(0x00AB,0x0889,"DPSono"),
SPDSXAX(0x00AC,0x0744,"SPDSxax"),
DPSDAOXN(0x00AD,0x06E9,"DPSDaoxn"),
DSPNAO(0x00AE,0x0B06,"DSPnao"),
DPNO(0x00AF,0x0229,"DPno"),
PDSNOA(0x00B0,0x0E05,"PDSnoa"),
PDSPXOXN(0x00B1,0x0665,"PDSPxoxn"),
SSPXDSXOX(0x00B2,0x1974,"SSPxDSxox"),
SDPANAN(0x00B3,0x0CE8,"SDPanan"),
PSDNAX(0x00B4,0x070A,"PSDnax"),
DPSDOAXN(0x00B5,0x07A9,"DPSDoaxn"),
DPSDPAOXX(0x00B6,0x16E9,"DPSDPaoxx"),
SDPXAN(0x00B7,0x0348,"SDPxan"),
PSDPXAX(0x00B8,0x074A,"PSDPxax"),
DSPDAOXN(0x00B9,0x06E6,"DSPDaoxn"),
DPSNAO(0x00BA,0x0B09,"DPSnao"),
MERGEPAINT(0x00BB,0x0226,"DSno"),
SPDSANAX(0x00BC,0x1CE4,"SPDSanax"),
SDXPDXAN(0x00BD,0x0D7D,"SDxPDxan"),
DPSXO(0x00BE,0x0269,"DPSxo"),
DPSANO(0x00BF,0x08C9,"DPSano"),
MERGECOPY(0x00C0,0x00CA,"PSa"),
SPDSNAOXN(0x00C1,0x1B04,"SPDSnaoxn"),
SPDSONOXN(0x00C2,0x1884,"SPDSonoxn"),
PSXN(0x00C3,0x006A,"PSxn"),
SPDNOA(0x00C4,0x0E04,"SPDnoa"),
SPDSXOXN(0x00C5,0x0664,"SPDSxoxn"),
SDPNAX(0x00C6,0x0708,"SDPnax"),
PSDPOAXN(0x00C7,0x07AA,"PSDPoaxn"),
SDPOA(0x00C8,0x03A8,"SDPoa"),
SPDOXN(0x00C9,0x0184,"SPDoxn"),
DPSDXAX(0x00CA,0x0749,"DPSDxax"),
SPDSAOXN(0x00CB,0x06E4,"SPDSaoxn"),
SRCCOPY(0x00CC,0x0020,"S"),
SDPONO(0x00CD,0x0888,"SDPono"),
SDPNAO(0x00CE,0x0B08,"SDPnao"),
SPNO(0x00CF,0x0224,"SPno"),
PSDNOA(0x00D0,0x0E0A,"PSDnoa"),
PSDPXOXN(0x00D1,0x066A,"PSDPxoxn"),
PDSNAX(0x00D2,0x0705,"PDSnax"),
SPDSOAXN(0x00D3,0x07A4,"SPDSoaxn"),
SSPXPDXAX(0x00D4,0x1D78,"SSPxPDxax"),
DPSANAN(0x00D5,0x0CE9,"DPSanan"),
PSDPSAOXX(0x00D6,0x16EA,"PSDPSaoxx"),
DPSXAN(0x00D7,0x0349,"DPSxan"),
PDSPXAX(0x00D8,0x0745,"PDSPxax"),
SDPSAOXN(0x00D9,0x06E8,"SDPSaoxn"),
DPSDANAX(0x00DA,0x1CE9,"DPSDanax"),
SPXDSXAN(0x00DB,0x0D75,"SPxDSxan"),
SPDNAO(0x00DC,0x0B04,"SPDnao"),
SDNO(0x00DD,0x0228,"SDno"),
SDPXO(0x00DE,0x0268,"SDPxo"),
SDPANO(0x00DF,0x08C8,"SDPano"),
PDSOA(0x00E0,0x03A5,"PDSoa"),
PDSOXN(0x00E1,0x0185,"PDSoxn"),
DSPDXAX(0x00E2,0x0746,"DSPDxax"),
PSDPAOXN(0x00E3,0x06EA,"PSDPaoxn"),
SDPSXAX(0x00E4,0x0748,"SDPSxax"),
PDSPAOXN(0x00E5,0x06E5,"PDSPaoxn"),
SDPSANAX(0x00E6,0x1CE8,"SDPSanax"),
SPXPDXAN(0x00E7,0x0D79,"SPxPDxan"),
SSPXDSXAX(0x00E8,0x1D74,"SSPxDSxax"),
DSPDSANAXXN(0x00E9,0x5CE6,"DSPDSanaxxn"),
DPSAO(0x00EA,0x02E9,"DPSao"),
DPSXNO(0x00EB,0x0849,"DPSxno"),
SDPAO(0x00EC,0x02E8,"SDPao"),
SDPXNO(0x00ED,0x0848,"SDPxno"),
SRCPAINT(0x00EE,0x0086,"DSo"),
SDPNOO(0x00EF,0x0A08,"SDPnoo"),
PATCOPY(0x00F0,0x0021,"P"),
PDSONO(0x00F1,0x0885,"PDSono"),
PDSNAO(0x00F2,0x0B05,"PDSnao"),
PSNO(0x00F3,0x022A,"PSno"),
PSDNAO(0x00F4,0x0B0A,"PSDnao"),
PDNO(0x00F5,0x0225,"PDno"),
PDSXO(0x00F6,0x0265,"PDSxo"),
PDSANO(0x00F7,0x08C5,"PDSano"),
PDSAO(0x00F8,0x02E5,"PDSao"),
PDSXNO(0x00F9,0x0845,"PDSxno"),
DPO(0x00FA,0x0089,"DPo"),
PATPAINT(0x00FB,0x0A09,"DPSnoo"),
PSO(0x00FC,0x008A,"PSo"),
PSDNOO(0x00FD,0x0A0A,"PSDnoo"),
DPSOO(0x00FE,0x02A9,"DPSoo"),
WHITENESS(0x00FF,0x0062,"1");
int opIndex;
int opCode;
String opCmd;
WmfTernaryRasterOp(int opIndex, int opCode, String opCmd) {
this.opIndex=opIndex;
this.opCode=opCode;
this.opCmd=opCmd;
}
public static WmfTernaryRasterOp fromOpIndex(int opIndex) {
for (WmfTernaryRasterOp bb : WmfTernaryRasterOp.values()) {
if (bb.opIndex == opIndex) {
return bb;
}
}
return null;
}
public String describeCmd() {
String stack[] = new String[10];
int stackPnt = 0;
for (char c : opCmd.toCharArray()) {
switch (c) {
case 'S':
case 'D':
case 'P':
stack[stackPnt++] = ""+c;
break;
case 'n':
stack[stackPnt-1] = "not("+stack[stackPnt-1]+")";
break;
case 'a':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" and "+stack[stackPnt-2]+")";
stackPnt--;
break;
case 'o':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" or "+stack[stackPnt-2]+")";
stackPnt--;
break;
case 'x':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" xor "+stack[stackPnt-2]+")";
stackPnt--;
break;
case '1':
stack[stackPnt++] = "all white";
break;
case '0':
stack[stackPnt++] = "all black";
break;
default:
throw new RuntimeException("unknown cmd '"+c+"'.");
}
}
return stack[--stackPnt];
}
}

View File

@ -0,0 +1,316 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfText {
/**
* The META_SETTEXTCHAREXTRA record defines inter-character spacing for text justification in the
* playback device context. Spacing is added to the white space between each character, including
* break characters, when a line of justified text is output.
*/
public static class WmfSetTextCharExtra implements WmfRecord {
/**
* A 16-bit unsigned integer that defines the amount of extra space, in
* logical units, to be added to each character. If the current mapping mode is not MM_TEXT,
* this value is transformed and rounded to the nearest pixel. For details about setting the
* mapping mode, see META_SETMAPMODE
*/
int charExtra;
public WmfRecordType getRecordType() {
return WmfRecordType.setTextCharExtra;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
charExtra = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETTEXTCOLOR record defines the text foreground color in the playback device context.
*/
public static class WmfSetTextColor implements WmfRecord {
WmfColorRef colorRef;
public WmfRecordType getRecordType() {
return WmfRecordType.setTextColor;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
WmfColorRef colorRef = new WmfColorRef();
return colorRef.init(leis);
}
}
/**
* The META_SETTEXTJUSTIFICATION record defines the amount of space to add to break characters
* in a string of justified text.
*/
public static class WmfSetTextJustification implements WmfRecord {
/**
* A 16-bit unsigned integer that specifies the number of space characters in the line.
*/
int breakCount;
/**
* A 16-bit unsigned integer that specifies the total extra space, in logical
* units, to be added to the line of text. If the current mapping mode is not MM_TEXT, the value
* identified by the BreakExtra member is transformed and rounded to the nearest pixel. For
* details about setting the mapping mode, see {@link WmfSetMapMode}.
*/
int breakExtra;
public WmfRecordType getRecordType() {
return WmfRecordType.setBkColor;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
breakCount = leis.readUShort();
breakExtra = leis.readUShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_TEXTOUT record outputs a character string at the specified location by using the font,
* background color, and text color that are defined in the playback device context.
*/
public static class WmfTextOut implements WmfRecord {
/**
* A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.
*/
int stringLength;
/**
* The size of this field MUST be a multiple of two. If StringLength is an odd
* number, then this field MUST be of a size greater than or equal to StringLength + 1.
* A variable-length string that specifies the text to be drawn.
* The string does not need to be null-terminated, because StringLength specifies the
* length of the string.
* The string is written at the location specified by the XStart and YStart fields.
*/
String text;
/**
* A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical
* units, of the point where drawing is to start.
*/
int yStart;
/**
* A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in
* logical units, of the point where drawing is to start.
*/
int xStart;
public WmfRecordType getRecordType() {
return WmfRecordType.textOut;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
stringLength = leis.readShort();
byte buf[] = new byte[stringLength+(stringLength%2)];
leis.readFully(buf);
text = new String(buf, "UTF16-LE").trim();
yStart = leis.readShort();
xStart = leis.readShort();
return 3*LittleEndianConsts.SHORT_SIZE+buf.length;
}
}
/**
* The META_EXTTEXTOUT record outputs text by using the font, background color, and text color that
* are defined in the playback device context. Optionally, dimensions can be provided for clipping,
* opaquing, or both.
*/
public static class WmfExtTextOut implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, where the
text string is to be located.
*/
int y;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, where the
text string is to be located.
*/
int x;
/**
* A 16-bit signed integer that defines the length of the string.
*/
int stringLength;
/**
* A 16-bit unsigned integer that defines the use of the application-defined
* rectangle. This member can be a combination of one or more values in the
* ExtTextOutOptions Flags:
*
* ETO_OPAQUE (0x0002):
* Indicates that the background color that is defined in the playback device context
* SHOULD be used to fill the rectangle.
*
* ETO_CLIPPED (0x0004):
* Indicates that the text SHOULD be clipped to the rectangle.
*
* ETO_GLYPH_INDEX (0x0010):
* Indicates that the string to be output SHOULD NOT require further processing
* with respect to the placement of the characters, and an array of character
* placement values SHOULD be provided. This character placement process is
* useful for fonts in which diacritical characters affect character spacing.
*
* ETO_RTLREADING (0x0080):
* Indicates that the text MUST be laid out in right-to-left reading order, instead of
* the default left-to-right order. This SHOULD be applied only when the font that is
* defined in the playback device context is either Hebrew or Arabic. <37>
*
* ETO_NUMERICSLOCAL (0x0400):
* Indicates that to display numbers, digits appropriate to the locale SHOULD be
* used.
*
* ETO_NUMERICSLATIN (0x0800):
* Indicates that to display numbers, European digits SHOULD be used. <39>
*
* ETO_PDY (0x2000):
* Indicates that both horizontal and vertical character displacement values
* SHOULD be provided.
*/
int fwOpts;
/**
* An optional 8-byte Rect Object (section 2.2.2.18) that defines the
* dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.
*
* The corners are given in the order left, top, right, bottom.
* Each value is a 16-bit signed integer that defines the coordinate, in logical coordinates, of
* the upper-left corner of the rectangle
*/
int left,top,right,bottom;
/**
* A variable-length string that specifies the text to be drawn. The string does
* not need to be null-terminated, because StringLength specifies the length of the string. If
* the length is odd, an extra byte is placed after it so that the following member (optional Dx) is
* aligned on a 16-bit boundary.
*/
String text;
/**
* An optional array of 16-bit signed integers that indicate the distance between
* origins of adjacent character cells. For example, Dx[i] logical units separate the origins of
* character cell i and character cell i + 1. If this field is present, there MUST be the same
* number of values as there are characters in the string.
*/
int dx[];
public WmfRecordType getRecordType() {
return WmfRecordType.extTextOut;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
stringLength = leis.readShort();
fwOpts = leis.readUShort();
left = leis.readShort();
top = leis.readShort();
right = leis.readShort();
bottom = leis.readShort();
byte buf[] = new byte[stringLength+(stringLength%2)];
leis.readFully(buf);
text = new String(buf, "UTF16-LE");
int size = 8*LittleEndianConsts.SHORT_SIZE+buf.length;
if (size < recordSize) {
dx = new int[text.length()];
for (int i=0; i<dx.length; i++) {
dx[i] = leis.readShort();
}
size += dx.length*LittleEndianConsts.SHORT_SIZE;
}
return size;
}
}
/**
* The META_SETTEXTALIGN record defines text-alignment values in the playback device context.
*/
public static class WmfSetTextAlign implements WmfRecord {
/**
* A 16-bit unsigned integer that defines text alignment.
* This value MUST be a combination of one or more TextAlignmentMode Flags
* for text with a horizontal baseline, and VerticalTextAlignmentMode Flags
* for text with a vertical baseline.
*
* TextAlignmentMode Flags:
* TA_NOUPDATECP (0x0000):
* The drawing position in the playback device context MUST NOT be updated after each
* text output call. The reference point MUST be passed to the text output function.
*
* TA_LEFT (0x0000):
* The reference point MUST be on the left edge of the bounding rectangle.
*
* TA_TOP (0x0000):
* The reference point MUST be on the top edge of the bounding rectangle.
*
* TA_UPDATECP (0x0001):
* The drawing position in the playback device context MUST be updated after each text
* output call. It MUST be used as the reference point.
*
* TA_RIGHT (0x0002):
* The reference point MUST be on the right edge of the bounding rectangle.
*
* TA_CENTER (0x0006):
* The reference point MUST be aligned horizontally with the center of the bounding
* rectangle.
*
* TA_BOTTOM (0x0008):
* The reference point MUST be on the bottom edge of the bounding rectangle.
*
* TA_BASELINE (0x0018):
* The reference point MUST be on the baseline of the text.
*
* TA_RTLREADING (0x0100):
* The text MUST be laid out in right-to-left reading order, instead of the default
* left-toright order. This SHOULD be applied only when the font that is defined in the
* playback device context is either Hebrew or Arabic.
*
*
* VerticalTextAlignmentMode Flags (e.g. for Kanji fonts)
* VTA_TOP (0x0000):
* The reference point MUST be on the top edge of the bounding rectangle.
*
* VTA_RIGHT (0x0000):
* The reference point MUST be on the right edge of the bounding rectangle.
*
* VTA_BOTTOM (0x0002):
* The reference point MUST be on the bottom edge of the bounding rectangle.
*
* VTA_CENTER (0x0006):
* The reference point MUST be aligned vertically with the center of the bounding
* rectangle.
*
* VTA_LEFT (0x0008):
* The reference point MUST be on the left edge of the bounding rectangle.
*
* VTA_BASELINE (0x0018):
* The reference point MUST be on the baseline of the text.
*/
int textAlignmentMode;
public WmfRecordType getRecordType() {
return WmfRecordType.setTextAlign;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
textAlignmentMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
}

View File

@ -0,0 +1,399 @@
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class WmfWindowing {
/**
* The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the
* specified offsets.
*/
public static class WmfOffsetClipRgn implements WmfRecord {
/**
* A 16-bit signed integer that defines the number of logical units to move up or down.
*/
int yOffset;
/**
* A 16-bit signed integer that defines the number of logical units to move left or right.
*/
int xOffset;
public WmfRecordType getRecordType() {
return WmfRecordType.offsetClipRgn;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yOffset = leis.readShort();
xOffset = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETVIEWPORTORG record defines the viewport origin in the playback device context.
*/
public static class WmfSetViewportOrg implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical offset, in device units.
*/
int y;
/**
* A 16-bit signed integer that defines the horizontal offset, in device units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.setViewportOrg;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETVIEWPORTEXT record sets the horizontal and vertical extents
* of the viewport in the playback device context.
*/
public static class WmfSetViewportExt implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical extent
* of the viewport in device units.
*/
int y;
/**
* A 16-bit signed integer that defines the horizontal extent
* of the viewport in device units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.setViewportExt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_OFFSETVIEWPORTORG record moves the viewport origin in the playback device context
* by specified horizontal and vertical offsets.
*/
public static class WmfOffsetViewportOrg implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical offset, in device units.
*/
int yOffset;
/**
* A 16-bit signed integer that defines the horizontal offset, in device units.
*/
int xOffset;
public WmfRecordType getRecordType() {
return WmfRecordType.offsetViewportOrg;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yOffset = leis.readShort();
xOffset = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETWINDOWORG record defines the output window origin in the playback device context.
*/
public static class WmfSetWindowOrg implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units.
*/
int y;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.setWindowOrg;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SETWINDOWEXT record defines the horizontal and vertical extents
* of the output window in the playback device context.
*/
public static class WmfSetWindowExt implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical extent of
* the window in logical units.
*/
int y;
/**
* A 16-bit signed integer that defines the horizontal extent of
* the window in logical units.
*/
int x;
public WmfRecordType getRecordType() {
return WmfRecordType.setWindowExt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
y = leis.readShort();
x = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_OFFSETWINDOWORG record moves the output window origin in the
* playback device context by specified horizontal and vertical offsets.
*/
public static class WmfOffsetWindowOrg implements WmfRecord {
/**
* A 16-bit signed integer that defines the vertical offset, in device units.
*/
int yOffset;
/**
* A 16-bit signed integer that defines the horizontal offset, in device units.
*/
int xOffset;
public WmfRecordType getRecordType() {
return WmfRecordType.offsetWindowOrg;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yOffset = leis.readShort();
xOffset = leis.readShort();
return 2*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_OFFSETWINDOWORG record moves the output window origin in the
* playback device context by specified horizontal and vertical offsets.
*/
public static class WmfScaleWindowExt implements WmfRecord {
/**
* A 16-bit signed integer that defines the amount by which to divide the
* result of multiplying the current y-extent by the value of the yNum member.
*/
int yDenom;
/**
* A 16-bit signed integer that defines the amount by which to multiply the
* current y-extent.
*/
int yNum;
/**
* A 16-bit signed integer that defines the amount by which to divide the
* result of multiplying the current x-extent by the value of the xNum member.
*/
int xDenom;
/**
* A 16-bit signed integer that defines the amount by which to multiply the
* current x-extent.
*/
int xNum;
public WmfRecordType getRecordType() {
return WmfRecordType.scaleWindowExt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yDenom = leis.readShort();
yNum = leis.readShort();
xDenom = leis.readShort();
xNum = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_SCALEVIEWPORTEXT record scales the horizontal and vertical extents of the viewport
* that is defined in the playback device context by using the ratios formed by the specified
* multiplicands and divisors.
*/
public static class WmfScaleViewportExt implements WmfRecord {
/**
* A 16-bit signed integer that defines the amount by which to divide the
* result of multiplying the current y-extent by the value of the yNum member.
*/
int yDenom;
/**
* A 16-bit signed integer that defines the amount by which to multiply the
* current y-extent.
*/
int yNum;
/**
* A 16-bit signed integer that defines the amount by which to divide the
* result of multiplying the current x-extent by the value of the xNum member.
*/
int xDenom;
/**
* A 16-bit signed integer that defines the amount by which to multiply the
* current x-extent.
*/
int xNum;
public WmfRecordType getRecordType() {
return WmfRecordType.scaleViewportExt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
yDenom = leis.readShort();
yNum = leis.readShort();
xDenom = leis.readShort();
xNum = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_EXCLUDECLIPRECT record sets the clipping region in the playback device context to the
* existing clipping region minus the specified rectangle.
*/
public static class WmfExcludeClipRect implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* lower-right corner of the rectangle.
*/
int bottom;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* lower-right corner of the rectangle.
*/
int right;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int top;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int left;
public WmfRecordType getRecordType() {
return WmfRecordType.excludeClipRect;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
bottom = leis.readShort();
right = leis.readShort();
top = leis.readShort();
left = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the
* intersection of the existing clipping region and the specified rectangle.
*/
public static class WmfIntersectClipRect implements WmfRecord {
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* lower-right corner of the rectangle.
*/
int bottom;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* lower-right corner of the rectangle.
*/
int right;
/**
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int top;
/**
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the
* upper-left corner of the rectangle.
*/
int left;
public WmfRecordType getRecordType() {
return WmfRecordType.intersectClipRect;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
bottom = leis.readShort();
right = leis.readShort();
top = leis.readShort();
left = leis.readShort();
return 4*LittleEndianConsts.SHORT_SIZE;
}
}
/**
* The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the
* intersection of the existing clipping region and the specified rectangle.
*/
public static class WmfSelectClipRegion implements WmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be clipped.
*/
int region;
public WmfRecordType getRecordType() {
return WmfRecordType.selectClipRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
}