poi word 添加水印

news/2024/9/17 23:41:37/ 标签: word, java

poi word 添加水印

  • 依赖
  • DocxUtil
  • 调用
  • 遇到的问题
    • 部分客户给的word无法添加水印
      • 水印文案 过长会导致字变小变形 超过一定长度就会显示异常。消失等情况

依赖

        <!--poi-tl--><dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>

DocxUtil

import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;import java.io.InputStream;
import java.util.stream.Stream;import static org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse.FALSE;
import static org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse.T;/*** @author wangshuai9776* @date 2024/8/8 13:37*/
public class DocxUtil {//	public final static String DEFAULT_WATERMARK = "XXX科技有限公司"; // 后续按 系统设置获取public final static String DEFAULT_FONT_COLOR = "#d8d8d8";// 字体大小public static final String FONT_SIZE = "0.5pt";// 文本旋转角度public static final String STYLE_ROTATION = "-45";/*** 水印参数*/// private static final String fontColor = "#D3D3D3"; // 字体颜色/*** 艺术字水印参数*/private static final String fontName = "Microsoft YaHei"; // word字体// private static final String fontSize = "0.5pt"; // 字体大小private static final int widthPerWord = 10; // 一个字平均长度,单位pt,用于:计算文本占用的长度(文本总个数*单字长度)// private static final String styleRotation = "-45"; // 文本旋转角度private static final String SHAPE_TYPE = "#_x0000_t136"; // 形状类型:多边形private static final String SHAPE_SPID = "_x0000_s102";/*** word文字水印(调用poi封装的createWatermark方法)* @param doc XWPFDocument对象* @param markStr 水印文字*/public static void setWordWaterMark(XWPFDocument doc, String markStr,String fontColor) {XWPFParagraph paragraph = doc.createParagraph();XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();if (headerFooterPolicy == null) {headerFooterPolicy = doc.createHeaderFooterPolicy();}// create default Watermark - fill color black and not rotatedheaderFooterPolicy.createWatermark(markStr);// get the default header// Note: createWatermark also sets FIRST and EVEN headers// but this code does not updating those other headersXWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);paragraph = header.getParagraphArray(0);
//            // get com.microsoft.schemas.vml.CTShape where fill color and rotation is setparagraph.getCTP().newCursor();org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape"));if (xmlobjects.length > 0) {CTShape ctshape = (CTShape) xmlobjects[0];ctshape.setFillcolor(fontColor);ctshape.setStyle(ctshape.getStyle() + ";rotation:315");}}/*** 以艺术字方式加上水印(平铺)* @param docx XWPFDocument对象* @param customText 水印文字*/public static void makeFullWaterMarkByWordArt(XWPFDocument docx, String customText,String fontColor,String fontSize,String styleRotation) {customText = customText + repeatString(" ", 16); // 水印文字之间使用8个空格分隔customText = repeatString(customText, 3); // 一行水印重复水印文字次数 //重复次数不能太多,内容过长会导致字体展示不出来。String styleTop = "0pt";  // 与顶部的间距if (docx == null) {return;}// 遍历文档,添加水印for (int lineIndex = -10; lineIndex < 20; lineIndex++) {styleTop = 200 * lineIndex + "pt";waterMarkDocXDocument(docx, customText, styleTop, 1,fontColor, fontSize ,styleRotation);}}/*** 以艺术字方式加上水印(单个)* @param docx XWPFDocument对象* @param customText 水印文字*/public static void makeWaterMarkByWordArt(XWPFDocument docx, String customText,String fontColor,String fontSize,String rotation) {String styleTop = "0pt";  // 与顶部的间距if (docx == null) {return;}// 添加水印waterMarkDocXDocument(docx, customText, styleTop, 2,fontColor,fontSize,rotation);}/*** 将指定的字符串重复repeats次.* @param pattern 字符串* @param repeats 重复次数* @return 生成的字符串*/private static String repeatString(String pattern, int repeats) {StringBuilder buffer = new StringBuilder(pattern.length() * repeats);Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);return new String(buffer);}/*** 为文档添加水印* 实现参考了{@link XWPFHeaderFooterPolicy#(String, int)}* @param doc 需要被处理的docx文档对象* @param customText 水印文本* @param type 类型:1.平铺;2.单个*/private static void waterMarkDocXDocument(XWPFDocument doc, String customText, String styleTop, int type,String fontColor,String fontSize,String rotation) {XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT); // 如果之前已经创建过 DEFAULT 的Header,将会复用之int size = header.getParagraphs().size();if (size == 0) {header.createParagraph();}CTP ctp = header.getParagraphArray(0).getCTP();byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();ctp.setRsidP(rsidr);ctp.setRsidRDefault(rsidrdefault);CTPPr ppr = ctp.addNewPPr();ppr.addNewPStyle().setVal("Header");for (int i = 0; i < 3; i++) {// 开始加水印CTR ctr = ctp.addNewR();CTRPr ctrpr = ctr.addNewRPr();ctrpr.addNewNoProof();CTGroup group = CTGroup.Factory.newInstance();CTShape shape = group.addNewShape();shape.setSpid(SHAPE_SPID);shape.setType(SHAPE_TYPE);if(type != 2){shape.setStyle(getShapeStyle(customText, styleTop,rotation)); // 设置形状样式(旋转,位置,相对路径等参数)}else{shape.setStyle(getShapeStyle()); // 设置形状样式(旋转,位置,相对路径等参数)}shape.setFillcolor(fontColor);shape.setStroked(FALSE); // 字体设置为实心CTLock lock = shape.addNewLock();lock.setExt(STExt.VIEW);CTTextPath shapeTextPath = shape.addNewTextpath(); // 绘制文本的路径shapeTextPath.setOn(T);shapeTextPath.setFitshape(T);shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize); // 设置文本字体与大小shapeTextPath.setString(customText+i);CTPicture pict = ctr.addNewPict();pict.set(group);}}/*** 加载docx格式的word文档* @param inputStream* @return*/private static XWPFDocument loadDocXDocument(InputStream inputStream) {XWPFDocument doc;try {doc = new XWPFDocument(inputStream);} catch (Exception e) {throw new RuntimeException("文档加载失败!!");}return doc;}/*** 构建Shape的样式参数* @param customText 水印文本* @return*/private static String getShapeStyle(String customText, String styleTop,String styleRotation) {StringBuilder sb = new StringBuilder();sb.append("position: ").append("absolute"); // 文本path绘制的定位方式sb.append(";width: ").append(customText.length() * widthPerWord).append("pt"); // 计算文本占用的长度(文本总个数*单字长度)sb.append(";height: ").append("20pt"); // 字体高度sb.append(";z-index: ").append("-251654144");sb.append(";mso-wrap-edited: ").append("f");sb.append(";margin-top: ").append(styleTop);sb.append(";mso-position-horizontal-relative: ").append("margin");sb.append(";mso-position-horizontal: ").append("center");sb.append(";mso-position-vertical-relative: ").append("margin");sb.append(";mso-position-vertical: ").append("left");sb.append(";rotation: ").append(styleRotation);return sb.toString();}/*** 构建Shape的样式参数* @return*/private static String getShapeStyle() {StringBuilder sb = new StringBuilder();sb.append("position: ").append("absolute"); // 文本path绘制的定位方式sb.append(";left: ").append("opt");sb.append(";width: ").append("500pt"); // 计算文本占用的长度(文本总个数*单字长度)sb.append(";height: ").append("150pt"); // 字体高度sb.append(";z-index: ").append("-251654144");sb.append(";mso-wrap-edited: ").append("f");sb.append(";margin-left: ").append("-50pt");sb.append(";margin-top: ").append("270pt");sb.append(";mso-position-horizontal-relative: ").append("margin");sb.append(";mso-position-vertical-relative: ").append("margin");sb.append(";mso-width-relative: ").append("page");sb.append(";mso-height-relative: ").append("page");sb.append(";rotation: ").append("-2949120f");return sb.toString();}}

调用

DocxUtil.makeFullWaterMarkByWordArt(doc, watermark, DocxUtil.DEFAULT_FONT_COLOR, DocxUtil.FONT_SIZE, DocxUtil.STYLE_ROTATION);

遇到的问题

word_256">部分客户给的word无法添加水印

  • 在选取模式下 有水印
    在这里插入图片描述
  • 编辑模式下就看不见水印了
    在这里插入图片描述

水印文案 过长会导致字变小变形 超过一定长度就会显示异常。消失等情况

在这里插入图片描述


http://www.ppmy.cn/news/1517034.html

相关文章

捕获神经网络的精髓:深入探索PyTorch的torch.jit.trace方法

标题&#xff1a;捕获神经网络的精髓&#xff1a;深入探索PyTorch的torch.jit.trace方法 在深度学习领域&#xff0c;模型的部署和优化是至关重要的环节。PyTorch作为最受欢迎的深度学习框架之一&#xff0c;提供了多种工具来帮助开发者优化和部署模型。torch.jit.trace是PyTo…

设计模式 10 外观模式

设计模式 10 创建型模式&#xff08;5&#xff09;&#xff1a;工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式结构型模式&#xff08;7&#xff09;&#xff1a;适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式行为型模式&#xff…

ansible的tags标签

1、tags模块 可以给任务定义标签&#xff0c;可以根据标签来运行指定的任务 2、标签的类型 always&#xff1a;设定了标签名为always&#xff0c;除非指定跳过这个标签&#xff0c;否则该任务将始终会运行&#xff0c;即使指定了标签还会运行never&#xff1a;始终不运行的任…

CPU、MPU、MCU、SOC分别是什么?

CPU、MPU、MCU和SoC都是与微电子和计算机科学相关的术语&#xff0c;它们在功能定位、应用场景以及处理能力等方面有所区别。具体如下&#xff1a; CPU&#xff1a;CPU是中央处理单元的缩写&#xff0c;它通常指计算机内部负责执行程序指令的芯片。CPU是所有类型计算机&#x…

java 读取mysql中的表并按照指定格式导出excel

在Java中读取MySQL中的数据表并将其导出到Excel文件中&#xff0c;你需要以下几个步骤&#xff1a; 连接MySQL数据库&#xff1a;使用JDBC驱动程序连接到MySQL数据库。执行SQL查询&#xff1a;获取表数据。使用Apache POI库生成Excel文件&#xff1a;将数据写入Excel格式。保存…

SpringBoot文档之构建包的阅读笔记

Packaging Spring Boot Applications Efficient Deployments Efficient Deployments 默认情况下&#xff0c;基于SpringBoot框架开发应用时&#xff0c;构建插件spring-boot-maven-plugin将项目打包为fat jar。 执行如下命令&#xff0c;解压构建得到的jar文件。 java -Djarmo…

Python 程序设计基础教程

Python 程序设计基础教程 撰稿人&#xff1a;南星六月雪 第 一 章 变量与简单数据类型 1.1 变量 先来观察以下程序&#xff1a; world "Hello Python!" print(world)world "Hello Python,I love you!" print(world)运行这个程序&#xff0c;将看到两…

0827作业+梳理(c++day01)

一、作业&#xff1a; 1、代码 #include <iostream> using namespace std; int main() {string str;cout<<"请输入一个字符串"<<endl;getline(cin,str);cout<<"str "<<str<<endl;//初始化各类字符个数int size_num …

如何保证Redis与数据库之间的一致性

在现代应用程序架构中&#xff0c;Redis等内存数据库因其高性能和低延迟特性而被广泛用于缓存、会话管理、消息队列等多种场景。然而&#xff0c;当Redis作为数据库&#xff08;如MySQL、PostgreSQL&#xff09;的缓存层时&#xff0c;确保数据在Redis和数据库之间的一致性变得…

jmeter中CSV 数据文件设置用例

1、CSV数据文件的基础使用 线程组->添加->配置远近->CSV数据文件设置 2、多条用例运行CSV数据文件 由于我的csv请求的json数据有“&#xff0c;”所以我这边 分隔符选择了*号 写了两行需要测试的用例&#xff0c;需要添加一个“循环控制器” 线程组->添加-&g…

splunk Enterprise 的HTTP收集器-windows

1.创建HTTP收集器 2.使用HTTP收集器 然后打开全局设置&#xff1a;把ssl给去掉&#xff0c;点保存&#xff08;保存之后&#xff0c;可以看到这些状态全部都是已启用了&#xff09;&#xff1a; 3.测试&#xff1a; curl --location --request POST http://192.168.11.131:808…

List<String> 和 ArrayList<String>的区别

List<String> list new ArrayList<>() 这种形式实际上是一种向上转型&#xff08;upcasting&#xff09;的体现&#xff0c;ArrayList 实现了 List 接口&#xff0c;可以看成是从 List 继承而来&#xff0c;一个子类的对象可以指向它父类。 为什么不是 ArrayList…

国标GB28181视频监控EasyCVR视频汇聚平台国标注册被陌生IP入侵如何处理?

GB28181国标/GA/T1400协议/安防综合管理系统EasyCVR视频汇聚平台能在复杂的网络环境中&#xff0c;将前端设备统一集中接入与汇聚管理。智慧安防/视频存储/视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级…

Leetcode 78 子集 回溯 C++实现

Leetcode 78. 子集 问题&#xff1a;给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 方法1&#xff1a; 创建返回二维数组 ans &#xff0c;和…

★ 算法OJ题 ★ 力扣283 - 移动零

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将和大家一起做一道双指针算法题--移动零~ 目录 一 题目 二 算法解析 三 编写算法 一 题目 283. 移动零 - 力扣&#xff08;LeetCode&#xff09;链接&#xff1a;283. 移动零 - 力扣&#xff08;LeetCode&am…

linux 安装kafaka单体服务

1.下载kafka的linux安装包 前往Apache Kafka官方网站下载页面&#xff08;Apache Kafkahttps://kafka.apache.org/downloads&#xff09;&#xff0c;选择最新稳定版的Kafka二进制分发文件&#xff0c;通常是以.tgz结尾的文件。 手动下载kafka_2.13-3.8.0.tgz到本地&#xff0…

[图论]游戏

题目描述 B B B 经常与 A A A 一起玩游戏。今天&#xff0c;他们在一棵树上玩游戏。 A A A 有 m 1 m1 m1 块石子&#xff0c; B B B 有 m 2 m2 m2 块石子&#xff0c;游戏一开始&#xff0c;所有石头放在树的节点处&#xff0c;除了树根。 A A A 先移动石子。然后两人轮流移…

Java学习Day31:HTML 第一章:观音禅院

1.结构介绍 1.标签的分类 <单词> &#xff1a;元素标签 <元素 单词>&#xff1a;首先<>中至少有两个单词&#xff0c;那第一个肯定是元素标签&#xff0c;元素标签后跟的都是属性标签 2.文本元素 段落元素 段落元素 换行标签 br 水平线标签 标签会在页面…

【石子合并】

题目 错解 #include <bits/stdc.h> using namespace std; const int N 310; int a[N], s[N], f[N][N]; int main() {int n;cin >> n;memset(f, 0x3f, sizeof f);for(int i 1; i < n; i){cin >> a[i];s[i] s[i-1] a[i];f[i][i] 0;}for(int i 1; i &…

Datawhale X 李宏毅苹果书 AI夏令营-深度学习基础-Task1

# Datawhale AI 夏令营 夏令营手册&#xff1a;向李宏毅学深度学习 深度学习临界点 临界点&#xff1a;梯度为零的点 在神经网络训练过程中&#xff0c;当参数对损失微分为零的时候&#xff0c;梯度下降就不能再更新参数了&#xff0c;训练就停下来了&#xff0c;损失不再下…