NPOI 是 POI 项目的 .NET 版本。POI是一个开源的Java读写Excel、WORD等微软OLE2组件文档的项目我们需要实现的目标就是读模板->写入数据->生成word。
但是有个很普遍的问题,使用NPOI在Word中插入图片的时候出现了无法打开文件,因为内容有错误或者就是打开后不显示图片。
这个问题是由于NPOI官方的一个BUG,NPOI未将图片的XML段正确地插入到XML文档中,也就是说NPOI给word这插入图片的时候插入的XML是完整的,错误的所以导致导出的word无法打开
我们也可以自己分析一下要导出的xml,插入图片后,到底添加了什么呢?
XML文档
<?xml version="1.0" encoding="utf-8"?> <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"> <w:body> <w:p w:rsidR="009F1D27" w:rsidRDefault="00892110" w:rsidP="006D677D"> <w:pPr> <w:pStyle w:val="1"/> </w:pPr> <w:r> <w:rPr> <w:rFonts w:hint="eastAsia"/> </w:rPr> <w:t xml:space="preserve">测试</w:t> </w:r> </w:p> <w:p w:rsidR="006D677D" w:rsidRPr="006D677D" w:rsidRDefault="002A5658" w:rsidP="008C112B"> <w:pPr/> <w:r> <w:t xml:space="preserve"/> <w:drawing> <wp:inline distT="0" distB="0" distL="0" distR="0"> <wp:extent cx="4762500" cy="3810000"/> <wp:effectExtent l="0" t="0" r="0" b="0"/> <wp:docPr id="2" name="Picture 2.jpg" descr="Generated"/> <wp:cNvGraphicFramePr> <a:graphicFrameLocks noChangeAspect="1"/> </wp:cNvGraphicFramePr> <a:graphic> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"> <pic:nvPicPr> <pic:cNvPr id="2" name="Generated"/> <pic:cNvPicPr/> </pic:nvPicPr> <pic:blipFill> <a:blip r:embed="rId6"></a:blip> <a:stretch> <a:fillRect/> </a:stretch> </pic:blipFill> <pic:spPr> <a:xfrm> <a:off x="0" y="0"/> <a:ext cx="4762500" cy="3810000"/> </a:xfrm> <a:prstGeom prst="rect"> <a:avLst/> </a:prstGeom> </pic:spPr> </pic:pic> </a:graphicData> </a:graphic> </wp:inline> </w:drawing> </w:r> <w:bookmarkStart w:id="0" w:name="_GoBack"/> <w:bookmarkEnd w:id="0"/> </w:p> <w:sectPr w:rsidR="006D677D" w:rsidRPr="006D677D" w:rsidSect="009A6015"> <w:pgSz w:w="11906" w:h="16838"/> <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992"/> <w:cols w:space="425"/> <w:docGrid w:type="lines" w:linePitch="312"/> </w:sectPr> </w:body> </w:document>
既然之前有人提到了问题出在NPOI未将图片的XML段正确地插入到XML文档中,那我们是不是能给他补上是不是就能解决整个问题了?我用下面的代码来重新添加正确的XML
public class MyXWPFDocument : XWPFDocument // 重写[/size][size=3]XWPFDocument 类,添加[/size][size=3]AddPicture方法来添加图片[/size][size=3] { //public MyXWPFDocument(Stream stream) : base(stream) //{ //} public void AddPicture(XWPFRun r, String blipId, int id, int width, int height) { const int EMU = 9525; width *= EMU; height *= EMU; CT_Inline inline = r.GetCTR().AddNewDrawing().AddNewInline(); String picXml = "" + "<pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + "<pic:nvPicPr>" + "<pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" + "<pic:cNvPicPr/>" + "</pic:nvPicPr>" + "<pic:blipFill>" + "<a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" + "<a:stretch>" + "<a:fillRect/>" + "</a:stretch>" + "</pic:blipFill>" + "<pic:spPr>" + "<a:xfrm>" + "<a:off x=\"0\" y=\"0\"/>" + "<a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" + "</a:xfrm>" + "<a:prstGeom prst=\"rect\">" + "<a:avLst/>" + "</a:prstGeom>" + "</pic:spPr>" + "</pic:pic>"; inline.graphic = new NPOI.OpenXmlFormats.Dml.CT_GraphicalObject(); NPOI.OpenXmlFormats.Dml.CT_GraphicalObjectData graphicalObjectData = inline.graphic.AddNewGraphicData(); graphicalObjectData.uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"; graphicalObjectData.AddPicElement(picXml); NPOI.OpenXmlFormats.Dml.WordProcessing.CT_NonVisualDrawingProps docPr = inline.AddNewDocPr(); docPr.id = (uint)id; docPr.name = "Picture " + id + ".jpg"; docPr.descr = "Generated"; NPOI.OpenXmlFormats.Dml.WordProcessing.CT_PositiveSize2D extent = inline.AddNewExtent(); extent.cx = width; extent.cy = height; inline.cNvGraphicFramePr = new NPOI.OpenXmlFormats.Dml.WordProcessing.CT_NonVisualGraphicFrameProperties(); inline.cNvGraphicFramePr.graphicFrameLocks = new NPOI.OpenXmlFormats.Dml.CT_GraphicalObjectFrameLocking(); inline.cNvGraphicFramePr.graphicFrameLocks.noChangeAspect = true; inline.effectExtent = new CT_EffectExtent(); inline.effectExtent.l = 0; inline.effectExtent.t = 0; inline.effectExtent.r = 0; inline.effectExtent.b = 0; inline.distB = 0; inline.distL = 0; inline.distR = 0; inline.distT = 0; } }
代码中的picXml 是我们手动添加的图片部分,同样可以举一反三,添加自己需要的组件类型。在应用场景中,我们使用如下方法调用:
using (FileStream fs = File.OpenRead(picAbsolutePath))//[/ size][size = 3] { byte[] bytes = new byte[fs.Length]; fs.Read(bytes, 0, (int)fs.Length); String picId = doc.AddPictureData(bytes, (int)PictureType.JPEG); // 将图片添加到段落中 XWPFParagraph p = Cell.AddParagraph(); XWPFRun run = p.CreateRun(); run.SetText(time); doc.AddPicture(run, picId, doc.GetNextPicNameNumber((int)PictureType.JPEG), 250, 200); // 用图片替换掉Run中的内容[/size][size=3] }
还没有评论,来说两句吧...