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

  @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;}

成果:

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/66735.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据分库分表和迁移方案

在我们业务快速发展的过程中&#xff0c;数据量必然也会迎来突飞猛涨。那么当我们的数据量百倍、千倍、万倍、亿倍增长后&#xff0c;原有的单表性能就不能满足我们日常的查询和写入了&#xff0c;此时数据架构就不得不进行拆分&#xff0c;比如单表拆分成10张表、100张表、单个…

线上突发:MySQL 自增 ID 用完,怎么办?

线上突发&#xff1a;MySQL 自增 ID 用完&#xff0c;怎么办&#xff1f; 1. 问题背景2. 场景复现3. 自增id用完怎么办&#xff1f;4. 总结 1. 问题背景 最近&#xff0c;我们在数据库巡检的时候发现了一个问题&#xff1a;线上的地址表自增主键用的是int类型。随着业务越做越…

Java导出通过Word模板导出docx文件并通过QQ邮箱发送

一、创建Word模板 {{company}}{{Date}}服务器运行情况报告一、服务器&#xff1a;总告警次数&#xff1a;{{ServerTotal}} 服务器IP:{{IPA}}&#xff0c;总共告警次数:{{ServerATotal}} 服务器IP:{{IPB}}&#xff0c;总共告警次数:{{ServerBTotal}} 服务器IP:{{IPC}}&#x…

【22】Word:小李-高新技术企业政策❗

目录 题目​ NO1.2 NO3 NO4 NO5.6 NO7.8 NO9.10 若文章中存在删除空白行等要求&#xff0c;可以到最后来完成。注意最后一定要检查此部分&#xff01;注意&#xff1a;大多是和事例一样即可&#xff0c;不用一摸一样&#xff0c;但也不要差太多。 题目 NO1.2 F12Fn&a…

自动化部署(三):项目管理平台

一、项目管理平台作用 帮助团队高效规划、执行和监控项目进度&#xff0c;确保任务按时完成并实现目标 敏捷开发&#xff1a;提供标准敏捷研发管理&#xff0c;支持Scrum 与 Kanban 规模化敏捷&#xff1a;支持大型研发团队跨项目协同&#xff0c;实现多项目路线图规划和资源管…

常用集合-数据结构-MySql

目录 java核心&#xff1a; 常用集合与数据结构: 单例集合: 双列集合: 线程安全的集合: ConcurrentHashMap集合: HashTable集合: CopyOnWriteArrayList集合: CopyOnWriteArraySet集合: ConcurrentLinkedQueue队列: ConcurrentSkipListMap和ConcurrentSkipListSet&…

IP属地与视频定位位置不一致:现象解析与影响探讨

在数字化时代&#xff0c;IP属地和视频定位位置已成为我们获取网络信息、判断内容真实性的重要依据。然而&#xff0c;有时我们会发现&#xff0c;某些视频内容中展示的定位位置与其发布者的IP属地并不一致。这种不一致现象引发了广泛的关注和讨论。本文旨在深入剖析IP属地与视…

计算机毕业设计hadoop+spark股票基金推荐系统 股票基金预测系统 股票基金可视化系统 股票基金数据分析 股票基金大数据 股票基金爬虫

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

机器学习-数据集划分

文章目录 一. 为什么要划分数据集二. 数据集划分的方法1. 留出法&#xff1a;2. 交叉验证&#xff1a;将数据集划分为训练集&#xff0c;验证集&#xff0c;测试集3. 留一法&#xff1a;4. 自助法&#xff1a; 一. 为什么要划分数据集 为了能够评估模型的泛化能力&#xff0c;可…

Vue 拦截监听原理

Vue 渐进式JavaScript 框架 学习笔记 - Vue 拦截监听原理 目录 拦截监听原理 如何跟踪变化 拦截监听示例 观察者 注意:vue3的变化 总结 拦截监听原理 如何跟踪变化 当你把一个普通的Javascript 对象传入 Vue 实例作为data选项&#xff0c;Vue 将遍历此对象所有的proper…

全面评测 DOCA 开发环境下的 DPU:性能表现、机器学习与金融高频交易下的计算能力分析

本文介绍了我在 DOCA 开发环境下对 DPU 进行测评和计算能力测试的一些真实体验和记录。在测评过程中&#xff0c;我主要关注了 DPU 在高并发数据传输和深度学习场景下的表现&#xff0c;以及基本的系统性能指标&#xff0c;包括 CPU 计算、内存带宽、多线程/多进程能力和 I/O 性…

基于JAVA的校园二手商品交易平台的设计与开发

摘 要&#xff1a;政府政策引导与社会观念的转变使得国内大学生的创业意识逐渐提高&#xff0c;很多高校大学生开始自主创业。目前我国各大高校暂且还没有较为成型的针对校内学生创业者的校园网络服务平台。本文首先主要是介绍了关于java语言以及web开发的相关技术&#xff0c;…

HarmonyOS Next 应用UI生成工具介绍

背景 HarmonyOS Next适配开发过程中难买难要参考之前逻辑&#xff0c;但是可能时间较长文档不全&#xff0c;只能参考Android或iOS代码&#xff0c;有些逻辑较重的场景还可以通过AI工具将Android 的Java代码逻辑转成TS完成部分复用。对于一些UI场景只能手动去写&#xff0c;虽…

总结6..

背包问题的解决过程 在解决问题之前&#xff0c;为描述方便&#xff0c;首先定义一些变量&#xff1a;Vi表示第 i 个物品的价值&#xff0c;Wi表示第 i 个物品的体积&#xff0c;定义V(i,j)&#xff1a;当前背包容量 j&#xff0c;前 i 个物品最佳组合对应的价值&#xff0c;同…

【数据结构篇】顺序表 超详细

目录 一.顺序表的定义 1.顺序表的概念及结构 1.1线性表 2.顺序表的分类 2.1静态顺序表 2.2动态顺序表 二.动态顺序表的实现 1.准备工作和注意事项 2.顺序表的基本接口&#xff1a; 2.0 创建一个顺序表 2.1 顺序表的初始化 2.2 顺序表的销毁 2.3 顺序表的打印 3.顺序…

上位机工作感想-2024年工作总结和来年计划

随着工作年限的增增长&#xff0c;发现自己越来越不喜欢在博客里面写一些掺杂自己感想的东西了&#xff0c;或许是逐渐被工作逼得“成熟”了吧。2024年&#xff0c;学到了很多东西&#xff0c;做了很多项目&#xff0c;也帮别人解决了很多问题&#xff0c;唯独没有涨工资。来这…

阿里云-银行核心系统转型之业务建模与技术建模

业务领域建模包括业务建模和技术建模&#xff0c;整体建模流程图如下&#xff1a; 业务建模包括业务流程建模和业务对象建模 业务流程建模&#xff1a;通过对业务流程现状分析&#xff0c;结合目标核心系统建设能力要求&#xff0c;参考行业建 模成果&#xff0c;形成结构化的…

【C++笔记】红黑树封装map和set深度剖析

【C笔记】红黑树封装map和set深度剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】红黑树封装map和set深度剖析前言一. 源码及框架分析1.1 源码框架分析 二. 模拟实现map和set2.1封装map和set 三.迭代器3.1思路…

win32汇编环境,怎么得到磁盘的盘符

;运行效果 ;win32汇编环境,怎么得到磁盘的盘符 ;以下代码主要为了展示一下原理&#xff0c;应用GetLogicalDrives、GetLogicalDriveStrings函数、屏蔽某些二进制位、按双字节复制内容等。以下代码最多查8个盘&#xff0c;即返回值中的1个字节的信息 ;直接抄进RadAsm可编译运行。…

mybatis(19/134)

大致了解了一下工具类&#xff0c;自己手敲了一边&#xff0c;java的封装还是真的省去了很多麻烦&#xff0c;封装成一个工具类就可以不用写很多重复的步骤&#xff0c;一个工厂对应一个数据库一个environment就好了。 mybatis中调用sql中的delete占位符里面需要有字符&#xf…