From: Andreas Beeker Date: Mon, 21 Dec 2015 01:26:39 +0000 (+0000) Subject: #56004 - Support for WMF rendering (parsing the WMF records) X-Git-Tag: REL_3_14_FINAL~174 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=70d75027d3013e0e812b8fa746026fae3dcdb04e;p=poi.git #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 --- diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java new file mode 100644 index 0000000000..52ea1d9f14 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmap16.java @@ -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> 4) << 1) * height; + assert (bytes == size2); + + size += size2; + + + return size; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java new file mode 100644 index 0000000000..c3317d1dc3 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java @@ -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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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. + *
+ * 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 colorList = new ArrayList(); + for (int i=0; i>(7-j))&1); + } + break; + case BI_BITCOUNT_2: + wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, (v>>4)&15); + pixel++; + if (pixel> 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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java new file mode 100644 index 0000000000..5568e2b144 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBrushStyle.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java new file mode 100644 index 0000000000..9a5288feae --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfColorRef.java @@ -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; + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java new file mode 100644 index 0000000000..81526dd0b6 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java @@ -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 ((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; + } + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java new file mode 100644 index 0000000000..af6703ef0c --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java new file mode 100644 index 0000000000..18922bfe71 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java @@ -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; + } +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java new file mode 100644 index 0000000000..a36cfd4d90 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHeader.java @@ -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); + } + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java new file mode 100644 index 0000000000..ef539fb209 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java @@ -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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
BrushStyleColorRefBrushHatch
BS_SOLIDSHOULD be a ColorRef Object, which determines the color of the brush.Not used, and SHOULD be ignored.
BS_NULLNot used, and SHOULD be ignored.Not used, and SHOULD be ignored.
BS_PATTERNNot used, and SHOULD be ignored.Not used. A default object, such as a solidcolor black Brush Object, MAY be created.
BS_DIBPATTERNNot used, and SHOULD be ignored.Not used. A default object, such as a solidcolor black Brush Object, MAY be created
BS_DIBPATTERNPTNot used, and SHOULD be ignored.Not used. A default object, such as a solidcolor black Brush Object, MAY be created.
BS_HATCHEDSHOULD be a ColorRef Object, which determines the foreground color of the hatch pattern.A value from the {@link HwmfHatchStyle} Enumeration that specifies the orientation of lines used to create the hatch.
+ */ + 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; + } + } +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java new file mode 100644 index 0000000000..cbd0a60119 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java @@ -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; iInside the Windows Meta File Format + */ +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 clazz; + + HwmfRecordType(int id, Class 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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java new file mode 100644 index 0000000000..315eb11613 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java @@ -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]; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java new file mode 100644 index 0000000000..84dc4b1c03 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java @@ -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 soList = new ArrayList(); + 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; + } + } +} diff --git a/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java new file mode 100644 index 0000000000..b99b6b00d9 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java @@ -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 records = new ArrayList(); + + public List 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); + } + } + } + + +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java new file mode 100644 index 0000000000..ac5d6c016f --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java @@ -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 records = wmf.getRecords(); + assertEquals(581, records.size()); + } +}