亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java POI-TL設(shè)置Word圖片浮于文字上方

 更新時(shí)間:2025年03月13日 09:52:51   作者:qunwuhui  
這篇文章主要為大家詳細(xì)介紹了Java如何利用POI-TL設(shè)置Word圖片環(huán)繞方式為浮于文字上方而不是嵌入的方式,感興趣的小伙伴可以參考一下

需求描述

word導(dǎo)出時(shí)插入圖片,圖片浮于文字上方而不是嵌入的方式

poi-tl 原生的插入圖片

poi-tl渲染圖片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,該方法中有一段代碼:CTInline inline = drawing.addNewInline();意思就是默認(rèn)將圖片轉(zhuǎn)為inline類型,即行內(nèi)元素

解決方式 自定義圖片渲染插件

1. 自定義MyPictureRenderPolicy

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.AbstractRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import com.deepoove.poi.util.BufferedImageUtils;
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.IBodyElement;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.function.Supplier;

/**
 * 自定義圖片渲染
 */
public class MyPictureRenderPolicy extends AbstractRenderPolicy<Object> {

    @Override
    protected boolean validate(Object data) {
        if (null == data) {
            return false;
        } else if (data instanceof PictureRenderData) {
            return null != ((PictureRenderData) data).getPictureSupplier();
        } else {
            return true;
        }
    }

    @Override
    public void doRender(RenderContext<Object> context) throws Exception {
        Helper.renderPicture(context.getRun(), wrapper(context.getData()));
    }

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

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

        context.getRun().setText(alt, 0);
    }

    private static PictureRenderData wrapper(Object object) {
        return object instanceof PictureRenderData ? (PictureRenderData) object : Pictures.of(object.toString()).fitSize().create();
    }


    public static class Helper {
        public static void renderPicture(XWPFRun run, PictureRenderData picture) throws Exception {
            Supplier<byte[]> supplier = picture.getPictureSupplier();
            byte[] imageBytes = (byte[]) supplier.get();
            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(((IBodyElement) run.getParent()).getBody());
                            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);
                    Throwable var25 = null;

                    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));
                        //XWPFRunWrapper wrapper = new XWPFRunWrapper(run, false);


                        CTDrawing drawing = run.getCTR().getDrawingArray(0);
                        CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
                        //拿到新插入的圖片替換添加CTAnchor 設(shè)置浮動(dòng)屬性 刪除inline屬性
                        CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "Generated",
                                Units.toEMU(width), Units.toEMU(height),//圖片大小
                                Units.toEMU(270), Units.toEMU(-70), false);//相對(duì)當(dāng)前段落位置 需要計(jì)算段落已有內(nèi)容的左偏移

                        drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮動(dòng)屬性
                        drawing.removeInline(0);//刪除行內(nèi)屬性
                    } catch (Throwable var20) {
                        var25 = var20;
                        throw var20;
                    } finally {
                        if (stream != null) {
                            if (var25 != null) {
                                try {
                                    stream.close();
                                } catch (Throwable var19) {
                                    var25.addSuppressed(var19);
                                }
                            } else {
                                stream.close();
                            }
                        }

                    }

                }
            }
        }

    }

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

    /**
     * @param ctGraphicalObject 圖片數(shù)據(jù)
     * @param deskFileName      圖片描述
     * @param width             寬
     * @param height            高
     * @param leftOffset        水平偏移 left
     * @param topOffset         垂直偏移 top
     * @param behind            文字上方,文字下方
     * @return
     * @throws Exception
     */
    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                String deskFileName, int width, int height,
                                                int leftOffset, int topOffset, boolean behind) {
        String anchorXML =
                "<wp:anchor  xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                        + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                        + "<wp:simplePos x=\"0\" y=\"0\"/>"
                        + "<wp:positionH relativeFrom=\"column\">"
                        + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                        + "</wp:positionH>"
                        + "<wp:positionV relativeFrom=\"paragraph\">"
                        + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                        "</wp:positionV>"
                        + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                        + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                        + "<wp:wrapNone/>"
                        + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                        + "</wp:anchor>";


        CTDrawing drawing = null;
        try {
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            e.printStackTrace();
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }

}

2. 測(cè)試

該內(nèi)容將圖片自動(dòng)添加到word尾部

import cn.hutool.core.collection.CollectionUtil;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.data.Pictures;
import com.word.img.demo.picture.MyPictureRenderPolicy;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 數(shù)據(jù)處理-word 文檔尾部添加圖片
 *
 * @author: 
 * @date:
 * @description:
 */
public class PoiWordTest3 {

    public static void main(String[] args) throws IOException {
        //要寫入模板的數(shù)據(jù)
        Map<String, Object> exampleData = new HashMap<>();


        exampleData.put("image1", Pictures.ofLocal("src/main/resources/icecream.png").size(120, 120).create());


        FileInputStream inputStream = new FileInputStream("src/main/resources/test3.docx");
        XWPFDocument doc = new XWPFDocument(inputStream);
        List<XWPFParagraph> docParagraphs = doc.getParagraphs();
        if (CollectionUtil.isNotEmpty(docParagraphs)) {
            //最后一個(gè)段落
            XWPFParagraph paragraph = docParagraphs.get(docParagraphs.size() - 1);
            XWPFRun run = paragraph.createRun();

            run.setText("{{%image1}} "); //poi-tl 所需模板

        } else {
            //添加段落
            XWPFParagraph paragraph = doc.createParagraph();
            XWPFRun run = paragraph.createRun();

            run.setText("{{%image1}} "); //poi-tl 所需模板
        }


        //用于處理word文件,上傳
        File tempFileUpload = null;  //上傳臨時(shí)文件
        FileOutputStream tempFileOutputStreamUpload = null; //上傳臨時(shí)文件輸出流
        FileInputStream tempFileInputStreamUpload = null; //上傳臨時(shí)文件輸入流
        //臨時(shí)文件輸出流
        tempFileUpload = File.createTempFile("wordTempUpload", ".docx");
        tempFileOutputStreamUpload = new FileOutputStream(tempFileUpload);
        doc.write(tempFileOutputStreamUpload);
        tempFileInputStreamUpload = new FileInputStream(tempFileUpload);
        /********************* 把插件注冊(cè)為新標(biāo)簽類型 ***********************************/
        ConfigureBuilder builder = Configure.builder();
        builder.addPlugin('%',new MyPictureRenderPolicy());//把插件注冊(cè)為新標(biāo)簽類型
        XWPFTemplate template = XWPFTemplate.compile(tempFileInputStreamUpload,builder.build()).render(exampleData);

        //文件輸出流
        FileOutputStream out = new FileOutputStream("src/main/resources/test31.docx");
        template.write(out);

        out.flush();
        out.close();
        template.close();
    }


}

參考

Java使用poi-tl設(shè)置word圖片環(huán)繞方式為浮于在文字上方

java poi設(shè)置生成的word的圖片為上下型環(huán)繞以及其位置的實(shí)現(xiàn)

以上就是Java POI-TL設(shè)置Word圖片浮于文字上方的詳細(xì)內(nèi)容,更多關(guān)于Java POI-TL設(shè)置Word圖片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MyBatis-Plus數(shù)據(jù)庫(kù)配置與數(shù)據(jù)源整合方案

    MyBatis-Plus數(shù)據(jù)庫(kù)配置與數(shù)據(jù)源整合方案

    本文詳細(xì)介紹了在MyBatis-Plus中進(jìn)行數(shù)據(jù)庫(kù)配置與數(shù)據(jù)源整合的常見(jiàn)方法,包括單數(shù)據(jù)源和多數(shù)據(jù)源的配置步驟,以及如何使用SpringBoot的自動(dòng)配置和手動(dòng)配置來(lái)管理數(shù)據(jù)源,通過(guò)合理的配置,開(kāi)發(fā)者可以簡(jiǎn)化數(shù)據(jù)庫(kù)操作,實(shí)現(xiàn)高效的數(shù)據(jù)庫(kù)管理和復(fù)雜的應(yīng)用架構(gòu)
    2025-02-02
  • springboot如何獲取yml文件的自定義參數(shù)

    springboot如何獲取yml文件的自定義參數(shù)

    這篇文章主要介紹了springboot如何獲取yml文件的自定義參數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot異步實(shí)現(xiàn)的8種方式

    SpringBoot異步實(shí)現(xiàn)的8種方式

    異步執(zhí)行對(duì)于開(kāi)發(fā)者來(lái)說(shuō)并不陌生,在實(shí)際的開(kāi)發(fā)過(guò)程中,很多場(chǎng)景多會(huì)使用到異步,本文主要介紹了SpringBoot異步實(shí)現(xiàn)的8種方式,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • 使用IDEA如何把Java程序打包成jar

    使用IDEA如何把Java程序打包成jar

    這篇文章主要介紹了使用IDEA把Java程序打包成jar,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • Quarkus的Spring擴(kuò)展快速改造Spring項(xiàng)目

    Quarkus的Spring擴(kuò)展快速改造Spring項(xiàng)目

    這篇文章主要為大家介紹了Quarkus的Spring項(xiàng)目擴(kuò)展,帶大家快速改造Spring項(xiàng)目示例演繹,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • Java用BigDecimal類解決Double類型精度丟失的問(wèn)題

    Java用BigDecimal類解決Double類型精度丟失的問(wèn)題

    這篇文章主要介紹了Java用BigDecimal類解決Double類型精度丟失的問(wèn)題,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-12-12
  • Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼

    Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼

    有時(shí)我們希望將把數(shù)據(jù)保存在單個(gè)連續(xù)的數(shù)組中,以便快速、便捷地訪問(wèn)數(shù)據(jù),但這需要調(diào)整數(shù)組大小或者對(duì)其擴(kuò)展,下面這篇文章主要給大家介紹了關(guān)于Java自定義一個(gè)變長(zhǎng)數(shù)組的思路與代碼,需要的朋友可以參考下
    2022-12-12
  • java基礎(chǔ)之方法和方法的重載詳解

    java基礎(chǔ)之方法和方法的重載詳解

    這篇文章主要介紹了java基礎(chǔ)之方法和方法的重載詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • IDEA 2021.1 操作SVN 最新超詳細(xì)教程(圖文)

    IDEA 2021.1 操作SVN 最新超詳細(xì)教程(圖文)

    本教程將通過(guò)idea從svn服務(wù)器中的任意一個(gè)分支檢出代碼(本文采用branches),然后再idea中創(chuàng)建新的分支、提交代碼、拉取代碼、合并分支等操作進(jìn)行一一記錄,暫不包含代碼合并,對(duì)idea2021.1操作svn相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)下吧
    2021-05-05
  • Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析

    Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之插值查找解析,插值查找算法類似于二分查找,不同的就是插值查找每次從自適應(yīng)mid處開(kāi)始查找,需要的朋友可以參考下
    2023-12-12

最新評(píng)論