前言
在项目中遇到了需要把合同的pdf 展示给用户查看,这时候直接给用户查看 pdf 问题挺多的,首先是加载慢,然后还有安卓,ios等手机兼容问题,有个 pdfjs 组件,但是用起来也是问题挺多的,遂直接换套方案,直接将 pdf 生成的时候同时生成一份 png 图片后面展示给用户看。这里记录下。
方法
maven 导包
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/fontbox -->
<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>
<!-- 如果不导入这个包则很多字符转换出来会模糊不清晰 -->
<dependency>
<groupId>com.levigo.jbig2</groupId>
<artifactId>levigo-jbig2-imageio</artifactId>
<version>2.0</version>
</dependency>
工具类
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* @Description
* @Author ChengQichuan
* @Version V1.0.0
* @Since 1.0
* @Date 2020/10/21
*/
public class PdfUtils {
/**
* 下载网络的pdf附件转换成图片
* @param pdfUrl 网络pdf地址
* @return
*/
public static MultipartFile pdfToPng(String pdfUrl) throws MalformedURLException {
//将本地文件转为byte数组
byte[] bytes = urlTobyte(pdfUrl);
//转换图片
BufferedImage bufferedImage = pdfToPng(new ByteArrayInputStream(bytes));
MultipartFile multipartFile = FileUtil.inputStreamToMultipartFile(UUID.randomUUID().toString() + ".png", bufferedImageToInputStream(bufferedImage));
return multipartFile;
}
/**
* 远程url文件地址转成byte
* @param url
* @return
* @throws MalformedURLException
*/
public static byte[] urlTobyte(String url) throws MalformedURLException {
URL ur = new URL(url);
BufferedInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new BufferedInputStream(ur.openStream());
out = new ByteArrayOutputStream(1024);
byte[] temp = new byte[1024];
int size = 0;
while ((size = in.read(temp)) != -1) {
out.write(temp, 0, size);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
byte[] content = out.toByteArray();
return content;
}
/**
* 合并pdf
* @param byteList
* @return
*/
public static ByteArrayOutputStream mergePdf(List<byte[]> byteList){
// 接收合并后的pdf文件流对象
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 创建PDF合并对象
PDFMergerUtility merger = new PDFMergerUtility();
for (byte[] byteArr : byteList) {
// 添加待合并的PDF字节流
merger.addSource(new ByteArrayInputStream(byteArr));
}
// 设定合并后的输出流对象
merger.setDestinationStream(outputStream);
try {
// 合并PDF
merger.mergeDocuments(null);
} catch (IOException e) {
}
return outputStream;
}
/**
* 使用pdfbox将jpg转成pdf
*
* @param jpgStream jpg输入流
* @param pdfPath pdf文件存储路径
* @throws IOException IOException
*/
public static void jpgToPdf(InputStream jpgStream, String pdfPath) throws IOException {
PDDocument pdDocument = new PDDocument();
BufferedImage image = ImageIO.read(jpgStream);
PDPage pdPage = new PDPage(new PDRectangle(image.getWidth(), image.getHeight()));
pdDocument.addPage(pdPage);
PDImageXObject pdImageXObject = LosslessFactory.createFromImage(pdDocument, image);
PDPageContentStream contentStream = new PDPageContentStream(pdDocument, pdPage);
contentStream.drawImage(pdImageXObject, 0, 0, image.getWidth(), image.getHeight());
contentStream.close();
pdDocument.save(pdfPath);
pdDocument.close();
}
/**
* 产生缩略图
* @param source
* @param targetW
* @param targetH
* @return
*/
private static BufferedImage resize(BufferedImage source, int targetW, int targetH) {
int type = source.getType();
BufferedImage target = null;
double sx = (double) targetW / source.getWidth();
double sy = (double) targetH / source.getHeight();
if (sx > sy) {
sx = sy;
targetW = (int) (sx * source.getWidth());
} else {
sy = sx;
targetH = (int) (sy * source.getHeight());
}
if (type == BufferedImage.TYPE_CUSTOM) {
ColorModel cm = source.getColorModel();
WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
boolean alphaPremultiplied = cm.isAlphaPremultiplied();
target = new BufferedImage(cm, raster, alphaPremultiplied, null);
} else {
target = new BufferedImage(targetW, targetH, type);
}
Graphics2D g = target.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
g.dispose();
return target;
}
/**
* pdf 转 图片
* @param pdfInputStream
*/
public static BufferedImage pdfToPng(InputStream pdfInputStream) {
try {
PDDocument doc = PDDocument.load(pdfInputStream);
PDFRenderer renderer = new PDFRenderer(doc);
int pages = doc.getNumberOfPages();
//设置最大宽度和总长度
int maxWidth = 0;
int sumHeight = 0;
List<BufferedImage> bufferedImageList = new ArrayList<>();
//得到 BufferedImage list
for(int i = 0 ; i < pages; i++){
BufferedImage imageBuffer = renderer.renderImageWithDPI(i, 150, ImageType.RGB);
// BufferedImage imageBuffer = renderer.renderImageWithDPI(i, 300, ImageType.RGB);
int width = imageBuffer.getWidth();
int height = imageBuffer.getHeight();
if (width > maxWidth){
maxWidth = width;
}
sumHeight += height;
bufferedImageList.add(imageBuffer);
}
//pdf分别转图片后合并
BufferedImage imageNew = new BufferedImage(maxWidth,sumHeight,BufferedImage.TYPE_INT_RGB);
int nowHeight = 0;
for (BufferedImage bufferedImage : bufferedImageList) {
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
int[] imageRgbArray = new int[width * height];
imageRgbArray = bufferedImage.getRGB(0, 0, width, height, imageRgbArray, 0, width);
//SEPARATE_DISTANCE 表示两张图片的间隔距离
imageNew.setRGB(0, nowHeight, width, height, imageRgbArray, 0, width);
nowHeight += height;
}
return imageNew;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* pdf 转 图片 List
* @param pdfInputStream
*/
public static List<BufferedImage> pdfToPngList(InputStream pdfInputStream) {
try {
PDDocument doc = PDDocument.load(pdfInputStream);
PDFRenderer renderer = new PDFRenderer(doc);
int pages = doc.getNumberOfPages();
//设置最大宽度和总长度
int maxWidth = 0;
int sumHeight = 0;
List<BufferedImage> bufferedImageList = new ArrayList<>();
//得到 BufferedImage list
for(int i = 0 ; i < pages; i++){
// BufferedImage imageBuffer = renderer.renderImage(i);
BufferedImage imageBuffer = renderer.renderImageWithDPI(i, 300, ImageType.RGB);
int width = imageBuffer.getWidth();
int height = imageBuffer.getHeight();
if (width > maxWidth){
maxWidth = width;
}
sumHeight += height;
bufferedImageList.add(imageBuffer);
}
return bufferedImageList;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* pdf 转 图片 备份
* @param pdfInputStream
*/
public static BufferedImage pdfToPngBak(InputStream pdfInputStream) {
try {
PDDocument doc = PDDocument.load(pdfInputStream);
PDFRenderer renderer = new PDFRenderer(doc);
int pages = doc.getNumberOfPages();
//pdf分别转图片后合并
BufferedImage imageNew = null;
for(int i = 0 ; i < pages; i++){
BufferedImage imageBuffer = renderer.renderImageWithDPI(i, 300, ImageType.RGB);
int width = imageBuffer.getWidth();
int height = imageBuffer.getHeight();
if(imageNew == null){
imageNew = new BufferedImage(width+10,(height+10) * pages,BufferedImage.TYPE_INT_RGB);
}
int[] imageRgbArray = new int[width * height];
imageRgbArray = imageBuffer.getRGB(0, 0, width, height, imageRgbArray, 0, width);
//SEPARATE_DISTANCE 表示两张图片的间隔距离
imageNew.setRGB(0, height * i, width, height, imageRgbArray, 0, width);
}
return imageNew;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 将BufferedImage转换为InputStream
* @param image
* @return
*/
public static InputStream bufferedImageToInputStream(BufferedImage image){
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", os);
InputStream input = new ByteArrayInputStream(os.toByteArray());
return input;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}