package com.artfess.file.util; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.poi.util.Units; import org.apache.poi.xwpf.usermodel.XWPFDocument; 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 com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.exception.RenderException; import com.deepoove.poi.policy.AbstractRenderPolicy; import com.deepoove.poi.render.RenderContext; /** * 签章图片套打插件 * * @company 阿特菲斯信息技术有限公司 * @author zhangxw * @email zhangxw@jee-soft.cn * @date 2020年12月16日 */ public class SignaturePictureRenderPolicy extends AbstractRenderPolicy { @Override protected boolean validate(PictureRenderData data) { return (null != data && (null != data.getData() || null != data.getPath())); } @Override public void doRender(RenderContext context) throws Exception { Helper.renderPicture(context.getRun(), context.getData()); } @Override protected void afterRender(RenderContext context) { clearPlaceholder(context, false); } @Override protected void reThrowException(RenderContext context, Exception e) { logger.info("Render picture " + context.getEleTemplate() + " error: {}", e.getMessage()); context.getRun().setText(context.getData().getAltMeta(), 0); } public static class Helper { public static final int EMU = 9525; public static void renderPicture(XWPFRun run, PictureRenderData picture) throws Exception { int suggestFileType = suggestFileType(picture.getPath()); try (InputStream ins = null == picture.getData() ? new FileInputStream(picture.getPath()) : new ByteArrayInputStream(picture.getData())) { run.addPicture(ins, suggestFileType, "Generated", picture.getWidth() * EMU, picture.getHeight() * EMU); //此处之外代码为源码PictureRenderPolicy类代码,此处做特殊处理,签章打印的图片需置于文字下方 String pictureText = run.getText(0); //解析签章套打占位符字段标示及下标 String regEx="[`{#}]"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(pictureText); pictureText = m.replaceAll("").trim(); String[] strArray = pictureText.split("_"); int idx = Integer.valueOf(strArray[1]); //签章图片与文档左侧的距离,由于同一签章字段可能有多个签章图片,所以leftWidth需根据签章图片下标改变,防止图片重叠 int leftWidth = 35; if(idx>0){ leftWidth += picture.getWidth()*idx; } CTDrawing drawing = run.getCTR().getDrawingArray(0); CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic(); //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性 CTAnchor anchor = getAnchorWithGraphic(graphicalobject, pictureText, Units.toEMU(picture.getWidth()), Units.toEMU(picture.getHeight()),//图片大小 Units.toEMU(leftWidth), Units.toEMU(-5), true);//相对当前段落位置 需要计算段落已有内容的左偏移 drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性 drawing.removeInline(0);//删除行内属性 } } public static int suggestFileType(String imgFile) { int format = 0; if (imgFile.endsWith(".emf")) format = XWPFDocument.PICTURE_TYPE_EMF; else if (imgFile.endsWith(".wmf")) format = XWPFDocument.PICTURE_TYPE_WMF; else if (imgFile.endsWith(".pict")) format = XWPFDocument.PICTURE_TYPE_PICT; else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")) format = XWPFDocument.PICTURE_TYPE_JPEG; else if (imgFile.endsWith(".png")) format = XWPFDocument.PICTURE_TYPE_PNG; else if (imgFile.endsWith(".dib")) format = XWPFDocument.PICTURE_TYPE_DIB; else if (imgFile.endsWith(".gif")) format = XWPFDocument.PICTURE_TYPE_GIF; else if (imgFile.endsWith(".tiff")) format = XWPFDocument.PICTURE_TYPE_TIFF; else if (imgFile.endsWith(".eps")) format = XWPFDocument.PICTURE_TYPE_EPS; else if (imgFile.endsWith(".bmp")) format = XWPFDocument.PICTURE_TYPE_BMP; else if (imgFile.endsWith(".wpg")) format = XWPFDocument.PICTURE_TYPE_WPG; else { throw new RenderException("Unsupported picture: " + imgFile + ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg"); } return format; } /** * @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, String deskFileName, int width, int height, int leftOffset, int topOffset, boolean behind) { String anchorXML = "" + "" + "" + "" + leftOffset + "" + "" + "" + "" + topOffset + "" + "" + "" + "" + "" + "" + ""; CTDrawing drawing = null; try { drawing = CTDrawing.Factory.parse(anchorXML); } catch (XmlException e) { e.printStackTrace(); } CTAnchor anchor = drawing.getAnchorArray(0); anchor.setGraphic(ctGraphicalObject); return anchor; } } }