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<Runnable>(50));      

初始化線程池,因系統默認一次預覽5張圖片,進行分頁分步預覽,所以設置核心線程池大小爲5.設置最後隊列爲new ArrayBlockingQueue(50)),可以排隊50個等待任務,若大於50則不建議預覽,或根據需要使用其他隊列。
可訪問:https://www.cnblogs.com/dafanjoy/p/9729358.html
2、主要轉換方法體
2.1、全部轉換

public List<String> pdfTurnImage(String filePath) throws CodeException {
        
        List<String> 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<Future<Boolean>> futureTaskList =new ArrayList<>();
            for(int i=0; i<pages; i++) {
                LOGGER.info(LogType.INFO, "讀取轉換第"+ (i+1) +"頁文件");
                PdfPreviewTask task = new PdfPreviewTask(fileImageList, i, i, filePath);
                futureTaskList.add(SystemEnvironment.executorService.submit(task));               
            }
            
            for (Future<Boolean> 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<Future> futureTaskList:list集合存放後續創建的線程,並且使用Future獲取小程返回結果,下方for循環保證文件全部轉換成功後關閉線程,並執行結束。(Boolean爲之後多線程PdfPreviewTask的返回值,可根據需要進行修改)。
fileImageList :定義固定大小的集合,之後將每個圖片放在集合的固定位置,防止轉換之後圖片放置順序錯誤。

2.2,分頁轉換

public List<String> getFileContent(int start, int numbers, String filePath) throws CodeException {
                      
        List<String> 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<Future<Boolean>> futureTaskList =new ArrayList<>();
            for(int i=0; i<numbers; i++) {
                LOGGER.info(LogType.INFO, "讀取轉換第"+ begin +"頁文件");
                PdfPreviewTask task = new PdfPreviewTask(fileImageList, begin, i, filePath);
                begin++;
                futureTaskList.add(SystemEnvironment.executorService.submit(task));               
            }
            
            for (Future<Boolean> 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、文件預覽線程

/**
 * <pre>
 * Modify Information:pdf文件預覽
 * Author       Date          Description
 * ============ ============= ============================
 * wumf         2020年7月1日          create this file
 * </pre>
 */
public class PdfPreviewTask implements Callable<Boolean>{

    private static Loggerx logger = Loggerx.getLogger("system");
    
    /**
     * 圖片列表
     */
    private List<String> imageList;
    /**
     * 圖片存放集合位置
     */
    private int listPosition;
    /**
     * 頁碼
     */
    private int pageNumbers;
    
    /**
     * 文件路徑
     */
    private String filePath;
    
    public PdfPreviewTask(List<String> 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格式編碼則不需要前端進行額外的轉換。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章