Bugzilla 49658 - Support embedding EMF/WMF pictures in HSSF
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1531622 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
451d9eb4af
commit
489b0b5bdb
@ -21,6 +21,7 @@ import org.apache.poi.util.HexDump;
|
||||
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.ByteArrayInputStream;
|
||||
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 final class EscherMetafileBlip extends EscherBlipRecord {
|
||||
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 final class EscherMetafileBlip extends EscherBlipRecord {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import org.apache.poi.POIDocument;
|
||||
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.usermodel.Row.MissingCellPolicy;
|
||||
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 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
||||
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,23 +1645,19 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
||||
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 ) ) );
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -17,17 +17,23 @@
|
||||
|
||||
package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
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.PictureData;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* Test <code>HSSFPicture</code>.
|
||||
*
|
||||
@ -210,4 +216,56 @@ public final class TestHSSFPicture extends BaseTestPicture {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user