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

成果:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ent.SetDatabaseDefaults()

在 AutoCAD 的 .NET API 中&#xff0c;ent.SetDatabaseDefaults() 这句代码通常用于将一个实体&#xff08;Entity&#xff09;对象的属性设置为与其所在的数据库&#xff08;Database&#xff09;的默认设置相匹配。这意味着&#xff0c;该实体将采用数据库级别的默认颜色、图…

python学opencv|读取图像(三十九 )阈值处理Otsu方法

【1】引言 前序学习了5种阈值处理方法&#xff0c;包括(反)阈值处理、(反)零值处理和截断处理&#xff0c;还学习了一种自适应处理方法&#xff0c;相关文章链接为&#xff1a; python学opencv|读取图像&#xff08;三十三&#xff09;阈值处理-灰度图像-CSDN博客 python学o…

深圳大学-计算机系统(3)-实验三取指和指令译码设计

实验目标 设计完成一个连续取指令并进行指令译码的电路&#xff0c;从而掌握设计简单数据通路的基本方法。 实验内容 本实验分成三周&#xff08;三次&#xff09;完成&#xff1a;1&#xff09;首先完成一个译码器&#xff08;30分&#xff09;&#xff1b;2&#xff09;接…

【JDBC】数据库连接的艺术:深入解析数据库连接池、Apache-DBUtils与BasicDAO

文章目录 前言&#x1f30d; 一.连接池❄️1. 传统获取Conntion问题分析❄️2. 数据库连接池❄️3.连接池之C3P0技术&#x1f341;3.1关键特性&#x1f341;3.2配置选项&#x1f341;3.3使用示例 ❄️4. 连接池之Druid技术&#x1f341; 4.1主要特性&#x1f341; 4.2 配置选项…

Glary Utilities Pro 多语便携版系统优化工具 v6.21.0.25

Glary Utilities是一款功能强大的系统优化工具软件&#xff0c;旨在帮助用户清理计算机垃圾文件、修复系统错误、优化系统性能等。 软件功能 清理和修复&#xff1a;可以清理系统垃圾文件、无效注册表项、无效快捷方式等&#xff0c;修复系统错误和蓝屏问题。 优化和加速&…

QT调用OpenSceneGraph

OSG和osgQt编译教程&#xff0c;实测通过 一、下载OpenSceneGraph OpenSceneGraphhttps://github.com/openscenegraph/OpenSceneGraph 二、使用CMAKE编译OpenSceneGraph 1.打开cmake&#xff0c;配置源代码目录 2. CMAKE_INSTALL_PREFIX设置为install文件夹&#xff0c;生…

基于JAVA的微信点餐小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

【Postgres_Python】使用python脚本批量创建和导入多个PG数据库

之前批量创建和导入数据库分为2个python脚本进行&#xff0c;现整合优化代码合并为一个python脚本&#xff0c;可同步实现数据库的创建和数据导入。之前的文章链接&#xff1a; 【Postgres_Python】使用python脚本批量创建PG数据库 【Postgres_Python】使用python脚本将多个.S…

数据结构——实验八·学生管理系统

嗨~~欢迎来到Tubishu的博客&#x1f338;如果你也是一名在校大学生&#xff0c;正在寻找各种编程资源&#xff0c;那么你就来对地方啦&#x1f31f; Tubishu是一名计算机本科生&#xff0c;会不定期整理和分享学习中的优质资源&#xff0c;希望能为你的编程之路添砖加瓦⭐&…

GitCode 助力 AutoTable:共创 MyBatis 生态的自动表格管理新篇章

项目仓库https://gitcode.com/dromara/auto-table 解放双手&#xff0c;专注业务&#xff1a;MyBatis 生态的“自动表格”创新 AutoTable 是一款致力于为 MyBatis 生态赋予“自动表格”功能的创新插件。其核心理念是通过 Java 实体类自动生成和维护数据库的表结构&#xff0c…

微信小程序使用picker根据接口给的省市区的数据实现省市区三级联动或者省市区街道等多级联动

接口数据如上图 省市区多级联动&#xff0c;都是使用的一个接口通过传参父类的code。返回我们想要的数据 比如获取省就直接不要参数。市就把省得code传给接口&#xff0c;区就把市的code作为参数。 <picker mode"multiSelector" :range"mulSelect1" …

nvm版本安装

安装 使用切换 MySQL5.7新安装 熟人命令 8.0 mysql -P3306 -uroot -p5.7 mysql -P3307 -uroot -p 记得用完关闭 navicat

rocketmq基本架构

简介 Name server 负责broker注册、心跳&#xff0c;路由等功能&#xff0c;类似Kafka的ZKname server节点之间不互相通信&#xff0c;broker需要和所有name server进行通信。扩容name server需要重启broker&#xff0c;不然broker不会和name server建立连接producer和consum…

k8s集成MinIo

本篇文章分享一下在 k8s怎么集成 minio做存储&#xff0c;并实现 PersistentVolume (PV)、PersistentVolumeClaim (PVC)、动态存储卷StorageClass&#xff0c;以及演示让pod使用这些存储卷的完整流程。 一、理论 1、PV概念 PV是对K8S存储资源的抽象&#xff0c;PV一般由运维…

PC端自动化测试实战教程-1-pywinauto 环境搭建(详细教程)

1.简介 之前总有人在群里或者私信留言问&#xff1a;Windows系统安装的软件如何自动化测试呢&#xff1f;因为没有接触过或者遇到过&#xff0c;所以说实话宏哥当时也不清楚怎么实现&#xff0c;怎么测试。然而在一次偶然的机会接触到了Python的一个模块说是它可以实现Microso…

STM32 GPIO工作模式

GPIO工作模式 1. GPIO简介2. GPIO工作模式2.1 输入浮空2.2 输入上拉2.3 输入下拉2.4 模拟2.5 开漏输出2.6 推挽输出2.7 开漏式复用功能2.8 推挽式复用功能 1. GPIO简介 GPIO 是通用输入输出端口的简称&#xff0c;简单来说就是 STM32 可控制的引脚&#xff0c;STM32 芯片的 GPI…

unity插件Excel转换Proto插件-ExcelToProtobufferTool

unity插件Excel转换Proto插件-ExcelToProtobufferTool **ExcelToProtobufTool 插件文档****1. 插件概述****2. 默认配置类&#xff1a;DefaultIProtoPathConfig****属性说明** **3. 自定义配置类****定义规则****示例代码** **4. 使用方式****4.1 默认路径****4.2 自定义路径**…

基于微信小程序的设备故障报修管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

LeRobot安装教程

LeRobot的下载与安装 使用Git下载源代码使用Anaconda安装LeRobot 使用Git下载源代码 使用Git从github仓库中远程下载项目&#xff1a;选择一个文件夹用于存放下载下来的项目&#xff08;可以新建一个空文件夹&#xff09;&#xff0c;然后在该文件夹内打开Git Bash Here,输入以…

HTML5使用favicon.ico图标

目录 1. 使用favicon.ico图标 1. 使用favicon.ico图标 favicon.ico一般用于作为网站标志&#xff0c;它显示在浏览器的地址栏或者标签上 制作favicon图标 选择一个png转ico的在线网站&#xff0c;这里以https://www.bitbug.net/为例。上传图片&#xff0c;目标尺寸选择48x48&a…