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