java poi设置生成的word的图片为上下型环绕以及其位置的实现|java|软件编程——建站教学网

问题描述

在使用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
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论