From 65cce551dec95a11c65b76ddabb7905ce9d1b100 Mon Sep 17 00:00:00 2001
From: Luke Quinane <luke.quinane@gmail.com>
Date: Mon, 18 Jun 2012 14:05:38 +1000
Subject: [PATCH] Improve HSLF handling of PNG files. Fix HSSF and HWPF when reading PNGs with a 16 byte header.

---
 .../apache/poi/hssf/usermodel/HSSFPictureData.java |   14 +++++-
 src/java/org/apache/poi/util/PngUtils.java         |   57 ++++++++++++++++++++
 .../src/org/apache/poi/hslf/blip/PNG.java          |   30 +++++------
 .../src/org/apache/poi/hwpf/usermodel/Picture.java |   10 ++++
 4 files changed, 94 insertions(+), 17 deletions(-)
 create mode 100644 src/java/org/apache/poi/util/PngUtils.java

diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
index 0516ccc..69bdae1 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java
@@ -22,6 +22,7 @@ import org.apache.poi.ddf.EscherBitmapBlip;
 import org.apache.poi.ddf.EscherBlipRecord;
 import org.apache.poi.ddf.EscherMetafileBlip;
 import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.util.PngUtils;
 
 /**
  * Represents binary data stored in the file.  Eg. A GIF, JPEG etc...
@@ -60,7 +61,18 @@ public class HSSFPictureData implements PictureData
      */
     public byte[] getData()
     {
-        return blip.getPicturedata();
+        byte[] pictureData = blip.getPicturedata();
+
+        //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+        //Just cut it off!.
+        if (PngUtils.matchesPngHeader(pictureData, 16))
+        {
+            byte[] png = new byte[pictureData.length-16];
+            System.arraycopy(pictureData, 16, png, 0, png.length);
+            pictureData = png;
+        }
+
+        return pictureData;
     }
 
     /**
diff --git a/src/java/org/apache/poi/util/PngUtils.java b/src/java/org/apache/poi/util/PngUtils.java
new file mode 100644
index 0000000..0ecb062
--- /dev/null
+++ b/src/java/org/apache/poi/util/PngUtils.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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class PngUtils {
+
+    /**
+     * File header for PNG format.
+     */
+    private static final byte[] PNG_FILE_HEADER =
+        new byte[] { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
+
+    private PngUtils() {
+        // no instances of this class
+    }
+
+    /**
+     * Checks if the offset matches the PNG header.
+     *
+     * @param data the data to check.
+     * @param offset the offset to check at.
+     * @return {@code true} if the offset matches.
+     */
+    public static boolean matchesPngHeader(byte[] data, int offset) {
+        if (data == null || data.length - offset < PNG_FILE_HEADER.length) {
+            return false;
+        }
+
+        for (int i = 0; i < PNG_FILE_HEADER.length; i++) {
+            if (PNG_FILE_HEADER[i] != data[i + offset]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
index 20016fd..12b98f1 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hslf.blip;
 
+import org.apache.poi.util.PngUtils;
 import org.apache.poi.hslf.model.Picture;
 import org.apache.poi.hslf.exceptions.HSLFException;
 
@@ -35,22 +36,19 @@ public final class PNG extends Bitmap {
     /**
      * @return PNG data
      */
-    public byte[] getData(){
-         byte[] data = super.getData();
-          try {
-              //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
-              //Just cut it off!.
-              BufferedImage bi = ImageIO.read(new ByteArrayInputStream(data));
-              if (bi == null){
-                  byte[] png = new byte[data.length-16];
-                  System.arraycopy(data, 16, png, 0, png.length);
-                  data = png;
-              }
-          } catch (IOException e){
-              throw new HSLFException(e);
-          }
-         return data;
-     }
+    public byte[] getData() {
+        byte[] data = super.getData();
+
+        //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+        //Just cut it off!.
+        if (PngUtils.matchesPngHeader(data, 16)) {
+            byte[] png = new byte[data.length-16];
+            System.arraycopy(data, 16, png, 0, png.length);
+            data = png;
+        }
+
+        return data;
+    }
 
     /**
      * @return type of  this picture
diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
index ff7af7c..670755d 100644
--- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java
@@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperty;
 import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hwpf.model.PICF;
 import org.apache.poi.hwpf.model.PICFAndOfficeArtData;
+import org.apache.poi.util.PngUtils;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
@@ -191,6 +192,15 @@ public final class Picture
         {
             // Raw data is not compressed.
             content = rawContent;
+
+            //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
+            //Just cut it off!.
+            if (PngUtils.matchesPngHeader(content, 16))
+            {
+                byte[] png = new byte[content.length-16];
+                System.arraycopy(content, 16, png, 0, png.length);
+                content = png;
+            }
         }
     }
 
-- 
1.7.4.msysgit.0.173.g83185.dirty

