前端傳回的png圖片數組,后端加水印加密碼生成pdf,返回給前端
- 場景:
- 重點:
- maven依賴
- controller
- service
場景:
當前需求,前端通過html2canvas將頁面報表生成圖片下載,可以仍然不滿意。
需要java后端將前端傳過來的圖片生成pdf,并且加密碼加水印。
重點:
pdf使用A4大小,但是要考慮。根據A4寬高縮放圖片后,圖片仍然大于A4長度,此時要對圖片進行裁剪(2頁,3頁…)
maven依賴
<!-- pdf文件水印添加 -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.1.4</version><type>pom</type>
</dependency>
controller
@PostMapping("/addMarkAndPasswordPdf")@ApiOperation(value = "文件處理-增加水印及密碼--入參為文件", notes = "")public void addMarkAndPasswordPdf(@RequestParam("fileStream") MultipartFile[] fileStreams,@RequestParam("filePdfName")String filePdfName, HttpServletRequest request, HttpServletResponse response) {Calendar calendar = Calendar.getInstance();String date = calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH) + 1);SysUserEntity uc = (SysUserEntity) request.getAttribute("UC");SysUserEntity uc1 = userService.getUserByCode(uc.getUserCode());fileProcessService.fileProcessPdf(fileStreams,filePdfName,uc1,response);}
service
@Overridepublic void fileProcessPdf(MultipartFile[] imageFiles,String filePdfName, SysUserEntity uc, HttpServletResponse response) {response.setHeader("Content-disposition", "attachment;filename=" + filePdfName);// 直接用瀏覽器或者用postmanresponse.setContentType("application/pdf");response.setCharacterEncoding("utf-8");try {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 創建PDF文檔 加密PDF文檔PdfWriter writer = new PdfWriter(byteArrayOutputStream,new WriterProperties().setStandardEncryption(// 用戶密碼uc.getPassword().getBytes(),// 所有者密碼uc.getPassword().getBytes(),// 允許的權限EncryptionConstants.ALLOW_PRINTING | EncryptionConstants.ALLOW_COPY,// 加密標準EncryptionConstants.STANDARD_ENCRYPTION_128));PdfDocument pdfDoc = new PdfDocument(writer);Document document = new Document(pdfDoc);// 讀取原始圖片.按照A4拆分圖片,放到pdffor(MultipartFile imageFile: imageFiles){BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());float maxHeight = (PageSize.A4.getHeight()/PageSize.A4.getWidth())*originalImage.getWidth();ArrayList<BufferedImage> cropImageList = cropImageByMaxHeight(originalImage, (int) maxHeight);for (BufferedImage bufferedImage : cropImageList) {// 添加圖片PdfPage page = pdfDoc.addNewPage();ByteArrayOutputStream ImageOutputStream = new ByteArrayOutputStream();ImageIO.write(bufferedImage, "png", ImageOutputStream);ImageData imageData = ImageDataFactory.create(ImageOutputStream.toByteArray());com.itextpdf.layout.element.Image image = new com.itextpdf.layout.element.Image(imageData);image.setHorizontalAlignment(HorizontalAlignment.CENTER);document.add(image);ImageOutputStream.close();// 循環為頁設置水印setPageWatermark(page, pdfDoc,uc.getCname() + ", " + uc.getDeptTwo(),140);}}// 關閉文檔以不再寫入內容document.close();pdfDoc.close();writer.close();// 將PDF寫入響應輸出流response.getOutputStream().write(byteArrayOutputStream.toByteArray());response.getOutputStream().flush();byteArrayOutputStream.close();} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}}/**** 為PDF頁繪畫水印* @param pdfPage PDF頁對象* @param msg 水印信息* @param interval 水印間隔* @throws IOException 這里的異常是無法獲取字體異常*/public static void setPageWatermark(PdfPage pdfPage,PdfDocument pdfDoc, String msg, int interval) throws IOException {// 通過PDF頁來構建畫布PdfCanvas pdfCanvas = new PdfCanvas(pdfPage);// 中文顯示字體
// PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");float width = pdfPage.getPageSize().getWidth();float height = pdfPage.getPageSize().getHeight();// 開始繪畫水印for (int x = 0; x < pdfPage.getPageSize().getWidth(); x += interval) {for (int y = 0; y < pdfPage.getPageSize().getHeight(); y += interval) {Canvas canvas = new Canvas(pdfCanvas, pdfDoc, new Rectangle(0, 0, width, height))// 顏色和透明度.setFontColor(ColorConstants.GRAY, .2f)// 文字樣式
// .setFont(font)// 字體大小(具體可以改).setFontSize(20).showTextAligned(msg, x, y, TextAlignment.CENTER,VerticalAlignment.MIDDLE, 19.5f);canvas.close();}}// 釋放畫布。使用完畫布后,請使用此方法。pdfCanvas.release();}/*** 將圖片進行裁剪** @param originalImage* @param maxHeight* @return*/public static ArrayList<BufferedImage> cropImageByMaxHeight(BufferedImage originalImage, int maxHeight) {ArrayList<BufferedImage> croppedImages = new ArrayList<>();int originalHeight = originalImage.getHeight();int numImages = originalHeight / maxHeight;int remainder = originalHeight % maxHeight;for (int i = 0; i < numImages; i++) {int y = i * maxHeight;BufferedImage croppedImage = originalImage.getSubimage(0, y, originalImage.getWidth(), maxHeight);croppedImages.add(croppedImage);}// 處理剩余高度(如有)if (remainder > 0) {int y = numImages * maxHeight;BufferedImage croppedImage = originalImage.getSubimage(0, y, originalImage.getWidth(), remainder);croppedImages.add(croppedImage);}return croppedImages;}
成果: