From: Andreas Beeker Date: Wed, 11 Sep 2019 21:24:34 +0000 (+0000) Subject: Unify PNG extraction X-Git-Tag: REL_4_1_1~31 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8f051a0b88b51ac4df4a1133b3dbf42bf3ba1e17;p=poi.git Unify PNG extraction git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1866809 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java index 267bd2e1d6..0bac1af0f6 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java @@ -18,12 +18,11 @@ package org.apache.poi.hssf.usermodel; -import org.apache.poi.ddf.EscherBitmapBlip; import org.apache.poi.ddf.EscherBlipRecord; -import org.apache.poi.ddf.EscherMetafileBlip; +import org.apache.poi.ddf.EscherRecordTypes; +import org.apache.poi.sl.image.ImageHeaderPNG; import org.apache.poi.ss.usermodel.PictureData; import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.util.PngUtils; /** * Represents binary data stored in the file. Eg. A GIF, JPEG etc... @@ -58,20 +57,8 @@ public class HSSFPictureData implements PictureData /* (non-Javadoc) * @see org.apache.poi.hssf.usermodel.PictureData#getData() */ - public byte[] getData() - { - 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; + public byte[] getData() { + return new ImageHeaderPNG(blip.getPicturedata()).extractPNG(); } /** @@ -93,18 +80,18 @@ public class HSSFPictureData implements PictureData * @return 'wmf', 'jpeg' etc depending on the format. never null */ public String suggestFileExtension() { - switch (blip.getRecordId()) { - case EscherMetafileBlip.RECORD_ID_WMF: + switch (EscherRecordTypes.forTypeID(blip.getRecordId())) { + case BLIP_WMF: return "wmf"; - case EscherMetafileBlip.RECORD_ID_EMF: + case BLIP_EMF: return "emf"; - case EscherMetafileBlip.RECORD_ID_PICT: + case BLIP_PICT: return "pict"; - case EscherBitmapBlip.RECORD_ID_PNG: + case BLIP_PNG: return "png"; - case EscherBitmapBlip.RECORD_ID_JPEG: + case BLIP_JPEG: return "jpeg"; - case EscherBitmapBlip.RECORD_ID_DIB: + case BLIP_DIB: return "dib"; default: return ""; @@ -115,18 +102,18 @@ public class HSSFPictureData implements PictureData * Returns the mime type for the image */ public String getMimeType() { - switch (blip.getRecordId()) { - case EscherMetafileBlip.RECORD_ID_WMF: + switch (EscherRecordTypes.forTypeID(blip.getRecordId())) { + case BLIP_WMF: return "image/x-wmf"; - case EscherMetafileBlip.RECORD_ID_EMF: + case BLIP_EMF: return "image/x-emf"; - case EscherMetafileBlip.RECORD_ID_PICT: + case BLIP_PICT: return "image/x-pict"; - case EscherBitmapBlip.RECORD_ID_PNG: + case BLIP_PNG: return "image/png"; - case EscherBitmapBlip.RECORD_ID_JPEG: + case BLIP_JPEG: return "image/jpeg"; - case EscherBitmapBlip.RECORD_ID_DIB: + case BLIP_DIB: return "image/bmp"; default: return "image/unknown"; @@ -144,18 +131,18 @@ public class HSSFPictureData implements PictureData * @see Workbook#PICTURE_TYPE_WMF */ public int getPictureType() { - switch (blip.getRecordId()) { - case EscherMetafileBlip.RECORD_ID_WMF: + switch (EscherRecordTypes.forTypeID(blip.getRecordId())) { + case BLIP_WMF: return Workbook.PICTURE_TYPE_WMF; - case EscherMetafileBlip.RECORD_ID_EMF: + case BLIP_EMF: return Workbook.PICTURE_TYPE_EMF; - case EscherMetafileBlip.RECORD_ID_PICT: + case BLIP_PICT: return Workbook.PICTURE_TYPE_PICT; - case EscherBitmapBlip.RECORD_ID_PNG: + case BLIP_PNG: return Workbook.PICTURE_TYPE_PNG; - case EscherBitmapBlip.RECORD_ID_JPEG: + case BLIP_JPEG: return Workbook.PICTURE_TYPE_JPEG; - case EscherBitmapBlip.RECORD_ID_DIB: + case BLIP_DIB: return Workbook.PICTURE_TYPE_DIB; default: return -1; diff --git a/src/java/org/apache/poi/sl/image/ImageHeaderPNG.java b/src/java/org/apache/poi/sl/image/ImageHeaderPNG.java new file mode 100644 index 0000000000..400bedd74e --- /dev/null +++ b/src/java/org/apache/poi/sl/image/ImageHeaderPNG.java @@ -0,0 +1,59 @@ +/* ==================================================================== + 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.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.poi.poifs.filesystem.FileMagic; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.RecordFormatException; + +public final class ImageHeaderPNG { + + private static final int MAGIC_OFFSET = 16; + + private byte[] data; + + /** + * @param data The raw image data + */ + public ImageHeaderPNG(byte[] data) { + this.data = data; + } + + /** + * PNG created on MAC may have a 16-byte prefix which prevents successful reading. + * @return the trimmed PNG data + */ + public byte[] extractPNG() { + // + //Just cut it off!. + try (InputStream is = new ByteArrayInputStream(data)) { + if (is.skip(MAGIC_OFFSET) == MAGIC_OFFSET && FileMagic.valueOf(is) == FileMagic.PNG) { + return IOUtils.toByteArray(is); + } + } catch (IOException e) { + throw new RecordFormatException("Unable to parse PNG header", e); + } + + return data; + } +} diff --git a/src/java/org/apache/poi/util/PngUtils.java b/src/java/org/apache/poi/util/PngUtils.java deleted file mode 100644 index f9126c9392..0000000000 --- a/src/java/org/apache/poi/util/PngUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* ==================================================================== - 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; - - -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 f2abc4068d..8e05aa7611 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.util.PngUtils; +import org.apache.poi.sl.image.ImageHeaderPNG; /** * Represents a PNG picture data in a PPT file @@ -26,17 +26,7 @@ public final class PNG extends Bitmap { @Override 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 new ImageHeaderPNG(super.getData()).extractPNG(); } @Override 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 a7ed1adc4b..d8ab165f03 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Picture.java @@ -34,7 +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.sl.image.ImageHeaderPNG; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; import org.apache.poi.util.StringUtil; @@ -169,16 +169,7 @@ public final class Picture { else { // 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; - } + content = new ImageHeaderPNG(rawContent).extractPNG(); } }