Java使用多线程完成PDF文件转图片

多线程完成PDF文件转图片

系统需要将PDF文件由后台直接转为img图片,供前端页面直接展示,不需要用户下载即可预览文件内容。直接转换时如果文件过大,耗时很长,影响用户体验,后调研后使用多线程方式进行,显著加快图片转换速度。
原始版访问:https://blog.csdn.net/wmf_helloWorld/article/details/104051137

1、创建线程池

ExecutorService executorService = 
new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(50));      

初始化线程池,因系统默认一次预览5张图片,进行分页分步预览,所以设置核心线程池大小为5.设置最后队列为new ArrayBlockingQueue(50)),可以排队50个等待任务,若大于50则不建议预览,或根据需要使用其他队列。
可访问:https://www.cnblogs.com/dafanjoy/p/9729358.html
2、主要转换方法体
2.1、全部转换

public List pdfTurnImage(String filePath) throws CodeException {
        
        List fileImageList;
        
        File file = new File(filePath);
        try(PDDocument pdDocument = PDDocument.load(file)) {
            PdfReader reader = new PdfReader(filePath);
            int pages = reader.getNumberOfPages();
            LOGGER.info(LogType.INFO, "pdf文件共有"+ pages +"页文件");
            String[] imgStrArr = new String[pages];
            fileImageList = Arrays.asList(imgStrArr);
            List> futureTaskList =new ArrayList<>();
            for(int i=0; i future : futureTaskList) {
                if(future.get()) {
                    future.cancel(true);
                }
            }
        } catch (Exception e) {
            LOGGER.error(LogType.ERROR, e);
            throw new CodeException(XYRFileServerConstants.ERROR_CODE_2017, XYRFileServerConstants.ERROR_MESSAGE_2017, e);
        }
        
        return fileImageList;
    }

filePath:文件路径
List futureTaskList:list集合存放后续创建的线程,并且使用Future获取小程返回结果,下方for循环保证文件全部转换成功后关闭线程,并执行结束。(Boolean为之后多线程PdfPreviewTask的返回值,可根据需要进行修改)。
fileImageList :定义固定大小的集合,之后将每个图片放在集合的固定位置,防止转换之后图片放置顺序错误。

2.2,分页转换

public List getFileContent(int start, int numbers, String filePath) throws CodeException {
                      
        List fileImageList;      
        File file = new File(filePath);
        int begin = start-1;
        try(PDDocument pdDocument = PDDocument.load(file)) {
            PdfReader reader = new PdfReader(filePath);
            int pages = reader.getNumberOfPages();
            LOGGER.info(LogType.INFO, "pdf文件共有"+ pages +"页文件");
            String[] imgStrArr = new String[numbers];
            fileImageList = Arrays.asList(imgStrArr);
            List> futureTaskList =new ArrayList<>();
            for(int i=0; i future : futureTaskList) {
                if(future.get()) {
                    future.cancel(true);
                }
            }
        } catch (Exception e) {
            LOGGER.error(LogType.ERROR, e);
            throw new CodeException(XYRFileServerConstants.ERROR_CODE_2017, XYRFileServerConstants.ERROR_MESSAGE_2017, e);
        }
        
        return fileImageList;
  
    }

start:开始页码
numbers:分页转换页数
filePath:文件路径

3、文件预览线程

/**
 * 
 * Modify Information:pdf文件预览
 * Author       Date          Description
 * ============ ============= ============================
 * wumf         2020年7月1日          create this file
 * 
*/ public class PdfPreviewTask implements Callable{ private static Loggerx logger = Loggerx.getLogger("system"); /** * 图片列表 */ private List imageList; /** * 图片存放集合位置 */ private int listPosition; /** * 页码 */ private int pageNumbers; /** * 文件路径 */ private String filePath; public PdfPreviewTask(List imageList, int pageNumbers, int listPosition, String filePath) { this.imageList = imageList; this.listPosition = listPosition; this.pageNumbers = pageNumbers; this.filePath = filePath; } @Override public Boolean call() throws Exception { File file = new File(filePath); try(PDDocument pdDocument = PDDocument.load(file)) { PDFRenderer renderer = new PDFRenderer(pdDocument); logger.info(LogType.INFO, TimeUtil.getTimeStamp()+"线程开始执行,转换第"+pageNumbers+"页文件"); BufferedImage image = renderer.renderImageWithDPI(pageNumbers, Integer.parseInt(SystemEnvironment.dpi)); String imageBase64 = base64Image(image); if (StringUtil.isNotEmpty(imageBase64)) { if (!imageBase64.startsWith("data:image")) { imageBase64 = "data:image/jpeg;base64," + imageBase64; } imageList.set(listPosition, imageBase64); } logger.info(LogType.INFO, TimeUtil.getTimeStamp()+"线程执行结束,转换第"+pageNumbers+"页文件"); return true; } catch (Exception e) { logger.error(LogType.ERROR, "线程执行异常结束"+e.getMessage(), e); } return false; } private static String base64Image(BufferedImage image) throws CodeException { try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { ImageIO.write(image, "png", baos);//写入流中 byte[] bytes = baos.toByteArray();//转换成字节 return new String(Base64.encode(bytes),"UTF-8"); } catch (Exception e) { throw new CodeException(XYRFileServerConstants.ERROR_CODE_2017, XYRFileServerConstants.ERROR_MESSAGE_2017, e); } }

通过初始化线程时的构造方法参数,设置所需的内容。
renderer.renderImageWithDPI(pageNumbers, Integer.parseInt(SystemEnvironment.dpi));为主要转换方法。具体参数百度。转换为base64格式编码则不需要前端进行额外的转换。

你可能感兴趣的:(java,多线程)