一、有个需求:将PDF文件转图片上传到腾讯云。
之前一直没有做过pdf转图片的功能,在网上搜了一下,发现有三种方法:icepdf、pdfbox、jedal。
对比一下:
1、使用icepdf转换,会带官方水印,还需要专门的方法去水印,技术复杂;
2、使用pdfbox转换,能识别大部分内容,部分内容无法识别;
3、使用jedal转换,对中文不友好,而且官方很久不维护了。
最终选择使用pdfbox。
第一步:引入jar包
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
<version>2.0.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.9</version>
</dependency>
第二步:写代码
public static List<String> pdfToImg(MultipartFile pdfFile) {
List<String> imgUuids = new ArrayList<>();
try {
String filename = pdfFile.getName();
PDDocument doc = PDDocument.load(pdfFile.getInputStream());
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
BufferedImage image = renderer.renderImageWithDPI(i, 144); // Windows native DPI
// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图
String originalFilename = filename+"_"+(i+1)+".png";
ImageIO.write(image, "png",os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
MultipartFile multipartFile =new MockMultipartFile("file", originalFilename, "text/plain", input);
imgUuids.add(UploadUtil.uploadSinglePicture(multipartFile,null));
}
} catch (Exception e) {
throw new YbgException("2000","上传文件失败","上传文件失败",e);
}
return imgUuids;
}
这里分几步:
1、Controller是通过MultipartFile 接收;
2、通过pdfbox将pdf文件转图片;
3、通过工具类上传图片到腾讯云。
经过测试:是能成功转成图片并上传到腾讯云成功的,并且也能正常获取到上传的图片。但是,有个蛋疼的地方,我们的pdf文件是自带水印的,转成的图片也必须有这个水印。项目在本地测试是可以的,但是在linux环境上,生成的图片除了第一张是有水印的,其他图片都没有水印。
这个问题很奇怪:为什么就第一张图片有水印,其他的就没有?在网上搜索也没发现有人遇到这方面的问题。
一下子没有什么头绪,就想着换一个实现方式:icepdf。
第一步:
<dependency>
<groupId>org.icepdf.os</groupId>
<artifactId>icepdf-core</artifactId>
<version>6.1.2</version>
<exclusions>
<exclusion>
<groupId>javax.media</groupId>
<artifactId>jai-core</artifactId>
</exclusion>
</exclusions>
</dependency>
第二步:
public static List<String> pdfToImg(MultipartFile pdfFile) {
List<String> imgUuids = new ArrayList<>();
try {
Document document = new Document();
document.setInputStream(pdfFile.getInputStream(),null);
float scale = 2.5f;//缩放比例
float rotation = 0f;//旋转角度
String filename = pdfFile.getOriginalFilename();
for (int i = 0; i < document.getNumberOfPages(); i++) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
BufferedImage image = (BufferedImage)document.getPageImage(i, GraphicsRenderingHints.SCREEN,
org.icepdf.core.pobjects.Page.BOUNDARY_CROPBOX, rotation, scale);
String originalFilename = filename+"_"+(i+1)+".png";
ImageIO.write(image, "png",os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
MultipartFile multipartFile =new MockMultipartFile("file", originalFilename, "text/plain", input);
imgUuids.add(UploadUtil.uploadSinglePicture(multipartFile,null));
}
} catch (Exception e) {
throw new YbgException("2000","上传文件失败","上传文件失败",e);
}
return imgUuids;
}
测试结果:在本地测试是成功的,但是部署到linux服务器上,图片全是乱码。比使用pdfbox更不符合我们的需求。
分析问题:在本地环境(windows)成功,在linux环境乱码。对比差异,在网上搜索一下,有的说·是linux的字体问题,不支持宋体(pdf文件中文是宋体)。
我当时也不确定是否是字体问题,然后我在linux服务器上查看一下它支持的字体,确实是没有安装宋体,到这里就感觉到找到解决方案了。就尝试着在linux上安装宋体字体,然后是pdfbox的方式测试,结果生成的图片都带上了原文件水印。使用icepdf也可以,但是最终我还是用pdfbox,因为更简单。