diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java new file mode 100644 index 000000000..c47a37242 --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java @@ -0,0 +1,90 @@ +/* ==================================================================== + Copyright 2002-2004 Apache Software Foundation + + Licensed 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.hssf.usermodel; + +import org.apache.poi.ddf.EscherBitmapBlip; + +/** + * Represents binary data stored in the file. Eg. A GIF, JPEG etc... + * + * @author Daniel Noll + */ +public class HSSFPictureData +{ + // MSOBI constants for various formats. + public static final short MSOBI_WMF = 0x2160; + public static final short MSOBI_EMF = 0x3D40; + public static final short MSOBI_PICT = 0x5420; + public static final short MSOBI_PNG = 0x6E00; + public static final short MSOBI_JPEG = 0x46A0; + public static final short MSOBI_DIB = 0x7A80; + // Mask of the bits in the options used to store the image format. + public static final short FORMAT_MASK = (short) 0xFFF0; + + /** + * Underlying escher blip record containing the bitmap data. + */ + private EscherBitmapBlip blip; + + /** + * Constructs a picture object. + * + * @param blip the underlying blip record containing the bitmap data. + */ + HSSFPictureData( EscherBitmapBlip blip ) + { + this.blip = blip; + } + + /** + * Gets the picture data. + * + * @return the picture data. + */ + public byte[] getData() + { + return blip.getPicturedata(); + } + + /** + * Suggests a file extension for this image. + * + * @return the file extension. + */ + public String suggestFileExtension() + { + switch (blip.getOptions() & FORMAT_MASK) + { + case MSOBI_WMF: + return "wmf"; + case MSOBI_EMF: + return "emf"; + case MSOBI_PICT: + return "pict"; + case MSOBI_PNG: + return "png"; + case MSOBI_JPEG: + return "jpeg"; + case MSOBI_DIB: + return "dib"; + default: + return ""; + } + } +} + diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 9ce9f171b..f90717e98 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -26,6 +26,7 @@ package org.apache.poi.hssf.usermodel; import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBitmapBlip; import org.apache.poi.ddf.EscherRecord; +import org.apache.poi.ddf.EscherBlipRecord; import org.apache.poi.hssf.eventmodel.EventRecordFactory; import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Workbook; @@ -114,14 +115,12 @@ public class HSSFWorkbook private HSSFDataFormat formatter; - /// NOT YET SUPPORTED: /** Extended windows meta file */ - //public static final int PICTURE_TYPE_EMF = 2; + public static final int PICTURE_TYPE_EMF = 2; /** Windows Meta File */ - //public static final int PICTURE_TYPE_WMF = 3; + public static final int PICTURE_TYPE_WMF = 3; /** Mac PICT format */ - //public static final int PICTURE_TYPE_PICT = 4; - + public static final int PICTURE_TYPE_PICT = 4; /** JPEG format */ public static final int PICTURE_TYPE_JPEG = 5; /** PNG format */ @@ -217,6 +216,11 @@ public class HSSFWorkbook Sheet sheet = Sheet.createSheet(records, sheetNum++, recOffset ); recOffset = sheet.getEofLoc()+1; + if (recOffset == 1) + { + break; + } + HSSFSheet hsheet = new HSSFSheet(workbook, sheet); sheets.add(hsheet); @@ -1274,12 +1278,27 @@ public class HSSFWorkbook byte[] uid = newUID(); EscherBitmapBlip blipRecord = new EscherBitmapBlip(); blipRecord.setRecordId( (short) ( EscherBitmapBlip.RECORD_ID_START + format ) ); - if (format == HSSFWorkbook.PICTURE_TYPE_PNG) - blipRecord.setOptions( (short) 0x6E00 ); // MSOBI - else if (format == HSSFWorkbook.PICTURE_TYPE_JPEG) - blipRecord.setOptions( (short) 0x46A0 ); // MSOBI - else if (format == HSSFWorkbook.PICTURE_TYPE_DIB) - blipRecord.setOptions( (short) 0x7A8 ); // MSOBI + switch (format) + { + case PICTURE_TYPE_EMF: + blipRecord.setOptions(HSSFPictureData.MSOBI_EMF); + break; + case PICTURE_TYPE_WMF: + blipRecord.setOptions(HSSFPictureData.MSOBI_WMF); + break; + case PICTURE_TYPE_PICT: + blipRecord.setOptions(HSSFPictureData.MSOBI_PICT); + break; + case PICTURE_TYPE_PNG: + blipRecord.setOptions(HSSFPictureData.MSOBI_PNG); + break; + case HSSFWorkbook.PICTURE_TYPE_JPEG: + blipRecord.setOptions(HSSFPictureData.MSOBI_JPEG); + break; + case HSSFWorkbook.PICTURE_TYPE_DIB: + blipRecord.setOptions(HSSFPictureData.MSOBI_DIB); + break; + } blipRecord.setUID( uid ); blipRecord.setMarker( (byte) 0xFF ); @@ -1300,6 +1319,60 @@ public class HSSFWorkbook return workbook.addBSERecord( r ); } + /** + * Gets all pictures from the Workbook. + * + * @return the list of pictures (a list of {@link HSSFPictureData} objects.) + */ + public List getAllPictures() + { + List pictures = new ArrayList(); + Iterator recordIter = workbook.getRecords().iterator(); + while (recordIter.hasNext()) + { + Object obj = recordIter.next(); + if (obj instanceof AbstractEscherHolderRecord) + { + ((AbstractEscherHolderRecord) obj).decode(); + List escherRecords = ((AbstractEscherHolderRecord) obj).getEscherRecords(); + searchForPictures(escherRecords, pictures); + } + } + return pictures; + } + + /** + * Performs a recursive search for pictures in the given list of escher records. + * + * @param escherRecords the escher records. + * @param pictures the list to populate with the pictures. + */ + private void searchForPictures(List escherRecords, List pictures) + { + Iterator recordIter = escherRecords.iterator(); + while (recordIter.hasNext()) + { + Object obj = recordIter.next(); + if (obj instanceof EscherRecord) + { + EscherRecord escherRecord = (EscherRecord) obj; + + if (escherRecord instanceof EscherBSERecord) + { + EscherBlipRecord blip = ((EscherBSERecord) escherRecord).getBlipRecord(); + if (blip instanceof EscherBitmapBlip) + { + // TODO: Some kind of structure. + pictures.add(new HSSFPictureData((EscherBitmapBlip) blip)); + } + } + + // Recursive call. + searchForPictures(escherRecord.getChildRecords(), pictures); + } + } + } + private byte[] newUID() { byte[] bytes = new byte[16]; diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java new file mode 100644 index 000000000..a31d933d5 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPictureData.java @@ -0,0 +1,75 @@ +/* ==================================================================== + 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. +==================================================================== */ + + +/* + * HSSFWorkbook.java + * + * Created on September 30, 2001, 3:37 PM + */ +package org.apache.poi.hssf.usermodel; + +import junit.framework.TestCase; + +import javax.imageio.ImageIO; +import java.io.*; +import java.util.*; +import java.awt.image.BufferedImage; + +/** + * Test HSSFPictureData. + * The code to retrieve images from a workbook provided by Trejkaz (trejkaz at trypticon dot org) in Bug 41223. + * + * @author Yegor Kozlov (yegor at apache dot org) + * @author Trejkaz (trejkaz at trypticon dot org) + */ +public class TestHSSFPictureData extends TestCase{ + + static String cwd = System.getProperty("HSSF.testdata.path"); + + public void testPictures() throws IOException { + FileInputStream is = new FileInputStream(new File(cwd, "SimpleWithImages.xls")); + HSSFWorkbook wb = new HSSFWorkbook(is); + is.close(); + + List lst = wb.getAllPictures(); + assertEquals(2, lst.size()); + + for (Iterator it = lst.iterator(); it.hasNext(); ) { + HSSFPictureData pict = (HSSFPictureData)it.next(); + String ext = pict.suggestFileExtension(); + byte[] data = pict.getData(); + if (ext.equals("jpeg")){ + //try to read image data using javax.imageio.* (JDK 1.4+) + BufferedImage jpg = ImageIO.read(new ByteArrayInputStream(data)); + assertNotNull(jpg); + assertEquals(192, jpg.getWidth()); + assertEquals(176, jpg.getHeight()); + } else if (ext.equals("png")){ + //try to read image data using javax.imageio.* (JDK 1.4+) + BufferedImage png = ImageIO.read(new ByteArrayInputStream(data)); + assertNotNull(png); + assertEquals(300, png.getWidth()); + assertEquals(300, png.getHeight()); + + } else { + fail("unexpected picture type: " + ext); + } + } + + } +}