java 根据前端传回的png图片数组,后端加水印加密码生成pdf,返回给前端
前端传回的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
@Override
public void fileProcessPdf(MultipartFile[] imageFiles,String filePdfName, SysUserEntity uc, HttpServletResponse response) {
response.setHeader("Content-disposition", "attachment;filename=" + filePdfName);
// 直接用浏览器或者用postman
response.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拆分图片,放到pdf
for(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;
}
成果: