1.所需jar包
<!--PDF轉圖片--> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.20</version> </dependency>
如果需要改變字體的話,還需要加上這個:
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/fontbox --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>fontbox</artifactId> <version>2.0.9</version> </dependency>
2.代碼實現
通過Apache的pdfbox實現
/* * PDF轉圖片 * @attention: 將整個PDF文件轉圖片(所有頁) * @date: 2021-05-12 10:46 * @param: imgPath * 圖片全路徑 * @param: imgNamePrefix * 圖片名稱前綴 * @param: pdfBytes * PDF二進制流 * @return: boolean */ public static boolean toImageFromBytes(String imgPath, String imgNamePrefix, byte[] pdfBytes) { return toImageFromBytes(imgPath, imgNamePrefix,"png", pdfBytes); } /* * PDF轉圖片 * @attention: * @date: 2021-06-21 14:46 * @param: imgPath * @param: imgNamePrefix * @param: pdfBytes * @param: imgType * @return: boolean */ public static boolean toImageFromBytes(String imgPath, String imgNamePrefix, String imgType, byte[] pdfBytes) { return toImageFromBytes(imgPath, imgNamePrefix, imgType, pdfBytes, 0, -1); }
/* * PDF轉圖片 * @attention: 支持自主選擇起始頁和結束頁 * @date: 2021-05-12 10:41 * @param: imgPath * 圖片全路徑 * @param: imgNamePrefix * 圖片名稱前綴 * @param: imgType * 圖片類型 * @param: pdfBytes * PDF二進制流 * @param: pageStartIndex * 開始頁:開始轉換的頁碼(第1頁,頁碼為0) * @param: pageEndIndex * 結束頁:結束轉換的頁碼(最后1頁,頁碼為-1) * @return: boolean * 只有PDF文件所有頁數轉換成功才返回true */ public static boolean toImageFromBytes(String imgPath, String imgNamePrefix, String imgType, byte[] pdfBytes, int pageStartIndex, int pageEndIndex) { if (StringUtils.isEmpty(imgPath)) { log.info("圖片保存路徑不能為空"); return false; } if (StringUtils.isEmpty(imgNamePrefix)) { log.info("圖片名稱不能為空"); return false; } if (pdfBytes == null) { log.info("pdf字節數組不能為空"); return false; } if (StringUtils.isEmpty(imgType)) { log.info("圖片格式不能為空"); return false; } if (pageStartIndex < -1 || pageEndIndex < -1) { log.info("PDF轉圖片的起始頁或結束頁必須>=-1"); return false; } if (pageEndIndex != -1 && pageStartIndex > pageEndIndex) { log.info("PDF轉圖片的起始頁不能>結束頁"); return false; } // 圖片類型處理 if (!imgType.startsWith(".")) imgType = "." + imgType; // 圖片名稱處理(注意文件名里不要有點,否則一律視為后綴名被抹掉) if (imgNamePrefix.indexOf(".") > 0) imgNamePrefix = imgNamePrefix.substring(0, imgNamePrefix.indexOf(".") ); // 添加路徑分隔符 if (!imgPath.endsWith("/") && !imgPath.endsWith("\\")) imgPath += File.separator; try { // Date:2021-05-24 // 創建圖片目錄(確保圖片的上級目錄存在) File directory = new File(imgPath); // 目錄不存在就創建 directory.mkdirs(); // 加載PDF PDDocument doc = PDDocument.load(pdfBytes); PDFRenderer renderer = new PDFRenderer(doc); // pdf總頁數 int pageCount = doc.getNumberOfPages(); log.info("該pdf文件共有" + pageCount + "頁"); // 如果是起始頁是末頁的話,設置首頁的下標索引(末頁頁碼-1) if (pageStartIndex == -1) { pageStartIndex = pageCount - 1; } // 如果是結束頁是末頁的話,設置末頁的下標索引(末頁頁碼-1) if (pageEndIndex == -1) { pageEndIndex = pageCount - 1; } for (int i = pageStartIndex; i <= pageEndIndex; i++) { // dpi越大轉換后越清晰,相對轉換速度越慢 BufferedImage image = renderer.renderImageWithDPI(i, 250); // Windows native DPI // BufferedImage srcImage = resize(image, 240, 240);//產生縮略圖 // 生成圖片 // Date:2021-06-21 // ImageIO.write()第二個參數代表圖片的類型,不能帶".",否則圖片生成失敗 if (pageCount == 1) ImageIO.write(image, imgType.substring(1), new File(imgPath + imgNamePrefix + imgType)); else ImageIO.write(image, imgType.substring(1), new File(imgPath + imgNamePrefix + "_" + (i + 1) + imgType)); log.info("pdf第" + (i + 1) + "頁轉圖片成功"); } log.info("pdf-->圖片成功(起始頁:" + (pageStartIndex + 1) + ",結束頁:" + (pageEndIndex + 1) + ")"); return true; } catch (IOException e) { e.printStackTrace(); log.error("pdf-->圖片失敗:" + e.getMessage()); return false; } }
3.調用
toImageFromBytes("C:\\Users\\Marydon\\Desktop", "圖片", Base64Utils.decodeToBytes(sb.toString()));
注意:
我曾嘗試直接將PDF數據強制輸出到圖片文件中,結果發現這樣是行不通的(生成的圖片文件無法打開)
這,也就證明了PDF的數據流和圖片的數據流,雖然都可以通過java轉換成流,但兩個本質還是不一樣的。
2021-06-21
4.補充
增加PDF文件直接轉圖片的方法,其核心點在於:文件轉bytes[]
/* * pdf文件轉img * @attention: * @date: 2021-06-21 16:38 * @param: pdfCompletePath * @param: saveImgPath * @param: imgName * @return: boolean */ public static boolean toImageFromFile(String pdfCompletePath, String saveImgPath, String imgName) { if (StringUtils.isEmpty(pdfCompletePath)) { log.info("PDF文件所在完整路徑不能為空"); return false; } // 設置圖片路徑 if (StringUtils.isEmpty(saveImgPath)) { saveImgPath = "D:" + File.separator; } // 設置圖片名稱 if (StringUtils.isEmpty(imgName)) imgName = DateUtils.getSysdateStr("yyyyMMddHHmmssSSS"); return toImageFromFile(pdfCompletePath, saveImgPath, imgName, ".png"); } /* * pdf文件轉img * @attention: * @date: 2021-06-21 16:38 * @param: pdfCompletePath * @param: saveImgPath * @param: imgName * @param: imgType * @return: boolean */ public static boolean toImageFromFile(String pdfCompletePath, String saveImgPath, String imgName, String imgType) { return toImageFromFile(pdfCompletePath, saveImgPath, imgName, imgType,0, -1); }
/* * pdf文件轉img * @attention: * @date: 2021-06-21 16:25 * @param: pdfCompletePath pdf完整路徑 * @param: imgPath 圖片路徑 * @param: imgName 圖片名稱 * @param: imgType 圖片類型 * @param: pageStartIndex PDF的起始頁 * 開始轉換的頁碼(第1頁,頁碼為0) * @param: pageEndIndex PDF的結束頁 * 結束頁:結束轉換的頁碼(最后1頁,頁碼為-1) * @return: boolean */ public static boolean toImageFromFile(String pdfCompletePath, String imgPath, String imgName, String imgType, int pageStartIndex, int pageEndIndex) { if (StringUtils.isEmpty(pdfCompletePath)) { log.info("PDF文件所在完整路徑不能為空"); return false; } if (StringUtils.isEmpty(imgPath)) { log.info("圖片保存路徑不能為空"); return false; } if (StringUtils.isEmpty(imgName)) { log.info("圖片名稱不能為空"); return false; } if (StringUtils.isEmpty(imgType)) { log.info("圖片類型不能為空"); return false; } byte[] pdfBytes = null; try { // 文件轉文件流 pdfBytes = Files.readAllBytes(Paths.get(pdfCompletePath)); } catch (IOException e) { log.error("PDF文件-->Bytes[]失敗:" + e.getMessage()); e.printStackTrace(); return false; } return toImageFromBytes(imgPath, imgName, imgType, pdfBytes, pageStartIndex, pageEndIndex); }
調用:
toImageFromFile("C:\\Users\\Marydon\\Desktop\\個人信用報告.pdf","C:\\Users\\Marydon\\Desktop","cc", "png", -1, -1);