Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pdf附件支持,通过OLE方式嵌入 #1024

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

wangwenwwx
Copy link

@wangwenwwx wangwenwwx commented Jul 22, 2023

新增一种附件文件格式,对应word操作为插入对象->从文件创建
屏幕截图 2023-07-22 183325

插入后双击打开,由系统根据文件名后缀选择默认程序打开,理论上可以插入任意格式文件。
屏幕截图 2023-07-22 183052

暂未添加工厂方法,需要作者帮忙完善下

由于poi的实现方式,文件名目前不能包含中文,否则无法打开嵌入文件。
在win10 word2021和wps2023上测试可打开正常打开附件

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

这个pr单元测试后打开附件报错:

找不到服务器应用程序、源文件或项目。
请确保应用程序已正确安装,而且未被删除、移动、重命名或被策略阻止。

@wangwenwwx
Copy link
Author

wangwenwwx commented Aug 7, 2023

这个pr单元测试后打开附件报错:

找不到服务器应用程序、源文件或项目。 请确保应用程序已正确安装,而且未被删除、移动、重命名或被策略阻止。

这是我单元测试生成的文件,在我的电脑上可以打开附件,win10/deepin下都可以打开。你看看你那里能打开附件吗?
out_render_attachment.docx

image

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

你的附件我也打不开,Word MacV16.39.

image

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

刚下载了最新的LibreOfficeV7.5.5.2,第一次打开报错,再次点击图标可以打开。

image

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

image wps可以打开,会显示一个警告。

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

我猜测这个PR功能对打开的Office软件有版本的要求。

@wangwenwwx
Copy link
Author

我猜测这个PR功能对打开的Office软件有版本的要求。

看起来这些软件在不同系统下打开的逻辑不太一样,我没有mac,没有在mac上测试过,win10下的word2013,word2019,wps,linux上的wps,LibreOffice7.4.2.3我有试过可以打开

@Sayi
Copy link
Owner

Sayi commented Aug 7, 2023

可能任意格式附件这个是ODT支持的格式,需要在兼容ODT的office版本中打开,较新的office应该都能打开,旧版本不支持打开。

@wangwenwwx
Copy link
Author

可能任意格式附件这个是ODT支持的格式,需要在兼容ODT的office版本中打开,较新的office应该都能打开,旧版本不支持打开。

我今天尝试使用mac word2021,发现mac word没有插入对象附件这个功能,windows word 上手动插入的附件,mac word上也无法打开,应该是mac word 没有实现这个功能

@zzbl1145141919
Copy link

@wangwenwwx 您好 我执行完您写的测试用例之后 无法像您一样打开文件,显示
image
但是我打开您在上面那个对话中给出的这个文件out_render_attachment.docx 是可以的
想咨询一下您jdk的版本和操作系统的版本 谢谢

@wangwenwwx
Copy link
Author

@wangwenwwx 您好 我执行完您写的测试用例之后 无法像您一样打开文件,显示 image 但是我打开您在上面那个对话中给出的这个文件out_render_attachment.docx 是可以的 想咨询一下您jdk的版本和操作系统的版本 谢谢

作者那个提交多删了一点代码,你把poi-tl/src/main/java/com/deepoove/poi/data/OleObjectRenderData.java这个文件回滚到我的那个版本

@azh3ng
Copy link

azh3ng commented Oct 27, 2023

插入【PDF】格式的文件到 Word 里,打不开,提示“用于创建此对象的程序是package,你的计算机尚未安装此程序或者程序无响应。”,请问知道这是怎么回事吗?有解决办法吗?

@wangwenwwx
Copy link
Author

插入【PDF】格式的文件到 Word 里,打不开,提示“用于创建此对象的程序是package,你的计算机尚未安装此程序或者程序无响应。”,请问知道这是怎么回事吗?有解决办法吗?

发一下你生成的word文件

@tobebetter9527
Copy link

我把poi升级到5.2.4,插入中文名的文件,还是报错。

image

@tobebetter9527
Copy link

插入文件时,如何生成这种带文件名的图标,而不是上面带问号的图标? 谢谢。
image

@wangwenwwx
Copy link
Author

我把poi升级到5.2.4,插入中文名的文件,还是报错。

image

文件名编码那部分逻辑在poi的代码里,目前有个暴力一点的办法来支持中文文件名,直接把相关代码拷出来改一下

public class OleObjectRenderData extends AttachmentRenderData{

	private static final Logger logger = LoggerFactory.getLogger(ByteUtils.class);

	private final byte[] origin;

	private final String fileName;

	public OleObjectRenderData(byte[] origin,String fileName) {
		this.origin = origin;
		this.fileName = fileName;
		this.setFileType(AttachmentType.OLE);
	}

	@Override
	public byte[] readAttachmentData() {

		try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(origin.length+500)) {
			writeOut(bos);
			try (POIFSFileSystem poifs = new POIFSFileSystem()) {
				DirectoryNode root = poifs.getRoot();
				root.createDocument(Ole10Native.OLE10_NATIVE, bos.toInputStream());
				root.setStorageClsid(ClassIDPredefined.OLE_V1_PACKAGE.getClassID());
				try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
					poifs.writeFilesystem(os);
					return os.toByteArray();
				}
			}
		} catch (IOException e) {
			logger.error("get OleObjectData error,{},{}", fileName, e);
		}
		return null;
	}

	private void writeOut(OutputStream out) throws IOException {
		LittleEndianOutputStream leosOut = new LittleEndianOutputStream(out);
		UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();

		try (LittleEndianOutputStream leos = new LittleEndianOutputStream(bos)){
			leos.writeShort(2);
			leos.write(this.fileName.getBytes("GBK"));
			leos.write(0);
			leos.write(this.fileName.getBytes("GBK"));
			leos.write(0);
			leos.writeShort(0);
			leos.writeShort(3);
			leos.writeInt(this.fileName.getBytes("GBK").length + 1);
			leos.write(this.fileName.getBytes("GBK"));
			leos.write(0);
			leos.writeInt(this.origin.length);
			leos.write(this.origin);
			leos.writeShort(0);
		}
		leosOut.writeInt(bos.size());
		bos.writeTo(out);
	}
}

@wangwenwwx
Copy link
Author

插入文件时,如何生成这种带文件名的图标,而不是上面带问号的图标? 谢谢。 image

生成带文件名的图标比较困难,不过作者的附件策略是支持你自定义图标的,你可以自己指定图标

@wangwenwwx
Copy link
Author

@Sayi 我又改了改,之前把OLE视为一种文件类型不太恰当,改成了新增pdf类型(这个比较常用)并用ole方式嵌入,如果需要嵌入其他类型,就复制一下pdf的枚举定义,改改后缀名,图标,fileMagics就行。使用方法和之前的嵌入word/excel一致。除了在mac的word上,其他平台应该都可用

@wangwenwwx wangwenwwx changed the title ole附件支持 pdf附件支持,通过OLE方式嵌入 Mar 19, 2024
@Sayi
Copy link
Owner

Sayi commented Mar 19, 2024

Thanks,将会在下个版本中考虑合并这个PR。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants