forkJoinPool框架概述和注意事项可参考: http://ifeve.com/fork-join-1/
@SofaReference
private OssClientService ossClientService;
/***
* PDF文件转PNG图片,全部页数,使用forkJoinPool
*
* @param pdfOssKey pdf文件ossKey
* @param dpi dpi越大转换后越清晰,相对转换速度越慢,例如:300
* @return
*/
@Override
public List<byte[]> pdfToPng(String pdfOssKey, int dpi) {
Stopwatch stopwatch = Stopwatch.createStarted();
PDDocument pdDocument = null;
InputStream inputStream = null;
List<byte[]> imageByteArrayList = new LinkedList<>();
try {
inputStream = ossClientService.getFileInputStream(pdfOssKey);
pdDocument = PDDocument.load(inputStream);
PDFRenderer renderer = new PDFRenderer(pdDocument);
int totalPage = pdDocument.getNumberOfPages();
if (totalPage <= 0) {
return imageByteArrayList;
}
PdfToPngTask task = new PdfToPngTask(1, totalPage, dpi, renderer);
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<List<byte[]>> submitResult = pool.submit(task);
imageByteArrayList = submitResult.get();
pool.shutdown();
stopwatch.stop();
log.info("PDF文档转PNG图片成功!耗时: " + (stopwatch.elapsed(TimeUnit.MILLISECONDS)) + "毫秒");
return imageByteArrayList;
} catch (Exception e) {
log.error("PDF分页转图片发生异常,e={}", e);
throw new RuntimeException("PDF分页转图片发生异常");
} finally {
IOUtils.closeQuietly(pdDocument);
IOUtils.closeQuietly(inputStream);
}
}
/**
* 使用ForkJoinPool多线程执行PDF转图片,提高速度
*/
public class PdfToPngTask extends RecursiveTask<List<byte[]>> {
/**
* 每次执行的页数
*/
private static final int THRESHOLD = 2;
/**
* 开始页
*/
private int startPage;
/**
* 结束页
*/
private int endPage;
private int dpi;
private PDFRenderer renderer;
public PdfToPngTask(int startPage, int endPage, int dpi, PDFRenderer renderer) {
this.startPage = startPage;
this.endPage = endPage;
this.dpi = dpi;
this.renderer = renderer;
}
@Override
protected List<byte[]> compute() {
List<byte[]> imageByteArrayList = new LinkedList<>();
log.info("PDF转图片: startPage={},endPage={}", startPage, endPage);
boolean canCompute = (endPage - startPage) < THRESHOLD;
if (canCompute) {
for (int pageIndex = startPage; pageIndex <= endPage; pageIndex++) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
BufferedImage image = renderer.renderImageWithDPI(pageIndex - 1, dpi);
ImageIO.write(image, "png", byteArrayOutputStream);
byte[] imageByteArray = byteArrayOutputStream.toByteArray();
imageByteArrayList.add(imageByteArray);
} catch (Exception e) {
log.error("使用ForkJoin线程池执行PDF转图片过程中发生异常,pageIndex={},e={}", pageIndex, e);
} finally {
IOUtils.closeQuietly(byteArrayOutputStream);
}
}
} else {
int middlPage = (startPage + endPage) / 2;
PdfToPngTask leftTask = new PdfToPngTask(startPage, middlPage, dpi, renderer);
PdfToPngTask rightTask = new PdfToPngTask(middlPage + 1, endPage, dpi, renderer);
invokeAll(leftTask, rightTask);
imageByteArrayList.addAll(leftTask.join());
imageByteArrayList.addAll(rightTask.join());
}
return imageByteArrayList;
}
}