--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.draw;\r
+\r
+import java.awt.Color;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+\r
+import org.apache.poi.hwmf.record.HwmfBrushStyle;\r
+import org.apache.poi.hwmf.record.HwmfColorRef;\r
+import org.apache.poi.hwmf.record.HwmfFill.WmfSetPolyfillMode.HwmfPolyfillMode;\r
+import org.apache.poi.hwmf.record.HwmfHatchStyle;\r
+import org.apache.poi.hwmf.record.HwmfMapMode;\r
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle;\r
+\r
+public class HwmfDrawProperties {\r
+ private Rectangle2D window = new Rectangle2D.Double(0, 0, 1, 1);\r
+ private Rectangle2D viewport = new Rectangle2D.Double(0, 0, 1, 1);\r
+ private Point2D location = new Point2D.Double(0,0);\r
+ private HwmfMapMode mapMode = HwmfMapMode.MM_ANISOTROPIC;\r
+ private HwmfColorRef backgroundColor = new HwmfColorRef(Color.BLACK);\r
+ private HwmfBrushStyle brushStyle = HwmfBrushStyle.BS_SOLID;\r
+ private HwmfColorRef brushColor = new HwmfColorRef(Color.BLACK);\r
+ private HwmfHatchStyle brushHatch = HwmfHatchStyle.HS_HORIZONTAL;\r
+ private BufferedImage brushBitmap = null;\r
+ private double penWidth = 1;\r
+ private HwmfPenStyle penStyle = HwmfPenStyle.valueOf(0);\r
+ private HwmfColorRef penColor = new HwmfColorRef(Color.BLACK);\r
+ private double penMiterLimit = 10;\r
+ private HwmfBkMode bkMode = HwmfBkMode.OPAQUE;\r
+ private HwmfPolyfillMode polyfillMode = HwmfPolyfillMode.WINDING;\r
+\r
+ public void setViewportExt(double width, double height) {\r
+ double x = viewport.getX();\r
+ double y = viewport.getY();\r
+ double w = (width != 0) ? width : viewport.getWidth();\r
+ double h = (height != 0) ? height : viewport.getHeight();\r
+ viewport.setRect(x, y, w, h);\r
+ }\r
+\r
+ public void setViewportOrg(double x, double y) {\r
+ double w = viewport.getWidth();\r
+ double h = viewport.getHeight();\r
+ viewport.setRect(x, y, w, h);\r
+ }\r
+\r
+ public Rectangle2D getViewport() {\r
+ return (Rectangle2D)viewport.clone();\r
+ }\r
+\r
+ public void setWindowExt(double width, double height) {\r
+ double x = window.getX();\r
+ double y = window.getY();\r
+ double w = (width != 0) ? width : window.getWidth();\r
+ double h = (height != 0) ? height : window.getHeight();\r
+ window.setRect(x, y, w, h);\r
+ }\r
+\r
+ public void setWindowOrg(double x, double y) {\r
+ double w = window.getWidth();\r
+ double h = window.getHeight();\r
+ window.setRect(x, y, w, h);\r
+ }\r
+\r
+ public Rectangle2D getWindow() {\r
+ return (Rectangle2D)window.clone();\r
+ }\r
+\r
+ public void setLocation(double x, double y) {\r
+ location.setLocation(x, y);\r
+ }\r
+\r
+ public Point2D getLocation() {\r
+ return (Point2D)location.clone();\r
+ }\r
+\r
+ public void setMapMode(HwmfMapMode mapMode) {\r
+ this.mapMode = mapMode;\r
+ }\r
+\r
+ public HwmfMapMode getMapMode() {\r
+ return mapMode;\r
+ }\r
+\r
+ public HwmfBrushStyle getBrushStyle() {\r
+ return brushStyle;\r
+ }\r
+\r
+ public void setBrushStyle(HwmfBrushStyle brushStyle) {\r
+ this.brushStyle = brushStyle;\r
+ }\r
+\r
+ public HwmfHatchStyle getBrushHatch() {\r
+ return brushHatch;\r
+ }\r
+\r
+ public void setBrushHatch(HwmfHatchStyle brushHatch) {\r
+ this.brushHatch = brushHatch;\r
+ }\r
+\r
+ public HwmfColorRef getBrushColor() {\r
+ return brushColor;\r
+ }\r
+\r
+ public void setBrushColor(HwmfColorRef brushColor) {\r
+ this.brushColor = brushColor;\r
+ }\r
+\r
+ public HwmfBkMode getBkMode() {\r
+ return bkMode;\r
+ }\r
+\r
+ public void setBkMode(HwmfBkMode bkMode) {\r
+ this.bkMode = bkMode;\r
+ }\r
+\r
+ public HwmfPenStyle getPenStyle() {\r
+ return penStyle;\r
+ }\r
+\r
+ public void setPenStyle(HwmfPenStyle penStyle) {\r
+ this.penStyle = penStyle;\r
+ }\r
+\r
+ public HwmfColorRef getPenColor() {\r
+ return penColor;\r
+ }\r
+\r
+ public void setPenColor(HwmfColorRef penColor) {\r
+ this.penColor = penColor;\r
+ }\r
+\r
+ public double getPenWidth() {\r
+ return penWidth;\r
+ }\r
+\r
+ public void setPenWidth(double penWidth) {\r
+ this.penWidth = penWidth;\r
+ }\r
+\r
+ public double getPenMiterLimit() {\r
+ return penMiterLimit;\r
+ }\r
+\r
+ public void setPenMiterLimit(double penMiterLimit) {\r
+ this.penMiterLimit = penMiterLimit;\r
+ }\r
+\r
+ public HwmfColorRef getBackgroundColor() {\r
+ return backgroundColor;\r
+ }\r
+\r
+ public void setBackgroundColor(HwmfColorRef backgroundColor) {\r
+ this.backgroundColor = backgroundColor;\r
+ }\r
+\r
+ public HwmfPolyfillMode getPolyfillMode() {\r
+ return polyfillMode;\r
+ }\r
+\r
+ public void setPolyfillMode(HwmfPolyfillMode polyfillMode) {\r
+ this.polyfillMode = polyfillMode;\r
+ }\r
+\r
+ public BufferedImage getBrushBitmap() {\r
+ return brushBitmap;\r
+ }\r
+\r
+ public void setBrushBitmap(BufferedImage brushBitmap) {\r
+ this.brushBitmap = brushBitmap;\r
+ }\r
+}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.draw;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.Paint;\r
+import java.awt.Rectangle;\r
+import java.awt.Shape;\r
+import java.awt.TexturePaint;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.Rectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.util.ArrayDeque;\r
+import java.util.Deque;\r
+\r
+import org.apache.poi.hwmf.record.HwmfBrushStyle;\r
+import org.apache.poi.hwmf.record.HwmfHatchStyle;\r
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle;\r
+import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;\r
+import org.apache.poi.util.Units;\r
+\r
+public class HwmfGraphics {\r
+ private final Graphics2D graphicsCtx;\r
+ private final Deque<HwmfDrawProperties> propStack = new ArrayDeque<HwmfDrawProperties>();\r
+ HwmfDrawProperties prop;\r
+\r
+ public HwmfGraphics(Graphics2D graphicsCtx) {\r
+ this.graphicsCtx = graphicsCtx;\r
+ prop = new HwmfDrawProperties();\r
+ propStack.push(prop);\r
+ }\r
+\r
+ public HwmfDrawProperties getProperties() {\r
+ return prop;\r
+ }\r
+\r
+ public void draw(Shape shape) {\r
+ HwmfLineDash lineDash = prop.getPenStyle().getLineDash();\r
+ if (lineDash == HwmfLineDash.NULL) {\r
+ // line is not drawn\r
+ return;\r
+ }\r
+\r
+ Shape tshape = fitShapeToView(shape);\r
+ BasicStroke stroke = getStroke();\r
+\r
+ // first draw a solid background line (depending on bkmode)\r
+ // only makes sense if the line is not solid\r
+ if (prop.getBkMode() == HwmfBkMode.OPAQUE && (lineDash != HwmfLineDash.SOLID && lineDash != HwmfLineDash.INSIDEFRAME)) {\r
+ graphicsCtx.setStroke(new BasicStroke(stroke.getLineWidth()));\r
+ graphicsCtx.setColor(prop.getBackgroundColor().getColor());\r
+ graphicsCtx.draw(tshape);\r
+ }\r
+\r
+ // then draw the (dashed) line\r
+ graphicsCtx.setStroke(stroke);\r
+ graphicsCtx.setColor(prop.getPenColor().getColor());\r
+ graphicsCtx.draw(tshape);\r
+ }\r
+\r
+ public void fill(Shape shape) {\r
+ if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {\r
+ GeneralPath gp = new GeneralPath(shape);\r
+ gp.setWindingRule(prop.getPolyfillMode().awtFlag);\r
+ Shape tshape = fitShapeToView(gp);\r
+ graphicsCtx.setPaint(getFill());\r
+ graphicsCtx.fill(tshape);\r
+ }\r
+\r
+ draw(shape);\r
+ }\r
+\r
+ protected Shape fitShapeToView(Shape shape) {\r
+ int scaleUnits = prop.getMapMode().scale;\r
+ Rectangle2D view = prop.getViewport(), win = prop.getWindow();\r
+ double scaleX, scaleY;\r
+ switch (scaleUnits) {\r
+ case -1:\r
+ scaleX = view.getWidth() / win.getWidth();\r
+ scaleY = view.getHeight() / win.getHeight();\r
+ break;\r
+ case 0:\r
+ scaleX = scaleY = 1;\r
+ break;\r
+ default:\r
+ scaleX = scaleY = scaleUnits / (double)Units.POINT_DPI;\r
+ }\r
+\r
+ AffineTransform at = new AffineTransform();\r
+ at.translate(view.getX(), view.getY());\r
+ at.scale(scaleX, scaleY);\r
+ at.translate(-win.getX(), -win.getY());\r
+ at.translate(-view.getX(), -view.getY());\r
+\r
+ return at.createTransformedShape(shape);\r
+ }\r
+\r
+ protected BasicStroke getStroke() {\r
+ Rectangle2D view = prop.getViewport(), win = prop.getWindow();\r
+ float width = (float)(prop.getPenWidth() * view.getWidth() / win.getWidth());\r
+ HwmfPenStyle ps = prop.getPenStyle();\r
+ int cap = ps.getLineCap().awtFlag;\r
+ int join = ps.getLineJoin().awtFlag;\r
+ float miterLimit = (float)prop.getPenMiterLimit();\r
+ float dashes[] = ps.getLineDash().dashes;\r
+ boolean dashAlt = ps.isAlternateDash();\r
+ // This value is not an integer index into the dash pattern array.\r
+ // Instead, it is a floating-point value that specifies a linear distance.\r
+ float dashStart = (dashAlt && dashes.length > 1) ? dashes[0] : 0;\r
+\r
+ return new BasicStroke(width, cap, join, miterLimit, dashes, dashStart);\r
+ }\r
+\r
+ protected Paint getFill() {\r
+ switch (prop.getBrushStyle()) {\r
+ default:\r
+ case BS_INDEXED:\r
+ case BS_PATTERN8X8:\r
+ case BS_DIBPATTERN8X8:\r
+ case BS_MONOPATTERN:\r
+ case BS_NULL: return null;\r
+ case BS_PATTERN:\r
+ case BS_DIBPATTERN:\r
+ case BS_DIBPATTERNPT: return getPatternPaint();\r
+ case BS_SOLID: return getSolidFill();\r
+ case BS_HATCHED: return getHatchedFill();\r
+ }\r
+ }\r
+\r
+ protected Paint getSolidFill() {\r
+ return prop.getBrushColor().getColor();\r
+ }\r
+\r
+ protected Paint getHatchedFill() {\r
+ int dim = 7, mid = 3;\r
+ BufferedImage bi = new BufferedImage(dim, dim, BufferedImage.TYPE_4BYTE_ABGR);\r
+ Graphics2D g = bi.createGraphics();\r
+ Color c = (prop.getBkMode() == HwmfBkMode.TRANSPARENT)\r
+ ? new Color(0, true)\r
+ : prop.getBackgroundColor().getColor();\r
+ g.setColor(c);\r
+ g.fillRect(0, 0, dim, dim);\r
+ g.setColor(prop.getBrushColor().getColor());\r
+ HwmfHatchStyle h = prop.getBrushHatch();\r
+ if (h == HwmfHatchStyle.HS_HORIZONTAL || h == HwmfHatchStyle.HS_CROSS) {\r
+ g.drawLine(0, mid, dim, mid);\r
+ }\r
+ if (h == HwmfHatchStyle.HS_VERTICAL || h == HwmfHatchStyle.HS_CROSS) {\r
+ g.drawLine(mid, 0, mid, dim);\r
+ }\r
+ if (h == HwmfHatchStyle.HS_FDIAGONAL || h == HwmfHatchStyle.HS_DIAGCROSS) {\r
+ g.drawLine(0, 0, dim, dim);\r
+ }\r
+ if (h == HwmfHatchStyle.HS_BDIAGONAL || h == HwmfHatchStyle.HS_DIAGCROSS) {\r
+ g.drawLine(0, dim, dim, 0);\r
+ }\r
+ g.dispose();\r
+ return new TexturePaint(bi, new Rectangle(0,0,dim,dim));\r
+ }\r
+\r
+ protected Paint getPatternPaint() {\r
+ BufferedImage bi = prop.getBrushBitmap();\r
+ return (bi == null) ? null\r
+ : new TexturePaint(bi, new Rectangle(0,0,bi.getWidth(),bi.getHeight()));\r
+ }\r
+}\r
package org.apache.poi.hwmf.record;\r
\r
import java.awt.image.BufferedImage;\r
-import java.io.ByteArrayInputStream;\r
+import java.io.FileOutputStream;\r
import java.io.IOException;\r
\r
-import javax.imageio.stream.ImageInputStream;\r
-import javax.imageio.stream.MemoryCacheImageInputStream;\r
-\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
assert(skipSize == 18);\r
size += 18+LittleEndianConsts.INT_SIZE;\r
}\r
+\r
+ int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;\r
+ byte buf[] = new byte[bytes];\r
+ leis.read(buf);\r
\r
- BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+ FileOutputStream fos = new FileOutputStream("bla16.bmp");\r
+ fos.write(buf);\r
+ fos.close();\r
\r
- int size2 = 0;\r
- byte buf[] = new byte[widthBytes];\r
- for (int h=0; h<height; h++) {\r
- leis.read(buf);\r
- size2 += widthBytes;\r
-\r
- ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));\r
-\r
- for (int w=0; w<width; w++) {\r
- long bitsAtPixel = iis.readBits(bitsPixel);\r
- // TODO: is bitsPixel a multiple of 3 (r,g,b)\r
- // which colortable should be used for the various bit sizes???\r
- \r
- }\r
- }\r
\r
- int bytes = (((width * bitsPixel + 15) >> 4) << 1) * height;\r
- assert (bytes == size2);\r
-\r
- size += size2;\r
+// BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
+// \r
+// int size2 = 0;\r
+// byte buf[] = new byte[widthBytes];\r
+// for (int h=0; h<height; h++) {\r
+// leis.read(buf);\r
+// size2 += widthBytes;\r
+//\r
+// ImageInputStream iis = new MemoryCacheImageInputStream(new ByteArrayInputStream(buf));\r
+//\r
+// for (int w=0; w<width; w++) {\r
+// long bitsAtPixel = iis.readBits(bitsPixel);\r
+// // TODO: is bitsPixel a multiple of 3 (r,g,b)\r
+// // which colortable should be used for the various bit sizes???\r
+// \r
+// }\r
+// }\r
+// \r
+// assert (bytes == size2);\r
+//\r
+// size += size2;\r
\r
\r
return size;\r
}\r
+\r
+ public BufferedImage getImage() {\r
+ BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);\r
+ return bi;\r
+ }\r
+\r
}\r
\r
import java.awt.Color;\r
import java.awt.image.BufferedImage;\r
-import java.awt.image.IndexColorModel;\r
-import java.awt.image.WritableRaster;\r
+import java.io.BufferedInputStream;\r
+import java.io.ByteArrayInputStream;\r
import java.io.IOException;\r
import java.util.ArrayList;\r
import java.util.List;\r
\r
+import javax.imageio.ImageIO;\r
+\r
+import org.apache.poi.hssf.record.RecordFormatException;\r
+import org.apache.poi.util.LittleEndian;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
* Each pixel in the bitmap is represented by a 16-bit value.\r
* <br/>\r
* If the Compression field of the BitmapInfoHeader Object is BI_RGB, the Colors field of DIB\r
- * is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of \r
- * red, green, and blue are represented with 5 bits for each color component. The value for blue \r
- * is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant \r
- * bit is not used. The color table is used for optimizing colors on palette-based devices, and \r
- * contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+ * is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of\r
+ * red, green, and blue are represented with 5 bits for each color component. The value for blue\r
+ * is in the least significant 5 bits, followed by 5 bits each for green and red. The most significant\r
+ * bit is not used. The color table is used for optimizing colors on palette-based devices, and\r
+ * contains the number of entries specified by the ColorUsed field of the BitmapInfoHeader\r
* Object.\r
* <br/>\r
- * If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field \r
+ * If the Compression field of the BitmapInfoHeader Object is BI_BITFIELDS, the Colors field\r
* contains three DWORD color masks that specify the red, green, and blue components,\r
* respectively, of each pixel. Each WORD in the bitmap array represents a single pixel.\r
* <br/>\r
- * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be \r
+ * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask MUST be\r
* contiguous and SHOULD NOT overlap the bits of another mask.\r
*/\r
BI_BITCOUNT_4(0x0010),\r
/**\r
- * The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is \r
- * NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, \r
- * and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on \r
+ * The bitmap has a maximum of 2^24 colors, and the Colors field of DIB is\r
+ * NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green,\r
+ * and red, respectively, for a pixel. The Colors color table is used for optimizing colors used on\r
* palette-based devices, and MUST contain the number of entries specified by the ColorUsed\r
* field of the BitmapInfoHeader Object.\r
*/\r
/**\r
* The bitmap has a maximum of 2^24 colors.\r
* <br/>\r
- * If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field \r
- * of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of \r
- * blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The \r
- * Colors color table is used for optimizing colors used on palette-based devices, and MUST \r
- * contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader \r
+ * If the Compression field of the BitmapInfoHeader Object is set to BI_RGB, the Colors field\r
+ * of DIB is set to NULL. Each DWORD in the bitmap array represents the relative intensities of\r
+ * blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The\r
+ * Colors color table is used for optimizing colors used on palette-based devices, and MUST\r
+ * contain the number of entries specified by the ColorUsed field of the BitmapInfoHeader\r
* Object.\r
* <br/>\r
* If the Compression field of the BitmapInfoHeader Object is set to BI_BITFIELDS, the Colors\r
- * field contains three DWORD color masks that specify the red, green, and blue components, \r
+ * field contains three DWORD color masks that specify the red, green, and blue components,\r
* respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.\r
* <br/>\r
- * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be \r
- * contiguous and should not overlap the bits of another mask. All the bits in the pixel do not \r
+ * When the Compression field is set to BI_BITFIELDS, bits set in each DWORD mask must be\r
+ * contiguous and should not overlap the bits of another mask. All the bits in the pixel do not\r
* need to be used.\r
*/\r
BI_BITCOUNT_6(0x0020);\r
- \r
+\r
int flag;\r
BitCount(int flag) {\r
this.flag = flag;\r
*/\r
BI_BITFIELDS(0x0003),\r
/**\r
- * The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in \r
- * certain bitmap operations, such as JPEG pass-through. The application MUST query for the \r
- * pass-through support, since not all devices support JPEG pass-through. Using non-RGB \r
- * bitmaps MAY limit the portability of the metafile to other devices. For instance, display device \r
+ * The image is a JPEG image, as specified in [JFIF]. This value SHOULD only be used in\r
+ * certain bitmap operations, such as JPEG pass-through. The application MUST query for the\r
+ * pass-through support, since not all devices support JPEG pass-through. Using non-RGB\r
+ * bitmaps MAY limit the portability of the metafile to other devices. For instance, display device\r
* contexts generally do not support this pass-through.\r
*/\r
BI_JPEG(0x0004),\r
/**\r
- * The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be \r
- * used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query \r
- * for the pass-through support, because not all devices support JPEG/PNG pass-through. Using \r
- * non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance, \r
+ * The image is a PNG image, as specified in [RFC2083]. This value SHOULD only be\r
+ * used certain bitmap operations, such as JPEG/PNG pass-through. The application MUST query\r
+ * for the pass-through support, because not all devices support JPEG/PNG pass-through. Using\r
+ * non-RGB bitmaps MAY limit the portability of the metafile to other devices. For instance,\r
* display device contexts generally do not support this pass-through.\r
*/\r
BI_PNG(0x0005),\r
* color indexes.\r
*/\r
BI_CMYKRLE4(0x000D);\r
- \r
+\r
int flag;\r
Compression(int flag) {\r
this.flag = flag;\r
if (c.flag == flag) return c;\r
}\r
return null;\r
- } \r
+ }\r
}\r
+\r
+ private static final int BMP_HEADER_SIZE = 14;\r
\r
- \r
- int headerSize;\r
- int headerWidth;\r
- int headerHeight;\r
- int headerPlanes;\r
- BitCount headerBitCount;\r
- Compression headerCompression;\r
- long headerImageSize = -1;\r
- int headerXPelsPerMeter = -1;\r
- int headerYPelsPerMeter = -1;\r
- long headerColorUsed = -1;\r
- long headerColorImportant = -1;\r
- \r
- Color colorTable[];\r
- int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;\r
- \r
- public int init(LittleEndianInputStream leis) throws IOException {\r
- int size = 0;\r
- size += readHeader(leis);\r
- size += readColors(leis);\r
- int size2;\r
- switch (headerBitCount) {\r
- default:\r
- case BI_BITCOUNT_0:\r
- throw new RuntimeException("JPG and PNG formats aren't supported yet.");\r
- case BI_BITCOUNT_1:\r
- case BI_BITCOUNT_2:\r
- case BI_BITCOUNT_3:\r
- size2 = readBitmapIndexed(leis);\r
- break;\r
- case BI_BITCOUNT_4:\r
- case BI_BITCOUNT_5:\r
- case BI_BITCOUNT_6:\r
- size2 = readBitmapDirect(leis);\r
- break;\r
- }\r
+ private int headerSize;\r
+ private int headerWidth;\r
+ private int headerHeight;\r
+ private int headerPlanes;\r
+ private BitCount headerBitCount;\r
+ private Compression headerCompression;\r
+ private long headerImageSize = -1;\r
+ @SuppressWarnings("unused")\r
+ private int headerXPelsPerMeter = -1;\r
+ @SuppressWarnings("unused")\r
+ private int headerYPelsPerMeter = -1;\r
+ private long headerColorUsed = -1;\r
+ @SuppressWarnings("unused")\r
+ private long headerColorImportant = -1;\r
+\r
+ @SuppressWarnings("unused")\r
+ private Color colorTable[];\r
+ @SuppressWarnings("unused")\r
+ private int colorMaskRed=0,colorMaskGreen=0,colorMaskBlue=0;\r
+\r
+ // size of header and color table, for start of image data calculation\r
+ private int introSize;\r
+ private byte imageData[];\r
+\r
+ public int init(LittleEndianInputStream leis, int recordSize) throws IOException {\r
+ leis.mark(10000);\r
\r
- assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == size2);\r
- assert ( headerSize == 0x0C || headerImageSize == size2 );\r
+ // need to read the header to calculate start of bitmap data correct\r
+ introSize = readHeader(leis);\r
+ assert(introSize == headerSize);\r
+ introSize += readColors(leis);\r
+ assert(introSize < 10000);\r
+\r
+ int fileSize = (headerImageSize != 0) ? (int)(introSize+headerImageSize) : recordSize;\r
\r
- size += size2;\r
+ imageData = new byte[fileSize];\r
+ leis.reset();\r
+ leis.read(imageData, 0, fileSize);\r
\r
- return size;\r
+ assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == headerImageSize);\r
+\r
+ return fileSize;\r
}\r
\r
protected int readHeader(LittleEndianInputStream leis) throws IOException {\r
int size = 0;\r
- \r
+\r
/**\r
* DIBHeaderInfo (variable): Either a BitmapCoreHeader Object or a\r
* BitmapInfoHeader Object that specifies information about the image.\r
- * \r
+ *\r
* The first 32 bits of this field is the HeaderSize value.\r
* If it is 0x0000000C, then this is a BitmapCoreHeader; otherwise, this is a BitmapInfoHeader.\r
*/\r
headerSize = leis.readInt();\r
size += LittleEndianConsts.INT_SIZE;\r
- \r
- // BitmapCoreHeader\r
- // A 16-bit unsigned integer that defines the width of the DIB, in pixels.\r
- headerWidth = leis.readUShort();\r
- // A 16-bit unsigned integer that defines the height of the DIB, in pixels.\r
- headerHeight = leis.readUShort();\r
- // A 16-bit unsigned integer that defines the number of planes for the target\r
- // device. This value MUST be 0x0001.\r
- headerPlanes = leis.readUShort();\r
- // A 16-bit unsigned integer that defines the format of each pixel, and the\r
- // maximum number of colors in the DIB.\r
- headerBitCount = BitCount.valueOf(leis.readUShort());\r
- size += 4*LittleEndianConsts.SHORT_SIZE;\r
\r
- if (headerSize > 0x0C) {\r
+ if (headerSize == 0x0C) {\r
+ // BitmapCoreHeader\r
+ // A 16-bit unsigned integer that defines the width of the DIB, in pixels.\r
+ headerWidth = leis.readUShort();\r
+ // A 16-bit unsigned integer that defines the height of the DIB, in pixels.\r
+ headerHeight = leis.readUShort();\r
+ // A 16-bit unsigned integer that defines the number of planes for the target\r
+ // device. This value MUST be 0x0001.\r
+ headerPlanes = leis.readUShort();\r
+ // A 16-bit unsigned integer that defines the format of each pixel, and the\r
+ // maximum number of colors in the DIB.\r
+ headerBitCount = BitCount.valueOf(leis.readUShort());\r
+ size += 4*LittleEndianConsts.SHORT_SIZE;\r
+ } else {\r
// BitmapInfoHeader\r
- // A 32-bit unsigned integer that defines the compression mode of the \r
- // DIB. \r
+ // A 32-bit signed integer that defines the width of the DIB, in pixels.\r
+ // This value MUST be positive.\r
+ // This field SHOULD specify the width of the decompressed image file,\r
+ // if the Compression value specifies JPEG or PNG format.\r
+ headerWidth = leis.readInt();\r
+ // A 32-bit signed integer that defines the height of the DIB, in pixels.\r
+ // This value MUST NOT be zero.\r
+ // - If this value is positive, the DIB is a bottom-up bitmap,\r
+ // and its origin is the lower-left corner.\r
+ // This field SHOULD specify the height of the decompressed image file,\r
+ // if the Compression value specifies JPEG or PNG format.\r
+ // - If this value is negative, the DIB is a top-down bitmap,\r
+ // and its origin is the upper-left corner. Top-down bitmaps do not support compression.\r
+ headerHeight = leis.readInt();\r
+ // A 16-bit unsigned integer that defines the number of planes for the target\r
+ // device. This value MUST be 0x0001.\r
+ headerPlanes = leis.readUShort();\r
+ // A 16-bit unsigned integer that defines the format of each pixel, and the\r
+ // maximum number of colors in the DIB.\r
+ headerBitCount = BitCount.valueOf(leis.readUShort());\r
+ // A 32-bit unsigned integer that defines the compression mode of the DIB.\r
// This value MUST NOT specify a compressed format if the DIB is a top-down bitmap,\r
// as indicated by the Height value.\r
headerCompression = Compression.valueOf((int)leis.readUInt());\r
// A 32-bit unsigned integer that defines the size, in bytes, of the image.\r
// If the Compression value is BI_RGB, this value SHOULD be zero and MUST be ignored.\r
- // If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG \r
+ // If the Compression value is BI_JPEG or BI_PNG, this value MUST specify the size of the JPEG\r
// or PNG image buffer, respectively.\r
headerImageSize = leis.readUInt();\r
- // A 32-bit signed integer that defines the horizontal resolution, \r
+ // A 32-bit signed integer that defines the horizontal resolution,\r
// in pixels-per-meter, of the target device for the DIB.\r
headerXPelsPerMeter = leis.readInt();\r
// A 32-bit signed integer that defines the vertical resolution,\r
// A 32-bit unsigned integer that defines the number of color indexes that are\r
// required for displaying the DIB. If this value is zero, all color indexes are required.\r
headerColorImportant = leis.readUInt();\r
- size += 6*LittleEndianConsts.INT_SIZE;\r
+ size += 8*LittleEndianConsts.INT_SIZE+2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+ assert(size == headerSize);\r
return size;\r
}\r
\r
return readRGBQuad(leis, 16);\r
case BI_BITCOUNT_3:\r
// 256 colors\r
- return readRGBQuad(leis, 256);\r
+ return readRGBQuad(leis, (int)headerColorUsed);\r
case BI_BITCOUNT_5:\r
colorMaskRed=0xFF;\r
colorMaskGreen=0xFF;\r
colorMaskRed = leis.readInt();\r
return 3*LittleEndianConsts.INT_SIZE;\r
}\r
- case BI_BITCOUNT_6: \r
+ case BI_BITCOUNT_6:\r
if (headerCompression == Compression.BI_RGB) {\r
colorMaskBlue = colorMaskGreen = colorMaskRed = 0xFF;\r
return 0;\r
}\r
}\r
}\r
- \r
+\r
protected int readRGBQuad(LittleEndianInputStream leis, int count) throws IOException {\r
int size = 0;\r
List<Color> colorList = new ArrayList<Color>();\r
colorTable = colorList.toArray(new Color[colorList.size()]);\r
return size;\r
}\r
- \r
- protected int readBitmapIndexed(LittleEndianInputStream leis) throws IOException {\r
- assert(colorTable != null);\r
- byte r[] = new byte[colorTable.length];\r
- byte g[] = new byte[colorTable.length];\r
- byte b[] = new byte[colorTable.length];\r
- for (int i=0; i<colorTable.length; i++) {\r
- r[i] = (byte)colorTable[i].getRed();\r
- g[i] = (byte)colorTable[i].getGreen();\r
- b[i] = (byte)colorTable[i].getBlue();\r
- }\r
- int bits = 32-Integer.numberOfLeadingZeros(colorTable.length);\r
- IndexColorModel cm = new IndexColorModel(bits,colorTable.length,r,g,b);\r
- \r
- BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_BYTE_INDEXED, cm);\r
- WritableRaster wr = bi.getRaster();\r
- \r
- int pixelCount = headerWidth*headerHeight;\r
- int size = 0;\r
- for (int pixel=0; pixel<pixelCount; size++) {\r
- int v = leis.readUByte();\r
- switch (headerBitCount) {\r
- default:\r
- throw new RuntimeException("invalid bitcount for indexed image");\r
- case BI_BITCOUNT_1:\r
- for (int j=0; j<8 && pixel<pixelCount; j++,pixel++) {\r
- wr.setSample(pixel/headerWidth,pixel%headerWidth,0,(v>>(7-j))&1);\r
- }\r
- break;\r
- case BI_BITCOUNT_2:\r
- wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, (v>>4)&15);\r
- pixel++;\r
- if (pixel<pixelCount) {\r
- wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v&15);\r
- pixel++;\r
- }\r
- break;\r
- case BI_BITCOUNT_3:\r
- wr.setSample(pixel/headerWidth, pixel%headerWidth, 0, v);\r
- pixel++;\r
- break;\r
- }\r
+\r
+ public BufferedImage getImage() {\r
+ if (imageData == null) {\r
+ throw new RecordFormatException("bitmap not initialized ... need to call init() before");\r
}\r
- return size;\r
- }\r
- \r
- protected int readBitmapDirect(LittleEndianInputStream leis) throws IOException {\r
- assert(colorTable == null);\r
- \r
- BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_RGB);\r
- WritableRaster wr = bi.getRaster();\r
+\r
+ // create the image data and leave the parsing to the ImageIO api\r
+ byte buf[] = new byte[BMP_HEADER_SIZE+imageData.length];\r
+\r
+ // https://en.wikipedia.org/wiki/BMP_file_format # Bitmap file header\r
+ buf[0] = (byte)'B';\r
+ buf[1] = (byte)'M';\r
+ // the full size of the bmp\r
+ LittleEndian.putInt(buf, 2, (int)(BMP_HEADER_SIZE + introSize + headerImageSize));\r
+ // the next 4 bytes are unused\r
+ LittleEndian.putInt(buf, 6, 0);\r
+ // start of image = BMP header length + dib header length + color tables length\r
+ LittleEndian.putInt(buf, 10, BMP_HEADER_SIZE + introSize);\r
\r
- int bitShiftRed=0,bitShiftGreen=0,bitShiftBlue=0;\r
- if (headerCompression == Compression.BI_BITFIELDS) {\r
- bitShiftGreen = 32-Integer.numberOfLeadingZeros(this.colorMaskBlue);\r
- bitShiftRed = 32-Integer.numberOfLeadingZeros(this.colorMaskGreen);\r
- }\r
+ System.arraycopy(imageData, 0, buf, BMP_HEADER_SIZE, imageData.length);\r
\r
- int pixelCount = headerWidth*headerHeight;\r
- int size = 0;\r
- int rgb[] = new int[3];\r
- for (int pixel=0; pixel<pixelCount; pixel++) {\r
- int v;\r
- switch (headerBitCount) {\r
- default:\r
- throw new RuntimeException("invalid bitcount for indexed image");\r
- case BI_BITCOUNT_4:\r
- v = leis.readUShort();\r
- rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
- rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
- rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
- size += LittleEndianConsts.SHORT_SIZE;\r
- break;\r
- case BI_BITCOUNT_5:\r
- rgb[2] = leis.readUByte();\r
- rgb[1] = leis.readUByte();\r
- rgb[0] = leis.readUByte();\r
- size += 3*LittleEndianConsts.BYTE_SIZE;\r
- break;\r
- case BI_BITCOUNT_6:\r
- v = leis.readInt();\r
- rgb[0] = (v & colorMaskRed) >> bitShiftRed;\r
- rgb[1] = (v & colorMaskGreen) >> bitShiftGreen;\r
- rgb[2] = (v & colorMaskBlue) >> bitShiftBlue;\r
- size += LittleEndianConsts.INT_SIZE;\r
- break;\r
- }\r
- wr.setPixel(pixel/headerWidth,pixel%headerWidth,rgb);\r
+ try {\r
+ return ImageIO.read(new ByteArrayInputStream(buf));\r
+ } catch (IOException e) {\r
+ // ... shouldn't happen\r
+ throw new RecordFormatException("invalid bitmap data", e);\r
}\r
- \r
- return size;\r
}\r
}\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
+/**\r
+ * A 32-bit ColorRef Object that defines the color value.\r
+ * Red (1 byte): An 8-bit unsigned integer that defines the relative intensity of red.\r
+ * Green (1 byte): An 8-bit unsigned integer that defines the relative intensity of green.\r
+ * Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.\r
+ * Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.\r
+ */\r
public class HwmfColorRef {\r
- /**\r
- * A 32-bit ColorRef Object that defines the color value.\r
- * Red (1 byte): An 8-bit unsigned integer that defines the relative intensity of red.\r
- * Green (1 byte): An 8-bit unsigned integer that defines the relative intensity of green.\r
- * Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.\r
- * Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.\r
- */\r
- Color colorRef;\r
+ private Color colorRef = Color.BLACK;\r
+ \r
+ public HwmfColorRef() {}\r
+ \r
+ public HwmfColorRef(Color colorRef) {\r
+ this.colorRef = colorRef;\r
+ }\r
\r
public int init(LittleEndianInputStream leis) throws IOException {\r
int red = leis.readUByte();\r
return 4*LittleEndianConsts.BYTE_SIZE;\r
}\r
\r
+ public Color getColor() {\r
+ return colorRef;\r
+ }\r
}\r
\r
package org.apache.poi.hwmf.record;\r
\r
+import java.awt.Polygon;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.Line2D;\r
+import java.awt.geom.Point2D;\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
* point.\r
*/\r
public static class WmfMoveTo implements HwmfRecord {\r
- \r
+\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units.\r
*/\r
- int y;\r
- \r
+ private int y;\r
+\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units.\r
*/\r
- int x;\r
- \r
+ private int x;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.moveTo;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
y = leis.readShort();\r
x = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+ \r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setLocation(x, y);\r
+ }\r
}\r
- \r
+\r
/**\r
* The META_LINETO record draws a line from the drawing position that is defined in the playback\r
* device context up to, but not including, the specified point.\r
*/\r
public static class WmfLineTo implements HwmfRecord {\r
- \r
+\r
/**\r
* A 16-bit signed integer that defines the vertical component of the drawing\r
* destination position, in logical units.\r
*/\r
- int y;\r
- \r
+ private int y;\r
+\r
/**\r
* A 16-bit signed integer that defines the horizontal component of the drawing\r
* destination position, in logical units.\r
*/\r
- int x;\r
- \r
+ private int x;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.lineTo;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
y = leis.readShort();\r
x = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+ \r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ Point2D start = ctx.getProperties().getLocation();\r
+ Line2D line = new Line2D.Double(start.getX(), start.getY(), x, y);\r
+ ctx.draw(line);\r
+ ctx.getProperties().setLocation(x, y);\r
+ }\r
}\r
- \r
+\r
/**\r
* The META_POLYGON record paints a polygon consisting of two or more vertices connected by\r
* straight lines. The polygon is outlined by using the pen and filled by using the brush and polygon fill\r
* mode that are defined in the playback device context.\r
*/\r
public static class WmfPolygon implements HwmfRecord {\r
- \r
+\r
/**\r
* A 16-bit signed integer that defines the number of points in the array.\r
*/\r
- int numberofPoints;\r
- \r
+ private int numberofPoints;\r
+\r
short xPoints[], yPoints[];\r
- \r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.polygon;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
numberofPoints = leis.readShort();\r
xPoints = new short[numberofPoints];\r
yPoints = new short[numberofPoints];\r
- \r
+\r
for (int i=0; i<numberofPoints; i++) {\r
// A 16-bit signed integer that defines the horizontal (x) coordinate of the point.\r
xPoints[i] = leis.readShort();\r
// A 16-bit signed integer that defines the vertical (y) coordinate of the point.\r
yPoints[i] = leis.readShort();\r
}\r
- \r
+\r
return LittleEndianConsts.SHORT_SIZE+numberofPoints*LittleEndianConsts.INT_SIZE;\r
}\r
+ \r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.fill(getShape());\r
+ }\r
+ \r
+ protected Polygon getShape() {\r
+ Polygon polygon = new Polygon();\r
+ for(int i = 0; i < numberofPoints; i++) {\r
+ polygon.addPoint(xPoints[i], yPoints[i]);\r
+ }\r
+ return polygon;\r
+ }\r
}\r
- \r
+\r
/**\r
* The META_POLYLINE record draws a series of line segments by connecting the points in the\r
* specified array.\r
*/\r
public static class WmfPolyline extends WmfPolygon {\r
- \r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.polyline;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.draw(getShape());\r
+ }\r
}\r
- \r
+\r
/**\r
* The META_ELLIPSE record draws an ellipse. The center of the ellipse is the center of the specified\r
* bounding rectangle. The ellipse is outlined by using the pen and is filled by using the brush; these\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int bottomRect;\r
+ private int bottomRect;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int rightRect;\r
+ private int rightRect;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the bounding rectangle.\r
*/\r
- int topRect;\r
+ private int topRect;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the bounding rectangle.\r
*/\r
- int leftRect;\r
- \r
+ private int leftRect;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.ellipse;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
bottomRect = leis.readShort();\r
rightRect = leis.readShort();\r
leftRect = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+ \r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get\r
* the region to be framed.\r
*/\r
- int region; \r
+ private int region;\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
* Brush to use for filling the region.\r
*/\r
- int brush;\r
+ private int brush;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the\r
* region frame.\r
*/\r
- int height;\r
+ private int height;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the\r
* region frame.\r
*/\r
- int width;\r
- \r
+ private int width;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.frameRegion;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
region = leis.readUShort();\r
brush = leis.readUShort();\r
width = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+ \r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
* device context. The polygons drawn by this function can overlap.\r
*/\r
public static class WmfPolyPolygon implements HwmfRecord {\r
- \r
+\r
/**\r
* A 16-bit unsigned integer that defines the number of polygons in the object.\r
*/\r
- int numberOfPolygons;\r
- \r
+ private int numberOfPolygons;\r
+\r
/**\r
* A NumberOfPolygons array of 16-bit unsigned integers that define the number of\r
* points for each polygon in the object.\r
*/\r
- int pointsPerPolygon[];\r
- \r
+ private int pointsPerPolygon[];\r
+\r
/**\r
* An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
*/\r
- int xPoints[][];\r
+ private int xPoints[][];\r
\r
/**\r
* An array of 16-bit unsigned integers that define the coordinates of the polygons.\r
*/\r
- int yPoints[][];\r
- \r
- \r
+ private int yPoints[][];\r
+\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.polyPolygon;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
// see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)\r
numberOfPolygons = leis.readUShort();\r
yPoints = new int[numberOfPolygons][];\r
\r
int size = LittleEndianConsts.SHORT_SIZE;\r
- \r
+\r
for (int i=0; i<numberOfPolygons; i++) {\r
pointsPerPolygon[i] = leis.readUShort();\r
size += LittleEndianConsts.SHORT_SIZE;\r
}\r
- \r
+\r
for (int i=0; i<numberOfPolygons; i++) {\r
- \r
+\r
xPoints[i] = new int[pointsPerPolygon[i]];\r
yPoints[i] = new int[pointsPerPolygon[i]];\r
- \r
+\r
for (int j=0; j<pointsPerPolygon[i]; j++) {\r
xPoints[i][j] = leis.readUShort();\r
yPoints[i][j] = leis.readUShort();\r
size += 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
}\r
- \r
+\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the rectangle.\r
*/\r
- int bottomRect;\r
+ private int bottomRect;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the rectangle.\r
*/\r
- int rightRect;\r
+ private int rightRect;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int topRect;\r
+ private int topRect;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the rectangle.\r
*/\r
- int leftRect;\r
- \r
+ private int leftRect;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.frameRegion;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
bottomRect = leis.readShort();\r
rightRect = leis.readShort();\r
leftRect = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
/**\r
* A ColorRef Object that defines the color value.\r
*/\r
- HwmfColorRef colorRef; \r
+ HwmfColorRef colorRef;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
* to be set.\r
*/\r
- int y;\r
- \r
+ private int y;\r
+\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
* to be set.\r
*/\r
- int x;\r
- \r
- \r
+ private int x;\r
+\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setPixel;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
colorRef = new HwmfColorRef();\r
int size = colorRef.init(leis);\r
x = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE+size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the height, in logical coordinates, of the\r
* ellipse used to draw the rounded corners.\r
*/\r
- int height;\r
- \r
+ private int height;\r
+\r
/**\r
* A 16-bit signed integer that defines the width, in logical coordinates, of the\r
* ellipse used to draw the rounded corners.\r
*/\r
- int width;\r
- \r
+ private int width;\r
+\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the rectangle.\r
*/\r
- int bottomRect;\r
- \r
+ private int bottomRect;\r
+\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the rectangle.\r
*/\r
- int rightRect;\r
- \r
+ private int rightRect;\r
+\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int topRect;\r
- \r
+ private int topRect;\r
+\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the rectangle.\r
*/\r
- int leftRect;\r
- \r
- \r
+ private int leftRect;\r
+\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.roundRect;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
height = leis.readShort();\r
width = leis.readShort();\r
leftRect = leis.readShort();\r
return 6*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
- \r
+\r
\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical\r
* coordinates, of the endpoint of the second radial.\r
*/\r
- int yRadial2;\r
+ private int yRadial2;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical\r
* coordinates, of the endpoint of the second radial.\r
*/\r
- int xRadial2;\r
+ private int xRadial2;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical\r
* coordinates, of the endpoint of the first radial.\r
*/\r
- int yRadial1;\r
+ private int yRadial1;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical\r
* coordinates, of the endpoint of the first radial.\r
*/\r
- int xRadial1; \r
+ private int xRadial1;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int bottomRect;\r
+ private int bottomRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int rightRect;\r
+ private int rightRect;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the bounding rectangle.\r
*/\r
- int topRect;\r
+ private int topRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the bounding rectangle.\r
*/\r
- int leftRect;\r
- \r
+ private int leftRect;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.pie;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yRadial2 = leis.readShort();\r
xRadial2 = leis.readShort();\r
leftRect = leis.readShort();\r
return 8*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the ending point of the radial line defining the ending point of the arc.\r
*/\r
- int yEndArc; \r
+ private int yEndArc;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the ending point of the radial line defining the ending point of the arc.\r
*/\r
- int xEndArc; \r
+ private int xEndArc;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the ending point of the radial line defining the starting point of the arc.\r
*/\r
- int yStartArc;\r
+ private int yStartArc;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the ending point of the radial line defining the starting point of the arc.\r
*/\r
- int xStartArc;\r
+ private int xStartArc;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int bottomRect;\r
+ private int bottomRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int rightRect;\r
+ private int rightRect;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the bounding rectangle.\r
*/\r
- int topRect;\r
+ private int topRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the bounding rectangle.\r
*/\r
- int leftRect;\r
- \r
+ private int leftRect;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.arc;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yEndArc = leis.readShort();\r
xEndArc = leis.readShort();\r
leftRect = leis.readShort();\r
return 8*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
*/\r
public static class WmfChord implements HwmfRecord {\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical\r
* coordinates, of the endpoint of the second radial.\r
*/\r
- int yRadial2;\r
+ private int yRadial2;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical\r
* coordinates, of the endpoint of the second radial.\r
*/\r
- int xRadial2;\r
+ private int xRadial2;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical\r
* coordinates, of the endpoint of the first radial.\r
*/\r
- int yRadial1;\r
+ private int yRadial1;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical\r
* coordinates, of the endpoint of the first radial.\r
*/\r
- int xRadial1;\r
+ private int xRadial1;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int bottomRect;\r
+ private int bottomRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the lower-right corner of the bounding rectangle.\r
*/\r
- int rightRect;\r
+ private int rightRect;\r
/**\r
- * A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
+ * A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the bounding rectangle.\r
*/\r
- int topRect;\r
+ private int topRect;\r
/**\r
- * A 16-bit signed integer that defines the x-coordinate, in logical units, of \r
+ * A 16-bit signed integer that defines the x-coordinate, in logical units, of\r
* the upper-left corner of the bounding rectangle.\r
*/\r
- int leftRect;\r
- \r
- \r
+ private int leftRect;\r
+\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.chord;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yRadial2 = leis.readShort();\r
xRadial2 = leis.readShort();\r
leftRect = leis.readShort();\r
return 8*LittleEndianConsts.SHORT_SIZE;\r
}\r
- }\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
+}\r
\r
\r
/**\r
- * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The \r
- * new object replaces the previous object of the same type, unless if the previous object is a palette \r
- * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be \r
- * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not \r
+ * The META_SELECTOBJECT record specifies a graphics object for the playback device context. The\r
+ * new object replaces the previous object of the same type, unless if the previous object is a palette\r
+ * object. If the previous object is a palette object, then the META_SELECTPALETTE record must be\r
+ * used instead of the META_SELECTOBJECT record, as the META_SELECTOBJECT record does not\r
* support replacing the palette object type.\r
*/\r
public static class WmfSelectObject implements HwmfRecord {\r
- \r
+\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to\r
* get the object to be selected.\r
*/\r
- int objectIndex;\r
- \r
+ private int objectIndex;\r
+\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.selectObject;\r
}\r
- \r
+\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
objectIndex = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
}\r
\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
+import org.apache.poi.util.HexDump;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
* A 16-bit unsigned integer that defines the escape function. The \r
* value MUST be from the MetafileEscapes enumeration.\r
*/\r
- int escapeFunction;\r
+ private int escapeFunction;\r
/**\r
* A 16-bit unsigned integer that specifies the size, in bytes, of the \r
* EscapeData field.\r
*/\r
- int byteCount;\r
+ private int byteCount;\r
/**\r
* An array of bytes of size ByteCount.\r
*/\r
- byte escapeData[];\r
+ private byte escapeData[];\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.escape;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
escapeFunction = leis.readUShort();\r
byteCount = leis.readUShort();\r
leis.read(escapeData);\r
return 2*LittleEndianConsts.SHORT_SIZE+byteCount;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
+ \r
+ public String toString() {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("escape - function: "+escapeFunction+"\n");\r
+ sb.append(HexDump.dump(escapeData, 0, 0));\r
+ return sb.toString();\r
+ }\r
}\r
\r
package org.apache.poi.hwmf.record;\r
\r
+import java.awt.geom.Path2D;\r
+import java.awt.image.BufferedImage;\r
+import java.io.File;\r
import java.io.IOException;\r
\r
+import javax.imageio.ImageIO;\r
+\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
public class HwmfFill {\r
+ /**\r
+ * A record which contains an image (to be extracted)\r
+ */\r
+ public interface HwmfImageRecord {\r
+ BufferedImage getImage();\r
+ }\r
+ \r
+ \r
/**\r
* The META_FILLREGION record fills a region using a specified brush.\r
*/\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get\r
* the region to be filled.\r
*/\r
- int region;\r
+ private int region;\r
\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get the\r
* brush to use for filling the region.\r
*/\r
- int brush;\r
+ private int brush;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.fillRegion;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
region = leis.readUShort();\r
brush = leis.readUShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
region = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
\r
/**\r
* A 32-bit ColorRef Object that defines the color value.\r
*/\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* point where filling is to start.\r
*/\r
- int yStart;\r
+ private int yStart;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* point where filling is to start.\r
*/\r
- int xStart;\r
+ private int xStart;\r
\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.floodFill;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
colorRef = new HwmfColorRef();\r
int size = colorRef.init(leis);\r
xStart = leis.readShort();\r
return size+2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
* graphics operations that fill polygons.\r
*/\r
public static class WmfSetPolyfillMode implements HwmfRecord {\r
+ /**\r
+ * A 16-bit unsigned integer that defines polygon fill mode.\r
+ * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002\r
+ */\r
+ public enum HwmfPolyfillMode {\r
+ /**\r
+ * Selects alternate mode (fills the area between odd-numbered and\r
+ * even-numbered polygon sides on each scan line).\r
+ */\r
+ ALTERNATE(0x0001, Path2D.WIND_EVEN_ODD),\r
+ /**\r
+ * Selects winding mode (fills any region with a nonzero winding value).\r
+ */\r
+ WINDING(0x0002, Path2D.WIND_NON_ZERO);\r
+\r
+ public int wmfFlag;\r
+ public int awtFlag;\r
+ HwmfPolyfillMode(int wmfFlag, int awtFlag) {\r
+ this.wmfFlag = wmfFlag;\r
+ this.awtFlag = awtFlag;\r
+ }\r
+\r
+ static HwmfPolyfillMode valueOf(int wmfFlag) {\r
+ for (HwmfPolyfillMode pm : values()) {\r
+ if (pm.wmfFlag == wmfFlag) return pm;\r
+ }\r
+ return null;\r
+ }\r
+ }\r
\r
/**\r
* A 16-bit unsigned integer that defines polygon fill mode.\r
* This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002\r
*/\r
- int polyFillMode;\r
+ private HwmfPolyfillMode polyfillMode;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setPolyFillMode;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- polyFillMode = leis.readUShort();\r
+ polyfillMode = HwmfPolyfillMode.valueOf(leis.readUShort());\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setPolyfillMode(polyfillMode);\r
+ }\r
}\r
\r
\r
* Filling continues outward in all directions as long as the color is encountered.\r
* This style is useful for filling areas with multicolored boundaries.\r
*/\r
- int mode;\r
+ private int mode;\r
\r
/**\r
* A 32-bit ColorRef Object that defines the color value.\r
*/\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the point\r
* to be set.\r
*/\r
- int y;\r
+ private int y;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the point\r
* to be set.\r
*/\r
- int x; \r
+ private int x; \r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.extFloodFill;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
mode = leis.readUShort();\r
colorRef = new HwmfColorRef();\r
x = leis.readShort();\r
return size+3*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get\r
* the region to be inverted.\r
*/\r
- int region;\r
+ private int region;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.invertRegion;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
region = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
\r
* A 32-bit unsigned integer that defines the raster operation code.\r
* This code MUST be one of the values in the Ternary Raster Operation enumeration table.\r
*/\r
- HwmfTernaryRasterOp rasterOperation;\r
+ private HwmfTernaryRasterOp rasterOperation;\r
\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the rectangle.\r
*/\r
- int height;\r
+ private int height;\r
\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the rectangle.\r
*/\r
- int width;\r
+ private int width;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle to be filled.\r
*/\r
- int yLeft;\r
+ private int yLeft;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the rectangle to be filled.\r
*/\r
- int xLeft;\r
+ private int xLeft;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.patBlt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
height = leis.readShort();\r
\r
return 6*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
* in the playback device context, and the destination pixels are to be combined to form the new \r
* image. This code MUST be one of the values in the Ternary Raster Operation Enumeration\r
*/\r
- HwmfTernaryRasterOp rasterOperation;\r
+ private HwmfTernaryRasterOp rasterOperation;\r
\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
*/\r
- int srcHeight; \r
+ private int srcHeight; \r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
*/\r
- int srcWidth; \r
+ private int srcWidth; \r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
* of the source rectangle.\r
*/\r
- int ySrc;\r
+ private int ySrc;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
* of the source rectangle.\r
*/\r
- int xSrc;\r
+ private int xSrc;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the destination rectangle.\r
*/\r
- int destHeight;\r
+ private int destHeight;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the destination rectangle.\r
*/\r
- int destWidth;\r
+ private int destWidth;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
* corner of the destination rectangle.\r
*/\r
- int yDest;\r
+ private int yDest;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
* corner of the destination rectangle.\r
*/\r
- int xDest;\r
+ private int xDest;\r
\r
/**\r
* A variable-sized Bitmap16 Object that defines source image content.\r
*/\r
HwmfBitmap16 target;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.stretchBlt;\r
}\r
\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
\r
int size = 0;\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
srcHeight = leis.readShort();\r
\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
/**\r
* The source of the color data is a DIB, and the destination of the transfer is\r
* the current output region in the playback device context.\r
*/\r
- public static class WmfStretchDib implements HwmfRecord {\r
+ public static class WmfStretchDib implements HwmfRecord, HwmfImageRecord {\r
/**\r
* A 32-bit unsigned integer that defines how the source pixels, the current brush in\r
* the playback device context, and the destination pixels are to be combined to\r
* form the new image.\r
*/\r
- HwmfTernaryRasterOp rasterOperation;\r
+ private HwmfTernaryRasterOp rasterOperation;\r
\r
/**\r
* A 16-bit unsigned integer that defines whether the Colors field of the\r
* DIB_PAL_COLORS = 0x0001,\r
* DIB_PAL_INDICES = 0x0002\r
*/\r
- int colorUsage;\r
+ private int colorUsage;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the\r
* source rectangle.\r
*/\r
- int srcHeight;\r
+ private int srcHeight;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the\r
* source rectangle.\r
*/\r
- int srcWidth; \r
+ private int srcWidth; \r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* source rectangle.\r
*/\r
- int ySrc;\r
+ private int ySrc;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
* source rectangle.\r
*/\r
- int xSrc;\r
+ private int xSrc;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the \r
* destination rectangle.\r
*/\r
- int destHeight;\r
+ private int destHeight;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the \r
* destination rectangle.\r
*/\r
- int destWidth;\r
+ private int destWidth;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the \r
* upper-left corner of the destination rectangle.\r
*/\r
- int yDst;\r
+ private int yDst;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the \r
* upper-left corner of the destination rectangle.\r
*/\r
- int xDst;\r
+ private int xDst;\r
/**\r
* A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the \r
* source of the color data.\r
*/\r
- HwmfBitmapDib dib;\r
+ private HwmfBitmapDib dib;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.stretchDib;\r
}\r
\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
colorUsage = leis.readUShort();\r
\r
int size = 11*LittleEndianConsts.SHORT_SIZE;\r
dib = new HwmfBitmapDib();\r
- size += dib.init(leis);\r
+ size += dib.init(leis, (int)(recordSize-6-size));\r
+\r
return size;\r
} \r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
+\r
+ @Override\r
+ public BufferedImage getImage() {\r
+ return dib.getImage();\r
+ }\r
}\r
\r
public static class WmfBitBlt implements HwmfRecord {\r
* A 32-bit unsigned integer that defines how the source pixels, the current brush in the playback \r
* device context, and the destination pixels are to be combined to form the new image.\r
*/\r
- HwmfTernaryRasterOp rasterOperation;\r
+ private HwmfTernaryRasterOp rasterOperation;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner \r
of the source rectangle.\r
*/\r
- int ySrc; \r
+ private int ySrc; \r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner \r
of the source rectangle.\r
*/\r
- int xSrc; \r
+ private int xSrc; \r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the source and \r
destination rectangles.\r
*/\r
- int height;\r
+ private int height;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the source and destination \r
rectangles.\r
*/\r
- int width;\r
+ private int width;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left \r
corner of the destination rectangle.\r
*/\r
- int yDest;\r
+ private int yDest;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
corner of the destination rectangle.\r
*/\r
- int xDest;\r
+ private int xDest;\r
\r
/**\r
* A variable-sized Bitmap16 Object that defines source image content.\r
* This object MUST be specified, even if the raster operation does not require a source.\r
*/\r
- HwmfBitmap16 target;\r
+ private HwmfBitmap16 target;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.bitBlt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
\r
int size = 0;\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
ySrc = leis.readShort();\r
\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
}\r
\r
\r
* using deviceindependent color data.\r
* The source of the color data is a DIB\r
*/\r
- public static class WmfSetDibToDev implements HwmfRecord {\r
+ public static class WmfSetDibToDev implements HwmfRecord, HwmfImageRecord {\r
\r
/**\r
* A 16-bit unsigned integer that defines whether the Colors field of the\r
* DIB_PAL_COLORS = 0x0001,\r
* DIB_PAL_INDICES = 0x0002\r
*/\r
- int colorUsage; \r
+ private int colorUsage; \r
/**\r
* A 16-bit unsigned integer that defines the number of scan lines in the source.\r
*/\r
- int scanCount;\r
+ private int scanCount;\r
/**\r
* A 16-bit unsigned integer that defines the starting scan line in the source.\r
*/\r
- int startScan; \r
+ private int startScan; \r
/**\r
* A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
* source rectangle.\r
*/\r
- int yDib; \r
+ private int yDib; \r
/**\r
* A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
* source rectangle.\r
*/\r
- int xDib; \r
+ private int xDib; \r
/**\r
* A 16-bit unsigned integer that defines the height, in logical units, of the\r
* source and destination rectangles.\r
*/\r
- int height;\r
+ private int height;\r
/**\r
* A 16-bit unsigned integer that defines the width, in logical units, of the\r
* source and destination rectangles.\r
*/\r
- int width;\r
+ private int width;\r
/**\r
* A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the destination rectangle.\r
*/\r
- int yDest;\r
+ private int yDest;\r
/**\r
* A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the destination rectangle.\r
*/\r
- int xDest;\r
+ private int xDest;\r
/**\r
* A variable-sized DeviceIndependentBitmap Object that is the source of the color data.\r
*/\r
- HwmfBitmapDib dib; \r
+ private HwmfBitmapDib dib; \r
\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setDibToDev;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
colorUsage = leis.readUShort();\r
scanCount = leis.readUShort();\r
\r
int size = 9*LittleEndianConsts.SHORT_SIZE;\r
dib = new HwmfBitmapDib();\r
- size += dib.init(leis);\r
+ size += dib.init(leis, (int)(recordSize-6-size));\r
\r
return size;\r
} \r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
+\r
+ @Override\r
+ public BufferedImage getImage() {\r
+ return dib.getImage();\r
+ }\r
}\r
\r
\r
- public static class WmfDibBitBlt implements HwmfRecord {\r
+ public static class WmfDibBitBlt implements HwmfRecord, HwmfImageRecord {\r
\r
/**\r
* A 32-bit unsigned integer that defines how the source pixels, the current brush\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the source rectangle.\r
*/\r
- int ySrc;\r
+ private int ySrc;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the source rectangle.\r
*/\r
- int xSrc;\r
+ private int xSrc;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the source and \r
* destination rectangles.\r
*/\r
- int height;\r
+ private int height;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the source and destination\r
* rectangles.\r
*/\r
- int width;\r
+ private int width;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left\r
* corner of the destination rectangle.\r
*/\r
- int yDest;\r
+ private int yDest;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left \r
* corner of the destination rectangle.\r
*/\r
- int xDest;\r
+ private int xDest;\r
\r
/**\r
* A variable-sized DeviceIndependentBitmap Object that defines image content.\r
* This object MUST be specified, even if the raster operation does not require a source.\r
*/\r
- HwmfBitmapDib target;\r
+ private HwmfBitmapDib target;\r
\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.dibBitBlt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
\r
int size = 0;\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
ySrc = leis.readShort();\r
size += 4*LittleEndianConsts.SHORT_SIZE;\r
if (hasBitmap) {\r
target = new HwmfBitmapDib();\r
- size += target.init(leis);\r
+ size += target.init(leis, (int)(recordSize-6-size));\r
}\r
\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
+\r
+ @Override\r
+ public BufferedImage getImage() {\r
+ return target.getImage();\r
+ }\r
}\r
\r
- public static class WmfDibStretchBlt implements HwmfRecord {\r
+ public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord {\r
/**\r
* A 32-bit unsigned integer that defines how the source pixels, the current brush\r
* in the playback device context, and the destination pixels are to be combined to form the\r
* new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.\r
*/\r
- HwmfTernaryRasterOp rasterOperation;\r
+ private HwmfTernaryRasterOp rasterOperation;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the source rectangle.\r
*/\r
- int srcHeight;\r
+ private int srcHeight;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the source rectangle.\r
*/\r
- int srcWidth;\r
+ private int srcWidth;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the source rectangle.\r
*/\r
- int ySrc;\r
+ private int ySrc;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the source rectangle.\r
*/\r
- int xSrc;\r
+ private int xSrc;\r
/**\r
* A 16-bit signed integer that defines the height, in logical units, of the\r
* destination rectangle.\r
*/\r
- int destHeight;\r
+ private int destHeight;\r
/**\r
* A 16-bit signed integer that defines the width, in logical units, of the\r
* destination rectangle.\r
*/\r
- int destWidth;\r
+ private int destWidth;\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units,\r
* of the upper-left corner of the destination rectangle.\r
*/\r
- int yDest;\r
+ private int yDest;\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units,\r
* of the upper-left corner of the destination rectangle.\r
*/\r
- int xDest;\r
+ private int xDest;\r
/**\r
* A variable-sized DeviceIndependentBitmap Object that defines image content.\r
* This object MUST be specified, even if the raster operation does not require a source.\r
*/\r
HwmfBitmapDib target;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.dibStretchBlt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));\r
\r
int size = 0;\r
- int rasterOpIndex = leis.readUShort();\r
int rasterOpCode = leis.readUShort();\r
+ int rasterOpIndex = leis.readUShort();\r
\r
- rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);\r
+ rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);\r
assert(rasterOpCode == rasterOperation.opCode);\r
\r
srcHeight = leis.readShort();\r
size += 4*LittleEndianConsts.SHORT_SIZE;\r
if (hasBitmap) {\r
target = new HwmfBitmapDib();\r
- size += target.init(leis);\r
+ size += target.init(leis, (int)(recordSize-6-size));\r
}\r
\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ \r
+ }\r
+\r
+ @Override\r
+ public BufferedImage getImage() {\r
+ return target.getImage();\r
+ }\r
}\r
}\r
import java.io.IOException;\r
import java.nio.charset.Charset;\r
\r
+import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
/**\r
*\r
* @see WmfClipPrecision\r
*/\r
- int clipPrecision;\r
+ WmfClipPrecision clipPrecision;\r
\r
/**\r
* An 8-bit unsigned integer that defines the output quality.\r
strikeOut = leis.readByte() != 0;\r
charSet = WmfCharset.valueOf(leis.readUByte());\r
outPrecision = WmfOutPrecision.valueOf(leis.readUByte());\r
+ clipPrecision = WmfClipPrecision.valueOf(leis.readUByte());\r
quality = WmfFontQuality.valueOf(leis.readUByte());\r
int pitchAndFamily = leis.readUByte();\r
family = WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);\r
pitch = WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);\r
\r
- byte buf[] = new byte[32], readBytes;\r
- for (readBytes = 0; readBytes < 32; readBytes++) {\r
- if ((buf[readBytes] = leis.readByte()) == 0) {\r
- break;\r
+ byte buf[] = new byte[32], b, readBytes = 0;\r
+ do {\r
+ if (readBytes == 32) {\r
+ throw new IOException("Font facename can't be determined.");\r
}\r
- }\r
- if (readBytes == 1 || readBytes == 32) {\r
- throw new IOException("Font facename can't be determined.");\r
- }\r
+\r
+ buf[readBytes++] = b = leis.readByte();\r
+ } while (b != 0 && b != -1 && readBytes <= 32);\r
+ \r
facename = new String(buf, 0, readBytes-1, Charset.forName("ISO-8859-1"));\r
\r
- return 17+readBytes;\r
+ return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;\r
}\r
}\r
* The HatchStyle Enumeration specifies the hatch pattern.\r
*/\r
public enum HwmfHatchStyle {\r
- /** A horizontal hatch */\r
+ /** ----- - A horizontal hatch */\r
HS_HORIZONTAL(0x0000),\r
- /** A vertical hatch */\r
+ /** ||||| - A vertical hatch */\r
HS_VERTICAL(0x0001),\r
- /** A 45-degree downward, left-to-right hatch. */\r
+ /** \\\\\ - A 45-degree downward, left-to-right hatch. */\r
HS_FDIAGONAL(0x0002),\r
- /** A 45-degree upward, left-to-right hatch. */\r
+ /** ///// - A 45-degree upward, left-to-right hatch. */\r
HS_BDIAGONAL(0x0003),\r
- /** A horizontal and vertical cross-hatch. */\r
+ /** +++++ - A horizontal and vertical cross-hatch. */\r
HS_CROSS(0x0004),\r
- /** A 45-degree crosshatch. */\r
+ /** xxxxx - A 45-degree crosshatch. */\r
HS_DIAGCROSS(0x0005);\r
\r
int flag;\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+/**\r
+ * A 16-bit unsigned integer that defines the mapping mode.\r
+ *\r
+ * The MapMode defines how logical units are mapped to physical units;\r
+ * that is, assuming that the origins in both the logical and physical coordinate systems\r
+ * are at the same point on the drawing surface, what is the physical coordinate (x',y')\r
+ * that corresponds to logical coordinate (x,y).\r
+ *\r
+ * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that\r
+ * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical\r
+ * coordinate (4,5) would map to physical coordinate (4,5) in pixels.\r
+ *\r
+ * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous\r
+ * example. Given the following definition of that mapping mode, logical coordinate (4,-5)\r
+ * would map to physical coordinate (0.04,0.05) in inches.\r
+ */\r
+public enum HwmfMapMode {\r
+ /**\r
+ * Each logical unit is mapped to one device pixel.\r
+ * Positive x is to the right; positive y is down.\r
+ */\r
+ MM_TEXT(0x0001, 0),\r
+ \r
+ /**\r
+ * Each logical unit is mapped to 0.1 millimeter.\r
+ * Positive x is to the right; positive y is up.\r
+ */\r
+ MM_LOMETRIC(0x0002, 254),\r
+ \r
+ /**\r
+ * Each logical unit is mapped to 0.01 millimeter.\r
+ * Positive x is to the right; positive y is up.\r
+ */\r
+ MM_HIMETRIC(0x0003, 2540),\r
+ \r
+ /**\r
+ * Each logical unit is mapped to 0.01 inch.\r
+ * Positive x is to the right; positive y is up.\r
+ */\r
+ MM_LOENGLISH(0x0004, 100),\r
+ \r
+ /**\r
+ * Each logical unit is mapped to 0.001 inch.\r
+ * Positive x is to the right; positive y is up.\r
+ */\r
+ MM_HIENGLISH(0x0005, 1000),\r
+ \r
+ /**\r
+ * Each logical unit is mapped to one twentieth (1/20) of a point.\r
+ * In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.\r
+ * This unit is also known as a "twip".\r
+ * Positive x is to the right; positive y is up.\r
+ */\r
+ MM_TWIPS(0x0006, 1440),\r
+ \r
+ /**\r
+ * Logical units are mapped to arbitrary device units with equally scaled axes;\r
+ * that is, one unit along the x-axis is equal to one unit along the y-axis.\r
+ * The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the\r
+ * orientation of the axes.\r
+ * The processing application SHOULD make adjustments as necessary to ensure the x and y\r
+ * units remain the same size. For example, when the window extent is set, the viewport\r
+ * SHOULD be adjusted to keep the units isotropic.\r
+ */\r
+ MM_ISOTROPIC(0x0007, -1),\r
+ \r
+ /**\r
+ * Logical units are mapped to arbitrary units with arbitrarily scaled axes.\r
+ */\r
+ MM_ANISOTROPIC(0x0008, -1);\r
+ \r
+ /**\r
+ * native flag\r
+ */\r
+ public final int flag;\r
+ \r
+ /**\r
+ * transformation units - usually scale relative to current dpi.\r
+ * when scale == 0, then don't scale\r
+ * when scale == -1, then scale relative to window dimension. \r
+ */\r
+ public final int scale;\r
+ \r
+ HwmfMapMode(int flag, int scale) {\r
+ this.flag = flag;\r
+ this.scale = scale;\r
+ }\r
+\r
+ static HwmfMapMode valueOf(int flag) {\r
+ for (HwmfMapMode mm : values()) {\r
+ if (mm.flag == flag) return mm;\r
+ }\r
+ return null;\r
+ } \r
+}
\ No newline at end of file
\r
package org.apache.poi.hwmf.record;\r
\r
+import java.awt.image.BufferedImage;\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
+import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
* The META_SAVEDC record saves the playback device context for later retrieval.\r
*/\r
public static class WmfSaveDc implements HwmfRecord {\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.saveDc; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.saveDc;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
return 0;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* The META_SETRELABS record is reserved and not supported.\r
*/\r
public static class WmfSetRelabs implements HwmfRecord {\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.setRelabs; }\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.setRelabs;\r
+ }\r
\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
return 0;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* member is positive, nSavedDC represents a specific instance of the state to be restored. If\r
* this member is negative, nSavedDC represents an instance relative to the current state.\r
*/\r
- int nSavedDC;\r
+ private int nSavedDC;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.restoreDc;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
nSavedDC = leis.readShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
*/\r
public static class WmfSetBkColor implements HwmfRecord {\r
\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setBkColor;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
colorRef = new HwmfColorRef();\r
return colorRef.init(leis);\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setBackgroundColor(colorRef);\r
+ }\r
}\r
\r
/**\r
\r
/**\r
* A 16-bit unsigned integer that defines background mix mode.\r
- * This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002\r
*/\r
- int bkMode;\r
+ public enum HwmfBkMode {\r
+ TRANSPARENT(0x0001), OPAQUE(0x0002);\r
+\r
+ int flag;\r
+ HwmfBkMode(int flag) {\r
+ this.flag = flag;\r
+ }\r
+\r
+ static HwmfBkMode valueOf(int flag) {\r
+ for (HwmfBkMode bs : values()) {\r
+ if (bs.flag == flag) return bs;\r
+ }\r
+ return null;\r
+ }\r
+ }\r
+\r
+ private HwmfBkMode bkMode;\r
\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setBkMode;\r
}\r
\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- bkMode = leis.readUShort();\r
+ bkMode = HwmfBkMode.valueOf(leis.readUShort());\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setBkMode(bkMode);\r
+ }\r
}\r
\r
/**\r
* LAYOUT_RTL = 0x0001\r
* LAYOUT_BITMAPORIENTATIONPRESERVED = 0x0008\r
*/\r
- int layout;\r
+ private int layout;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setLayout;\r
}\r
\r
@SuppressWarnings("unused")\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
layout = leis.readUShort();\r
// A 16-bit field that MUST be ignored.\r
int reserved = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
*/\r
public static class WmfSetMapMode implements HwmfRecord {\r
\r
- /**\r
- * A 16-bit unsigned integer that defines the mapping mode.\r
- *\r
- * The MapMode defines how logical units are mapped to physical units;\r
- * that is, assuming that the origins in both the logical and physical coordinate systems\r
- * are at the same point on the drawing surface, what is the physical coordinate (x',y')\r
- * that corresponds to logical coordinate (x,y).\r
- *\r
- * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that\r
- * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical\r
- * coordinate (4,5) would map to physical coordinate (4,5) in pixels.\r
- *\r
- * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous\r
- * example. Given the following definition of that mapping mode, logical coordinate (4,-5)\r
- * would map to physical coordinate (0.04,0.05) in inches.\r
- *\r
- * This MUST be one of the following:\r
- *\r
- * MM_TEXT (= 0x0001):\r
- * Each logical unit is mapped to one device pixel.\r
- * Positive x is to the right; positive y is down.\r
- *\r
- * MM_LOMETRIC (= 0x0002):\r
- * Each logical unit is mapped to 0.1 millimeter.\r
- * Positive x is to the right; positive y is up.\r
- *\r
- * MM_HIMETRIC (= 0x0003):\r
- * Each logical unit is mapped to 0.01 millimeter.\r
- * Positive x is to the right; positive y is up.\r
- *\r
- * MM_LOENGLISH (= 0x0004):\r
- * Each logical unit is mapped to 0.01 inch.\r
- * Positive x is to the right; positive y is up.\r
- *\r
- * MM_HIENGLISH (= 0x0005):\r
- * Each logical unit is mapped to 0.001 inch.\r
- * Positive x is to the right; positive y is up.\r
- *\r
- * MM_TWIPS (= 0x0006):\r
- * Each logical unit is mapped to one twentieth (1/20) of a point.\r
- * In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.\r
- * This unit is also known as a "twip".\r
- * Positive x is to the right; positive y is up.\r
- *\r
- * MM_ISOTROPIC (= 0x0007):\r
- * Logical units are mapped to arbitrary device units with equally scaled axes;\r
- * that is, one unit along the x-axis is equal to one unit along the y-axis.\r
- * The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the\r
- * orientation of the axes.\r
- * The processing application SHOULD make adjustments as necessary to ensure the x and y\r
- * units remain the same size. For example, when the window extent is set, the viewport\r
- * SHOULD be adjusted to keep the units isotropic.\r
- *\r
- * MM_ANISOTROPIC (= 0x0008):\r
- * Logical units are mapped to arbitrary units with arbitrarily scaled axes.\r
- */\r
- int mapMode;\r
+ private HwmfMapMode mapMode;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setMapMode;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- mapMode = leis.readUShort();\r
+ mapMode = HwmfMapMode.valueOf(leis.readUShort());\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setMapMode(mapMode);\r
+ }\r
}\r
\r
/**\r
* match a font's aspect ratio to the current device's aspect ratio. If bit 0 is\r
* set, the mapper selects only matching fonts.\r
*/\r
- long mapperValues;\r
+ private long mapperValues;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setMapperFlags;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
mapperValues = leis.readUInt();\r
return LittleEndianConsts.INT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* R2_MERGEPEN = 0x000F,\r
* R2_WHITE = 0x0010\r
*/\r
- int drawMode;\r
+ private int drawMode;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setRop2;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
drawMode = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* COLORONCOLOR = 0x0003,\r
* HALFTONE = 0x0004\r
*/\r
- int setStretchBltMode;\r
+ private int setStretchBltMode;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setStretchBltMode;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
setStretchBltMode = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a\r
* pattern specified by a DeviceIndependentBitmap (DIB) Object\r
*/\r
- public static class WmfDibCreatePatternBrush implements HwmfRecord {\r
+ public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord {\r
\r
- HwmfBrushStyle style;\r
+ private HwmfBrushStyle style;\r
\r
/**\r
* A 16-bit unsigned integer that defines whether the Colors field of a DIB\r
* DIB_PAL_COLORS = 0x0001,\r
* DIB_PAL_INDICES = 0x0002\r
*/\r
- int colorUsage;\r
+ private int colorUsage;\r
\r
- HwmfBitmapDib patternDib;\r
- HwmfBitmap16 pattern16;\r
+ private HwmfBitmapDib patternDib;\r
+ private HwmfBitmap16 pattern16;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.dibCreatePatternBrush;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
style = HwmfBrushStyle.valueOf(leis.readUShort());\r
colorUsage = leis.readUShort();\r
case BS_DIBPATTERN:\r
case BS_DIBPATTERNPT:\r
case BS_HATCHED:\r
- patternDib = new HwmfBitmapDib();\r
- size += patternDib.init(leis);\r
- break;\r
case BS_PATTERN:\r
- pattern16 = new HwmfBitmap16();\r
- size += pattern16.init(leis);\r
+ patternDib = new HwmfBitmapDib();\r
+ size += patternDib.init(leis, (int)(recordSize-6-size));\r
break;\r
case BS_INDEXED:\r
case BS_DIBPATTERN8X8:\r
}\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ HwmfDrawProperties prop = ctx.getProperties();\r
+ prop.setBrushStyle(style);\r
+ prop.setBrushBitmap(getImage());\r
+ }\r
+\r
+ @Override\r
+ public BufferedImage getImage() {\r
+ if (patternDib != null) {\r
+ return patternDib.getImage();\r
+ } else if (pattern16 != null) {\r
+ return pattern16.getImage();\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
}\r
\r
/**\r
public static class WmfDeleteObject implements HwmfRecord {\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to\r
- get the object to be deleted.\r
+ * get the object to be deleted.\r
*/\r
- int objectIndex;\r
+ private int objectIndex;\r
\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.deleteObject; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.deleteObject;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
objectIndex = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
public static class WmfCreatePatternBrush implements HwmfRecord {\r
\r
- HwmfBitmap16 pattern;\r
+ private HwmfBitmap16 pattern;\r
\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.createPatternBrush; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.createPatternBrush;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
pattern = new HwmfBitmap16(true);\r
return pattern.init(leis);\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
public static class WmfCreatePenIndirect implements HwmfRecord {\r
\r
- /**\r
- * A 16-bit unsigned integer that specifies the pen style.\r
- * The value MUST be defined from the PenStyle Enumeration table.\r
- *\r
- * PS_COSMETIC = 0x0000,\r
- * PS_ENDCAP_ROUND = 0x0000,\r
- * PS_JOIN_ROUND = 0x0000,\r
- * PS_SOLID = 0x0000,\r
- * PS_DASH = 0x0001,\r
- * PS_DOT = 0x0002,\r
- * PS_DASHDOT = 0x0003,\r
- * PS_DASHDOTDOT = 0x0004,\r
- * PS_NULL = 0x0005,\r
- * PS_INSIDEFRAME = 0x0006,\r
- * PS_USERSTYLE = 0x0007,\r
- * PS_ALTERNATE = 0x0008,\r
- * PS_ENDCAP_SQUARE = 0x0100,\r
- * PS_ENDCAP_FLAT = 0x0200,\r
- * PS_JOIN_BEVEL = 0x1000,\r
- * PS_JOIN_MITER = 0x2000\r
- */\r
- int penStyle;\r
+ private HwmfPenStyle penStyle;\r
/**\r
* A 32-bit PointS Object that specifies a point for the object dimensions.\r
* The xcoordinate is the pen width. The y-coordinate is ignored.\r
*/\r
- int xWidth, yWidth;\r
+ private int xWidth;\r
+ @SuppressWarnings("unused")\r
+ private int yWidth;\r
/**\r
* A 32-bit ColorRef Object that specifies the pen color value.\r
*/\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.createPenIndirect; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.createPenIndirect;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- penStyle = leis.readUShort();\r
+ penStyle = HwmfPenStyle.valueOf(leis.readUShort());\r
xWidth = leis.readShort();\r
yWidth = leis.readShort();\r
colorRef = new HwmfColorRef();\r
- int size = 3*LittleEndianConsts.SHORT_SIZE;\r
- size += colorRef.init(leis);\r
- return size;\r
+ int size = colorRef.init(leis);\r
+ return size+3*LittleEndianConsts.SHORT_SIZE;\r
+ }\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ HwmfDrawProperties p = ctx.getProperties();\r
+ p.setPenStyle(penStyle);\r
+ p.setPenColor(colorRef);\r
+ p.setPenWidth(xWidth);\r
}\r
}\r
\r
/**\r
* The META_CREATEBRUSHINDIRECT record creates a Brush Object\r
* from a LogBrush Object.\r
- * \r
+ *\r
* The following table shows the relationship between values in the BrushStyle,\r
* ColorRef and BrushHatch fields in a LogBrush Object. Only supported brush styles are listed.\r
- * \r
+ *\r
* <table>\r
* <tr>\r
* <th>BrushStyle</th>\r
* </table>\r
*/\r
public static class WmfCreateBrushIndirect implements HwmfRecord {\r
- HwmfBrushStyle brushStyle;\r
+ private HwmfBrushStyle brushStyle;\r
\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
\r
/**\r
* A 16-bit field that specifies the brush hatch type.\r
* Its interpretation depends on the value of BrushStyle.\r
- * \r
+ *\r
*/\r
- HwmfHatchStyle brushHatch;\r
+ private HwmfHatchStyle brushHatch;\r
\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.createBrushIndirect; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.createBrushIndirect;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
brushStyle = HwmfBrushStyle.valueOf(leis.readUShort());\r
colorRef = new HwmfColorRef();\r
int size = colorRef.init(leis);\r
brushHatch = HwmfHatchStyle.valueOf(leis.readUShort());\r
- size += 4;\r
- return size;\r
+ return size+2*LittleEndianConsts.SHORT_SIZE;\r
+ }\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ HwmfDrawProperties p = ctx.getProperties();\r
+ p.setBrushStyle(brushStyle);\r
+ p.setBrushColor(colorRef);\r
+ p.setBrushHatch(brushHatch);\r
}\r
}\r
}
\ No newline at end of file
\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
// Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.\r
// Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.\r
// Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.\r
- int values, blue, green, red;\r
+ private int values, blue, green, red;\r
\r
public int init(LittleEndianInputStream leis) throws IOException {\r
values = leis.readUByte();\r
* used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.\r
* When used with META_CREATEPALETTE, it MUST be 0x0300\r
*/\r
- int start;\r
+ private int start;\r
\r
/**\r
* NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in\r
* aPaletteEntries. \r
*/\r
- int numberOfEntries;\r
+ private int numberOfEntries;\r
\r
PaletteEntry entries[];\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
start = leis.readUShort();\r
numberOfEntries = leis.readUShort();\r
}\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* The META_CREATEPALETTE record creates a Palette Object\r
*/\r
public static class WmfCreatePalette extends WmfPaletteParent {\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.createPalette;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* palette that is defined in the playback device context.\r
*/\r
public static class WmfSetPaletteEntries extends WmfPaletteParent {\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setPalEntries;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
*/\r
int numberOfEntries;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.resizePalette;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
numberOfEntries = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
} \r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get\r
* the Palette Object to be selected.\r
*/\r
- int palette;\r
+ private int palette;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.selectPalette;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
palette = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
} \r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* is defined in the playback device context to the system palette.\r
*/\r
public static class WmfRealizePalette implements HwmfRecord {\r
- public HwmfRecordType getRecordType() { return HwmfRecordType.realizePalette; }\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.realizePalette;\r
+ }\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
return 0;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* this record SHOULD have no effect.\r
*/\r
public static class WmfAnimatePalette extends WmfPaletteParent {\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.animatePalette;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
}\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hwmf.record;\r
+\r
+import java.awt.BasicStroke;\r
+\r
+import org.apache.poi.util.BitField;\r
+import org.apache.poi.util.BitFieldFactory;\r
+\r
+/**\r
+ * The 16-bit PenStyle Enumeration is used to specify different types of pens\r
+ * that can be used in graphics operations.\r
+ * \r
+ * Various styles can be combined by using a logical OR statement, one from\r
+ * each subsection of Style, EndCap, Join, and Type (Cosmetic).\r
+ * \r
+ * The defaults in case the other values of the subsection aren't set are\r
+ * solid, round end caps, round joins and cosmetic type.\r
+ */\r
+public class HwmfPenStyle {\r
+ public enum HwmfLineCap {\r
+ /** Rounded ends */\r
+ ROUND(0, BasicStroke.CAP_ROUND),\r
+ /** Square protrudes by half line width */\r
+ SQUARE(1, BasicStroke.CAP_SQUARE),\r
+ /** Line ends at end point*/\r
+ FLAT(2, BasicStroke.CAP_BUTT); \r
+\r
+ public int wmfFlag;\r
+ public int awtFlag;\r
+ HwmfLineCap(int wmfFlag, int awtFlag) {\r
+ this.wmfFlag = wmfFlag;\r
+ this.awtFlag = awtFlag;\r
+ }\r
+\r
+ static HwmfLineCap valueOf(int wmfFlag) {\r
+ for (HwmfLineCap hs : values()) {\r
+ if (hs.wmfFlag == wmfFlag) return hs;\r
+ }\r
+ return null;\r
+ } \r
+ }\r
+ \r
+ public enum HwmfLineJoin {\r
+ /**Line joins are round. */\r
+ ROUND(0, BasicStroke.JOIN_ROUND),\r
+ /** Line joins are beveled. */\r
+ BEVEL(1, BasicStroke.JOIN_BEVEL),\r
+ /**\r
+ * Line joins are mitered when they are within the current limit set by the\r
+ * SETMITERLIMIT META_ESCAPE record. A join is beveled when it would exceed the limit\r
+ */\r
+ MITER(2, BasicStroke.JOIN_MITER);\r
+\r
+ public int wmfFlag;\r
+ public int awtFlag;\r
+ HwmfLineJoin(int wmfFlag, int awtFlag) {\r
+ this.wmfFlag = wmfFlag;\r
+ this.awtFlag = awtFlag;\r
+ }\r
+\r
+ static HwmfLineJoin valueOf(int wmfFlag) {\r
+ for (HwmfLineJoin hs : values()) {\r
+ if (hs.wmfFlag == wmfFlag) return hs;\r
+ }\r
+ return null;\r
+ } \r
+ }\r
+ \r
+ public enum HwmfLineDash {\r
+ /**\r
+ * The pen is solid.\r
+ */\r
+ SOLID(0x0000, 10),\r
+ /**\r
+ * The pen is dashed. (-----) \r
+ */\r
+ DASH(0x0001, 10, 8),\r
+ /**\r
+ * The pen is dotted. (.....)\r
+ */\r
+ DOT(0x0002, 2, 4),\r
+ /**\r
+ * The pen has alternating dashes and dots. (_._._._)\r
+ */\r
+ DASHDOT(0x0003, 10, 8, 2, 8),\r
+ /**\r
+ * The pen has dashes and double dots. (_.._.._)\r
+ */\r
+ DASHDOTDOT(0x0004, 10, 4, 2, 4, 2, 4),\r
+ /**\r
+ * The pen is invisible.\r
+ */\r
+ NULL(0x0005),\r
+ /**\r
+ * The pen is solid. When this pen is used in any drawing record that takes a\r
+ * bounding rectangle, the dimensions of the figure are shrunk so that it fits\r
+ * entirely in the bounding rectangle, taking into account the width of the pen.\r
+ */\r
+ INSIDEFRAME(0x0006, 10),\r
+ /**\r
+ * The pen uses a styling array supplied by the user.\r
+ * (this is currently not supported and drawn as solid ... no idea where the user\r
+ * styling is supposed to come from ...)\r
+ */\r
+ USERSTYLE(0x0007, 10);\r
+ \r
+\r
+ public int wmfFlag;\r
+ public float[] dashes;\r
+ HwmfLineDash(int wmfFlag, float... dashes) {\r
+ this.wmfFlag = wmfFlag;\r
+ this.dashes = dashes;\r
+ }\r
+\r
+ static HwmfLineDash valueOf(int wmfFlag) {\r
+ for (HwmfLineDash hs : values()) {\r
+ if (hs.wmfFlag == wmfFlag) return hs;\r
+ }\r
+ return null;\r
+ } \r
+ }\r
+ \r
+ private static final BitField SUBSECTION_DASH = BitFieldFactory.getInstance(0x0007);\r
+ private static final BitField SUBSECTION_ALTERNATE = BitFieldFactory.getInstance(0x0008);\r
+ private static final BitField SUBSECTION_ENDCAP = BitFieldFactory.getInstance(0x0300);\r
+ private static final BitField SUBSECTION_JOIN = BitFieldFactory.getInstance(0x3000);\r
+ \r
+ private int flag;\r
+ \r
+ public static HwmfPenStyle valueOf(int flag) {\r
+ HwmfPenStyle ps = new HwmfPenStyle();\r
+ ps.flag = flag;\r
+ return ps;\r
+ }\r
+ \r
+ public HwmfLineCap getLineCap() {\r
+ return HwmfLineCap.valueOf(SUBSECTION_ENDCAP.getValue(flag));\r
+ }\r
+\r
+ public HwmfLineJoin getLineJoin() {\r
+ return HwmfLineJoin.valueOf(SUBSECTION_JOIN.getValue(flag));\r
+ }\r
+ \r
+ public HwmfLineDash getLineDash() {\r
+ return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag));\r
+ }\r
+ \r
+\r
+ /**\r
+ * The pen sets every other pixel (this style is applicable only for cosmetic pens).\r
+ */\r
+ public boolean isAlternateDash() {\r
+ return SUBSECTION_ALTERNATE.isSet(flag);\r
+ }\r
+}\r
\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
public interface HwmfRecord {\r
* @throws IOException\r
*/\r
int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;\r
+ \r
+ /**\r
+ * Apply the record settings to the graphics context\r
+ *\r
+ * @param ctx the graphics context to modify\r
+ */\r
+ void draw(HwmfGraphics ctx);\r
}\r
this.opCmd=opCmd;\r
}\r
\r
- public static HwmfTernaryRasterOp fromOpIndex(int opIndex) {\r
+ public static HwmfTernaryRasterOp valueOf(int opIndex) {\r
for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {\r
if (bb.opIndex == opIndex) {\r
return bb;\r
\r
import java.io.IOException;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
+import org.apache.poi.util.LocaleUtil;\r
+import org.apache.poi.util.RecordFormatException;\r
\r
public class HwmfText {\r
\r
* this value is transformed and rounded to the nearest pixel. For details about setting the\r
* mapping mode, see META_SETMAPMODE\r
*/\r
- int charExtra;\r
+ private int charExtra;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setTextCharExtra;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
charExtra = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
*/\r
public static class WmfSetTextColor implements HwmfRecord {\r
\r
- HwmfColorRef colorRef;\r
+ private HwmfColorRef colorRef;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setTextColor;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
colorRef = new HwmfColorRef();\r
return colorRef.init(leis);\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
/**\r
* A 16-bit unsigned integer that specifies the number of space characters in the line.\r
*/\r
- int breakCount;\r
+ private int breakCount;\r
\r
/**\r
* A 16-bit unsigned integer that specifies the total extra space, in logical\r
* identified by the BreakExtra member is transformed and rounded to the nearest pixel. For\r
* details about setting the mapping mode, see {@link WmfSetMapMode}.\r
*/\r
- int breakExtra;\r
+ private int breakExtra;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setBkColor;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
breakCount = leis.readUShort();\r
breakExtra = leis.readUShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
/**\r
* A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.\r
*/\r
- int stringLength;\r
+ private int stringLength;\r
/**\r
* The size of this field MUST be a multiple of two. If StringLength is an odd\r
* number, then this field MUST be of a size greater than or equal to StringLength + 1.\r
* length of the string.\r
* The string is written at the location specified by the XStart and YStart fields.\r
*/\r
- String text;\r
+ private String text;\r
/**\r
* A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical\r
* units, of the point where drawing is to start.\r
*/\r
- int yStart;\r
+ private int yStart;\r
/**\r
* A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in\r
* logical units, of the point where drawing is to start.\r
*/\r
- int xStart; \r
+ private int xStart; \r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.textOut;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
stringLength = leis.readShort();\r
- byte buf[] = new byte[stringLength+(stringLength%2)];\r
+ byte buf[] = new byte[stringLength+(stringLength&1)];\r
leis.readFully(buf);\r
- text = new String(buf, "UTF16-LE").trim();\r
+ text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252).trim();\r
yStart = leis.readShort();\r
xStart = leis.readShort();\r
return 3*LittleEndianConsts.SHORT_SIZE+buf.length;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, where the \r
text string is to be located.\r
*/\r
- int y; \r
+ private int y; \r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, where the \r
text string is to be located.\r
*/\r
- int x; \r
+ private int x; \r
/**\r
* A 16-bit signed integer that defines the length of the string.\r
*/\r
- int stringLength;\r
+ private int stringLength;\r
/**\r
* A 16-bit unsigned integer that defines the use of the application-defined \r
* rectangle. This member can be a combination of one or more values in the \r
* Indicates that both horizontal and vertical character displacement values \r
* SHOULD be provided.\r
*/\r
- int fwOpts;\r
+ private int fwOpts;\r
/**\r
* An optional 8-byte Rect Object (section 2.2.2.18) that defines the \r
* dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.\r
* Each value is a 16-bit signed integer that defines the coordinate, in logical coordinates, of \r
* the upper-left corner of the rectangle\r
*/\r
- int left,top,right,bottom;\r
+ private int left,top,right,bottom;\r
/**\r
* A variable-length string that specifies the text to be drawn. The string does \r
* not need to be null-terminated, because StringLength specifies the length of the string. If \r
* the length is odd, an extra byte is placed after it so that the following member (optional Dx) is \r
* aligned on a 16-bit boundary.\r
*/\r
- String text;\r
+ private String text;\r
/**\r
* An optional array of 16-bit signed integers that indicate the distance between \r
* origins of adjacent character cells. For example, Dx[i] logical units separate the origins of \r
* character cell i and character cell i + 1. If this field is present, there MUST be the same \r
* number of values as there are characters in the string.\r
*/\r
- int dx[];\r
+ private int dx[];\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.extTextOut;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
y = leis.readShort();\r
x = leis.readShort();\r
stringLength = leis.readShort();\r
fwOpts = leis.readUShort();\r
- left = leis.readShort();\r
- top = leis.readShort();\r
- right = leis.readShort();\r
- bottom = leis.readShort();\r
\r
- byte buf[] = new byte[stringLength+(stringLength%2)];\r
+ int size = 4*LittleEndianConsts.SHORT_SIZE;\r
+ \r
+ if (fwOpts != 0) {\r
+ // the bounding rectangle is optional and only read when fwOpts are given\r
+ left = leis.readShort();\r
+ top = leis.readShort();\r
+ right = leis.readShort();\r
+ bottom = leis.readShort();\r
+ size += 4*LittleEndianConsts.SHORT_SIZE;\r
+ }\r
+ \r
+ byte buf[] = new byte[stringLength+(stringLength&1)];\r
leis.readFully(buf);\r
- text = new String(buf, "UTF16-LE");\r
+ text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252);\r
+ size += buf.length;\r
\r
- int size = 8*LittleEndianConsts.SHORT_SIZE+buf.length;\r
- if (size < recordSize) {\r
- dx = new int[text.length()];\r
+ // -6 bytes of record function and length header\r
+ int remainingRecordSize = (int)(recordSize-6);\r
+ if (size < remainingRecordSize) {\r
+ if (size + stringLength*LittleEndianConsts.SHORT_SIZE < remainingRecordSize) {\r
+ throw new RecordFormatException("can't read Dx array - given recordSize doesn't contain enough values for string length "+stringLength);\r
+ }\r
+ \r
+ dx = new int[stringLength];\r
for (int i=0; i<dx.length; i++) {\r
dx[i] = leis.readShort();\r
}\r
\r
return size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
\r
* VTA_BASELINE (0x0018):\r
* The reference point MUST be on the baseline of the text.\r
*/\r
- int textAlignmentMode;\r
+ private int textAlignmentMode;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setTextAlign;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
textAlignmentMode = leis.readUShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
public static class WmfCreateFontIndirect implements HwmfRecord {\r
- HwmfFont font;\r
+ private HwmfFont font;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.createFontIndirect;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
font = new HwmfFont();\r
return font.init(leis);\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
}\r
\r
package org.apache.poi.hwmf.record;\r
\r
+import java.awt.geom.Rectangle2D;\r
import java.io.IOException;\r
import java.util.ArrayList;\r
import java.util.List;\r
\r
+import org.apache.poi.hwmf.draw.HwmfGraphics;\r
import org.apache.poi.util.LittleEndianConsts;\r
import org.apache.poi.util.LittleEndianInputStream;\r
\r
public class HwmfWindowing {\r
\r
- /**\r
- * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the\r
- * specified offsets.\r
- */\r
- public static class WmfOffsetClipRgn implements HwmfRecord {\r
-\r
- /**\r
- * A 16-bit signed integer that defines the number of logical units to move up or down.\r
- */\r
- int yOffset;\r
-\r
- /**\r
- * A 16-bit signed integer that defines the number of logical units to move left or right.\r
- */\r
- int xOffset;\r
-\r
- public HwmfRecordType getRecordType() {\r
- return HwmfRecordType.offsetClipRgn;\r
- }\r
-\r
- public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- yOffset = leis.readShort();\r
- xOffset = leis.readShort();\r
- return 2*LittleEndianConsts.SHORT_SIZE;\r
- }\r
- }\r
-\r
-\r
/**\r
* The META_SETVIEWPORTORG record defines the viewport origin in the playback device context.\r
*/\r
/**\r
* A 16-bit signed integer that defines the vertical offset, in device units.\r
*/\r
- int y;\r
+ private int y;\r
\r
/**\r
* A 16-bit signed integer that defines the horizontal offset, in device units.\r
*/\r
- int x;\r
+ private int x;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setViewportOrg;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
y = leis.readShort();\r
x = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setViewportOrg(x, y);\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the vertical extent\r
* of the viewport in device units.\r
*/\r
- int y;\r
+ private int height;\r
\r
/**\r
* A 16-bit signed integer that defines the horizontal extent\r
* of the viewport in device units.\r
*/\r
- int x;\r
+ private int width;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setViewportExt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- y = leis.readShort();\r
- x = leis.readShort();\r
+ height = leis.readShort();\r
+ width = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setViewportExt(width, height);\r
+ }\r
}\r
\r
/**\r
/**\r
* A 16-bit signed integer that defines the vertical offset, in device units.\r
*/\r
- int yOffset;\r
+ private int yOffset;\r
\r
/**\r
* A 16-bit signed integer that defines the horizontal offset, in device units.\r
*/\r
- int xOffset;\r
+ private int xOffset;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.offsetViewportOrg;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yOffset = leis.readShort();\r
xOffset = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ Rectangle2D viewport = ctx.getProperties().getViewport();\r
+ ctx.getProperties().setViewportOrg(viewport.getX()+xOffset, viewport.getY()+yOffset);\r
+ }\r
}\r
\r
/**\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units.\r
*/\r
- int y;\r
+ private int y;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units.\r
*/\r
- int x;\r
+ private int x;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setWindowOrg;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
y = leis.readShort();\r
x = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setWindowOrg(x, y);\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the vertical extent of\r
* the window in logical units.\r
*/\r
- int y;\r
+ private int height;\r
\r
/**\r
* A 16-bit signed integer that defines the horizontal extent of\r
* the window in logical units.\r
*/\r
- int x;\r
+ private int width;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.setWindowExt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
- y = leis.readShort();\r
- x = leis.readShort();\r
+ height = leis.readShort();\r
+ width = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ ctx.getProperties().setWindowExt(width, height);\r
+ }\r
}\r
\r
/**\r
/**\r
* A 16-bit signed integer that defines the vertical offset, in device units.\r
*/\r
- int yOffset;\r
+ private int yOffset;\r
\r
/**\r
* A 16-bit signed integer that defines the horizontal offset, in device units.\r
*/\r
- int xOffset;\r
+ private int xOffset;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.offsetWindowOrg;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yOffset = leis.readShort();\r
xOffset = leis.readShort();\r
return 2*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ Rectangle2D window = ctx.getProperties().getWindow();\r
+ ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to divide the\r
* result of multiplying the current y-extent by the value of the yNum member.\r
*/\r
- int yDenom;\r
+ private int yDenom;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to multiply the\r
* current y-extent.\r
*/\r
- int yNum;\r
+ private int yNum;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to divide the\r
* result of multiplying the current x-extent by the value of the xNum member.\r
*/\r
- int xDenom;\r
+ private int xDenom;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to multiply the\r
* current x-extent.\r
*/\r
- int xNum;\r
+ private int xNum;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.scaleWindowExt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yDenom = leis.readShort();\r
yNum = leis.readShort();\r
xNum = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ Rectangle2D window = ctx.getProperties().getWindow();\r
+ double width = window.getWidth() * xNum / xDenom;\r
+ double height = window.getHeight() * yNum / yDenom;\r
+ ctx.getProperties().setWindowExt(width, height);\r
+ }\r
}\r
\r
\r
* A 16-bit signed integer that defines the amount by which to divide the\r
* result of multiplying the current y-extent by the value of the yNum member.\r
*/\r
- int yDenom;\r
+ private int yDenom;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to multiply the\r
* current y-extent.\r
*/\r
- int yNum;\r
+ private int yNum;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to divide the\r
* result of multiplying the current x-extent by the value of the xNum member.\r
*/\r
- int xDenom;\r
+ private int xDenom;\r
\r
/**\r
* A 16-bit signed integer that defines the amount by which to multiply the\r
* current x-extent.\r
*/\r
- int xNum;\r
+ private int xNum;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.scaleViewportExt;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
yDenom = leis.readShort();\r
yNum = leis.readShort();\r
xNum = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+ Rectangle2D viewport = ctx.getProperties().getViewport();\r
+ double width = viewport.getWidth() * xNum / xDenom;\r
+ double height = viewport.getHeight() * yNum / yDenom;\r
+ ctx.getProperties().setViewportExt(width, height);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The META_OFFSETCLIPRGN record moves the clipping region in the playback device context by the\r
+ * specified offsets.\r
+ */\r
+ public static class WmfOffsetClipRgn implements HwmfRecord {\r
+\r
+ /**\r
+ * A 16-bit signed integer that defines the number of logical units to move up or down.\r
+ */\r
+ private int yOffset;\r
+\r
+ /**\r
+ * A 16-bit signed integer that defines the number of logical units to move left or right.\r
+ */\r
+ private int xOffset;\r
+\r
+ @Override\r
+ public HwmfRecordType getRecordType() {\r
+ return HwmfRecordType.offsetClipRgn;\r
+ }\r
+\r
+ @Override\r
+ public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
+ yOffset = leis.readShort();\r
+ xOffset = leis.readShort();\r
+ return 2*LittleEndianConsts.SHORT_SIZE;\r
+ }\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int bottom;\r
+ private int bottom;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int right;\r
+ private int right;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int top;\r
+ private int top;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int left;\r
+ private int left;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.excludeClipRect;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
bottom = leis.readShort();\r
right = leis.readShort();\r
left = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int bottom;\r
+ private int bottom;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int right;\r
+ private int right;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int top;\r
+ private int top;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int left;\r
+ private int left;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.intersectClipRect;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
bottom = leis.readShort();\r
right = leis.readShort();\r
left = leis.readShort();\r
return 4*LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
/**\r
- * The META_INTERSECTCLIPRECT record sets the clipping region in the playback device context to the\r
- * intersection of the existing clipping region and the specified rectangle.\r
+ * The META_SELECTCLIPREGION record specifies a Region Object to be the current clipping region.\r
*/\r
public static class WmfSelectClipRegion implements HwmfRecord {\r
\r
* A 16-bit unsigned integer used to index into the WMF Object Table to get\r
* the region to be clipped.\r
*/\r
- int region;\r
+ private int region;\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.selectClipRegion;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
region = leis.readShort();\r
return LittleEndianConsts.SHORT_SIZE;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
\r
public static class WmfScanObject {\r
* coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right\r
* endpoints are required to specify each scanline.\r
*/\r
- int count;\r
+ private int count;\r
/**\r
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the top scanline.\r
*/\r
- int top;\r
+ private int top;\r
/**\r
* A 16-bit unsigned integer that defines the vertical (y-axis) coordinate, in logical units, of the bottom scanline.\r
*/\r
- int bottom;\r
+ private int bottom;\r
/**\r
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
* in logical units, of the left endpoint of the scanline.\r
*/\r
- int left_scanline[];\r
+ private int left_scanline[];\r
/**\r
* A 16-bit unsigned integer that defines the horizontal (x-axis) coordinate,\r
* in logical units, of the right endpoint of the scanline.\r
*/\r
- int right_scanline[];\r
+ private int right_scanline[];\r
/**\r
* A 16-bit unsigned integer that MUST be the same as the value of the Count\r
* field; it is present to allow upward travel in the structure.\r
*/\r
- int count2;\r
+ private int count2;\r
\r
public int init(LittleEndianInputStream leis) {\r
count = leis.readUShort();\r
/**\r
* A 16-bit signed integer. A value that MUST be ignored.\r
*/\r
- int nextInChain;\r
+ private int nextInChain;\r
/**\r
* A 16-bit signed integer that specifies the region identifier. It MUST be 0x0006.\r
*/\r
- int objectType;\r
+ private int objectType;\r
/**\r
* A 32-bit unsigned integer. A value that MUST be ignored.\r
*/\r
- int objectCount;\r
+ private int objectCount;\r
/**\r
* A 16-bit signed integer that defines the size of the region in bytes plus the size of aScans in bytes.\r
*/\r
- int regionSize;\r
+ private int regionSize;\r
/**\r
* A 16-bit signed integer that defines the number of scanlines composing the region.\r
*/\r
- int scanCount;\r
+ private int scanCount;\r
\r
/**\r
* A 16-bit signed integer that defines the maximum number of points in any one scan in this region.\r
*/\r
- int maxScan;\r
+ private int maxScan;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int bottom;\r
+ private int bottom;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* lower-right corner of the rectangle.\r
*/\r
- int right;\r
+ private int right;\r
\r
/**\r
* A 16-bit signed integer that defines the y-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int top;\r
+ private int top;\r
\r
/**\r
* A 16-bit signed integer that defines the x-coordinate, in logical units, of the\r
* upper-left corner of the rectangle.\r
*/\r
- int left;\r
+ private int left;\r
\r
/**\r
* An array of Scan objects that define the scanlines in the region.\r
*/\r
- WmfScanObject scanObjects[];\r
+ private WmfScanObject scanObjects[];\r
\r
+ @Override\r
public HwmfRecordType getRecordType() {\r
return HwmfRecordType.createRegion;\r
}\r
\r
+ @Override\r
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {\r
nextInChain = leis.readShort();\r
objectType = leis.readShort();\r
\r
return 20 + size;\r
}\r
+\r
+ @Override\r
+ public void draw(HwmfGraphics ctx) {\r
+\r
+ }\r
}\r
}\r
\r
package org.apache.poi.hwmf.usermodel;\r
\r
+import java.io.BufferedInputStream;\r
+import java.io.FileOutputStream;\r
import java.io.IOException;\r
import java.io.InputStream;\r
import java.util.ArrayList;\r
}\r
\r
public HwmfPicture(InputStream inputStream) throws IOException {\r
- LittleEndianInputStream leis = new LittleEndianInputStream(inputStream);\r
+ BufferedInputStream bis = new BufferedInputStream(inputStream, 10000);\r
+ LittleEndianInputStream leis = new LittleEndianInputStream(bis);\r
HwmfPlaceableHeader placeableHeader = HwmfPlaceableHeader.readHeader(leis);\r
HwmfHeader header = new HwmfHeader(leis);\r
\r
}\r
\r
consumedSize += wr.init(leis, recordSize, recordFunction);\r
- if (consumedSize < recordSize) {\r
- leis.skip(recordSize - consumedSize);\r
+ int remainingSize = (int)(recordSize - consumedSize);\r
+ assert(remainingSize >= 0);\r
+ if (remainingSize > 0) {\r
+ byte remaining[] = new byte[remainingSize];\r
+ leis.read(remaining);\r
+ FileOutputStream fos = new FileOutputStream("remaining.dat");\r
+ fos.write(remaining);\r
+ fos.close();\r
+// leis.skip(remainingSize);\r
}\r
}\r
}\r
\r
import static org.junit.Assert.assertEquals;\r
\r
+import java.awt.image.BufferedImage;\r
+import java.io.ByteArrayInputStream;\r
import java.io.File;\r
+import java.io.FileFilter;\r
import java.io.FileInputStream;\r
+import java.io.FileOutputStream;\r
import java.io.IOException;\r
import java.util.List;\r
+import java.util.Locale;\r
+\r
+import javax.imageio.ImageIO;\r
\r
import org.apache.poi.POIDataSamples;\r
+import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;\r
import org.apache.poi.hwmf.record.HwmfRecord;\r
import org.apache.poi.hwmf.usermodel.HwmfPicture;\r
+import org.apache.poi.sl.usermodel.PictureData;\r
+import org.apache.poi.sl.usermodel.PictureData.PictureType;\r
+import org.apache.poi.sl.usermodel.SlideShow;\r
+import org.apache.poi.sl.usermodel.SlideShowFactory;\r
+import org.junit.Ignore;\r
import org.junit.Test;\r
\r
public class TestHwmfParsing {\r
List<HwmfRecord> records = wmf.getRecords();\r
assertEquals(581, records.size());\r
}\r
+\r
+ @Test\r
+ @Ignore\r
+ public void extract() throws IOException {\r
+ File dir = new File("test-data/slideshow");\r
+ File files[] = dir.listFiles(new FileFilter() {\r
+ public boolean accept(File pathname) {\r
+ return pathname.getName().matches("(?i).*\\.pptx?$");\r
+ }\r
+ });\r
+\r
+ boolean outputFiles = false;\r
+\r
+ File outdir = new File("build/ppt");\r
+ if (outputFiles) {\r
+ outdir.mkdirs();\r
+ }\r
+ int wmfIdx = 1;\r
+ for (File f : files) {\r
+ try {\r
+ SlideShow<?,?> ss = SlideShowFactory.create(f);\r
+ for (PictureData pd : ss.getPictureData()) {\r
+ if (pd.getType() != PictureType.WMF) continue;\r
+ byte wmfData[] = pd.getData();\r
+ if (outputFiles) {\r
+ String filename = String.format(Locale.ROOT, "pic%04d.wmf", wmfIdx);\r
+ FileOutputStream fos = new FileOutputStream(new File(outdir, filename));\r
+ fos.write(wmfData);\r
+ fos.close();\r
+ }\r
+\r
+ HwmfPicture wmf = new HwmfPicture(new ByteArrayInputStream(wmfData));\r
+\r
+ int bmpIndex = 1;\r
+ for (HwmfRecord r : wmf.getRecords()) {\r
+ if (r instanceof HwmfImageRecord) {\r
+ BufferedImage bi = ((HwmfImageRecord)r).getImage();\r
+ if (outputFiles) {\r
+ String filename = String.format(Locale.ROOT, "pic%04d-%04d.png", wmfIdx, bmpIndex);\r
+ ImageIO.write(bi, "PNG", new File(outdir, filename));\r
+ }\r
+ bmpIndex++;\r
+ }\r
+ }\r
+\r
+ wmfIdx++;\r
+ }\r
+ ss.close();\r
+ } catch (Exception e) {\r
+ System.out.println(f+" ignored.");\r
+ }\r
+ }\r
+ }\r
+\r
}\r