admin 管理员组

文章数量: 887016

文章目录

    • 准备工作
    • 简单读取
    • 复杂读取
    • 查看Word的XML
    • 特别说明:Word中的Svg图片
    • 第一种写入图片到Word中的方式
    • 第二种写入图片到Word中的方式
    • 最后

准备工作

这里就不在复述了,可以看上一篇博文 java使用poi读写word中的内容(包含表格内容)(一)

代码中MyUnits工具类在我另一篇博文中 word中各种长度转换为px(工具类)

简单读取

如果后期还有回写到word中不建议使用这种方式读取。

	@Test
	public void test() throws FileNotFoundException, IOException {
		XWPFDocument document = new XWPFDocument(new FileInputStream("D:\\Test\\word\\test1.docx"));
		try {
			List<XWPFParagraph> paragraphs = document.getParagraphs();
			for (XWPFParagraph paragraph : paragraphs) {
				List<XWPFRun> runs = paragraph.getRuns();
				for (XWPFRun run : runs) {
					List<XWPFPicture> pictures = run.getEmbeddedPictures();
					// 我这里是偷懒,请使用循环
					XWPFPicture picture = pictures.get(0);
					XWPFPictureData pictureData = picture.getPictureData();
					
					System.out.println(pictureData.getPictureType());
					System.out.println(pictureData.getFileName());
					System.out.println(pictureData.getData());
				}
			}
		} finally {
			document.close();
		}
	}

上面代码中,可以直接取出word中的图片,但是无法取出图片在word中的大小此处要注意,word中图片的大小可能与图片的大小不一致操作word你就知道,图片放入word中后是可以放大或缩小的

复杂读取

	@Test
	public void test1() throws FileNotFoundException, IOException {
		XWPFDocument document = new XWPFDocument(new FileInputStream("D:\\Test\\word\\test1.docx"));
		try {
			List<XWPFParagraph> paragraphs = document.getParagraphs();
			for (XWPFParagraph paragraph : paragraphs) {
				List<XWPFRun> runs = paragraph.getRuns();
				for (XWPFRun run : runs) {
					Node node = run.getCTR().getDomNode();
					// drawing 一个绘画的图片
					Node drawingNode = getChildNode(node, "w:drawing");
					if (drawingNode == null) {
						continue;
					}
					// 绘画图片的宽和高
					Node extentNode = getChildNode(drawingNode, "wp:extent");
					NamedNodeMap extentAttrs = extentNode.getAttributes();
					System.out.println("宽:".concat(extentAttrs.getNamedItem("cx").getNodeValue()).concat("emu"));
					System.out.println("高:".concat(extentAttrs.getNamedItem("cy").getNodeValue()).concat("emu"));
					
					// 绘画图片具体引用
					Node blipNode = getChildNode(drawingNode, "a:blip");
					NamedNodeMap blipAttrs = blipNode.getAttributes();
					String rid = blipAttrs.getNamedItem("r:embed").getNodeValue();
					System.out.println("word中图片ID:".concat(rid));
					
					// 获取图片信息
					PackagePart part = document.getPartById(rid);
					System.out.println(part.getContentType());
					System.out.println(part.getPartName().getName());
					System.out.println(part.getInputStream());
					System.out.println("------ run ------");
				}
				System.out.println("------ paragraph ------");
			}
		} finally {
			document.close();
		}
	}

	private Node getChildNode(Node node, String nodeName) {
		if (!node.hasChildNodes()) {
			return null;
		}
		NodeList childNodes = node.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++) {
			Node childNode = childNodes.item(i);
			if (nodeName.equals(childNode.getNodeName())) {
				return childNode;
			}
			childNode = getChildNode(childNode, nodeName);
			if (childNode != null) {
				return childNode;
			}
		}
		return null;
	}

上面代码中既可以读取到图片在word中的宽高,也可以读取到图片的信息
注意宽和高的单位为emu
emupx的工具类我已经共享出来了,word中各种长度转换为px(工具类)

查看Word的XML

w:drawingwp:extenta:blip等等,这些我是怎么知道的呢?
当然是直接在word里面看见的了,下面教大家如何看word的xml

首先要安装压缩工具(我用的是360压缩)

选择用360压缩打开

打开后双击word文件夹

document.xml拉倒桌面,然后将文件里的xml格式化一下就可以看到了,如图

特别说明:Word中的Svg图片

这里特别说明一下,如果将svg(手动操作Word并非程序操作)图片插入word中的话,Word会生成一张png图片。Word中显示的也是png图片。这里我们看下xml
仔细看,这段xml中有两处r:embed

第一处r:embed="rId6"引用的是png图片

第二处r:embed="rId7"引用的才是你插入的svg图片

<w:drawing>
    <wp:inline distT="0" distB="0" distL="0" distR="0" wp14:anchorId="43206650" wp14:editId="4D01F649">
        <wp:extent cx="352425" cy="200025"/>
        <wp:effectExtent l="0" t="0" r="9525" b="9525"/>
        <wp:docPr id="1" name="图形 1"/>
        <wp:cNvGraphicFramePr>
            <a:graphicFrameLocks
                xmlns:a="http://schemas.openxmlformats/drawingml/2006/main" noChangeAspect="1"/>
            </wp:cNvGraphicFramePr>
            <a:graphic
                xmlns:a="http://schemas.openxmlformats/drawingml/2006/main">
                <a:graphicData uri="http://schemas.openxmlformats/drawingml/2006/picture">
                    <pic:pic
                        xmlns:pic="http://schemas.openxmlformats/drawingml/2006/picture">
                        <pic:nvPicPr>
                            <pic:cNvPr id="1" name=""/>
                            <pic:cNvPicPr/>
                        </pic:nvPicPr>
                        <pic:blipFill>
                            <a:blip r:embed="rId6">
                                <a:extLst>
                                    <a:ext uri="{96DAC541-7B7A-43D3-8B79-37D633B846F1}">
                                        <asvg:svgBlip
                                            xmlns:asvg="http://schemas.microsoft/office/drawing/2016/SVG/main" r:embed="rId7"/>
                                        </a:ext>
                                    </a:extLst>
                                </a:blip>
                                <a:stretch>
                                    <a:fillRect/>
                                </a:stretch>
                            </pic:blipFill>
                            <pic:spPr>
                                <a:xfrm>
                                    <a:off x="0" y="0"/>
                                    <a:ext cx="352425" cy="200025"/>
                                </a:xfrm>
                                <a:prstGeom prst="rect">
                                    <a:avLst/>
                                </a:prstGeom>
                            </pic:spPr>
                        </pic:pic>
                    </a:graphicData>
                </a:graphic>
            </wp:inline>
        </w:drawing>

第一种写入图片到Word中的方式

注意:这种方式写入图片,宽高单位必须是emu

	@Test
	public void test2() throws IOException, InvalidFormatException {
		XWPFDocument document = new XWPFDocument();
		try {
			XWPFParagraph paragraph = document.createParagraph();
			XWPFRun run = paragraph.createRun();

			InputStream is = new FileInputStream("D:\\Test\\word\\aa.png");
			// 因为FileInputStream没有重写reset() 所有将流转为了byte数组
			byte[] bs = IOUtils.toByteArray(is);
			BufferedImage image = ImageIO.read(new ByteArrayInputStream(bs));

			
			int width = MyUnits.pxToEMU(image.getWidth());
			int height = MyUnits.pxToEMU(image.getHeight());

			run.addPicture(new ByteArrayInputStream(bs), Document.PICTURE_TYPE_PNG, "", width, height);

			OutputStream stream = new FileOutputStream("D:\\Test\\word\\w_test.docx");
			document.write(stream);
		} finally {
			document.close();
		}
	}

看看写入的效果

第二种写入图片到Word中的方式

相对第一种这种方式要复杂一点
注意:这种方式写入图片的宽高inmmcmptpx都可以使用,我这里用的是pt.

	@Test
	public void test3() throws IOException {
		XWPFDocument document = new XWPFDocument();
		try {
			XWPFParagraph paragraph = document.createParagraph();
			XWPFRun run = paragraph.createRun();

			// 获取图片
			InputStream is = new FileInputStream("D:\\Test\\word\\aa.png");
			byte[] bs = IOUtils.toByteArray(is);
			BufferedImage image = ImageIO.read(new ByteArrayInputStream(bs));

			// 获取组装图片宽高,单位pt
			StringBuffer dataSize = new StringBuffer();
			dataSize.append("width:").append(MyUnits.pxToPt(image.getWidth())).append("pt;");
			dataSize.append("height:").append(MyUnits.pxToPt(image.getHeight())).append("pt;");

			// 添加图片到Word中
			String rid = document.addPictureData(bs, Document.PICTURE_TYPE_PNG);

			StringBuffer xml = new StringBuffer();
			xml.append("<w:pict xmlns:w=\"http://schemas.openxmlformats/wordprocessingml/2006/main\"");
			xml.append(" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\"");
			xml.append(" xmlns:r=\"http://schemas.openxmlformats/officeDocument/2006/relationships\">\r\n");
			xml.append("	<v:shape id=\"图片1").append("\" o:spid=\"\" type=\"\" alt=\"\" style=\"").append(dataSize).append("\">\r\n");
			xml.append("		<v:imagedata r:id=\"").append(rid).append("\" o:title=\"\" />");
			xml.append("	</v:shape>\r\n");
			xml.append("</w:pict>");

			InputSource source = new InputSource(new StringReader(xml.toString()));
			org.w3c.dom.Document pictDoc = DocumentHelper.readDocument(source);
			// 将信息写入run中
			run.setEmbossed(true);
			XmlObject xmlObject = XmlObject.Factory.parse(pictDoc.getDocumentElement(), POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
			run.getCTR().set(xmlObject);
			
			OutputStream stream = new FileOutputStream("D:\\Test\\word\\w_test1.docx");
			document.write(stream);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			document.close();
		}
	}

看看写入效果

最后

如果有什么不明白的可以留言。
欢迎大家留言讨论。

本文标签: 图片 java poi Word