Index: src/java/org/apache/poi/ddf/EscherMetafileBlip.java =================================================================== --- src/java/org/apache/poi/ddf/EscherMetafileBlip.java (revision 1531406) +++ src/java/org/apache/poi/ddf/EscherMetafileBlip.java (working copy) @@ -21,6 +21,7 @@ import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; +import org.apache.poi.hssf.usermodel.HSSFPictureData; import java.awt.Dimension; import java.awt.Rectangle; @@ -28,6 +29,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.InflaterInputStream; +import java.util.zip.DeflaterOutputStream; /** * @author Daniel Noll @@ -39,13 +41,6 @@ public static final short RECORD_ID_WMF = (short) 0xF018 + 3; public static final short RECORD_ID_PICT = (short) 0xF018 + 4; - /** - * BLIP signatures as defined in the escher spec - */ - public static final short SIGNATURE_EMF = 0x3D40; - public static final short SIGNATURE_WMF = 0x2160; - public static final short SIGNATURE_PICT = 0x5420; - private static final int HEADER_SIZE = 8; private byte[] field_1_UID; @@ -288,11 +283,37 @@ */ public short getSignature() { switch (getRecordId()) { - case RECORD_ID_EMF: return SIGNATURE_EMF; - case RECORD_ID_WMF: return SIGNATURE_WMF; - case RECORD_ID_PICT: return SIGNATURE_PICT; + case RECORD_ID_EMF: return HSSFPictureData.MSOBI_EMF; + case RECORD_ID_WMF: return HSSFPictureData.MSOBI_WMF; + case RECORD_ID_PICT: return HSSFPictureData.MSOBI_PICT; } log.log(POILogger.WARN, "Unknown metafile: " + getRecordId()); return 0; } + + public void setPictureData(byte[] pictureData) { + super.setPictureData(pictureData); + setUncompressedSize(pictureData.length); + + // info of chicago project: + // "... LZ compression algorithm in the format used by GNU Zip deflate/inflate with a 32k window ..." + // not sure what to do, when lookup tables exceed 32k ... + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(bos); + dos.write(pictureData); + dos.close(); + raw_pictureData = bos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Can't compress metafile picture data", e); + } + + setCompressedSize(raw_pictureData.length); + setCompressed(true); + } + + public void setFilter(byte filter) { + field_7_fFilter = filter; + } } Index: src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java =================================================================== --- src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java (revision 1531406) +++ src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java (working copy) @@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBitmapBlip; import org.apache.poi.ddf.EscherBlipRecord; +import org.apache.poi.ddf.EscherMetafileBlip; import org.apache.poi.ddf.EscherRecord; import org.apache.poi.hssf.OldExcelFormatException; import org.apache.poi.hssf.model.DrawingManager2; @@ -57,6 +58,7 @@ import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.WorkbookUtil; import org.apache.poi.util.Configurator; +import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -1587,7 +1589,40 @@ initDrawings(); byte[] uid = DigestUtils.md5(pictureData); - EscherBitmapBlip blipRecord = new EscherBitmapBlip(); + EscherBlipRecord blipRecord; + int blipSize; + short escherTag; + switch (format) { + case PICTURE_TYPE_WMF: + // remove first 22 bytes if file starts with magic bytes D7-CD-C6-9A + // see also http://de.wikipedia.org/wiki/Windows_Metafile#Hinweise_zur_WMF-Spezifikation + if (LittleEndian.getInt(pictureData) == 0x9AC6CDD7) { + byte picDataNoHeader[] = new byte[pictureData.length-22]; + System.arraycopy(pictureData, 22, picDataNoHeader, 0, pictureData.length-22); + pictureData = picDataNoHeader; + } + // fall through + case PICTURE_TYPE_EMF: + EscherMetafileBlip blipRecordMeta = new EscherMetafileBlip(); + blipRecord = blipRecordMeta; + blipRecordMeta.setUID(uid); + blipRecordMeta.setPictureData(pictureData); + // taken from libre office export, it won't open, if this is left to 0 + blipRecordMeta.setFilter((byte)-2); + blipSize = blipRecordMeta.getCompressedSize() + 58; + escherTag = 0; + break; + default: + EscherBitmapBlip blipRecordBitmap = new EscherBitmapBlip(); + blipRecord = blipRecordBitmap; + blipRecordBitmap.setUID( uid ); + blipRecordBitmap.setMarker( (byte) 0xFF ); + blipRecordBitmap.setPictureData( pictureData ); + blipSize = pictureData.length + 25; + escherTag = (short) 0xFF; + break; + } + blipRecord.setRecordId( (short) ( EscherBitmapBlip.RECORD_ID_START + format ) ); switch (format) { @@ -1610,11 +1645,7 @@ blipRecord.setOptions(HSSFPictureData.MSOBI_DIB); break; } - - blipRecord.setUID( uid ); - blipRecord.setMarker( (byte) 0xFF ); - blipRecord.setPictureData( pictureData ); - + EscherBSERecord r = new EscherBSERecord(); r.setRecordId( EscherBSERecord.RECORD_ID ); r.setOptions( (short) ( 0x0002 | ( format << 4 ) ) ); @@ -1621,12 +1652,12 @@ r.setBlipTypeMacOS( (byte) format ); r.setBlipTypeWin32( (byte) format ); r.setUid( uid ); - r.setTag( (short) 0xFF ); - r.setSize( pictureData.length + 25 ); + r.setTag( escherTag ); + r.setSize( blipSize ); r.setRef( 0 ); r.setOffset( 0 ); r.setBlipRecord( blipRecord ); - + return workbook.addBSERecord( r ); } Index: src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java =================================================================== --- src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java (revision 1531406) +++ src/testcases/org/apache/poi/hssf/usermodel/TestHSSFPicture.java (working copy) @@ -17,17 +17,23 @@ package org.apache.poi.hssf.usermodel; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.apache.poi.POIDataSamples; import org.apache.poi.ddf.EscherBSERecord; +import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.HSSFITestDataProvider; import org.apache.poi.hssf.model.InternalSheet; import org.apache.poi.ss.usermodel.BaseTestPicture; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.PictureData; import org.apache.poi.ss.usermodel.Workbook; -import java.util.Arrays; -import java.util.List; - /** * Test HSSFPicture. * @@ -210,4 +216,56 @@ p1 = (HSSFPicture) dr.getChildren().get(0); assertEquals(p1.getFileName(), "aaa"); } + + public void test49658() throws IOException { + // test if inserted EscherMetafileBlip will be read again + HSSFWorkbook wb = new HSSFWorkbook(); + + byte pictureDataEmf[] = POIDataSamples.getDocumentInstance().readFile("vector_image.emf"); + int indexEmf = wb.addPicture(pictureDataEmf, HSSFWorkbook.PICTURE_TYPE_EMF); + byte pictureDataPng[] = POIDataSamples.getSpreadSheetInstance().readFile("logoKarmokar4.png"); + int indexPng = wb.addPicture(pictureDataPng, HSSFWorkbook.PICTURE_TYPE_PNG); + byte pictureDataWmf[] = POIDataSamples.getSlideShowInstance().readFile("santa.wmf"); + int indexWmf = wb.addPicture(pictureDataWmf, HSSFWorkbook.PICTURE_TYPE_WMF); + + HSSFSheet sheet = wb.createSheet(); + HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); + CreationHelper ch = wb.getCreationHelper(); + + ClientAnchor anchor = ch.createClientAnchor(); + anchor.setCol1(2); + anchor.setCol2(5); + anchor.setRow1(1); + anchor.setRow2(6); + patriarch.createPicture(anchor, indexEmf); + + anchor = ch.createClientAnchor(); + anchor.setCol1(2); + anchor.setCol2(5); + anchor.setRow1(10); + anchor.setRow2(16); + patriarch.createPicture(anchor, indexPng); + + anchor = ch.createClientAnchor(); + anchor.setCol1(6); + anchor.setCol2(9); + anchor.setRow1(1); + anchor.setRow2(6); + patriarch.createPicture(anchor, indexWmf); + + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + byte pictureDataOut[] = wb.getAllPictures().get(0).getData(); + assertTrue(Arrays.equals(pictureDataEmf, pictureDataOut)); + + byte wmfNoHeader[] = new byte[pictureDataWmf.length-22]; + System.arraycopy(pictureDataWmf, 22, wmfNoHeader, 0, pictureDataWmf.length-22); + pictureDataOut = wb.getAllPictures().get(2).getData(); + assertTrue(Arrays.equals(wmfNoHeader, pictureDataOut)); + + FileOutputStream fos = new FileOutputStream("vect.xls"); + wb.write(fos); + fos.close(); + } + }