一、模板中用到的字体
1.水晶报表官方文档直接说明,如果需要导出PDF,则只支持ttf字体
2.在使用中发现,并非所有ttf字体都能导出PDF,如阿里巴巴普惠体。
由于对字体文件不熟悉,目前只知道在读取字体文件时,会查询一堆Table。
其中的ControlValueTable无法获取fontTableName,在此过程中抛出空指针异常,导致无法导出PDF。
3.初次读取报表模板文件时,优先从java运行时环境依赖下查询字体/jre/lib/font
,次之是系统安装的字体。
读取字体到结构Map<String,Font>中,其中String为字体名称。
在读取某些中文字体时,key为null,发现此现象的字体是从某个字体站下载的汉仪字体包。
4.除了以上字体外,目前使用的大部分ttf中文字体都可以正常导出PDF,如微软雅黑、楷体、宋体、文泉驿正黑等,但是会出现第二条问题,如下所示。
二、chrome浏览器无法显示个别中字
1.直接从浏览器打印也会打印空白字
2.不同字体不显示的字不同,尚未发现能完美显示所有字的中文字体
3.Firefox和IE正常显示所有字
4.从chrome保存到本地后,使用其他PDF编辑器(如acrobat)打开,所有字正常显示
5.从chrome中的PDF空白字处复制不显示的字符,到本地文本编辑器(如NotePad++)可以正常显示该字
6.使用水晶报表编辑工具SAP Crystal Reports无论是预览还是导出PDF均可以正常显示所有字
7.当模板中配置了【思源黑体.otf】且系统和jre/lib/font
下均不存在阿里巴巴普惠体时,
输出PDF到chrome浏览器可以显示所有字,但是点击下载或打印会导致浏览器崩溃。
偶尔可以下载成功,下载得到的PDF使用本地其他PDF编辑器打开会导致编辑器崩溃。
解决方案:
1.升级chrome至79.0.3945.88或以上,基本上可以确定是chrome对各个版本的pdf兼容性有自己的想法导致的问题。
2.先把水晶报表生成的PDF转成图片,再将图片嵌入新的PDF文档,最终将新的PDF文档输出至浏览器。
实例如下所示:
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());
畸变比较小,由于测试PDF内容存在圆形图片水印才被发现,可根据实际显示情况进行微调。
content.drawImage(pdImage, REPORT_X_OFFSET, 0,
page.getMediaBox().getWidth() - REPORT_WIDTH_OFFSET,
page.getMediaBox().getHeight());
畸变调整前:
畸变调整后:
三、Java bean作为数据源
1.修改CRConfig.xml配置,在SAP Crystal Reports2016中,需要修改:
- JavaDir32
- JavaDir64
- JavaBeansClassPath
2.通过阅读官方说明文档,Bean文件需要编译为.class文件或打包为.jar文件。
.class需配置JavaBeansClassPath为路径,.jar需配置JavaBeansClassPath为路径+xxx.jar。
3.bean文件中需要包含返回类型为java.sql.ResultSet的方法,不可以返回null,不可以是不能正常运行的SQL,否则在报表编辑器中连接时均无法连接。一个示例如下:
public ResultSet getDoorBean() throws ReportSDKException {
List<DoorBean> doorItems = new ArrayList<>();
POJOResultSetHelper helper = new POJOResultSetHelper(DoorBean.class);
return helper.createResultSet(doorItems);
}
其中,getDoorBean会成为编辑器中数据源连接的表名,也是读取并注入数据源时需要写入的表名。
4.编译为.class文件并且正确配置JavaBeansClassPath后,打开SAP Crystal Reports2016,选择Java bean connectivity,在下拉框中应当出现javaservertype=javabeans javabeanname=
的字样。
并非直接出现bean的名称,只有连接成功后下拉框中才会出现bean名称列表。
成功连接后,bean字段与jdbc方式获取的字段一样,可以拖拽到模板中。
5.如果bean字段修改,可以通过【验证数据库】操作进行字段更新,避免重新连接数据源导致重新配置字段,验证的字段通过名称进行比对映射。
四、图片
1.暂时未发现使用相对路径读取到图片的方法
2.使用绝对路径可以读取图片
3.使用URL可以读取图片,但是官方论坛的答复是:不支持https
4.可以通过公式字段获取模板的绝对路径,再通过模板与图片的相对位置关系获得图片路径,如下所示:
Left(Filename,length(filename) - Length(Mid (Filename ,InstrRev (Filename,"\") + 1) ))
但是不解决问题,因为使用tomcat运行后端时,读取一次模板文件,就默认在tomcat/temp下生成临时模板数据。
此时获取到的模板路径是tomcat/temp,而非项目路径。
5.关于模板文件
在本地运行中发现,如果删除tomcat路径下的temp文件夹,临时文件被生成到idea intellij的安装路径下的temp文件夹中。
论坛的答复是,只要ReportClientDocument流被close,临时文件就会被删除,实际上并没有。
6.透明背景
Crystal Reports converts images to .bmp which unfortunately does not support transparency for images.