CrystalReports > 转图片嵌入 PDF

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());

畸变调整前:

畸变调整前

畸变调整后:

畸变调整后