Crystal Reports生成的PDF转图片
原问题:Chrome终于可以正常显示CrystalReports输出的PDF
陈永伟提出了永久解决方案:
由于是浏览器无法显示,为了兼容各自情况下的浏览器显示情况,可以先把水晶报表生成的PDF转成图片,再将图片嵌入新的PDF文档,最终将新的PDF文档输出至浏览器。
经过测试,该方案可在低版本chrome也正常显示所有字。
1.pdfbox
引入第三方库。
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.18</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox-tools -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.18</version>
</dependency>
2.PDF转图片
非最佳实现,仅供参考。
PDDocument originDocument = PDDocument.load(reportStream);
PDFRenderer originRender = new PDFRenderer(originDocument);
String rootPath = new File(".").getAbsolutePath() + "/tmp_report_";
int pageSize = originDocument.getNumberOfPages();
try (PDDocument targetDocument = new PDDocument()) {
for (int pageNum = 0; pageNum < pageSize; ++pageNum) {
// 将一页转为图片
String filePath = rootPath + pageNum + ".png";
BufferedImage bufferedImage = originRender.renderImageWithDPI(pageNum, REPORT_DPI, ImageType.GRAY);
// int REPORT_DPI = 300
ImageIOUtil.writeImage(bufferedImage, filePath, REPORT_DPI);
// 载入图片并转为PDF图像对象
PDImageXObject pdImage = PDImageXObject.createFromFile(filePath, targetDocument);
PDPage page = new PDPage();
// 创建新的PDF文档并添加图片
targetDocument.addPage(page);
PDPageContentStream content = new PDPageContentStream(targetDocument, page);
content.drawImage(pdImage, 0, 0, page.getMediaBox().getWidth(),
page.getMediaBox().getHeight());
content.close();
Files.deleteIfExists(Paths.get(filePath));
}
// 将新的PDF文档输出到响应流
targetDocument.save(response.getOutputStream());
} catch (Exception e) {
LoggerUtil.getLogger().error("PDF渲染失败", e);
}
值得注意是:dpi、图片格式、渲染类型。
- dpi设为300,保证清晰度
- 图片格式为
png
- 渲染类型为
ImageType.GRAY
经过测试,后两个值若为jpg+ImageType.RGB
等其他组合,则经过图片转换的PDF大小会增长很多(数倍之多)。
故建议设为png+ImageType.GRAY
的组合,或有测试过更好的方式欢迎指正。
除此之外,将生成的图片嵌入新的PDF文档后,存在图片比例畸变的问题。
content.drawImage(pdImage, 0, 0, page.getMediaBox().getWidth(),
page.getMediaBox().getHeight());
畸变比较小,由于设备健康云的工单存在圆形图片水印才被发现,可根据实际显示情况进行微调。
content.drawImage(pdImage, REPORT_X_OFFSET, 0,
page.getMediaBox().getWidth() - REPORT_WIDTH_OFFSET,
page.getMediaBox().getHeight());
畸变调整前:
畸变调整后: