#56004 - Support for WMF rendering (parsing the WMF records)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1721078 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-12-21 01:26:39 +00:00
parent b69c64fe21
commit b333ed457d
20 changed files with 5002 additions and 0 deletions

View File

@ -0,0 +1,105 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfBitmap16 {
final boolean isPartial;
int type;
int width;
int height;
int widthBytes;
int planes;
int bitsPixel;
public HwmfBitmap16() {
this(false);
}
public HwmfBitmap16(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;
ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));
for (int w=0; w<width; w++) {
long bitsAtPixel = iis.readBits(bitsPixel);
// TODO: is bitsPixel a multiple of 3 (r,g,b)
// which colortable should be used for the various bit sizes???
}
}
int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;
assert (bytes == size2);
size += size2;
return size;
}
}

View File

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

View File

@ -0,0 +1,80 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
/**
* 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 enum HwmfBrushStyle {
/**
* 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;
HwmfBrushStyle(int flag) {
this.flag = flag;
}
static HwmfBrushStyle valueOf(int flag) {
for (HwmfBrushStyle bs : values()) {
if (bs.flag == flag) return bs;
}
return null;
}
}

View File

@ -0,0 +1,47 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
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 HwmfColorRef {
/**
* A 32-bit ColorRef Object that defines the color value.
* Red (1 byte): An 8-bit unsigned integer that defines the relative intensity of red.
* Green (1 byte): An 8-bit unsigned integer that defines the relative intensity of green.
* Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.
* Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.
*/
Color colorRef;
public int init(LittleEndianInputStream leis) throws IOException {
int red = leis.readUByte();
int green = leis.readUByte();
int blue = leis.readUByte();
@SuppressWarnings("unused")
int reserved = leis.readUByte();
colorRef = new Color(red, green, blue);
return 4*LittleEndianConsts.BYTE_SIZE;
}
}

View File

@ -0,0 +1,619 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfDraw {
/**
* The META_MOVETO record sets the output position in the playback device context to a specified
* point.
*/
public static class WmfMoveTo implements HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit signed integer that defines the number of points in the array.
*/
int numberofPoints;
short xPoints[], yPoints[];
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A ColorRef Object that defines the color value.
*/
HwmfColorRef 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 HwmfRecordType getRecordType() {
return HwmfRecordType.setPixel;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new HwmfColorRef();
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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to
* get the object to be selected.
*/
int objectIndex;
public HwmfRecordType getRecordType() {
return HwmfRecordType.selectObject;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
objectIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
}

View File

@ -0,0 +1,53 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfEscape implements HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.escape;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
escapeFunction = leis.readUShort();
byteCount = leis.readUShort();
escapeData = new byte[byteCount];
leis.read(escapeData);
return 2*LittleEndianConsts.SHORT_SIZE+byteCount;
}
}

View File

@ -0,0 +1,794 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfFill {
/**
* The META_FILLREGION record fills a region using a specified brush.
*/
public static class WmfFillRegion implements HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be painted.
*/
int region;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 32-bit ColorRef Object that defines the color value.
*/
HwmfColorRef 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 HwmfRecordType getRecordType() {
return HwmfRecordType.floodFill;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new HwmfColorRef();
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 HwmfRecord {
/**
* A 16-bit unsigned integer that defines polygon fill mode.
* This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
*/
int polyFillMode;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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.
*/
HwmfColorRef 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 HwmfRecordType getRecordType() {
return HwmfRecordType.extFloodFill;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
mode = leis.readUShort();
colorRef = new HwmfColorRef();
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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be inverted.
*/
int region;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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.
*/
HwmfTernaryRasterOp 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 HwmfRecordType getRecordType() {
return HwmfRecordType.patBlt;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = HwmfTernaryRasterOp.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 HwmfRecord {
/**
* 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
*/
HwmfTernaryRasterOp 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.
*/
HwmfBitmap16 target;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 = HwmfTernaryRasterOp.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 HwmfBitmap16();
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 HwmfRecord {
/**
* 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.
*/
HwmfTernaryRasterOp 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.
*/
HwmfBitmapDib dib;
public HwmfRecordType getRecordType() {
return HwmfRecordType.stretchDib;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
int rasterOpIndex = leis.readUShort();
int rasterOpCode = leis.readUShort();
rasterOperation = HwmfTernaryRasterOp.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 HwmfBitmapDib();
size += dib.init(leis);
return size;
}
}
public static class WmfBitBlt implements HwmfRecord {
/**
* 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.
*/
HwmfTernaryRasterOp 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.
*/
HwmfBitmap16 target;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 = HwmfTernaryRasterOp.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 HwmfBitmap16();
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 HwmfRecord {
/**
* 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.
*/
HwmfBitmapDib dib;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfBitmapDib();
size += dib.init(leis);
return size;
}
}
public static class WmfDibBitBlt implements HwmfRecord {
/**
* 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.
*/
HwmfTernaryRasterOp 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.
*/
HwmfBitmapDib target;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 = HwmfTernaryRasterOp.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 HwmfBitmapDib();
size += target.init(leis);
}
return size;
}
}
public static class WmfDibStretchBlt implements HwmfRecord {
/**
* 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.
*/
HwmfTernaryRasterOp 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.
*/
HwmfBitmapDib target;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 = HwmfTernaryRasterOp.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 HwmfBitmapDib();
size += target.init(leis);
}
return size;
}
}
}

View File

@ -0,0 +1,498 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import java.nio.charset.Charset;
import org.apache.poi.util.LittleEndianInputStream;
/**
* The Font object specifies the attributes of a logical font
*/
public class HwmfFont {
public enum WmfCharset {
/** Specifies the English character set. */
ANSI_CHARSET(0x00000000),
/**
* Specifies a character set based on the current system locale;
* for example, when the system locale is United States English,
* the default character set is ANSI_CHARSET.
*/
DEFAULT_CHARSET(0x00000001),
/** Specifies a character set of symbols. */
SYMBOL_CHARSET(0x00000002),
/** Specifies the Apple Macintosh character set. */
MAC_CHARSET(0x0000004D),
/** Specifies the Japanese character set. */
SHIFTJIS_CHARSET(0x00000080),
/** Also spelled "Hangeul". Specifies the Hangul Korean character set. */
HANGUL_CHARSET(0x00000081),
/** Also spelled "Johap". Specifies the Johab Korean character set. */
JOHAB_CHARSET(0x00000082),
/** Specifies the "simplified" Chinese character set for People's Republic of China. */
GB2312_CHARSET(0x00000086),
/**
* Specifies the "traditional" Chinese character set, used mostly in
* Taiwan and in the Hong Kong and Macao Special Administrative Regions.
*/
CHINESEBIG5_CHARSET(0x00000088),
/** Specifies the Greek character set. */
GREEK_CHARSET(0x000000A1),
/** Specifies the Turkish character set. */
TURKISH_CHARSET(0x000000A2),
/** Specifies the Vietnamese character set. */
VIETNAMESE_CHARSET(0x000000A3),
/** Specifies the Hebrew character set. */
HEBREW_CHARSET(0x000000B1),
/** Specifies the Arabic character set. */
ARABIC_CHARSET(0x000000B2),
/** Specifies the Baltic (Northeastern European) character set. */
BALTIC_CHARSET(0x000000BA),
/** Specifies the Russian Cyrillic character set. */
RUSSIAN_CHARSET(0x000000CC),
/** Specifies the Thai character set. */
THAI_CHARSET(0x000000DE),
/** Specifies a Eastern European character set. */
EASTEUROPE_CHARSET(0x000000EE),
/**
* Specifies a mapping to one of the OEM code pages,
* according to the current system locale setting.
*/
OEM_CHARSET(0x000000FF);
int flag;
WmfCharset(int flag) {
this.flag = flag;
}
static WmfCharset valueOf(int flag) {
for (WmfCharset cs : values()) {
if (cs.flag == flag) return cs;
}
return null;
}
}
/**
* The output precision defines how closely the output must match the requested font's height,
* width, character orientation, escapement, pitch, and font type.
*/
public enum WmfOutPrecision {
/**
* A value that specifies default behavior.
*/
OUT_DEFAULT_PRECIS(0x00000000),
/**
* A value that is returned when rasterized fonts are enumerated.
*/
OUT_STRING_PRECIS(0x00000001),
/**
* A value that is returned when TrueType and other outline fonts, and
* vector fonts are enumerated.
*/
OUT_STROKE_PRECIS(0x00000003),
/**
* A value that specifies the choice of a TrueType font when the system
* contains multiple fonts with the same name.
*/
OUT_TT_PRECIS(0x00000004),
/**
* A value that specifies the choice of a device font when the system
* contains multiple fonts with the same name.
*/
OUT_DEVICE_PRECIS(0x00000005),
/**
* A value that specifies the choice of a rasterized font when the system
* contains multiple fonts with the same name.
*/
OUT_RASTER_PRECIS(0x00000006),
/**
* A value that specifies the requirement for only TrueType fonts. If
* there are no TrueType fonts installed in the system, default behavior is specified.
*/
OUT_TT_ONLY_PRECIS(0x00000007),
/**
* A value that specifies the requirement for TrueType and other outline fonts.
*/
OUT_OUTLINE_PRECIS (0x00000008),
/**
* A value that specifies a preference for TrueType and other outline fonts.
*/
OUT_SCREEN_OUTLINE_PRECIS (0x00000009),
/**
* A value that specifies a requirement for only PostScript fonts. If there
* are no PostScript fonts installed in the system, default behavior is specified.
*/
OUT_PS_ONLY_PRECIS (0x0000000A);
int flag;
WmfOutPrecision(int flag) {
this.flag = flag;
}
static WmfOutPrecision valueOf(int flag) {
for (WmfOutPrecision op : values()) {
if (op.flag == flag) return op;
}
return null;
}
}
/**
* ClipPrecision Flags specify clipping precision, which defines how to clip characters that are
* partially outside a clipping region. These flags can be combined to specify multiple options.
*/
public enum WmfClipPrecision {
/**
* Specifies that default clipping MUST be used.
*/
CLIP_DEFAULT_PRECIS (0x00000000),
/**
* This value SHOULD NOT be used.
*/
CLIP_CHARACTER_PRECIS (0x00000001),
/**
* This value MAY be returned when enumerating rasterized, TrueType and vector fonts.
*/
CLIP_STROKE_PRECIS (0x00000002),
/**
* This value is used to control font rotation, as follows:
* If set, the rotation for all fonts SHOULD be determined by the orientation of the coordinate system;
* that is, whether the orientation is left-handed or right-handed.
*
* If clear, device fonts SHOULD rotate counterclockwise, but the rotation of other fonts
* SHOULD be determined by the orientation of the coordinate system.
*/
CLIP_LH_ANGLES (0x00000010),
/**
* This value SHOULD NOT be used.
*/
CLIP_TT_ALWAYS (0x00000020),
/**
* This value specifies that font association SHOULD< be turned off.
*/
CLIP_DFA_DISABLE (0x00000040),
/**
* This value specifies that font embedding MUST be used to render document content;
* embedded fonts are read-only.
*/
CLIP_EMBEDDED (0x00000080);
int flag;
WmfClipPrecision(int flag) {
this.flag = flag;
}
static WmfClipPrecision valueOf(int flag) {
for (WmfClipPrecision cp : values()) {
if (cp.flag == flag) return cp;
}
return null;
}
}
/**
* The output quality defines how carefully to attempt to match the logical font attributes to those of an actual
* physical font.
*/
public enum WmfFontQuality {
/**
* Specifies that the character quality of the font does not matter, so DRAFT_QUALITY can be used.
*/
DEFAULT_QUALITY (0x00),
/**
* Specifies that the character quality of the font is less important than the
* matching of logical attribuetes. For rasterized fonts, scaling SHOULD be enabled, which
* means that more font sizes are available.
*/
DRAFT_QUALITY (0x01),
/**
* Specifies that the character quality of the font is more important than the
* matching of logical attributes. For rasterized fonts, scaling SHOULD be disabled, and the font
* closest in size SHOULD be chosen.
*/
PROOF_QUALITY (0x02),
/**
* Specifies that anti-aliasing SHOULD NOT be used when rendering text.
*/
NONANTIALIASED_QUALITY (0x03),
/**
* Specifies that anti-aliasing SHOULD be used when rendering text, if the font supports it.
*/
ANTIALIASED_QUALITY (0x04),
/**
* Specifies that ClearType anti-aliasing SHOULD be used when rendering text, if the font supports it.
*
* Fonts that do not support ClearType anti-aliasing include type 1 fonts, PostScript fonts,
* OpenType fonts without TrueType outlines, rasterized fonts, vector fonts, and device fonts.
*/
CLEARTYPE_QUALITY (0x05);
int flag;
WmfFontQuality(int flag) {
this.flag = flag;
}
static WmfFontQuality valueOf(int flag) {
for (WmfFontQuality fq : values()) {
if (fq.flag == flag) return fq;
}
return null;
}
}
/**
* A property of a font that describes its general appearance.
*/
public enum WmfFontFamilyClass {
/**
* The default font is specified, which is implementation-dependent.
*/
FF_DONTCARE (0x00),
/**
* Fonts with variable stroke widths, which are proportional to the actual widths of
* the glyphs, and which have serifs. "MS Serif" is an example.
*/
FF_ROMAN (0x01),
/**
* Fonts with variable stroke widths, which are proportional to the actual widths of the
* glyphs, and which do not have serifs. "MS Sans Serif" is an example.
*/
FF_SWISS (0x02),
/**
* Fonts with constant stroke width, with or without serifs. Fixed-width fonts are
* usually modern. "Pica", "Elite", and "Courier New" are examples.
*/
FF_MODERN (0x03),
/**
* Fonts designed to look like handwriting. "Script" and "Cursive" are examples.
*/
FF_SCRIPT (0x04),
/**
* Novelty fonts. "Old English" is an example.
*/
FF_DECORATIVE (0x05);
int flag;
WmfFontFamilyClass(int flag) {
this.flag = flag;
}
static WmfFontFamilyClass valueOf(int flag) {
for (WmfFontFamilyClass ff : values()) {
if (ff.flag == flag) return ff;
}
return null;
}
}
/**
* A property of a font that describes the pitch, of the characters.
*/
public enum WmfFontPitch {
/**
* The default pitch, which is implementation-dependent.
*/
DEFAULT_PITCH (0x00),
/**
* A fixed pitch, which means that all the characters in the font occupy the same
* width when output in a string.
*/
FIXED_PITCH (0x01),
/**
* A variable pitch, which means that the characters in the font occupy widths
* that are proportional to the actual widths of the glyphs when output in a string. For example,
* the "i" and space characters usually have much smaller widths than a "W" or "O" character.
*/
VARIABLE_PITCH (0x02);
int flag;
WmfFontPitch(int flag) {
this.flag = flag;
}
static WmfFontPitch valueOf(int flag) {
for (WmfFontPitch fp : values()) {
if (fp.flag == flag) return fp;
}
return null;
}
}
/**
* A 16-bit signed integer that specifies the height, in logical units, of the font's
* character cell. The character height is computed as the character cell height minus the
* internal leading. The font mapper SHOULD interpret the height as follows.
*
* negative value:
* The font mapper SHOULD transform this value into device units and match its
* absolute value against the character height of available fonts.
*
* zero value:
* A default height value MUST be used when creating a physical font.
*
* positive value:
* The font mapper SHOULD transform this value into device units and match it
* against the cell height of available fonts.
*
* For all height comparisons, the font mapper SHOULD find the largest physical
* font that does not exceed the requested size.
*/
int height;
/**
* A 16-bit signed integer that defines the average width, in logical units, of
* characters in the font. If Width is 0x0000, the aspect ratio of the device SHOULD be matched
* against the digitization aspect ratio of the available fonts to find the closest match,
* determined by the absolute value of the difference.
*/
int width;
/**
* A 16-bit signed integer that defines the angle, in tenths of degrees, between the
* escapement vector and the x-axis of the device. The escapement vector is parallel
* to the base line of a row of text.
*/
int escapement;
/**
* A 16-bit signed integer that defines the angle, in tenths of degrees,
* between each character's base line and the x-axis of the device.
*/
int orientation;
/**
* A 16-bit signed integer that defines the weight of the font in the range 0
* through 1000. For example, 400 is normal and 700 is bold. If this value is 0x0000,
* a default weight SHOULD be used.
*/
int weight;
/**
* A 8-bit Boolean value that specifies the italic attribute of the font.
* 0 = not italic / 1 = italic.
*/
boolean italic;
/**
* An 8-bit Boolean value that specifies the underline attribute of the font.
* 0 = not underlined / 1 = underlined
*/
boolean underline;
/**
* An 8-bit Boolean value that specifies the strike out attribute of the font.
* 0 = not striked out / 1 = striked out
*/
boolean strikeOut;
/**
* An 8-bit unsigned integer that defines the character set.
* It SHOULD be set to a value in the {@link WmfCharset} Enumeration.
*
* The DEFAULT_CHARSET value MAY be used to allow the name and size of a font to fully
* describe the logical font. If the specified font name does not exist, a font in another character
* set MAY be substituted. The DEFAULT_CHARSET value is set to a value based on the current
* system locale. For example, when the system locale is United States, it is set to ANSI_CHARSET.
* If a typeface name in the FaceName field is specified, the CharSet value MUST match the
* character set of that typeface.
*/
WmfCharset charSet;
/**
* An 8-bit unsigned integer that defines the output precision.
*/
WmfOutPrecision outPrecision;
/**
* An 8-bit unsigned integer that defines the clipping precision.
* These flags can be combined to specify multiple options.
*
* @see WmfClipPrecision
*/
int clipPrecision;
/**
* An 8-bit unsigned integer that defines the output quality.
*/
WmfFontQuality quality;
/**
* Font families specify the look of fonts in a general way and are
* intended for specifying fonts when the exact typeface wanted is not available.
* (LSB 4 bits)
*/
WmfFontFamilyClass family;
/**
* A property of a font that describes the pitch (MSB 2 bits)
*/
WmfFontPitch pitch;
/**
* A null-terminated string of 8-bit Latin-1 [ISO/IEC-8859-1] ANSI
* characters that specifies the typeface name of the font. The length of this string MUST NOT
* exceed 32 8-bit characters, including the terminating null.
*/
String facename;
public int init(LittleEndianInputStream leis) throws IOException {
height = leis.readShort();
width = leis.readShort();
escapement = leis.readShort();
orientation = leis.readShort();
weight = leis.readShort();
italic = leis.readByte() != 0;
underline = leis.readByte() != 0;
strikeOut = leis.readByte() != 0;
charSet = WmfCharset.valueOf(leis.readUByte());
outPrecision = WmfOutPrecision.valueOf(leis.readUByte());
quality = WmfFontQuality.valueOf(leis.readUByte());
int pitchAndFamily = leis.readUByte();
family = WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);
pitch = WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);
byte buf[] = new byte[32], readBytes;
for (readBytes = 0; readBytes < 32; readBytes++) {
if ((buf[readBytes] = leis.readByte()) == 0) {
break;
}
}
if (readBytes == 1 || readBytes == 32) {
throw new IOException("Font facename can't be determined.");
}
facename = new String(buf, 0, readBytes-1, Charset.forName("ISO-8859-1"));
return 17+readBytes;
}
}

View File

@ -0,0 +1,48 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
/**
* The HatchStyle Enumeration specifies the hatch pattern.
*/
public enum HwmfHatchStyle {
/** A horizontal hatch */
HS_HORIZONTAL(0x0000),
/** A vertical hatch */
HS_VERTICAL(0x0001),
/** A 45-degree downward, left-to-right hatch. */
HS_FDIAGONAL(0x0002),
/** A 45-degree upward, left-to-right hatch. */
HS_BDIAGONAL(0x0003),
/** A horizontal and vertical cross-hatch. */
HS_CROSS(0x0004),
/** A 45-degree crosshatch. */
HS_DIAGCROSS(0x0005);
int flag;
HwmfHatchStyle(int flag) {
this.flag = flag;
}
static HwmfHatchStyle valueOf(int flag) {
for (HwmfHatchStyle hs : values()) {
if (hs.flag == flag) return hs;
}
return null;
}
}

View File

@ -0,0 +1,76 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfHeader {
private int type;
private int recordSize;
private int version;
private int filesize;
private int numberOfObjects;
private long maxRecord;
private int numberOfMembers;
public HwmfHeader(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-4;
// 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;
if (bytesLeft > 0) {
leis.skip(bytesLeft);
}
}
}

View File

@ -0,0 +1,506 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfMisc {
/**
* The META_SAVEDC record saves the playback device context for later retrieval.
*/
public static class WmfSaveDc implements HwmfRecord {
public HwmfRecordType getRecordType() { return HwmfRecordType.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 HwmfRecord {
public HwmfRecordType getRecordType() { return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
HwmfColorRef colorRef;
public HwmfRecordType getRecordType() {
return HwmfRecordType.setBkColor;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new HwmfColorRef();
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 HwmfRecord {
/**
* A 16-bit unsigned integer that defines background mix mode.
* This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002
*/
int bkMode;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
HwmfBrushStyle 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;
HwmfBitmapDib patternDib;
HwmfBitmap16 pattern16;
public HwmfRecordType getRecordType() {
return HwmfRecordType.dibCreatePatternBrush;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
style = HwmfBrushStyle.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 HwmfBitmapDib();
size += patternDib.init(leis);
break;
case BS_PATTERN:
pattern16 = new HwmfBitmap16();
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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to
get the object to be deleted.
*/
int objectIndex;
public HwmfRecordType getRecordType() { return HwmfRecordType.deleteObject; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
objectIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
public static class WmfCreatePatternBrush implements HwmfRecord {
HwmfBitmap16 pattern;
public HwmfRecordType getRecordType() { return HwmfRecordType.createPatternBrush; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
pattern = new HwmfBitmap16(true);
return pattern.init(leis);
}
}
public static class WmfCreatePenIndirect implements HwmfRecord {
/**
* 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.
*/
HwmfColorRef colorRef;
public HwmfRecordType getRecordType() { return HwmfRecordType.createPenIndirect; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
penStyle = leis.readUShort();
xWidth = leis.readShort();
yWidth = leis.readShort();
colorRef = new HwmfColorRef();
int size = 3*LittleEndianConsts.SHORT_SIZE;
size += colorRef.init(leis);
return size;
}
}
/**
* The META_CREATEBRUSHINDIRECT record creates a Brush Object
* from a LogBrush Object.
*
* The following table shows the relationship between values in the BrushStyle,
* ColorRef and BrushHatch fields in a LogBrush Object. Only supported brush styles are listed.
*
* <table>
* <tr>
* <th>BrushStyle</th>
* <th>ColorRef</th>
* <th>BrushHatch</th>
* </tr>
* <tr>
* <td>BS_SOLID</td>
* <td>SHOULD be a ColorRef Object, which determines the color of the brush.</td>
* <td>Not used, and SHOULD be ignored.</td>
* </tr>
* <tr>
* <td>BS_NULL</td>
* <td>Not used, and SHOULD be ignored.</td>
* <td>Not used, and SHOULD be ignored.</td>
* </tr>
* <tr>
* <td>BS_PATTERN</td>
* <td>Not used, and SHOULD be ignored.</td>
* <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created.</td>
* </tr>
* <tr>
* <td>BS_DIBPATTERN</td>
* <td>Not used, and SHOULD be ignored.</td>
* <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created</td>
* </tr>
* <tr>
* <td>BS_DIBPATTERNPT</td>
* <td>Not used, and SHOULD be ignored.</td>
* <td>Not used. A default object, such as a solidcolor black Brush Object, MAY be created.</td>
* </tr>
* <tr>
* <td>BS_HATCHED</td>
* <td>SHOULD be a ColorRef Object, which determines the foreground color of the hatch pattern.</td>
* <td>A value from the {@link HwmfHatchStyle} Enumeration that specifies the orientation of lines used to create the hatch.</td>
* </tr>
* </table>
*/
public static class WmfCreateBrushIndirect implements HwmfRecord {
HwmfBrushStyle brushStyle;
HwmfColorRef colorRef;
/**
* A 16-bit field that specifies the brush hatch type.
* Its interpretation depends on the value of BrushStyle.
*
*/
HwmfHatchStyle brushHatch;
public HwmfRecordType getRecordType() { return HwmfRecordType.createBrushIndirect; }
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
brushStyle = HwmfBrushStyle.valueOf(leis.readUShort());
colorRef = new HwmfColorRef();
int size = colorRef.init(leis);
brushHatch = HwmfHatchStyle.valueOf(leis.readUShort());
size += 4;
return size;
}
}
}

View File

@ -0,0 +1,163 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfPalette {
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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit unsigned integer that defines the number of entries in
* the logical palette.
*/
int numberOfEntries;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the Palette Object to be selected.
*/
int palette;
public HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
public HwmfRecordType getRecordType() { return HwmfRecordType.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 HwmfRecordType getRecordType() {
return HwmfRecordType.animatePalette;
}
}
}

View File

@ -0,0 +1,77 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfPlaceableHeader {
public static int WMF_HEADER_MAGIC = 0x9AC6CDD7;
protected HwmfPlaceableHeader(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 HwmfPlaceableHeader readHeader(LittleEndianInputStream leis) throws IOException {
leis.mark(LittleEndianConsts.INT_SIZE);
int magic = leis.readInt();
if (magic == WMF_HEADER_MAGIC) {
return new HwmfPlaceableHeader(leis);
} else {
leis.reset();
return null;
}
}
}

View File

@ -0,0 +1,35 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.util.LittleEndianInputStream;
public interface HwmfRecord {
HwmfRecordType getRecordType();
/**
* Init record from stream
*
* @param leis the little endian input stream
* @return count of processed bytes
* @throws IOException
*/
int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;
}

View File

@ -0,0 +1,111 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
/**
* Available record types for WMF
*
* @see <a href="http://www.symantec.com/avcenter/reference/inside.the.windows.meta.file.format.pdf">Inside the Windows Meta File Format</a>
*/
public enum HwmfRecordType {
eof(0x0000, null),
realizePalette(0x0035, HwmfPalette.WmfRealizePalette.class),
setPalEntries(0x0037, HwmfPalette.WmfSetPaletteEntries.class),
setBkMode(0x0102, HwmfMisc.WmfSetBkMode.class),
setMapMode(0x0103, HwmfMisc.WmfSetMapMode.class),
setRop2(0x0104, HwmfMisc.WmfSetRop2.class),
setRelabs(0x0105, HwmfMisc.WmfSetRelabs.class),
setPolyFillMode(0x0106, HwmfFill.WmfSetPolyfillMode.class),
setStretchBltMode(0x0107, HwmfMisc.WmfSetStretchBltMode.class),
setTextCharExtra(0x0108, HwmfText.WmfSetTextCharExtra.class),
restoreDc(0x0127, HwmfMisc.WmfRestoreDc.class),
resizePalette(0x0139, HwmfPalette.WmfResizePalette.class),
dibCreatePatternBrush(0x0142, HwmfMisc.WmfDibCreatePatternBrush.class),
setLayout(0x0149, HwmfMisc.WmfSetLayout.class),
setBkColor(0x0201, HwmfMisc.WmfSetBkColor.class),
setTextColor(0x0209, HwmfText.WmfSetTextColor.class),
offsetViewportOrg(0x0211, HwmfWindowing.WmfOffsetViewportOrg.class),
lineTo(0x0213, HwmfDraw.WmfLineTo.class),
moveTo(0x0214, HwmfDraw.WmfMoveTo.class),
offsetClipRgn(0x0220, HwmfWindowing.WmfOffsetClipRgn.class),
fillRegion(0x0228, HwmfFill.WmfFillRegion.class),
setMapperFlags(0x0231, HwmfMisc.WmfSetMapperFlags.class),
selectPalette(0x0234, HwmfPalette.WmfSelectPalette.class),
polygon(0x0324, HwmfDraw.WmfPolygon.class),
polyline(0x0325, HwmfDraw.WmfPolyline.class),
setTextJustification(0x020a, HwmfText.WmfSetTextJustification.class),
setWindowOrg(0x020b, HwmfWindowing.WmfSetWindowOrg.class),
setWindowExt(0x020c, HwmfWindowing.WmfSetWindowExt.class),
setViewportOrg(0x020d, HwmfWindowing.WmfSetViewportOrg.class),
setViewportExt(0x020e, HwmfWindowing.WmfSetViewportExt.class),
offsetWindowOrg(0x020f, HwmfWindowing.WmfOffsetWindowOrg.class),
scaleWindowExt(0x0410, HwmfWindowing.WmfScaleWindowExt.class),
scaleViewportExt(0x0412, HwmfWindowing.WmfScaleViewportExt.class),
excludeClipRect(0x0415, HwmfWindowing.WmfExcludeClipRect.class),
intersectClipRect(0x0416, HwmfWindowing.WmfIntersectClipRect.class),
ellipse(0x0418, HwmfDraw.WmfEllipse.class),
floodFill(0x0419, HwmfFill.WmfFloodFill.class),
frameRegion(0x0429, HwmfDraw.WmfFrameRegion.class),
animatePalette(0x0436, HwmfPalette.WmfAnimatePalette.class),
textOut(0x0521, HwmfText.WmfTextOut.class),
polyPolygon(0x0538, HwmfDraw.WmfPolyPolygon.class),
extFloodFill(0x0548, HwmfFill.WmfExtFloodFill.class),
rectangle(0x041b, HwmfDraw.WmfRectangle.class),
setPixel(0x041f, HwmfDraw.WmfSetPixel.class),
roundRect(0x061c, HwmfDraw.WmfRoundRect.class),
patBlt(0x061d, HwmfFill.WmfPatBlt.class),
saveDc(0x001e, HwmfMisc.WmfSaveDc.class),
pie(0x081a, HwmfDraw.WmfPie.class),
stretchBlt(0x0b23, HwmfFill.WmfStretchBlt.class),
escape(0x0626, HwmfEscape.class),
invertRegion(0x012a, HwmfFill.WmfInvertRegion.class),
paintRegion(0x012b, HwmfFill.WmfPaintRegion.class),
selectClipRegion(0x012c, HwmfWindowing.WmfSelectClipRegion.class),
selectObject(0x012d, HwmfDraw.WmfSelectObject.class),
setTextAlign(0x012e, HwmfText.WmfSetTextAlign.class),
arc(0x0817, HwmfDraw.WmfArc.class),
chord(0x0830, HwmfDraw.WmfChord.class),
bitBlt(0x0922, HwmfFill.WmfBitBlt.class),
extTextOut(0x0a32, HwmfText.WmfExtTextOut.class),
setDibToDev(0x0d33, HwmfFill.WmfSetDibToDev.class),
dibBitBlt(0x0940, HwmfFill.WmfDibBitBlt.class),
dibStretchBlt(0x0b41, HwmfFill.WmfDibStretchBlt.class),
stretchDib(0x0f43, HwmfFill.WmfStretchDib.class),
deleteObject(0x01f0, HwmfMisc.WmfDeleteObject.class),
createPalette(0x00f7, HwmfPalette.WmfCreatePalette.class),
createPatternBrush(0x01f9, HwmfMisc.WmfCreatePatternBrush.class),
createPenIndirect(0x02fa, HwmfMisc.WmfCreatePenIndirect.class),
createFontIndirect(0x02fb, HwmfText.WmfCreateFontIndirect.class),
createBrushIndirect(0x02fc, HwmfMisc.WmfCreateBrushIndirect.class),
createRegion(0x06ff, HwmfWindowing.WmfCreateRegion.class);
public int id;
public Class<? extends HwmfRecord> clazz;
HwmfRecordType(int id, Class<? extends HwmfRecord> clazz) {
this.id = id;
this.clazz = clazz;
}
public static HwmfRecordType getById(int id) {
for (HwmfRecordType wrt : values()) {
if (wrt.id == id) return wrt;
}
return null;
}
}

View File

@ -0,0 +1,336 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
public enum HwmfTernaryRasterOp {
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;
HwmfTernaryRasterOp(int opIndex, int opCode, String opCmd) {
this.opIndex=opIndex;
this.opCode=opCode;
this.opCmd=opCmd;
}
public static HwmfTernaryRasterOp fromOpIndex(int opIndex) {
for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {
if (bb.opIndex == opIndex) {
return bb;
}
}
return null;
}
public String describeCmd() {
String stack[] = new String[10];
int stackPnt = 0;
for (char c : opCmd.toCharArray()) {
switch (c) {
case 'S':
case 'D':
case 'P':
stack[stackPnt++] = ""+c;
break;
case 'n':
stack[stackPnt-1] = "not("+stack[stackPnt-1]+")";
break;
case 'a':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" and "+stack[stackPnt-2]+")";
stackPnt--;
break;
case 'o':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" or "+stack[stackPnt-2]+")";
stackPnt--;
break;
case 'x':
stack[stackPnt-2] = "("+stack[stackPnt-1]+" xor "+stack[stackPnt-2]+")";
stackPnt--;
break;
case '1':
stack[stackPnt++] = "all white";
break;
case '0':
stack[stackPnt++] = "all black";
break;
default:
throw new RuntimeException("unknown cmd '"+c+"'.");
}
}
return stack[--stackPnt];
}
}

View File

@ -0,0 +1,347 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfText {
/**
* 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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
HwmfColorRef colorRef;
public HwmfRecordType getRecordType() {
return HwmfRecordType.setTextColor;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
colorRef = new HwmfColorRef();
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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.setTextAlign;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
textAlignmentMode = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
public static class WmfCreateFontIndirect implements HwmfRecord {
HwmfFont font;
public HwmfRecordType getRecordType() {
return HwmfRecordType.createFontIndirect;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
font = new HwmfFont();
return font.init(leis);
}
}
}

View File

@ -0,0 +1,549 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.record;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfWindowing {
/**
* The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the
* specified offsets.
*/
public static class WmfOffsetClipRgn implements HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* 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 HwmfRecordType getRecordType() {
return HwmfRecordType.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 HwmfRecord {
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be clipped.
*/
int region;
public HwmfRecordType getRecordType() {
return HwmfRecordType.selectClipRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
region = leis.readShort();
return LittleEndianConsts.SHORT_SIZE;
}
}
public static class WmfScanObject {
/**
* A 16-bit unsigned integer that specifies the number of horizontal (x-axis)
* coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right
* endpoints are required to specify each scanline.
*/
int count;
/**
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline.
*/
int top;
/**
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline.
*/
int bottom;
/**
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,
* in logical units, of the left endpoint of the scanline.
*/
int left_scanline[];
/**
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,
* in logical units, of the right endpoint of the scanline.
*/
int right_scanline[];
/**
* A 16-bit unsigned integer that MUST be the same as the value of the Count
* field; it is present to allow upward travel in the structure.
*/
int count2;
public int init(LittleEndianInputStream leis) {
count = leis.readUShort();
top = leis.readUShort();
bottom = leis.readUShort();
left_scanline = new int[count];
right_scanline = new int[count];
for (int i=0; i*2<count; i++) {
left_scanline[i] = leis.readUShort();
right_scanline[i] = leis.readUShort();
}
count2 = leis.readUShort();
return 8 + count*4;
}
}
public static class WmfCreateRegion implements HwmfRecord {
/**
* A 16-bit signed integer. A value that MUST be ignored.
*/
int nextInChain;
/**
* A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006.
*/
int objectType;
/**
* A 32-bit unsigned integer. A value that MUST be ignored.
*/
int objectCount;
/**
* A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes.
*/
int regionSize;
/**
* A 16-bit signed integer that defines the number of scanlines composing the region.
*/
int scanCount;
/**
* A 16-bit signed integer that defines the maximum number of points in any one scan in this region.
*/
int maxScan;
/**
* 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;
/**
* An array of Scan objects that define the scanlines in the region.
*/
WmfScanObject scanObjects[];
public HwmfRecordType getRecordType() {
return HwmfRecordType.createRegion;
}
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
nextInChain = leis.readShort();
objectType = leis.readShort();
objectCount = leis.readUShort();
regionSize = leis.readShort();
scanCount = leis.readShort();
maxScan = leis.readShort();
bottom = leis.readShort();
right = leis.readShort();
top = leis.readShort();
left = leis.readShort();
List<WmfScanObject> soList = new ArrayList<WmfScanObject>();
int scanCountI = 0, size = 0;
do {
WmfScanObject so = new WmfScanObject();
size += so.init(leis);
scanCountI += so.count;
soList.add(so);
} while (scanCountI < scanCount);
scanObjects = soList.toArray(new WmfScanObject[soList.size()]);
return 20 + size;
}
}
}

View File

@ -0,0 +1,75 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf.usermodel;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.poi.hwmf.record.HwmfHeader;
import org.apache.poi.hwmf.record.HwmfPlaceableHeader;
import org.apache.poi.hwmf.record.HwmfRecord;
import org.apache.poi.hwmf.record.HwmfRecordType;
import org.apache.poi.util.LittleEndianInputStream;
public class HwmfPicture {
List<HwmfRecord> records = new ArrayList<HwmfRecord>();
public List<HwmfRecord> getRecords() {
return Collections.unmodifiableList(records);
}
public HwmfPicture(InputStream inputStream) throws IOException {
LittleEndianInputStream leis = new LittleEndianInputStream(inputStream);
HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);
HwmfHeader header = new HwmfHeader(leis);
for (;;) {
// recordSize in DWORDs
long recordSize = leis.readUInt()*2;
int recordFunction = leis.readShort();
// 4 bytes (recordSize) + 2 bytes (recordFunction)
int consumedSize = 6;
HwmfRecordType wrt = HwmfRecordType.getById(recordFunction);
if (wrt == null) {
throw new IOException("unexpected record type: "+recordFunction);
}
if (wrt == HwmfRecordType.eof) break;
if (wrt.clazz == null) {
throw new IOException("unsupported record type: "+recordFunction);
}
HwmfRecord wr;
try {
wr = wrt.clazz.newInstance();
records.add(wr);
} catch (Exception e) {
throw (IOException)new IOException("can't create wmf record").initCause(e);
}
consumedSize += wr.init(leis, recordSize, recordFunction);
if (consumedSize < recordSize) {
leis.skip(recordSize - consumedSize);
}
}
}
}

View File

@ -0,0 +1,42 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hwmf;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hwmf.record.HwmfRecord;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.junit.Test;
public class TestHwmfParsing {
@Test
public void parse() throws IOException {
File f = POIDataSamples.getSlideShowInstance().getFile("santa.wmf");
FileInputStream fis = new FileInputStream(f);
HwmfPicture wmf = new HwmfPicture(fis);
fis.close();
List<HwmfRecord> records = wmf.getRecords();
assertEquals(581, records.size());
}
}