[Java][POI]将EMF图像插入HSSF工作簿

[Java][POI]将EMF图像插入HSSF工作簿,java,apache-poi,xls,poi-hssf,Java,Apache Poi,Xls,Poi Hssf,我正在尝试将EMF映像插入HSSF工作簿(ApachePOI3.9)。但是当我打开结果文档时,我发现了一个内容错误。我正在寻找问题的解决方案,并在apache mail上找到了这封信: 据我所知,emf需要对数据进行特殊的(!)预处理 我查看了一个EMF类(org.apache.poi.hslf.blip),并尝试从中获取原始数据。 但这也没用 有人知道这个问题吗好的,这里有一个黑客程序,我在以下信息的帮助下混合在一起: HSSFWorkbook.addPicture的来源 一点关于这个问题

我正在尝试将EMF映像插入HSSF工作簿(ApachePOI3.9)。但是当我打开结果文档时,我发现了一个内容错误。我正在寻找问题的解决方案,并在apache mail上找到了这封信:

据我所知,emf需要对数据进行特殊的(!)预处理

我查看了一个EMF类(org.apache.poi.hslf.blip),并尝试从中获取原始数据。 但这也没用


有人知道这个问题吗

好的,这里有一个黑客程序,我在以下信息的帮助下混合在一起:

  • HSSFWorkbook.addPicture的来源
  • 一点关于这个问题的信息
  • Libre Office提供的带有EMF图形的简单.xls
  • 并通过
免责声明:由于此代码只是一个快速破解,仅使用一张图片进行测试,包含一些我不理解的复制和粘贴行,以及试用和错误值, 如果你能给出一些反馈,如果它能在你的环境中工作,那就太好了

检查部分的代码注释,我不太确定

(使用POI 3.9、Libre Office 4.0和MS Excel Viewer进行测试)

import java.awt.*;
导入java.io.*;
导入java.lang.reflect.*;
导入java.util.List;
导入java.util.zip.DeflaterOutputStream;
导入org.apache.commons.codec.digest.DigestUtils;
导入org.apache.poi.ddf.*;
导入org.apache.poi.hssf.dev.BiffViewer;
导入org.apache.poi.hssf.model.internal工作簿;
导入org.apache.poi.hssf.record.*;
导入org.apache.poi.hssf.usermodel.*;
导入org.apache.poi.ss.usermodel.*;
导入org.apache.poi.util.IOUtils;
@抑制警告(“未使用”)
公共级女性照片{
公共静态void main(字符串[]args)引发异常{
HSSFWorkbook wb=新的HSSFWorkbook();
FileInputStream fis=新的FileInputStream(“src/test/resources/allianz.emf”);
byte[]img_bytes=IOUtils.toByteArray(fis);
fis.close();
//代码取自HSSFWorkbook.addPicture
方法m=HSSFWorkbook.class.getDeclaredMethod(“initDrawings”);
m、 setAccessible(true);
m、 调用(wb);
int format=HSSFWorkbook.PICTURE\u TYPE\u EMF;
字节[]uid=DigestUtils.md5(img_字节);
EscherMetafileBlip blipRecord=新EscherMetafileBlip();
blipRecord.setRecordId((短)(eschermatfileblip.RECORD_ID_START+格式));
blipRecord.setOptions(HSSFPictureData.MSOBI_EMF);
blipRecord.setUID(uid);
bliprecard.setCompressed(true);
blipRecord.setPictureData(img_字节);
blipRecord.setUncompressedSize(img_bytes.length);
//芝加哥项目信息:
//“…GNU Zip使用的格式的LZ压缩算法使用32k窗口进行放气/充气…”
//不确定当查找表超过32k时要做什么。。。
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
DeflaterOutputStream dos=新的DeflaterOutputStream(bos);
写入(img_字节);
dos.close();
字节img_bytes_lz[]=bos.toByteArray();
blipRecord.setCompressedSize(img_字节长度);
Field Field=eschermatfileblip.class.getDeclaredField(“原始图片数据”);
字段。setAccessible(true);
字段集(blipercard,img_bytes_lz);
//尝试和错误,如果将其保留为0,它将不会打开
field=eschermatfileblip.class.getDeclaredField(“field_7_fFilter”);
字段。setAccessible(true);
字段集(blipRecord,(字节)-2);
EscherBSERecord r=新EscherBSERecord();
r、 setRecordId(EscherBSERecord.RECORD_ID);

r、 setOptions((短)(0x0002 |)(格式我仍在搜索poi解决方案,但如果这是您的选项,它可能可以使用。如果您在使用Libre Office之前保存了emf,则提取的流与我的输入emf相同,但如果您使用poi 3.9添加它,它将显示在不同的blip记录属性下,即“剩余数据”…如果您愿意的话,我相信Apache POI项目将非常成功!我将尝试在Apache POI中修复它,但在图像压缩方面存在一些问题。在我发布此黑客攻击后,Excel压缩算法与LZ不同,我尝试了其他emf文件,它也起了作用。jdk deflater也用于POI的其他领域,因此我认为nk这可能是正确的算法。在你的链接问题中,你能尝试使用文件而不是字节文本吗?只是为了确定,它不是一种整数到字节的转换。你使用的是哪个jvm版本?还有一件事…你的emf文件有多大?…你读过关于32kb窗口的评论吗(大概32kb lz字典大小)@gagravarr终于坏天气来临了,我有时间提交一些补丁。POI补丁可以在下找到。但不确定bugzilla如何处理部分解决的问题
import java.awt.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.List;
import java.util.zip.DeflaterOutputStream;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.dev.BiffViewer;
import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;

@SuppressWarnings("unused")
public class HssfEmfPicture {
    public static void main(String[] args) throws Exception {
        HSSFWorkbook wb = new HSSFWorkbook();
        FileInputStream fis = new FileInputStream("src/test/resources/allianz.emf");
        byte[] img_bytes = IOUtils.toByteArray(fis);
        fis.close();

        // code taken from HSSFWorkbook.addPicture 
        Method m = HSSFWorkbook.class.getDeclaredMethod("initDrawings");
        m.setAccessible(true);
        m.invoke(wb);

        int format = HSSFWorkbook.PICTURE_TYPE_EMF;

        byte[] uid = DigestUtils.md5(img_bytes);
        EscherMetafileBlip blipRecord = new EscherMetafileBlip();
        blipRecord.setRecordId((short) (EscherMetafileBlip.RECORD_ID_START + format));
        blipRecord.setOptions(HSSFPictureData.MSOBI_EMF);
        blipRecord.setUID(uid);
        blipRecord.setCompressed(true);
        blipRecord.setPictureData(img_bytes);
        blipRecord.setUncompressedSize(img_bytes.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 ...
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DeflaterOutputStream dos = new DeflaterOutputStream(bos);
        dos.write(img_bytes);
        dos.close();
        byte img_bytes_lz[] = bos.toByteArray();
        blipRecord.setCompressedSize(img_bytes_lz.length);

        Field field = EscherMetafileBlip.class.getDeclaredField("raw_pictureData");
        field.setAccessible(true);
        field.set(blipRecord, img_bytes_lz);

        // trial-and-error, it won't open, if this is left to 0
        field = EscherMetafileBlip.class.getDeclaredField("field_7_fFilter");
        field.setAccessible(true);
        field.set(blipRecord, (byte) -2);

        EscherBSERecord r = new EscherBSERecord();
        r.setRecordId(EscherBSERecord.RECORD_ID);
        r.setOptions((short) (0x0002 | (format << 4)));
        // libre office sets a png format for mac ... need to be tested ... 
        r.setBlipTypeMacOS((byte) format);
        r.setBlipTypeWin32((byte) format);
        r.setUid(uid);
        r.setTag((short) 0x0);
        // trial-and-error, with pngs (EscherBitmapBlip?) its 25
        // ... with emf (EscherMetafileBlip) it seems to be 58
        r.setSize(img_bytes_lz.length + 58);
        r.setRef(0);
        r.setOffset(0);
        r.setBlipRecord(blipRecord);

        field = HSSFWorkbook.class.getDeclaredField("workbook");
        field.setAccessible(true);
        InternalWorkbook iWb = (InternalWorkbook) field.get(wb);

        m = InternalWorkbook.class.getDeclaredMethod("addBSERecord", EscherBSERecord.class);
        m.setAccessible(true);
        int index = (Integer) m.invoke(iWb, r);

        // Anchor has to be valid ... otherwise the emf is not shown
        CreationHelper ch = wb.getCreationHelper();
        ClientAnchor anchor = ch.createClientAnchor();
        anchor.setCol1(2);
        anchor.setCol2(6);
        anchor.setRow1(1);
        anchor.setRow2(6);
        anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);

        HSSFSheet sheet = wb.createSheet();
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
        HSSFPicture pict = patriarch.createPicture(anchor, index);

        FileOutputStream fos = new FileOutputStream("hssf-emf.xls");
        wb.write(fos);
        fos.flush();
        fos.close();
    }
}