问题描述
在使用poi-tl word模版工具时,发现生成的文档中,图片格式为嵌入型,有的图片甚至被表格遮挡一半。而自己想要的图片格式为上下型环绕,并且图片需要居中。
问题分析
poi-tl渲染图片,使用的是org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,该方法中有一段代码:_CTInline inline = drawing.addNewInline();_意思就是默认将图片转为inline类型,即行内元素。
然后我们把生成的嵌入型图片的文档转换成xml文件,然后再新建一个文档,插入图片后,设置图片为上下型环绕,保存为另一个xml,比较下两个xml的区别。嵌入型图片的xml是:
上下型环绕的图片的xml是
我们看到两种格式的图片标签分别为inline和anchor。所以如果我们想把图片设置为上下型环绕,需要重写poi的addPicture方法,把图片转为anchor类型。
我们仿照org.apache.poi.xwpf.usermodel.XWPFRun的addPicture方法,将_CTInline inline = drawing.addNewInline();_换成 _CTAnchor anchor = drawing.addNewAnchor();_,然后对比着xml,依次对anchor的字段进行赋值。结果发现生成的word无法正常打开,查了很多资料,都说poi的CTAnchor有问题,使用后无法正常打开生成的word。
此路不通,那我们就尝试另一种思路,我们不通过CTAnchor来生成anchor标签,而是直接使用xml,将xml赋给poi的drawing。具体的处理方式在后面。
xml标签和图片格式解析
在word中,在图片上右键,选择大小和位置,就可以看到如下界面:
图中的上下型对应的是xml中的<wp:wrapTopAndBottom/>标签,不同环绕方式该标签值不一样。如果需要其他格式,可以设置好后,把文档保存为xml,找到对应的标签。
图中的距正文上下左右距离,对应的是<wp:anchor distT="71755" distB="71755" distL="114300" distR="114300" ...>中的disT、disB、disL、disR属性。
图中位置一栏,水平对齐方式居中、相对于栏对应的是xml中的<wp:positionH relativeFrom="column"><wp:align>center</wp:align></wp:positionH>。
垂直-绝对位置0.1cm,下侧段落对应的是xml中的<wp:positionV relativeFrom="paragraph"><wp:posOffset>36195</wp:posOffset></wp:positionV>。
我们可以根据不同的需要来设置不同的xml。
我使用的xml是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
String xml = "<
`wp:anchor
allowOverlap="0" layoutInCell="1" locked="0" behindDoc="0" relativeHeight="0"`
simplePos=\"0\" distR=\"0\" distL=\"0\" distB=\"0\" distT=\"0\" " +
" xmlns:wp=\"[http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing](http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing)\"" +
" xmlns:wp14=\"[http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing](http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing)\"" +
" xmlns:r=\"[http://schemas.openxmlformats.org/officeDocument/2006/relationships](http://schemas.openxmlformats.org/officeDocument/2006/relationships)\" >" +
"<
`wp:simplePos
y="0" x="0"/>" +`
"<
`wp:positionH
relativeFrom="column">" +`
"<
`wp:align>center</
wp:align`>" +
"</
`wp:positionH`>" +
"<
`wp:positionV
relativeFrom="paragraph">" +`
"<
`wp:posOffset>0</
wp:posOffset`>" +
"</
`wp:positionV`>" +
"<
`wp:extent
cy=""+height+"" cx=""+width+""/>" +`
"<
`wp:effectExtent
b="0" r="0" t="0" l="0"/>" +`
"<
`wp:wrapTopAndBottom`/>" +
"<
`wp:docPr
descr="Picture Alt" name="Picture Hit" id="0"/>" +`
"<
`wp:cNvGraphicFramePr`>" +
"<
`a:graphicFrameLocks
noChangeAspect="true" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />" +`
"</
`wp:cNvGraphicFramePr`>" +
"<
`a:graphic
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">" +`
"<
`a:graphicData
uri="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">" +`
"<
`pic:pic
xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">" +`
"<
`pic:nvPicPr`>" +
"<
`pic:cNvPr
name="Picture Hit" id="1"/>" +`
"<
`pic:cNvPicPr`/>" +
"</
`pic:nvPicPr`>" +
"<
`pic:blipFill`>" +
"<
`a:blip
r:embed=""+relationId+""/>" +`
"<
`a:stretch`>" +
"<
`a:fillRect`/>" +
"</
`a:stretch`>" +
"</
`pic:blipFill`>" +
"<
`pic:spPr`>" +
"<
`a:xfrm`>" +
"<
`a:off
y="0" x="0"/>" +`
"<
`a:ext
cy=""+height+"" cx=""+width+""/>" +`
"</
`a:xfrm`>" +
"<
`a:prstGeom
prst="rect">" +`
"<
`a:avLst`/>" +
"</
`a:prstGeom`>" +
"</
`pic:spPr`>" +
"</
`pic:pic`>" +
"</
`a:graphicData`>" +
"</
`a:graphic`>" +
"<
`wp14:sizeRelH
relativeFrom="margin">" +`
"<
`wp14:pctWidth>0</
wp14:pctWidth`>" +
"</
`wp14:sizeRelH`>" +
"<
`wp14:sizeRelV
relativeFrom="margin">" +`
"<
`wp14:pctHeight>0</
wp14:pctHeight`>" +
"</
`wp14:sizeRelV`>" +
"</
`wp:anchor`>";
其中width和height是图片的宽度和高度,relationId是图片的id。
解决方案
1,首先定义一个poi-tl的图片渲染器,使得其不再调用poi默认的图片渲染器,而是使用我们自己定义的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
public
class
MyPictureRenderPolicy
extends
AbstractRenderPolicy<PictureRenderData> {
@Override
protected
boolean
validate(PictureRenderData data) {
return
(
`null
!= data.getData() ||
null
!= data.getPath());`
}
@Override
public
void
doRender(RunTemplate runTemplate, PictureRenderData picture, XWPFTemplate template)
throws
Exception {
XWPFRun run = runTemplate.getRun();
MyPictureRenderPolicy.Helper.renderPicture(run, picture);
}
@Override
protected
void
afterRender(RenderContext context) {
clearPlaceholder(context,
false
`);`
}
@Override
protected
void
doRenderException(RunTemplate runTemplate, PictureRenderData data, Exception e) {
logger.info(
`"Render picture "
+ runTemplate +
" error: {}"`, e.getMessage());
runTemplate.getRun().setText(data.getAltMeta(),
0
`);`
}
public
static
class
Helper {
public
static
void
renderPicture(XWPFRun run, PictureRenderData picture)
throws
Exception {
int
suggestFileType = suggestFileType(picture.getPath());
InputStream ins =
null
== picture.getData() ?
new
FileInputStream(picture.getPath())
:
new
ByteArrayInputStream(picture.getData());
String relationId = run.getDocument().addPictureData(ins, suggestFileType);
long
width = Units.toEMU(picture.getWidth());
long
height = Units.toEMU(picture.getHeight());
CTDrawing drawing = run.getCTR().addNewDrawing();
String xml =
"<wp:anchor allowOverlap=\"0\" layoutInCell=\"1\" locked=\"0\" behindDoc=\"0\" relativeHeight=\"0\" simplePos=\"0\" distR=\"0\" distL=\"0\" distB=\"0\" distT=\"0\" "
+
" xmlns:wp=\"[http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing](http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing)\""
+
" xmlns:wp14=\"[http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing](http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing)\""
+
" xmlns:r=\"[http://schemas.openxmlformats.org/officeDocument/2006/relationships](http://schemas.openxmlformats.org/officeDocument/2006/relationships)\" >"
+
"<wp:simplePos y=\"0\" x=\"0\"/>"
+
"<wp:positionH relativeFrom=\"column\">"
+
"<wp:align>center</wp:align>"
+
"</wp:positionH>"
+
"<wp:positionV relativeFrom=\"paragraph\">"
+
"<wp:posOffset>0</wp:posOffset>"
+
"</wp:positionV>"
+
"<wp:extent cy=\""
`+height+"\" cx=\""
+width+`"\"/>"
+
"<wp:effectExtent b=\"0\" r=\"0\" t=\"0\" l=\"0\"/>"
+
"<wp:wrapTopAndBottom/>"
+
"<wp:docPr descr=\"Picture Alt\" name=\"Picture Hit\" id=\"0\"/>"
+
"<wp:cNvGraphicFramePr>"
+
"<a:graphicFrameLocks noChangeAspect=\"true\" xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\" />"
+
"</wp:cNvGraphicFramePr>"
+
"<a:graphic xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\">"
+
"<a:graphicData uri=\"[http://schemas.openxmlformats.org/drawingml/2006/picture](http://schemas.openxmlformats.org/drawingml/2006/picture)\" xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\">"
+
"<pic:pic xmlns:pic=\"[http://schemas.openxmlformats.org/drawingml/2006/picture](http://schemas.openxmlformats.org/drawingml/2006/picture)\">"
+
"<pic:nvPicPr>"
+
"<pic:cNvPr name=\"Picture Hit\" id=\"1\"/>"
+
"<pic:cNvPicPr/>"
+
"</pic:nvPicPr>"
+
"<pic:blipFill>"
+
"<a:blip r:embed=\""
`+relationId+`"\"/>"
+
"<a:stretch>"
+
"<a:fillRect/>"
+
"</a:stretch>"
+
"</pic:blipFill>"
+
"<pic:spPr>"
+
"<a:xfrm>"
+
"<a:off y=\"0\" x=\"0\"/>"
+
"<a:ext cy=\""
`+height+"\" cx=\""
+width+`"\"/>"
+
"</a:xfrm>"
+
"<a:prstGeom prst=\"rect\">"
+
"<a:avLst/>"
+
"</a:prstGeom>"
+
"</pic:spPr>"
+
"</pic:pic>"
+
"</a:graphicData>"
+
"</a:graphic>"
+
"<wp14:sizeRelH relativeFrom=\"margin\">"
+
"<wp14:pctWidth>0</wp14:pctWidth>"
+
"</wp14:sizeRelH>"
+
"<wp14:sizeRelV relativeFrom=\"margin\">"
+
"<wp14:pctHeight>0</wp14:pctHeight>"
+
"</wp14:sizeRelV>"
+
"</wp:anchor>"
`;`
drawing.set(XmlToken.Factory.parse(xml, DEFAULT_XML_OPTIONS));
CTPicture pic = getCTPictures(drawing).get(
`0`);
XWPFPicture xwpfPicture =
new
XWPFPicture(pic, run);
run.getEmbeddedPictures().add(xwpfPicture);
}
public
static
List<CTPicture> getCTPictures(XmlObject o) {
List<CTPicture> pictures =
new
ArrayList<>();
XmlObject[] picts = o.selectPath(
`"declare namespace pic='"`
+ CTPicture.type.getName().getNamespaceURI() +
"' .//pic:pic"
`);`
for
(XmlObject pict : picts) {
if
(pict
instanceof
XmlAnyTypeImpl) {
// Pesky XmlBeans bug - see Bugzilla #49934
try
{
pict = CTPicture.Factory.parse(pict.toString(),
DEFAULT_XML_OPTIONS);
}
catch
(XmlException e) {
throw
new
POIXMLException(e);
}
}
if
(pict
instanceof
CTPicture) {
pictures.add((CTPicture) pict);
}
}
return
pictures;
}
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;
}
}
}
然后在渲染模板的时候,配置我们自己定义的图片渲染器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public
static
void
main(String[] args)
throws
Exception{
String path =
"1.docx"
`;`
InputStream templateFile = Demo.
`class`.getClassLoader().getResourceAsStream(path);
Map map =
new
HashMap();
map.put(
`"pic",` `new` `PictureRenderData(
120,` `80
,
".png", Demo.
class.getClassLoader().getResourceAsStream(
"1.png"`)));
// 将数据整合到模板中去
Configure.ConfigureBuilder builder = Configure.newBuilder();
builder.supportGrammerRegexForAll();
builder.addPlugin(
`'@'`,
new
MyPictureRenderPolicy());
XWPFTemplate template = XWPFTemplate.compile(templateFile, builder.build()).render(map);
String docPath =
"C:\\Users\\csdc01\\Desktop\\out.docx"
`;`
FileOutputStream outputStream1 =
new
FileOutputStream(docPath);
template.write(outputStream1);
outputStream1.flush();
outputStream1.close();
}
源码:https://github.com/ksyzz/poi-tl-demo.git
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
原网址: 访问
创建于: 2023-06-05 09:47:50
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论