Docx4j使用FOP转PDF时如何删除临时图片或指定存储目录?
问题
在Linux环境下使用docx4j-export-fo通过XSL-FO将Docx转PDF时,含图片的文档转换后部分图片会被保存到/tmp目录,排查发现是AbstractConversionImageHandler.java在XSL-FO转换时存储图片导致的。
尝试设置FOSettings的ImageDirPath,但该设置仅对文档正文图片生效,页眉/页脚区域的图片仍会存入默认的/tmp目录——原因是FopAreeTreeHelper计算页眉/页脚区域大小时使用了FOP的默认设置,忽略了自定义的图片存储路径。
转换代码如下:
private static final String TEMP_IMAGE_DIR_PATH = "/tmp/images"; public static void convert(WordprocessingMLPackage wordMLPackage, OutputStream output) throws Exception { Mapper fontMapper = new BestMatchingMapper(); wordMLPackage.setFontMapper(fontMapper); FOSettings foSettings = new FOSettings(wordMLPackage); foSettings.setApacheFopMime("application/pdf"); foSettings.setImageDirPath(TEMP_IMAGE_DIR_PATH); foSettings.setFoDumpFile(null); FopFactoryBuilder fopFactoryBuilder = FORendererApacheFOP.getFopFactoryBuilder(foSettings); FopFactory fopFactory = fopFactoryBuilder.build(); FOUserAgent foUserAgent = FORendererApacheFOP.getFOUserAgent(foSettings, fopFactory); Docx4J.toFO(foSettings, output, Docx4J.FLAG_EXPORT_PREFER_XSL); // Clean up, so any ObfuscatedFontPart temp files can be deleted if (wordMLPackage.getMainDocumentPart().getFontTablePart() != null) { wordMLPackage.getMainDocumentPart().getFontTablePart().deleteEmbeddedFontTempFiles(); } foSettings = null; wordMLPackage = null; FileUtils.deleteDirectory(new File(TEMP_IMAGE_DIR_PATH)); }
目前仅能删除正文图片所在的TEMP_IMAGE_DIR_PATH目录,但页眉图片仍留在/tmp,不想删除/tmp下所有文件,询问是否有办法让Docx4j或FOP自动删除这些临时图片,或是为其指定存储目录?
解决方案
1. 为FOP全局指定临时文件目录
通过FopFactoryBuilder设置FOP的临时目录,覆盖默认的/tmp,这样页眉/页脚相关的临时图片会统一存储到自定义目录,转换后可直接删除该目录:
// 在创建FopFactoryBuilder后添加以下配置 fopFactoryBuilder.setTempDir(new File(TEMP_IMAGE_DIR_PATH));
修改后的完整代码片段:
FopFactoryBuilder fopFactoryBuilder = FORendererApacheFOP.getFopFactoryBuilder(foSettings); // 设置FOP全局临时目录 fopFactoryBuilder.setTempDir(new File(TEMP_IMAGE_DIR_PATH)); FopFactory fopFactory = fopFactoryBuilder.build();
这样所有临时文件(包括页眉图片)都会存入/tmp/images,转换后执行FileUtils.deleteDirectory(new File(TEMP_IMAGE_DIR_PATH))即可全部清理。
2. 自定义AbstractConversionImageHandler实现
如果需要更精细的控制,可以自定义AbstractConversionImageHandler的子类,重写getImageFile方法,强制所有图片(包括页眉页脚的)使用指定的存储路径:
public class CustomImageHandler extends AbstractConversionImageHandler { private final String customImageDir; public CustomImageHandler(String customImageDir) { this.customImageDir = customImageDir; } @Override protected File getImageFile(String imageKey, String extension) throws Exception { File dir = new File(customImageDir); if (!dir.exists()) { dir.mkdirs(); } return File.createTempFile(imageKey, "." + extension, dir); } }
然后在转换前注册这个自定义处理器:
foSettings.setImageHandler(new CustomImageHandler(TEMP_IMAGE_DIR_PATH));
3. 手动清理指定前缀的临时文件
如果无法修改存储目录,可以在转换后根据临时文件的命名规律(docx4j生成的临时图片通常带有特定前缀,比如docx4j-),遍历/tmp目录删除匹配的文件:
File tmpDir = new File("/tmp"); File[] tmpFiles = tmpDir.listFiles((dir, name) -> name.startsWith("docx4j-") && name.endsWith(".png")); if (tmpFiles != null) { for (File file : tmpFiles) { file.delete(); } }
注意:这种方式需要确保前缀匹配准确,避免误删其他程序的临时文件。
内容的提问来源于stack exchange,提问作者Aven

