使用openxml sdk将图像添加到excel中

我试图添加一个图像到excel文档,该文档是在生成电子表格之后使用openxml生成的(因为closedxml当前无法插入图像)。

我可以正确生成excel文件,但打开罚款,但是当我尝试插入图像,并尝试在Excel中打开它会给出一个错误。

我使用了一个小的控制台应用程序,发现错误是

Error 1 Description: The element has unexpected child element 'http://schemas.openxmlfor mats.org/spreadsheetml/2006/main:drawing'. Path: /x:worksheet[1] Part: /xl/worksheets/sheet.xml ------------------------------------------- 

电子表格如下所示:

 <?xml version="1.0" encoding="utf-8"?> <x:worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:sheetPr> <x:outlinePr summaryBelow="1" summaryRight="1" /> </x:sheetPr> <x:dimension ref="A1:M4" /> <x:sheetViews> <x:sheetView tabSelected="0" workbookViewId="0" /> </x:sheetViews> <x:sheetFormatPr defaultRowHeight="15" /> <x:cols> ... </x:cols> <x:sheetData> ... </x:sheetData> <x:printOptions horizontalCentered="0" verticalCentered="0" headings="0" gridLines="0" /> <x:pageMargins left="0.75" right="0.75" top="0.75" bottom="0.5" header="0.5" footer="0.75" /> <x:pageSetup paperSize="1" scale="100" pageOrder="downThenOver" orientation="default" blackAndWhite="0" draft="0" cellComments="none" errors="displayed" /> <x:headerFooter /> <x:tableParts count="0" /> <x:drawing r:id="R701e4d0efd7143ee" /> </x:worksheet> 

采取的

 

部分似乎允许文件正确validation。

我也尝试手动创build一个空白的Excel文档,并添加一个图像,它看起来非常相似:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"> <dimension ref="A1"/> <sheetViews> <sheetView tabSelected="1" workbookViewId="0"> <selection activeCell="D14" sqref="D14"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/> <sheetData/> <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/> <drawing r:id="rId1"/> </worksheet> 

我注意到的一件事是他们没有像生成的名字空间(x)那样做,但我不知道是否导致问题或不。

任何人都可以看到我失踪?

我用来插入图像的代码如下:

 public static void InsertImage(this Worksheet ws, long x, long y, long? width, long? height, string sImagePath) { try { var wsp = ws.WorksheetPart; var dp = default(DrawingsPart); var imgp = default(ImagePart); var wsd = default(WorksheetDrawing); var ipt = default(ImagePartType); switch (sImagePath.Substring(sImagePath.LastIndexOf('.') + 1).ToLower()) { case "png": ipt = ImagePartType.Png; break; // TODO: might not be correct. Was : Exit Select break; case "jpg": case "jpeg": ipt = ImagePartType.Jpeg; break; // TODO: might not be correct. Was : Exit Select break; case "gif": ipt = ImagePartType.Gif; break; // TODO: might not be correct. Was : Exit Select break; default: return; } if (wsp.DrawingsPart == null) { //----- no drawing part exists, add a new one dp = wsp.AddNewPart<DrawingsPart>(); imgp = dp.AddImagePart(ipt, wsp.GetIdOfPart(dp)); wsd = new WorksheetDrawing(); } else { //----- use existing drawing part dp = wsp.DrawingsPart; imgp = dp.AddImagePart(ipt); dp.CreateRelationshipToPart(imgp); wsd = dp.WorksheetDrawing; } using (var fs = new FileStream(sImagePath, FileMode.Open)) { imgp.FeedData(fs); } var imageNumber = 1; if (imageNumber == 1) { var drawing = new Drawing(); drawing.Id = dp.GetIdOfPart(imgp); ws.Append(drawing); } var nvdp = new NonVisualDrawingProperties(); nvdp.Id = new UInt32Value(Convert.ToUInt32(1024 + imageNumber)); nvdp.Name = "Picture " + imageNumber.ToString(); nvdp.Description = "Picture"; var picLocks = new PictureLocks(); picLocks.NoChangeAspect = true; picLocks.NoChangeArrowheads = true; var nvpdp = new NonVisualPictureDrawingProperties(); nvpdp.PictureLocks = picLocks; var nvpp = new NonVisualPictureProperties(); nvpp.NonVisualDrawingProperties = nvdp; nvpp.NonVisualPictureDrawingProperties = nvpdp; var stretch = new Stretch(); stretch.FillRectangle = new FillRectangle(); var blipFill = new BlipFill(); var blip = new Blip(); blip.Embed = dp.GetIdOfPart(imgp); blip.CompressionState = BlipCompressionValues.Print; blipFill.Blip = blip; blipFill.SourceRectangle = new SourceRectangle(); blipFill.Append(stretch); var t2d = new Transform2D(); var offset = new Offset(); offset.X = 0; offset.Y = 0; t2d.Offset = offset; var bm = new Bitmap(sImagePath); var extents = new Extents(); if (width == null) { extents.Cx = Convert.ToInt64(bm.Width)* Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.HorizontalResolution)); } else { extents.Cx = width; } if (height == null) { extents.Cy = Convert.ToInt64(bm.Height)* Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.VerticalResolution)); } else { extents.Cy = height; } bm.Dispose(); t2d.Extents = extents; var sp = new ShapeProperties(); sp.BlackWhiteMode = BlackWhiteModeValues.Auto; sp.Transform2D = t2d; var prstGeom = new PresetGeometry(); prstGeom.Preset = ShapeTypeValues.Rectangle; prstGeom.AdjustValueList = new AdjustValueList(); sp.Append(prstGeom); sp.Append(new NoFill()); var picture = new Picture(); picture.NonVisualPictureProperties = nvpp; picture.BlipFill = blipFill; picture.ShapeProperties = sp; var pos = new Position(); pos.X = x; pos.Y = y; var ext = new Extent(); ext.Cx = extents.Cx; ext.Cy = extents.Cy; var anchor = new AbsoluteAnchor(); anchor.Position = pos; anchor.Extent = ext; anchor.Append(picture); anchor.Append(new ClientData()); wsd.Append(anchor); wsd.Save(dp); } catch (Exception ex) { // or do something more interesting if you want throw ex; } } public static void InsertImage(MemoryStream stream, long x, long y, string sImagePath) { using (var mySpreadsheet = SpreadsheetDocument.Open(stream, true)) { var workbookPart = mySpreadsheet.WorkbookPart; var sheets = mySpreadsheet.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>(); var relationshipId = sheets.First().Id.Value; var worksheetPart = (WorksheetPart) mySpreadsheet.WorkbookPart.GetPartById(relationshipId); var workSheet = worksheetPart.Worksheet; //Dim sheets As worksheetpart = mySpreadsheet.WorkbookPart.Workbook. // For each sheet, display the sheet information. long width = 9525*193; long height = 9525*80; InsertImage(workSheet, x, y, width, height, sImagePath); } } 

问题可能是您分配的imageNumber为1。

 var imageNumber = 1; 

你可能会发现这有助于:

 var imageNumber = dp.ImageParts.Count<ImagePart>(); 

而且,这段代码与我在博客文章中发布的内容看起来很相似。 没关系。 另外,您可能会发现SpreadsheetLight会有所帮助。 这是一个电子表格库像ClosedXml,它可以插入图像就好了。 免责声明:我写了SpreadsheetLight。

哈哈哈,当我看到它的时候,就把我打碎了。 我正在做同样的事情。

我使用封闭的XML生成电子表格,然后使用Vincent的代码插入图像。

不幸的是我有同样的问题,但它与imageNumber声明为1无关

不过,我find了一个解决方法:

插入图像后,只需使用closures的xml重新打开文档并再次保存即可。

我只是用这个

 workbook = new XLWorkbook(filepath); workbook.save(); 

之后它应该打开没有问题。

希望这可以帮助其他有类似问题的人

编辑:

我可以通过改变这个细分来完全解决这个问题:

 var imageNumber = dp.ImageParts.Count<ImagePart>(); if (imageNumber == 1) { var drawing = new Drawing(); drawing.Id = dp.GetIdOfPart(imgp); ws.Append(drawing); } 

改变ws.Append(drawing);

 ws.InsertBefore(drawing, ws.Last) 

那么它会把它放在最后一个孩子之前,对我来说是<x:tableParts count="0"/>

把它之后,似乎是什么原因造成的问题

我有一个类似的问题。 当我在OpenXML生产力工具中比较了ClosedXML创build的文档和我在Excel中放置图像的文档之后,发现ClosedXML插入了一些元素节点,虽然它们不是无效的,但似乎使得绘图元素无效。 我删除了这些元素,电子表格中的图像可以在Excel中打开。 这是一个疯狂的 ,但它正在工作。 此代码位于InsertImage方法的顶部:

  //Remove superfluous worksheet elements. These break the inlcusion of the logo image. var element = ws.FirstChild; do { if(element.LocalName == null) continue; switch (element.LocalName) { case "pageSetup": case "headerFooter": case "tableParts": var prevElement = element; element = element.NextSibling(); ws.RemoveChild<OpenXmlElement>(prevElement); break; default: element = element.NextSibling(); break; } } while(element != null); // End of element removal 

HTH

安格斯

OpenXml并不是最简单的东西。

他们没有告诉你的一点是,元素的顺序通常很重要。 如上所述,索引号不是原因,您需要重新sorting您的xml标签,以便tableParts元素出现在drawing元素之前。

另外,因为你没有TableParts,你可以完全删除元素

所以从你的例子

 <?xml version="1.0" encoding="utf-8"?> <x:worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <x:sheetPr> <x:outlinePr summaryBelow="1" summaryRight="1" /> </x:sheetPr> <x:dimension ref="A1:M4" /> <x:sheetViews> <x:sheetView tabSelected="0" workbookViewId="0" /> </x:sheetViews> <x:sheetFormatPr defaultRowHeight="15" /> <x:cols> ... </x:cols> <x:sheetData> ... </x:sheetData> <x:printOptions horizontalCentered="0" verticalCentered="0" headings="0" gridLines="0" /> <x:pageMargins left="0.75" right="0.75" top="0.75" bottom="0.5" header="0.5" footer="0.75" /> <x:pageSetup paperSize="1" scale="100" pageOrder="downThenOver" orientation="default" blackAndWhite="0" draft="0" cellComments="none" errors="displayed" /> <x:headerFooter /> <x:drawing r:id="R701e4d0efd7143ee" /> <x:tableParts count="0" /> </x:worksheet> 

如果你正在写一个新的Excel文件,下面的代码是好的:

 if( dp.ImageParts.Count<ImagePart>() == 1 ) { var drawing = new Drawing(); drawing.Id = dp.GetIdOfPart(imgp); ws.Append(drawing); } 

如果您正在写入一个现有的可能已经有绘图部分的文件(但没有图像…这些graphics似乎是绘图部分的一部分),那么这将导致您的文档无法validation,甚至无法完全打开。

我通过执行以下操作来解决此问题:

 if (dp.ImageParts.Count<ImagePart>() == 1) { Drawing drawing = workSheet.GetFirstChild<Drawing>(); if (drawing == null) { drawing = new Drawing(); drawing.Id = dp.GetIdOfPart(imgp); workSheet.InsertAfter(drawing, workSheet.LastChild); } } 

似乎每个工作表只有一个绘图部分…花了我一段时间来追查问题,因为它不是很明显不幸。