diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java b/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
new file mode 100644
index 0000000000..3ecc6e55c7
--- /dev/null
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderBitmap.java
@@ -0,0 +1,57 @@
+/* ====================================================================
+ 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.sl.image;
+
+import java.awt.Dimension;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.imageio.ImageIO;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
+
+@Internal
+public class ImageHeaderBitmap {
+ private static final POILogger LOG = POILogFactory.getLogger(ImageHeaderBitmap.class);
+
+ private final Dimension size;
+
+ public ImageHeaderBitmap(byte data[], int offset) {
+ BufferedImage img = null;
+ try {
+ img = ImageIO.read(new ByteArrayInputStream(data, offset, data.length-offset));
+ } catch (IOException e) {
+ LOG.log(POILogger.WARN, "Can't determine image dimensions", e);
+ }
+ // set dummy size, in case of dummy dimension can't be set
+ size = (img == null)
+ ? new Dimension(200,200)
+ : new Dimension(
+ (int)Units.pixelToPoints(img.getWidth()),
+ (int)Units.pixelToPoints(img.getHeight())
+ );
+ }
+
+ public Dimension getSize() {
+ return size;
+ }
+}
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java b/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
new file mode 100644
index 0000000000..7845c0ff9b
--- /dev/null
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderEMF.java
@@ -0,0 +1,68 @@
+/* ====================================================================
+ 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.sl.image;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+@Internal
+public class ImageHeaderEMF {
+ private static POILogger LOG = POILogFactory.getLogger(ImageHeaderEMF.class);
+
+ private final static String EMF_SIGNATURE = " EMF"; // 0x464D4520 (LE)
+
+ // rectangular inclusive-inclusive bounds, in device units, of the smallest
+ // rectangle that can be drawn around the image stored in the metafile.
+ private final Rectangle deviceBounds;
+
+ public ImageHeaderEMF(byte data[], int offset) {
+ int type = (int)LittleEndian.getUInt(data, offset); offset += 4;
+ if (type != 1) {
+ LOG.log(POILogger.WARN, "Invalid EMF picture - invalid type");
+ deviceBounds = new Rectangle(0,0,200,200);
+ return;
+ }
+ // ignore header size
+ offset += 4;
+ int left = LittleEndian.getInt(data, offset); offset += 4;
+ int top = LittleEndian.getInt(data, offset); offset += 4;
+ int right = LittleEndian.getInt(data, offset); offset += 4;
+ int bottom = LittleEndian.getInt(data, offset); offset += 4;
+ deviceBounds = new Rectangle(left, top, right-left, bottom-top);
+ // ignore frame bounds
+ offset += 16;
+ String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252);
+ if (!EMF_SIGNATURE.equals(signature)) {
+ LOG.log(POILogger.WARN, "Invalid EMF picture - invalid signature");
+ }
+ }
+
+ public Dimension getSize() {
+ return deviceBounds.getSize();
+ }
+
+ public Rectangle getBounds() {
+ return deviceBounds;
+ }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderPICT.java b/src/java/org/apache/poi/sl/image/ImageHeaderPICT.java
new file mode 100644
index 0000000000..d994fb8ce3
--- /dev/null
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderPICT.java
@@ -0,0 +1,103 @@
+/* ====================================================================
+ 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.sl.image;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+
+@Internal
+public class ImageHeaderPICT {
+ /**
+ * skip the first 512 bytes - they are MAC specific crap
+ */
+ public static final int PICT_HEADER_OFFSET = 512;
+
+ public static final double DEFAULT_RESOLUTION = Units.POINT_DPI;
+
+ private static final byte V2_HEADER[] = {
+ 0x00, 0x11, // v2 version opcode
+ 0x02, (byte)0xFF, // version number of new picture
+ 0x0C, 0x00, // header opcode
+ (byte)0xFF, (byte)0xFE, 0x00, 0x00 // pic size dummy
+ };
+
+ private final Rectangle bounds;
+ private final double hRes, vRes;
+
+ public ImageHeaderPICT(byte data[], int offset) {
+ // http://mirrors.apple2.org.za/apple.cabi.net/Graphics/PICT.and_QT.INFO/PICT.file.format.TI.txt
+
+ // low order 16 bits of picture size - can be ignored
+ offset += 2;
+ // rectangular bounding box of picture, at 72 dpi
+ // rect : 8 bytes (top, left, bottom, right: integer)
+ int y1 = readUnsignedShort(data, offset); offset += 2;
+ int x1 = readUnsignedShort(data, offset); offset += 2;
+ int y2 = readUnsignedShort(data, offset); offset += 2;
+ int x2 = readUnsignedShort(data, offset); offset += 2;
+
+ // check for version 2 ... otherwise we don't read any further
+ boolean isV2 = true;
+ for (byte b : V2_HEADER) {
+ if (b != data[offset++]) {
+ isV2 = false;
+ break;
+ }
+ }
+
+ if (isV2) {
+ // 4 bytes - fixed, horizontal resolution (dpi) of source data
+ hRes = readFixedPoint(data, offset); offset += 4;
+ // 4 bytes - fixed, vertical resolution (dpi) of source data
+ vRes = readFixedPoint(data, offset); offset += 4;
+ } else {
+ hRes = DEFAULT_RESOLUTION;
+ vRes = DEFAULT_RESOLUTION;
+ }
+
+ bounds = new Rectangle(x1,y1,x2-x1,y2-y1);
+ }
+
+ public Dimension getSize() {
+ int height = (int)Math.round(bounds.height*DEFAULT_RESOLUTION/vRes);
+ int width = (int)Math.round(bounds.width*DEFAULT_RESOLUTION/hRes);
+ return new Dimension(width, height);
+ }
+
+ public Rectangle getBounds() {
+ return bounds;
+ }
+
+ private static int readUnsignedShort(byte data[], int offset) {
+ int b0 = data[offset] & 0xFF;
+ int b1 = data[offset+1] & 0xFF;
+ return b0 << 8 | b1;
+ }
+
+ private static double readFixedPoint(byte data[], int offset) {
+ int b0 = data[offset] & 0xFF;
+ int b1 = data[offset+1] & 0xFF;
+ int b2 = data[offset+2] & 0xFF;
+ int b3 = data[offset+3] & 0xFF;
+ int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+ return i / (double)0x10000;
+ }
+}
diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java b/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
new file mode 100644
index 0000000000..b57b4d0099
--- /dev/null
+++ b/src/java/org/apache/poi/sl/image/ImageHeaderWMF.java
@@ -0,0 +1,154 @@
+/* ====================================================================
+ 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.sl.image;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
+
+/**
+ * Aldus Placeable Metafile header - 22 byte structure before WMF data.
+ *
+ * - int Key; Magic number (always 9AC6CDD7h)
+ *
- short Handle; Metafile HANDLE number (always 0)
+ *
- short Left; Left coordinate in metafile units
+ *
- short Top; Top coordinate in metafile units
+ *
- short Right; Right coordinate in metafile units
+ *
- short Bottom; Bottom coordinate in metafile units
+ *
- short Inch; Number of metafile units per inch
+ *
- int Reserved; Reserved (always 0)
+ *
- short Checksum; Checksum value for previous 10 shorts
+ *
+ */
+@Internal
+public class ImageHeaderWMF {
+
+ public static final int APMHEADER_KEY = 0x9AC6CDD7;
+ private static POILogger LOG = POILogFactory.getLogger(ImageHeaderWMF.class);
+
+ @SuppressWarnings("unused")
+ private final int handle;
+ private final int left, top, right, bottom;
+
+ /**
+ * The number of logical units per inch used to represent the image.
+ * This value can be used to scale an image. By convention, an image is
+ * considered to be recorded at 1440 logical units (twips) per inch.
+ * Thus, a value of 720 specifies that the image SHOULD be rendered at
+ * twice its normal size, and a value of 2880 specifies that the image
+ * SHOULD be rendered at half its normal size.
+ */
+ private final int inch;
+ @SuppressWarnings("unused")
+ private final int reserved;
+ private int checksum;
+
+ public ImageHeaderWMF(Rectangle dim) {
+ handle = 0;
+ left = dim.x;
+ top = dim.y;
+ right = dim.x + dim.width;
+ bottom = dim.y + dim.height;
+ inch = Units.POINT_DPI; //default resolution is 72 dpi
+ reserved = 0;
+ }
+
+ public ImageHeaderWMF(byte[] data, int pos) {
+ int key = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE; //header key
+ if (key != APMHEADER_KEY) {
+ LOG.log(POILogger.WARN, "WMF file doesn't contain a placeable header - ignore parsing");
+ handle = 0;
+ left = 0;
+ top = 0;
+ right = 200;
+ bottom = 200;
+ inch = Units.POINT_DPI; //default resolution is 72 dpi
+ reserved = 0;
+ return;
+ }
+
+ handle = LittleEndian.getUShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ left = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ top = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ right = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ bottom = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+
+ inch = LittleEndian.getUShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE;
+
+ checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
+ if (checksum != getChecksum()){
+ LOG.log(POILogger.WARN, "WMF checksum does not match the header data");
+ }
+ }
+
+ /**
+ * Returns a checksum value for the previous 10 shorts in the header.
+ * The checksum is calculated by XORing each short value to an initial value of 0:
+ */
+ public int getChecksum(){
+ int cs = 0;
+ cs ^= (APMHEADER_KEY & 0x0000FFFF);
+ cs ^= ((APMHEADER_KEY & 0xFFFF0000) >> 16);
+ cs ^= left;
+ cs ^= top;
+ cs ^= right;
+ cs ^= bottom;
+ cs ^= inch;
+ return cs;
+ }
+
+ public void write(OutputStream out) throws IOException {
+ byte[] header = new byte[22];
+ int pos = 0;
+ LittleEndian.putInt(header, pos, APMHEADER_KEY); pos += LittleEndian.INT_SIZE; //header key
+ LittleEndian.putUShort(header, pos, 0); pos += LittleEndian.SHORT_SIZE; //hmf
+ LittleEndian.putUShort(header, pos, left); pos += LittleEndian.SHORT_SIZE; //left
+ LittleEndian.putUShort(header, pos, top); pos += LittleEndian.SHORT_SIZE; //top
+ LittleEndian.putUShort(header, pos, right); pos += LittleEndian.SHORT_SIZE; //right
+ LittleEndian.putUShort(header, pos, bottom); pos += LittleEndian.SHORT_SIZE; //bottom
+ LittleEndian.putUShort(header, pos, inch); pos += LittleEndian.SHORT_SIZE; //inch
+ LittleEndian.putInt(header, pos, 0); pos += LittleEndian.INT_SIZE; //reserved
+
+ checksum = getChecksum();
+ LittleEndian.putUShort(header, pos, checksum);
+
+ out.write(header);
+ }
+
+ public Dimension getSize() {
+ //coefficient to translate from WMF dpi to 72dpi
+ double coeff = ((double)Units.POINT_DPI)/inch;
+ return new Dimension((int)Math.round((right-left)*coeff), (int)Math.round((bottom-top)*coeff));
+ }
+
+ public Rectangle getBounds() {
+ return new Rectangle(left, top, right-left, bottom-top);
+ }
+
+ public int getLength(){
+ return 22;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
index 9f705e0e04..3405ef3725 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
@@ -20,28 +20,23 @@
package org.apache.poi.xslf.usermodel;
import java.awt.Dimension;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import javax.imageio.ImageIO;
-
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
-import org.apache.poi.hslf.blip.EMF;
-import org.apache.poi.hslf.blip.PICT;
-import org.apache.poi.hslf.blip.WMF;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.sl.image.ImageHeaderBitmap;
+import org.apache.poi.sl.image.ImageHeaderEMF;
+import org.apache.poi.sl.image.ImageHeaderPICT;
+import org.apache.poi.sl.image.ImageHeaderWMF;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.util.Beta;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
/**
@@ -49,8 +44,6 @@ import org.apache.poi.util.Units;
*/
@Beta
public final class XSLFPictureData extends POIXMLDocumentPart implements PictureData {
- private static final POILogger logger = POILogFactory.getLogger(XSLFPictureData.class);
-
private Long checksum = null;
// original image dimensions (for formats supported by BufferedImage)
@@ -171,30 +164,18 @@ public final class XSLFPictureData extends POIXMLDocumentPart implements Picture
switch (pt) {
case EMF:
- origSize = new EMF.NativeHeader(data, 0).getSize();
+ origSize = new ImageHeaderEMF(data, 0).getSize();
break;
case WMF:
// wmf files in pptx usually have their placeable header
// stripped away, so this returns only the dummy size
- origSize = new WMF.NativeHeader(data, 0).getSize();
+ origSize = new ImageHeaderWMF(data, 0).getSize();
break;
case PICT:
- origSize = new PICT.NativeHeader(data, 0).getSize();
+ origSize = new ImageHeaderPICT(data, 0).getSize();
break;
default:
- BufferedImage img = null;
- try {
- img = ImageIO.read(new ByteArrayInputStream(data));
- } catch (IOException e) {
- logger.log(POILogger.WARN, "Can't determine image dimensions", e);
- }
- // set dummy size, in case of dummy dimension can't be set
- origSize = (img == null)
- ? new Dimension(200,200)
- : new Dimension(
- (int)Units.pixelToPoints(img.getWidth()),
- (int)Units.pixelToPoints(img.getHeight())
- );
+ origSize = new ImageHeaderBitmap(data, 0).getSize();
break;
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
index 4d7de5f75d..7eb285dfb7 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java
@@ -18,7 +18,6 @@
package org.apache.poi.hslf.blip;
import java.awt.Dimension;
-import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -26,8 +25,7 @@ import java.io.InputStream;
import java.util.zip.InflaterInputStream;
import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.sl.image.ImageHeaderEMF;
import org.apache.poi.util.Units;
/**
@@ -35,38 +33,6 @@ import org.apache.poi.util.Units;
*/
public final class EMF extends Metafile {
- public static class NativeHeader {
- // rectangular inclusive-inclusive bounds, in device units, of the smallest
- // rectangle that can be drawn around the image stored in the metafile.
- private final Rectangle deviceBounds;
-
- private final static String EMF_SIGNATURE = " EMF"; // 0x464D4520 (LE)
-
- public NativeHeader(byte data[], int offset) {
- int type = (int)LittleEndian.getUInt(data, offset); offset += 4;
- if (type != 1) {
- throw new HSLFException("Invalid EMF picture");
- }
- // ignore header size
- offset += 4;
- int left = LittleEndian.getInt(data, offset); offset += 4;
- int top = LittleEndian.getInt(data, offset); offset += 4;
- int right = LittleEndian.getInt(data, offset); offset += 4;
- int bottom = LittleEndian.getInt(data, offset); offset += 4;
- deviceBounds = new Rectangle(left, top, right-left, bottom-top);
- // ignore frame bounds
- offset += 16;
- String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252);
- if (!EMF_SIGNATURE.equals(signature)) {
- throw new HSLFException("Invalid EMF picture");
- }
- }
-
- public Dimension getSize() {
- return deviceBounds.getSize();
- }
- }
-
@Override
public byte[] getData(){
try {
@@ -96,11 +62,11 @@ public final class EMF extends Metafile {
public void setData(byte[] data) throws IOException {
byte[] compressed = compress(data, 0, data.length);
- NativeHeader nHeader = new NativeHeader(data, 0);
+ ImageHeaderEMF nHeader = new ImageHeaderEMF(data, 0);
Header header = new Header();
header.wmfsize = data.length;
- header.bounds = nHeader.deviceBounds;
+ header.bounds = nHeader.getBounds();
Dimension nDim = nHeader.getSize();
header.size = new Dimension(Units.toEMU(nDim.getWidth()), Units.toEMU(nDim.getHeight()));
header.zipsize = compressed.length;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
index d68b4f7016..c79bade364 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java
@@ -18,13 +18,13 @@
package org.apache.poi.hslf.blip;
import java.awt.Dimension;
-import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.InflaterInputStream;
import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.sl.image.ImageHeaderPICT;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Units;
@@ -35,79 +35,6 @@ import org.apache.poi.util.Units;
public final class PICT extends Metafile {
private static final POILogger LOG = POILogFactory.getLogger(PICT.class);
- public static class NativeHeader {
- /**
- * skip the first 512 bytes - they are MAC specific crap
- */
- public static final int PICT_HEADER_OFFSET = 512;
-
- public static final double DEFAULT_RESOLUTION = Units.POINT_DPI;
-
- private static final byte V2_HEADER[] = {
- 0x00, 0x11, // v2 version opcode
- 0x02, (byte)0xFF, // version number of new picture
- 0x0C, 0x00, // header opcode
- (byte)0xFF, (byte)0xFE, 0x00, 0x00 // pic size dummy
- };
-
- public final Rectangle bounds;
- public final double hRes, vRes;
-
- public NativeHeader(byte data[], int offset) {
- // http://mirrors.apple2.org.za/apple.cabi.net/Graphics/PICT.and_QT.INFO/PICT.file.format.TI.txt
-
- // low order 16 bits of picture size - can be ignored
- offset += 2;
- // rectangular bounding box of picture, at 72 dpi
- // rect : 8 bytes (top, left, bottom, right: integer)
- int y1 = readUnsignedShort(data, offset); offset += 2;
- int x1 = readUnsignedShort(data, offset); offset += 2;
- int y2 = readUnsignedShort(data, offset); offset += 2;
- int x2 = readUnsignedShort(data, offset); offset += 2;
-
- // check for version 2 ... otherwise we don't read any further
- boolean isV2 = true;
- for (byte b : V2_HEADER) {
- if (b != data[offset++]) {
- isV2 = false;
- break;
- }
- }
-
- if (isV2) {
- // 4 bytes - fixed, horizontal resolution (dpi) of source data
- hRes = readFixedPoint(data, offset); offset += 4;
- // 4 bytes - fixed, vertical resolution (dpi) of source data
- vRes = readFixedPoint(data, offset); offset += 4;
- } else {
- hRes = DEFAULT_RESOLUTION;
- vRes = DEFAULT_RESOLUTION;
- }
-
- bounds = new Rectangle(x1,y1,x2-x1,y2-y1);
- }
-
- public Dimension getSize() {
- int height = (int)Math.round(bounds.height*DEFAULT_RESOLUTION/vRes);
- int width = (int)Math.round(bounds.width*DEFAULT_RESOLUTION/hRes);
- return new Dimension(width, height);
- }
-
- private static int readUnsignedShort(byte data[], int offset) {
- int b0 = data[offset] & 0xFF;
- int b1 = data[offset+1] & 0xFF;
- return b0 << 8 | b1;
- }
-
- private static double readFixedPoint(byte data[], int offset) {
- int b0 = data[offset] & 0xFF;
- int b1 = data[offset+1] & 0xFF;
- int b2 = data[offset+2] & 0xFF;
- int b3 = data[offset+3] & 0xFF;
- int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
- return i / (double)0x10000;
- }
- }
@Override
public byte[] getData(){
@@ -163,14 +90,14 @@ public final class PICT extends Metafile {
@Override
public void setData(byte[] data) throws IOException {
// skip the first 512 bytes - they are MAC specific crap
- final int nOffset = NativeHeader.PICT_HEADER_OFFSET;
- NativeHeader nHeader = new NativeHeader(data, nOffset);
+ final int nOffset = ImageHeaderPICT.PICT_HEADER_OFFSET;
+ ImageHeaderPICT nHeader = new ImageHeaderPICT(data, nOffset);
Header header = new Header();
header.wmfsize = data.length - nOffset;
byte[] compressed = compress(data, nOffset, header.wmfsize);
header.zipsize = compressed.length;
- header.bounds = nHeader.bounds;
+ header.bounds = nHeader.getBounds();
Dimension nDim = nHeader.getSize();
header.size = new Dimension(Units.toEMU(nDim.getWidth()), Units.toEMU(nDim.getHeight()));
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
index 9dbc7f3bc3..78aa9f364f 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java
@@ -18,18 +18,14 @@
package org.apache.poi.hslf.blip;
import java.awt.Dimension;
-import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.poi.hslf.exceptions.HSLFException;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
+import org.apache.poi.sl.image.ImageHeaderWMF;
import org.apache.poi.util.Units;
/**
@@ -49,7 +45,7 @@ public final class WMF extends Metafile {
long len = is.skip(header.getSize() + CHECKSUM_SIZE*uidInstanceCount);
assert(len == header.getSize() + CHECKSUM_SIZE*uidInstanceCount);
- NativeHeader aldus = new NativeHeader(header.bounds);
+ ImageHeaderWMF aldus = new ImageHeaderWMF(header.bounds);
aldus.write(out);
InflaterInputStream inflater = new InflaterInputStream( is );
@@ -68,14 +64,14 @@ public final class WMF extends Metafile {
@Override
public void setData(byte[] data) throws IOException {
int pos = 0;
- NativeHeader nHeader = new NativeHeader(data, pos);
+ ImageHeaderWMF nHeader = new ImageHeaderWMF(data, pos);
pos += nHeader.getLength();
byte[] compressed = compress(data, pos, data.length-pos);
Header header = new Header();
header.wmfsize = data.length - nHeader.getLength();
- header.bounds = new Rectangle((short)nHeader.left, (short)nHeader.top, (short)nHeader.right-(short)nHeader.left, (short)nHeader.bottom-(short)nHeader.top);
+ header.bounds = nHeader.getBounds();
Dimension nDim = nHeader.getSize();
header.size = new Dimension(Units.toEMU(nDim.getWidth()), Units.toEMU(nDim.getHeight()));
header.zipsize = compressed.length;
@@ -118,122 +114,4 @@ public final class WMF extends Metafile {
throw new IllegalArgumentException(signature+" is not a valid instance/signature value for WMF");
}
}
-
- /**
- * Aldus Placeable Metafile header - 22 byte structure before WMF data.
- *
- * - int Key; Magic number (always 9AC6CDD7h)
- *
- short Handle; Metafile HANDLE number (always 0)
- *
- short Left; Left coordinate in metafile units
- *
- short Top; Top coordinate in metafile units
- *
- short Right; Right coordinate in metafile units
- *
- short Bottom; Bottom coordinate in metafile units
- *
- short Inch; Number of metafile units per inch
- *
- int Reserved; Reserved (always 0)
- *
- short Checksum; Checksum value for previous 10 shorts
- *
- */
- @SuppressWarnings("unused")
- public static class NativeHeader {
- public static final int APMHEADER_KEY = 0x9AC6CDD7;
- private static POILogger logger = POILogFactory.getLogger(NativeHeader.class);
-
- private final int handle;
- private final int left, top, right, bottom;
-
- /**
- * The number of logical units per inch used to represent the image.
- * This value can be used to scale an image. By convention, an image is
- * considered to be recorded at 1440 logical units (twips) per inch.
- * Thus, a value of 720 specifies that the image SHOULD be rendered at
- * twice its normal size, and a value of 2880 specifies that the image
- * SHOULD be rendered at half its normal size.
- */
- private final int inch;
- private final int reserved;
- private int checksum;
-
- public NativeHeader(Rectangle dim) {
- handle = 0;
- left = dim.x;
- top = dim.y;
- right = dim.x + dim.width;
- bottom = dim.y + dim.height;
- inch = Units.POINT_DPI; //default resolution is 72 dpi
- reserved = 0;
- }
-
- public NativeHeader(byte[] data, int pos) {
- int key = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE; //header key
- if (key != APMHEADER_KEY) {
- logger.log(POILogger.WARN, "WMF file doesn't contain a placeable header - ignore parsing");
- handle = 0;
- left = 0;
- top = 0;
- right = 200;
- bottom = 200;
- inch = Units.POINT_DPI; //default resolution is 72 dpi
- reserved = 0;
- return;
- }
-
- handle = LittleEndian.getUShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- left = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- top = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- right = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- bottom = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
-
- inch = LittleEndian.getUShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- reserved = LittleEndian.getInt(data, pos); pos += LittleEndian.INT_SIZE;
-
- checksum = LittleEndian.getShort(data, pos); pos += LittleEndian.SHORT_SIZE;
- if (checksum != getChecksum()){
- logger.log(POILogger.WARN, "WMF checksum does not match the header data");
- }
- }
-
- /**
- * Returns a checksum value for the previous 10 shorts in the header.
- * The checksum is calculated by XORing each short value to an initial value of 0:
- */
- public int getChecksum(){
- int cs = 0;
- cs ^= (APMHEADER_KEY & 0x0000FFFF);
- cs ^= ((APMHEADER_KEY & 0xFFFF0000) >> 16);
- cs ^= left;
- cs ^= top;
- cs ^= right;
- cs ^= bottom;
- cs ^= inch;
- return cs;
- }
-
- public void write(OutputStream out) throws IOException {
- byte[] header = new byte[22];
- int pos = 0;
- LittleEndian.putInt(header, pos, APMHEADER_KEY); pos += LittleEndian.INT_SIZE; //header key
- LittleEndian.putUShort(header, pos, 0); pos += LittleEndian.SHORT_SIZE; //hmf
- LittleEndian.putUShort(header, pos, left); pos += LittleEndian.SHORT_SIZE; //left
- LittleEndian.putUShort(header, pos, top); pos += LittleEndian.SHORT_SIZE; //top
- LittleEndian.putUShort(header, pos, right); pos += LittleEndian.SHORT_SIZE; //right
- LittleEndian.putUShort(header, pos, bottom); pos += LittleEndian.SHORT_SIZE; //bottom
- LittleEndian.putUShort(header, pos, inch); pos += LittleEndian.SHORT_SIZE; //inch
- LittleEndian.putInt(header, pos, 0); pos += LittleEndian.INT_SIZE; //reserved
-
- checksum = getChecksum();
- LittleEndian.putUShort(header, pos, checksum);
-
- out.write(header);
- }
-
- public Dimension getSize() {
- //coefficient to translate from WMF dpi to 72dpi
- double coeff = ((double)Units.POINT_DPI)/inch;
- return new Dimension((int)Math.round((right-left)*coeff), (int)Math.round((bottom-top)*coeff));
- }
-
- public int getLength(){
- return 22;
- }
- }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java
index 3afcfe5962..398603cb78 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPictures.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import java.awt.Dimension;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.net.URL;
import java.util.List;
@@ -34,6 +35,9 @@ import org.apache.poi.hslf.blip.JPEG;
import org.apache.poi.hslf.blip.PICT;
import org.apache.poi.hslf.blip.PNG;
import org.apache.poi.hslf.blip.WMF;
+import org.apache.poi.sl.image.ImageHeaderEMF;
+import org.apache.poi.sl.image.ImageHeaderPICT;
+import org.apache.poi.sl.image.ImageHeaderWMF;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.util.Units;
import org.junit.Ignore;
@@ -51,13 +55,13 @@ public final class TestPictures {
* Test read/write Macintosh PICT
*/
@Test
- public void testPICT() throws Exception {
+ public void testPICT() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
byte[] src_bytes = slTests.readFile("cow.pict");
HSLFPictureData data = ppt.addPicture(src_bytes, PictureType.PICT);
- PICT.NativeHeader nHeader = new PICT.NativeHeader(src_bytes, 512);
+ ImageHeaderPICT nHeader = new ImageHeaderPICT(src_bytes, 512);
final int expWidth = 197, expHeight = 137;
Dimension nDim = nHeader.getSize();
assertEquals(expWidth, nDim.getWidth(), 0);
@@ -114,13 +118,13 @@ public final class TestPictures {
* Test read/write WMF
*/
@Test
- public void testWMF() throws Exception {
+ public void testWMF() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
byte[] src_bytes = slTests.readFile("santa.wmf");
HSLFPictureData data = ppt.addPicture(src_bytes, PictureType.WMF);
- WMF.NativeHeader nHeader = new WMF.NativeHeader(src_bytes, 0);
+ ImageHeaderWMF nHeader = new ImageHeaderWMF(src_bytes, 0);
final int expWidth = 136, expHeight = 146;
Dimension nDim = nHeader.getSize();
assertEquals(expWidth, nDim.getWidth(), 0);
@@ -176,13 +180,13 @@ public final class TestPictures {
* Test read/write EMF
*/
@Test
- public void testEMF() throws Exception {
+ public void testEMF() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
byte[] src_bytes = slTests.readFile("wrench.emf");
HSLFPictureData data = ppt.addPicture(src_bytes, PictureType.EMF);
- EMF.NativeHeader nHeader = new EMF.NativeHeader(src_bytes, 0);
+ ImageHeaderEMF nHeader = new ImageHeaderEMF(src_bytes, 0);
final int expWidth = 190, expHeight = 115;
Dimension nDim = nHeader.getSize();
assertEquals(expWidth, nDim.getWidth(), 0);
@@ -233,7 +237,7 @@ public final class TestPictures {
* Test read/write PNG
*/
@Test
- public void testPNG() throws Exception {
+ public void testPNG() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
@@ -273,7 +277,7 @@ public final class TestPictures {
* Test read/write JPEG
*/
@Test
- public void testJPEG() throws Exception {
+ public void testJPEG() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
@@ -314,7 +318,7 @@ public final class TestPictures {
* Test read/write DIB
*/
@Test
- public void testDIB() throws Exception {
+ public void testDIB() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();
@@ -354,7 +358,7 @@ public final class TestPictures {
* Read pictures in different formats from a reference slide show
*/
@Test
- public void testReadPictures() throws Exception {
+ public void testReadPictures() throws IOException {
byte[] src_bytes, ppt_bytes, b1, b2;
HSLFPictureShape pict;
@@ -417,6 +421,7 @@ public final class TestPictures {
ppt_bytes = slTests.readFile("wrench.emf");
assertArrayEquals(src_bytes, ppt_bytes);
+ ppt.close();
}
/**
@@ -424,7 +429,7 @@ public final class TestPictures {
* crazy pictures of type 0, we do our best.
*/
@Test
- public void testZeroPictureType() throws Exception {
+ public void testZeroPictureType() throws IOException {
HSLFSlideShowImpl hslf = new HSLFSlideShowImpl(slTests.openResourceAsStream("PictureTypeZero.ppt"));
// Should still have 2 real pictures
@@ -452,6 +457,8 @@ public final class TestPictures {
pdata = pict.getPictureData();
assertTrue(pdata instanceof WMF);
assertEquals(PictureType.WMF, pdata.getType());
+
+ ppt.close();
}
/**
@@ -460,7 +467,7 @@ public final class TestPictures {
*/
@Test
@Ignore
- public void testZeroPictureLength() throws Exception {
+ public void testZeroPictureLength() throws IOException {
// take the data from www instead of test directory
URL url = new URL("http://www.cs.sfu.ca/~anoop/courses/CMPT-882-Fall-2002/chris.ppt");
HSLFSlideShowImpl hslf = new HSLFSlideShowImpl(url.openStream());
@@ -504,19 +511,21 @@ public final class TestPictures {
assertEquals(streamSize, offset);
assertEquals(3, ppt.getPictureData().size());
+ ppt.close();
}
@Test
- public void testGetPictureName() throws Exception {
+ public void testGetPictureName() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow(slTests.openResourceAsStream("ppt_with_png.ppt"));
HSLFSlide slide = ppt.getSlides().get(0);
HSLFPictureShape p = (HSLFPictureShape)slide.getShapes().get(0); //the first slide contains JPEG
assertEquals("test", p.getPictureName());
+ ppt.close();
}
@Test
- public void testSetPictureName() throws Exception {
+ public void testSetPictureName() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow();
HSLFSlide slide = ppt.createSlide();