Compare commits
4 Commits
master
...
wmf_render
Author | SHA1 | Date |
---|---|---|
Andreas Beeker | c8dee17f33 | |
Andreas Beeker | 87a6135199 | |
Andreas Beeker | f0c2bda1a6 | |
Andreas Beeker | 393e33492f |
|
@ -111,7 +111,7 @@ public class LittleEndian implements LittleEndianConsts
|
||||||
*
|
*
|
||||||
* @param data
|
* @param data
|
||||||
* the byte array
|
* the byte array
|
||||||
* @return the double (64-bit) value
|
* @return the float (32-bit) value
|
||||||
*/
|
*/
|
||||||
public static float getFloat( byte[] data )
|
public static float getFloat( byte[] data )
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ public class LittleEndian implements LittleEndianConsts
|
||||||
* the byte array
|
* the byte array
|
||||||
* @param offset
|
* @param offset
|
||||||
* a starting offset into the byte array
|
* 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 )
|
public static float getFloat( byte[] data, int offset )
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,9 +30,12 @@ import java.io.InputStream;
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput {
|
public class LittleEndianInputStream extends FilterInputStream implements LittleEndianInput {
|
||||||
|
private byte _buf[] = new byte[LittleEndianConsts.LONG_SIZE];
|
||||||
|
|
||||||
public LittleEndianInputStream(InputStream is) {
|
public LittleEndianInputStream(InputStream is) {
|
||||||
super(is);
|
super(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int available() {
|
public int available() {
|
||||||
try {
|
try {
|
||||||
return super.available();
|
return super.available();
|
||||||
|
@ -40,88 +43,45 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte readByte() {
|
public byte readByte() {
|
||||||
return (byte)readUByte();
|
readFully(_buf, 0, LittleEndianConsts.BYTE_SIZE);
|
||||||
|
return _buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readUByte() {
|
public int readUByte() {
|
||||||
int ch;
|
readFully(_buf, 0, LittleEndianConsts.BYTE_SIZE);
|
||||||
try {
|
return LittleEndian.getUByte(_buf);
|
||||||
ch = in.read();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
checkEOF(ch);
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
public double readDouble() {
|
|
||||||
return Double.longBitsToDouble(readLong());
|
|
||||||
}
|
|
||||||
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() {
|
public short readShort() {
|
||||||
return (short)readUShort();
|
readFully(_buf, 0, LittleEndianConsts.SHORT_SIZE);
|
||||||
|
return LittleEndian.getShort(_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readUShort() {
|
public int readUShort() {
|
||||||
int ch1;
|
readFully(_buf, 0, LittleEndianConsts.SHORT_SIZE);
|
||||||
int ch2;
|
return LittleEndian.getUShort(_buf);
|
||||||
try {
|
|
||||||
ch1 = in.read();
|
|
||||||
ch2 = in.read();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
checkEOF(ch1 | ch2);
|
|
||||||
return (ch2 << 8) + (ch1 << 0);
|
public int readInt() {
|
||||||
|
readFully(_buf, 0, LittleEndianConsts.INT_SIZE);
|
||||||
|
return LittleEndian.getInt(_buf);
|
||||||
}
|
}
|
||||||
private static void checkEOF(int value) {
|
|
||||||
if (value <0) {
|
public long readUInt() {
|
||||||
throw new RuntimeException("Unexpected end-of-file");
|
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) {
|
public void readFully(byte[] buf) {
|
||||||
|
@ -129,16 +89,19 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readFully(byte[] buf, int off, int len) {
|
public void readFully(byte[] buf, int off, int len) {
|
||||||
int max = off+len;
|
if (buf == null || buf.length == 0) {
|
||||||
for(int i=off; i<max; i++) {
|
return;
|
||||||
int ch;
|
}
|
||||||
|
|
||||||
|
int readBytes;
|
||||||
try {
|
try {
|
||||||
ch = in.read();
|
readBytes = super.read(buf, off, len);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
checkEOF(ch);
|
|
||||||
buf[i] = (byte) ch;
|
if (readBytes == -1 || readBytes < len ) {
|
||||||
|
throw new RuntimeException("Unexpected end-of-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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue