Bugzilla 53446 - Fixed some problems extracting PNGs

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1369263 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2012-08-04 05:30:19 +00:00
parent 27f82281ea
commit 63f3987cb0
11 changed files with 187 additions and 18 deletions

View File

@ -34,7 +34,8 @@
<changes> <changes>
<release version="3.9-beta1" date="2012-??-??"> <release version="3.9-beta1" date="2012-??-??">
<action dev="poi-developers" type="fix">53205 - Fix some parsing errors and encoding issues in HDGF </action> <action dev="poi-developers" type="add">53446 - Fixed some problems extracting PNGs </action>
<action dev="poi-developers" type="fix">53205 - Fixed some parsing errors and encoding issues in HDGF </action>
<action dev="poi-developers" type="add">53204 - Improved performanceof PageSettingsBlock in HSSF </action> <action dev="poi-developers" type="add">53204 - Improved performanceof PageSettingsBlock in HSSF </action>
<action dev="poi-developers" type="add">53500 - Getter for repeating rows and columns</action> <action dev="poi-developers" type="add">53500 - Getter for repeating rows and columns</action>
<action dev="poi-developers" type="fix">53369 - Fixed tests failing on JDK 1.7</action> <action dev="poi-developers" type="fix">53369 - Fixed tests failing on JDK 1.7</action>

View File

@ -22,6 +22,7 @@ import org.apache.poi.ddf.EscherBitmapBlip;
import org.apache.poi.ddf.EscherBlipRecord; import org.apache.poi.ddf.EscherBlipRecord;
import org.apache.poi.ddf.EscherMetafileBlip; import org.apache.poi.ddf.EscherMetafileBlip;
import org.apache.poi.ss.usermodel.PictureData; 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... * Represents binary data stored in the file. Eg. A GIF, JPEG etc...
@ -60,7 +61,18 @@ public class HSSFPictureData implements PictureData
*/ */
public byte[] getData() 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;
} }
/** /**

View File

@ -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;
}
}

View File

@ -17,6 +17,7 @@
package org.apache.poi.hslf.blip; package org.apache.poi.hslf.blip;
import org.apache.poi.util.PngUtils;
import org.apache.poi.hslf.model.Picture; import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
@ -35,22 +36,19 @@ public final class PNG extends Bitmap {
/** /**
* @return PNG data * @return PNG data
*/ */
public byte[] getData(){ public byte[] getData() {
byte[] data = super.getData(); byte[] data = super.getData();
try {
//PNG created on MAC may have a 16-byte prefix which prevents successful reading. //PNG created on MAC may have a 16-byte prefix which prevents successful reading.
//Just cut it off!. //Just cut it off!.
BufferedImage bi = ImageIO.read(new ByteArrayInputStream(data)); if (PngUtils.matchesPngHeader(data, 16)) {
if (bi == null){ byte[] png = new byte[data.length-16];
byte[] png = new byte[data.length-16]; System.arraycopy(data, 16, png, 0, png.length);
System.arraycopy(data, 16, png, 0, png.length); data = png;
data = png; }
}
} catch (IOException e){ return data;
throw new HSLFException(e); }
}
return data;
}
/** /**
* @return type of this picture * @return type of this picture

View File

@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hwpf.model.PICF; import org.apache.poi.hwpf.model.PICF;
import org.apache.poi.hwpf.model.PICFAndOfficeArtData; import org.apache.poi.hwpf.model.PICFAndOfficeArtData;
import org.apache.poi.util.PngUtils;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
@ -191,6 +192,15 @@ public final class Picture
{ {
// Raw data is not compressed. // Raw data is not compressed.
content = rawContent; 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;
}
} }
} }

View File

@ -20,10 +20,13 @@ package org.apache.poi.hslf.model;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import javax.imageio.ImageIO;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
@ -88,4 +91,41 @@ public final class TestPicture extends TestCase {
Graphics2D graphics = img.createGraphics(); Graphics2D graphics = img.createGraphics();
pict.draw(graphics); pict.draw(graphics);
} }
public void testMacImages() throws Exception {
HSLFSlideShow hss = new HSLFSlideShow(_slTests.openResourceAsStream("53446.ppt"));
PictureData[] pictures = hss.getPictures();
assertEquals(15, pictures.length);
int[][] expectedSizes = {
null, // WMF
{ 427, 428 }, // PNG
{ 371, 370 }, // PNG
{ 288, 183 }, // PNG
{ 285, 97 }, // PNG
{ 288, 168 }, // PNG
null, // WMF
null, // WMF
{ 199, 259 }, // PNG
{ 432, 244 }, // PNG
{ 261, 258 }, // PNG
null, // WMF
null, // WMF
null, // WMF
null // EMF
};
for (int i = 0; i < pictures.length; i++) {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(pictures[i].getData()));
if (pictures[i].getType() != Picture.WMF && pictures[i].getType() != Picture.EMF) {
assertNotNull(image);
int[] dimensions = expectedSizes[i];
assertEquals(dimensions[0], image.getWidth());
assertEquals(dimensions[1], image.getHeight());
}
}
}
} }

View File

@ -17,10 +17,14 @@
package org.apache.poi.hwpf; package org.apache.poi.hwpf;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hwpf.model.PicturesTable; import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.hwpf.usermodel.Picture; import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
@ -128,6 +132,30 @@ public final class TestHWPFPictures extends TestCase {
assertBytesSame(picBytes, pic.getContent()); assertBytesSame(picBytes, pic.getContent());
} }
public void testMacImages() throws Exception {
HWPFDocument docC = HWPFTestDataSamples.openSampleFile("53446.doc");
PicturesTable picturesTable = docC.getPicturesTable();
List<Picture> pictures = picturesTable.getAllPictures();
assertEquals(4, pictures.size());
int[][] expectedSizes = {
{ 185, 42 }, // PNG
{ 260, 114 }, // PNG
{ 185, 42 }, // PNG
{ 260, 114 }, // PNG
};
for (int i = 0; i < pictures.size(); i++) {
BufferedImage image = ImageIO.read(new ByteArrayInputStream(pictures.get(i).getContent()));
assertNotNull(image);
int[] dimensions = expectedSizes[i];
assertEquals(dimensions[0], image.getWidth());
assertEquals(dimensions[1], image.getHeight());
}
}
/** /**
* Pending the missing files being uploaded to * Pending the missing files being uploaded to
* bug #44937 * bug #44937

View File

@ -71,6 +71,29 @@ public final class TestHSSFPictureData extends TestCase{
} }
} }
} }
public void testMacPicture() throws IOException {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("53446.xls");
@SuppressWarnings("unchecked")
List<HSSFPictureData> lst = (List<HSSFPictureData>)(List<?>)wb.getAllPictures();
assertEquals(1, lst.size());
HSSFPictureData pict = lst.get(0);
String ext = pict.suggestFileExtension();
if (!ext.equals("png")) {
fail("Expected a PNG.");
}
//try to read image data using javax.imageio.* (JDK 1.4+)
byte[] data = pict.getData();
BufferedImage png = ImageIO.read(new ByteArrayInputStream(data));
assertNotNull(png);
assertEquals(78, png.getWidth());
assertEquals(76, png.getHeight());
assertEquals(HSSFWorkbook.PICTURE_TYPE_PNG, pict.getFormat());
assertEquals("image/png", pict.getMimeType());
}
public void testNotNullPictures() throws IOException { public void testNotNullPictures() throws IOException {

Binary file not shown.

Binary file not shown.

Binary file not shown.