需求描述
如下图,我需要在word里根据一个图片的名字,将名字替换成该图片(公章)
思路:
用POI遍历每一个表格里的每一行的每一个单元格,如果遇到我自己定义的"&章",则获取后面的图片的名字,然后利用POI的XWPFRun.addPicture(url,像素…)方法将图片添加到word里,然后将原有的文字清除掉。
注意:图片要放在表格的单元格里,最后单元格里的文本会被清除掉,只留下图片
简单生成图片和文字的代码:
注: 我的代码比较复杂,因为需求很复杂,如果你只需要简单生成下图片,可以参考这个
参考:https://stackoverflow.com/questions/26764889/how-to-insert-a-image-in-word-document-with-apache-poi
XWPFDocument doc = new XWPFDocument();
XWPFParagraph title = doc.createParagraph();
XWPFRun run = title.createRun();
run.setText("Fig.1 A Natural Scene");
run.setBold(true);
title.setAlignment(ParagraphAlignment.CENTER);
String imgFile = "encabezado.jpg"
FileInputStream is = new FileInputStream(imgFile);
run.addBreak();
run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(200), Units.toEMU(200)); // 200x200 pixels
is.close();
FileOutputStream fos = new FileOutputStream("test4.docx");
doc.write(fos);
fos.close();
详细代码(原创):
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
public class blog {
public static void main(String[] args) throws Exception {
//测试添加图片
String sourceFile="D:/测试模板.docx";
String targetFile="D:/test.docx";
addStampImage(sourceFile, targetFile);
}
public static void addStampImage(String sourceFile, String targetFile) {
XWPFDocument doc;
try {
doc = new XWPFDocument(new FileInputStream(sourceFile));
for(XWPFTable table : doc.getTables()) {
for(XWPFTableRow row : table.getRows()) {
for(XWPFTableCell cell : row.getTableCells()) {//遍历每一个单元格
if(cell.getText().contains("&章")) {//如果遇到"&章"则进行替换
try {
insertCellStamp(cell);//给带有要盖章字样的单元格 加上章的图片
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
FileOutputStream fos = new FileOutputStream(targetFile);
doc.write(fos);
fos.close();
doc.write(new FileOutputStream(targetFile));
} catch (Exception e) {
e.printStackTrace();
}
}
private static void insertCellStamp(XWPFTableCell cell) throws InvalidFormatException, IOException {//给带有要盖章字样的单元格 加上章的图片
List<String> stamps = new ArrayList<>();//存放要加入的图片
int stampOrder = 0;//图片的序号,从0开始
//获取需要的图片,
for(XWPFParagraph para :cell.getParagraphs()) {
String paraText = para.getText();//从段落中获取要盖的章的名称
// System.out.println("para.getText():" + paraText);
if(paraText != null) {
String[] split = para.getText().split(" ");
for(String s : split) {
s = s.trim();
if(!s.isEmpty() ) {
stamps.add(s.replace("&章", ""));//如:&章公章01.png,去掉标识符&章,只留下章的名字
}
}
}
}
String basedir = "E:";
for(XWPFParagraph para :cell.getParagraphs()) {
for (XWPFRun run : para.getRuns()) {
run.setText("", 0);//清空所有文字
}
// for (int i =para.getRuns().size()-1 ; i>=0; i--) {
// XWPFRun run = para.getRuns().get(i);
// System.out.println("清空所有文字后:run.getText(0): " + run.getText(0));
// }
//插入图片
for(int i = 0; i<stamps.size() && i<para.getRuns().size(); i++) {
try {
XWPFRun run = para.getRuns().get(i);
String imgFile = basedir + "/公章管理/" + stamps.get(stampOrder++);
System.out.println("插入盖章图片:" + imgFile);
FileInputStream is = new FileInputStream(imgFile);
run.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, imgFile, Units.toEMU(100), Units.toEMU(100)); // 100x100 pixels
is.close();
run.setText(" ",0);
} catch (Exception e) {
System.out.println("Error: ======== 插入单个公章图片时出错了:可能是图片路径不存在。不影响主流程");
e.printStackTrace();
}
}
}
}
}
最后样子:涉及保密就加了马赛克~
备注:有位朋友说他运行到doc = new XWPFDocument(new FileInputStream(sourceFile));这行时就直接报错:No valid entries or contents found, this is not a valid OOXML (Office Open XML) file报这个错,我和他一起尝试找了下原因,最后也是没找到原因不了了之了。
这段代码已经上线使用了,我这边需求比较复杂,坑也很多,所以建议大家如果需求简单的话就直接参考stackoverflow的代码。