【Poi-tl Documentation】自定义占位符来设置图片大小

前置说明:

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.1</version>
</dependency>

模板文件:
image_test.docx

image.png

package run.siyuan.poi.tl.policy;

import cn.hutool.core.util.ReUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.converter.ObjectToPictureRenderDataConverter;
import com.deepoove.poi.converter.ToRenderDataConverter;
import com.deepoove.poi.data.Paragraphs;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.data.style.PictureStyle;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.policy.PictureRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.BufferedImageUtils;
import com.deepoove.poi.util.RegexUtils;
import com.deepoove.poi.util.SVGConvertor;
import com.deepoove.poi.util.UnitUtils;
import com.deepoove.poi.xwpf.BodyContainer;
import com.deepoove.poi.xwpf.BodyContainerFactory;
import com.deepoove.poi.xwpf.WidthScalePattern;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;

import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @ClassName CustomPictureRenderPolicy
 * @Description TODO
 * @Author siyuan
 * @Date 2024/3/3 12:53
 */
public class CustomPictureRenderPolicy extends PictureRenderPolicy {

    public static void main(String[] args) throws IOException {
        // 读取模板文件
        FileInputStream fileInputStream = new FileInputStream("/Users/wuzhiqian/Desktop/HY/image_test.docx");
        // 创建模板配置
        ConfigureBuilder configureBuilder = Configure.builder();
//        configureBuilder.buildGrammerRegex(RegexUtils.createGeneral("{{", "}}"));
//        configureBuilder.buildGrammerRegex("((%)?[\\w\\u4e00-\\u9fa5]+(\\.[\\w\\u4e00-\\u9fa5]+)*(\\[\\d,\\d\\])?)?");
        configureBuilder.setValidErrorHandler(new Configure.DiscardHandler());
        configureBuilder.addPlugin('%', new CustomPictureRenderPolicy());
        // 创建模板上下文
        Map<String, Object> context = new HashMap<>();
        context.put("aaaa", Pictures.ofStream(Files.newInputStream(Paths.get("/Users/wuzhiqian/Desktop/HY/11111.png"))).create());
        context.put("name2", Pictures.ofStream(Files.newInputStream(Paths.get("/Users/wuzhiqian/Desktop/HY/11111.png"))).create());
        // 使用模板引擎替换文本标签
        XWPFTemplate compile = XWPFTemplate.compile(fileInputStream, configureBuilder.build());
        compile.render(context);
        // 保存生成的文档
        FileOutputStream outputStream = new FileOutputStream("/Users/wuzhiqian/Desktop/HY/image_test" + System.currentTimeMillis() + ".docx");
        compile.write(outputStream);
        outputStream.close();
        compile.close();
        fileInputStream.close();
    }


    private static ToRenderDataConverter<Object, PictureRenderData> converter = new ObjectToPictureRenderDataConverter();

    public CustomPictureRenderPolicy() {
    }

    public PictureRenderData cast(Object source) throws Exception {
        return (PictureRenderData)converter.convert(source);
    }

    protected boolean validate(PictureRenderData data) {
        return null != data;
    }

    protected void afterRender(RenderContext<PictureRenderData> context) {
        this.clearPlaceholder(context, false);
    }

    protected void reThrowException(RenderContext<PictureRenderData> context, Exception e) {
        this.logger.info("Render picture " + context.getEleTemplate() + " error: {}", e.getMessage());
        String alt = ((PictureRenderData)context.getData()).getAltMeta();
        context.getRun().setText(alt, 0);
    }

    public void beforeRender(RenderContext<PictureRenderData> context) {
        System.out.println("================");
        XWPFRun run = context.getRun();
        String source = context.getEleTemplate().getSource();
        String tagName = context.getEleTemplate().getTagName();
        System.out.println(source);
        Pattern pattern = Pattern.compile( "(.*)\\{\\{%"+tagName+"}}\\[\\d+,\\d+](.*)");
        XWPFParagraph parent = (XWPFParagraph) run.getParent();
        IBody body = parent.getBody();
        for (XWPFParagraph paragraph : body.getParagraphs()) {
            String text = paragraph.getText();
            System.out.println(text + "-------------------------------");

            if (text.contains(source) && ReUtil.isMatch(pattern,text) ) {
                String s = ReUtil.get("\\{\\{%"+tagName+"}}\\[\\d+,\\d+]", text, 0);
                System.out.println(s);
                s = ReUtil.get("\\[\\d+,\\d+]", s, 0);
                System.out.println(s);
                String[] split = s.replace("[", "").replace("]", "").split(",");
                Integer w = Integer.valueOf(split[0]);
                Integer h = Integer.valueOf(split[1]);
                PictureStyle pictureStyle = new PictureStyle();
                pictureStyle.setWidth(w);
                pictureStyle.setHeight(h);
                context.getData().setPictureStyle(pictureStyle);

                for (XWPFRun xwpfRun : paragraph.getRuns()) {
                    if (s.equals(xwpfRun.text())){
                        System.out.println(xwpfRun.text()+"   clean");
                        // 删除[200,214] 格式字符
                        BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(xwpfRun);
                        bodyContainer.clearPlaceholder(xwpfRun);
                    }

                }
            }
        }
    }

    public void doRender(RenderContext<PictureRenderData> context) throws Exception {
        CustomPictureRenderPolicy.Helper.renderPicture(context.getRun(), (PictureRenderData) context.getData());
    }

    public static class Helper {
        public Helper() {
        }

        public static void renderPicture(XWPFRun run, PictureRenderData picture) throws Exception {
            byte[] imageBytes = picture.readPictureData();
            if (null == imageBytes) {
                throw new IllegalStateException("Can't read picture byte arrays!");
            } else {
                // 根据图片流 设置图片类型
                PictureType pictureType = picture.getPictureType();
                if (null == pictureType) {
                    pictureType = PictureType.suggestFileType(imageBytes);
                }
                // 图片类型为空,报错
                if (null == pictureType) {
                    throw new RenderException("PictureRenderData must set picture type!");
                } else {
                    PictureStyle style = picture.getPictureStyle();
                    if (null == style) {
                        style = new PictureStyle();
                    }

                    int width = style.getWidth();
                    int height = style.getHeight();
                    if (pictureType == PictureType.SVG) {
                        imageBytes = SVGConvertor.toPng(imageBytes, (float) width, (float) height);
                        pictureType = PictureType.PNG;
                    }

                    if (!isSetSize(style)) {
                        BufferedImage original = BufferedImageUtils.readBufferedImage(imageBytes);
                        width = original.getWidth();
                        height = original.getHeight();
                        if (style.getScalePattern() == WidthScalePattern.FIT) {
                            BodyContainer bodyContainer = BodyContainerFactory.getBodyContainer(run);
                            int pageWidth = UnitUtils.twips2Pixel(bodyContainer.elementPageWidth((IBodyElement) run.getParent()));
                            if (width > pageWidth) {
                                double ratio = (double) pageWidth / (double) width;
                                width = pageWidth;
                                height = (int) ((double) height * ratio);
                            }
                        }
                    }

                    InputStream stream = new ByteArrayInputStream(imageBytes);

                    try {
                        PictureStyle.PictureAlign align = style.getAlign();
                        if (null != align && run.getParent() instanceof XWPFParagraph) {
                            ((XWPFParagraph) run.getParent()).setAlignment(ParagraphAlignment.valueOf(align.ordinal() + 1));
                        }

                        run.addPicture(stream, pictureType.type(), "Generated", Units.pixelToEMU(width), Units.pixelToEMU(height));
                    } catch (Throwable var13) {
                        try {
                            stream.close();
                        } catch (Throwable var12) {
                            var13.addSuppressed(var12);
                        }

                        throw var13;
                    }

                    stream.close();
                }
            }
        }

        private static boolean isSetSize(PictureStyle style) {
            return (style.getWidth() != 0 || style.getHeight() != 0) && style.getScalePattern() == WidthScalePattern.NONE;
        }
    }

}

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

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

相关文章

PyQt5---初识PyQt5相关及开发实战介绍

什么是GUI GUI是Graphical User Interface&#xff08;图形用户界面&#xff09;的缩写&#xff0c;是一种用户与计算机交互的方式&#xff0c;通过使用图形化的元素&#xff08;如按钮、窗口、菜单等&#xff09;来帮助用户完成任务。GUI使得用户可以通过鼠标、键盘等输入设备…

2024.3.17 机器学习周报

引言 Abstract 文献阅读 1、题目 R-TRANSFORMER: RECURRENT NEURAL NETWORK ENHANCED TRANSFORMER 2、引言 递归神经网络长期以来一直是序列建模的主要选择。然而&#xff0c;它严重遭受两个问题&#xff1a;在捕获非常长期的依赖性和无法并行化的顺序计算过程中无能为力…

【Javascript编程实操06】1、反转数组和字符串 2、将二维数组转一维数组

前言 1、反转数组和字符串 代码&#xff1a; 实现效果&#xff1a; 2、将二维数组转一维数组 代码&#xff1a; 实现效果&#xff1a; 总结 前言 本次主要是针对Javascript阶段的字符串与数组的实操练习&#xff0c;共有2个实操&#xff0c;大家可以在实操的过程中更加深…

程序人生——Java泛型和反射的使用建议

目录 引出泛型和反射建议93&#xff1a;Java的泛型是类型擦除的建议94&#xff1a;不能初始化泛型参数和数组建议95&#xff1a;强制声明泛型的实际类型 建议96&#xff1a;不同的场景使用不同的泛型通配符建议97&#xff1a;警惕泛型是不能协变和逆变的 建议98&#xff1a;建议…

基于springboot实现小区物业管理系统项目【项目源码+论文说明】

基于springboot实现小区物业管理系统演示 摘要 随着城镇人口居住的集中化加剧 &#xff0c;传统人工小区管理模式逐渐跟不上时代的潮流。这就要求我们提供一个专门的管理系统。来提高物管的工作效率、为住户提供更好的服务。 物业管理系统运用现代化的计算机管理手段,使物业的…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的安全帽检测系统(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;开发先进的安全帽识别系统对提升工作场所的安全性至关重要。本文详细介绍了使用深度学习技术创建此类系统的方法&#xff0c;并分享了完整的实现代码。系统采用了强大的YOLOv8算法&#xff0c;并对其与YOLOv7、YOLOv6、YOLOv5的性能进行了详细比较&#xff0c;…

MySQL:视图

1. 概述 在MySQL中&#xff0c;视图&#xff08;View&#xff09;是一个虚拟存在的表&#xff0c;其内容是由查询定义的。视图本身并不包含数据&#xff0c;它只包含一条SQL查询语句&#xff08;即定义视图的SELECT语句&#xff09;。当通过视图访问数据时&#xff0c;MySQL会执…

【SpringBoot3】整合Druid数据源和Mybatis 项目打包和运行

文章目录 一、整合Druid数据源二、整合Mybatis2.1 MyBatis整合步骤2.1 Mybatis整合实践2.1 声明式事务整合配置2.1 AOP整合配置 三、项目打包和运行命令启动和参数说明 总结web 与 springboot 打包区别JDK8的编译环境 执行17高版本jar 一、整合Druid数据源 创建模块 &#xff1…

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下 1. ForeverStrongCheng/OpenCV-tutorials2. Fork -> ForeverStrongCheng/R2CNN_Faster-RCNN_TensorflowReferences 访问仓库页面&#xff0c;点击 Fork 按钮创建自己的仓库。 Fork 是将 GitHub 的某个特定仓库复制到自己…

【Python编程基础】第一节.Python基本语法(上)

文章目录 前言⼀、Python介绍二、Python环境配置三、Pycharm 书写代码四、Python基本语法 4.1 print 函数的简单使用 4.2 注释 4.3 Python 代码中三种波浪线和 PEP8 4.4 在 cmd 终端中运⾏ Python 代码 4.5 变量 4.6 数据类型 4.7 类型转换…

【docker】docker的常用命令

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;中间件 ⛺️稳中求进&#xff0c;晒太阳 常规命令 docker version #查看docker 版本信息docker info #显示docker 的系统信息&#xff0c;包括镜像和容器数量docker --help #查看所有的命…

花钱买不到系列-linux信号[1]卷

我们下面要学的这个&#xff0c;信号&#xff0c;它呢就挺好玩的&#xff0c;虽然它也有一点点难&#xff0c;那么尤其是这里要进入第二阶段的进程地质空间的分享。 第一阶段&#xff0c;是当时在讲进程概念时&#xff0c;学了个进程地址空间&#xff0c;当时知道了地址空间页表…

基于大模型和向量数据库的 RAG 示例

1 RAG 介绍 RAG 是一种先进的自然语言处理方法&#xff0c;它结合了信息检索和文本生成技术&#xff0c;用于提高问答系统、聊天机器人等应用的性能。 2 RAG 的工作流程 文档加载&#xff08;Document Loading&#xff09; 从各种来源加载大量文档数据。这些文档…

操作系统——cpu、内存、缓存介绍

一、内存是什么 内存就是系统资源的代名词&#xff0c;它是其他硬件设备与 CPU 沟通的桥梁&#xff0c; 计算机中的所有程序都在内存中运行。其作用是暂时存放CPU的运算数据&#xff0c;以及与硬盘交换的数据。也是相当于CPU与硬盘沟通的桥梁。只要计算机在运行&#xff0c;CP…

应对恶意IP攻击的有效方法

在当今数字化时代&#xff0c;网络攻击已经成为了互联网安全的重大挑战之一。恶意IP攻击是网络安全领域中的一种常见威胁&#xff0c;它可能导致数据泄露、服务中断、系统瘫痪等严重后果。因此&#xff0c;有效地应对恶意IP攻击至关重要。IP数据云将深入探讨如何应对恶意IP攻击…

android中单例模式为什么会引起内存泄漏?

单例模式使用不恰当会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长, 如果一个对象已经不需要使用了,但是单例对象还持有该对象的引用,那么这个对象就不能被正常回收,因此会导致内存泄漏。 举个例子: ①新建一个工程。 ②配置好LeakCanary检…

SpringBoot Servlet容器启动解析

介绍 容器架构 容器处理请求 容器启动全局流程解析 启动前准备 WebServer创建入口 WebServer创建 Servlet启动 Web容器工厂类加载解析 Web容器个性化配置 属性注入 工厂类初始化 BeanPostProcessor方法实现 定制化流程 面试题 请描述下Servlet容器启动流程&#xff1f;介绍下…

下载程序到嵌入式开发板教程

一、设置共享目录 ubuntu与Window共同拥有的目录。 第一步&#xff1a;在Windows下创建一个文件夹share 第二部&#xff1a;点击虚拟机--->设置--->选项--->共享文件夹 进入共享目录的命令&#xff1a;cd/mnt/hgfs/share 二、C语言编译器 使用Linux平台下的gcc编…

发一下接口自动化测试框架(python3+requests+excel)

Git&#xff1a; https://github.com/lilinyu861/Interface-Test 环境配置&#xff1a; 开发工具&#xff1a;pycharm2018Excel 开发框架&#xff1a;python3requestsexcel 接口自动化测试框架介绍&#xff1a; 此接口测试框架&#xff0c;首先由用户设计原始的测试用例并为…

爬虫 某物流

目标地址 url "https://api.jdl.com/aging/feeInquiryNewByJDL" 加密参数 ciphertext和data 搜关键字ciphertext跟着栈走 很明显的DES加密 window globalconst e require(jsencrypt); // const e require(JSEncrypt) // e r(775).JSEncrypt // const t requi…