开发者

Java POI-TL设置Word图片浮于文字上方

开发者 https://www.devze.com 2025-03-15 14:56 出处:网络 作者: qunwuhui
目录需求描述poi-tl 原生的插入图片解决方式 自定义图片渲染插件1. 自定义MyPictureRenderPolicy2. 测试参考需求描述
目录
  • 需求描述
  • poi-tl 原生的插入图片
  • 解决方式 自定义图片渲染插件
    • 1. 自定义MyPictureRenderPolicy
    • 2. 测试
  • 参考

    需求描述

    word导出时插入图片,图片浮于文字上方而不是嵌入的方式

    poi-tl 原生的插入图片

    poi-tl渲染图片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,该方法中有一段代码:CTInline inline = drawing.addNewInline();意思就是默认将图片转为inline类型,即行内元素

    解决方式 自定义图片渲染插件

    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.utandroidil.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 extejsnds AbstractRenderPolicy<Object> {
    
        @Override
        protected boolean validate(Object data) {
            if (null == data) {
                return false;
            } else if (data instanceof PictureRenderData) {
                return null != ((PictureRenderData) data).getPictureSupplier();
            } else {
        js        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 设置浮动属性 删除inline属性
                            CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "Generated",
                                    Units.toEMU(width), Units.toEMU(height),//图片大小
                                    Units.toEMU(270), Units.toEMU(-70), false);//相对当前段落位置 需要计算段落已有内容的左偏移
    
                            drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
                            drawing.removeInline(0);//删除行内属性
                        } 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 图片数据
         * @param deskFileName      图片描述
         * @param width             宽
         * @param height            高
         * @param leftOffset        水平偏移 left
         * @param topOffset         垂直偏移 top
         * @param behind            文字上方,文字下方
         * @return
         * @throws Exception
         */
        public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                  cWuNgLzL                                  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:ef编程fectExtent 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. 测试

    该内容将图片自动添加到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;
    
    
    /**
     * 数据处理-word 文档尾部添加图片
     *
     * @author: 
     * @date:
     * @description:
     */
    public class PoiWordTest3 {
    
        public static void main(String[] args) throws IOException {
            //要写入模板的数据
            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)) {
                //最后一个段落
                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;  //上传临时文件
            FileOutputStream tempFileOutputStreamUpload = null; //上传临时文件输出流
            FileInputStream tempFileInputStreamUpload = null; //上传临时文件输入流
            //临时文件输出流
            tempFileUpload = File.createTempFile("wordTempUpload", ".docx");
            tempFileOutputStreamUpload = new FileOutputStream(tempFileUpload);
            doc.write(tempFileOutputStreamUpload);
            tempFileInputStreamUpload = new FileInputStream(tempFileUpload);
            /********************* 把插件注册为新标签类型 ***********************************/
            ConfigureBuilder builder = Configure.builder();
            builder.addPlugin('%',new MyPictureRenderPolicy());//把插件注册为新标签类型
            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设置word图片环绕方式为浮于在文字上方

    java poi设置生成的word的图片为上下型环绕以及其位置的实现

    以上就是Java POI-TL设置Word图片浮于文字上方的详细内容,更多关于Java POI-TL设置Word图片的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号