Epplus SetPosition图片问题

我正在使用Epplus库来生成Excel 2010和Asp.Net C#中的兼容文件。 我正在使用最新的3.1.2版本。

我先设置行高,然后再添加像这样的图片:

ExcelPackage pck = new ExcelPackage(); var ws = pck.Workbook.Worksheets.Add("sheet 1"); while (i < dt.Rows.Count + offset) { ws.Row(i).Height = 84; i++; } 

dt是DataTable的DataTable。 设置高度后,我再次循环行添加图片

 while (i < dt.Rows.Count + offset) { var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path)); prodImg.SetPosition(i - 1, 0, 14, 0); prodImg.SetSize(75); } 

这工作,但这不:

 var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path)); int w = prodImg.Image.Width; int h = prodImg.Image.Height; if (h > 140) // because height of 84 is 140 pixels in excel { double scale = h / 140.0; w = (int)Math.Floor(w / scale); h = 140; } int xOff = (150 - w) / 2; int yOff = (140 - h) / 2; prodImg.SetPosition(i - 1, xOff, 11, yOff); prodImg.SetSize(w, h); 

这会导致偏离中心的照片和未被复制的图像。 然后这个代码在同一个循环中:

 var prodImgDm = ws.Drawings.AddPicture("bcdm" + dr["code"].ToString(), new FileInfo(pathDm)); prodImgDm.SetPosition(i - 1, 25, 15, 40); prodImgDm.SetSize(100); 

这有时会起作用。 图片prodImgDm是具有静态宽度和高度的数据matrix图像,不需要resize,因为它们总是很小/很小。 所以也没有SetSize在一些行,它的工作原理和在其他一些行,它不起作用。 真的很奇怪,因为代码是一样的。 这可能是在图书馆和/或Excel中的东西。 也许我用错了? 任何epplus图片专家?

提前致谢!!

编辑有时候一张图片胜过千言万语,所以这里是截图。 如您所见,产品图像在单元格中不是水平和垂直alignment的。 而最右边的数据matrix有时也会缩放大约120%,即使我设置了SetSize(100)所以对我来说真的很奇怪。 所以最后一个datamatrix有正确的大小…我已经find了这个线程,但是这并不帮助我,我想。

epplus图像

编辑 2013/04/09埃森皮莱给了我一个提示设置

 pck.DoAdjustDrawings = false; 

但是这给了我更奇怪的图像:

doadjustdrawings

数据matrix仍然在行的基础上改变。 在行是好的,另一个不是。 而且ean13代码太宽了。

我与Epplus库有相同的问题。
我找不到解决办法,如何解决这个在我的代码中,我检查了这个库的源代码 。 Epplus创buildexcel图片总是作为twoCellAnchor绘图。 在xlsx文件中,您可以使用以下代码finddrawingXYZ.xml

 <xdr:twoCellAnchor editAs="oneCell"> <xdr:from> ... </xdr:from> <xdr:to> ... </xdr:to> <xdr:pic> ... </xdr:twoCellAnchor> 

所以,图片总是连接到两个单元格,而这不是Epplus库的可变部分。 你可以在ExcelDrawing.cs文件中find这部分代码。

  XmlElement drawNode = _drawingsXml.CreateElement( "xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings); colNode.AppendChild(drawNode); 

你可以很容易地创build自己的这个DLL的副本。 好消息是,你只需要修改两个文件来解决这个问题。 所以..

从本网站下载Epplus库的源代码副本,并在Visual Studio中打开。

我们需要生成drawing代码为oneCellAnchor ,所以我们必须移除图片的<xdr:to>元素,并创build图片尺寸为参数的元素<xdr:ext />
新的xml结构将如下所示:

 <xdr:oneCellAnchor editAs="oneCell"> <xdr:from> ... </xdr:from> <xdr:ext cx="1234567" cy="7654321" /> <xdr:pic> ... </xdr:oneCellAnchor> 

好吧,怎么做?

Epplus代码中的更改

ExcelDrawings.cs ( 链接到这里的文件 )

  1. 首先我们修改CreateDrawingXml()方法CreateDrawingXml() 。 为了保留原有的function,我们添加一个可选参数(如果创buildoneCellAnchor )与默认值。 在方法中,根据这个参数,我们创build一个或两个单元格锚,并创build或不创build<xdr:to>元素。

此方法代码的重要部分:

 private XmlElement CreateDrawingXml(bool twoCell = true) { if (DrawingXml.OuterXml == "") { ... } // not changed XmlNode colNode= _drawingsXml.SelectSingleNode("//xdr:wsDr", NameSpaceManager); //First change in method code XmlElement drawNode; if (twoCell) drawNode = _drawingsXml.CreateElement( "xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings); else drawNode = _drawingsXml.CreateElement( "xdr", "oneCellAnchor", ExcelPackage.schemaSheetDrawings); colNode.AppendChild(drawNode); //Add from position Element; // Not changed XmlElement fromNode = _drawingsXml.CreateElement( "xdr", "from", ExcelPackage.schemaSheetDrawings); drawNode.AppendChild(fromNode); fromNode.InnerXml = "<xdr:col>0</xdr:col><xdr:colOff>0</xdr:colOff>" + "<xdr:row>0</xdr:row><xdr:rowOff>0</xdr:rowOff>"; //Add to position Element; //Second change in method if (twoCell) { XmlElement toNode = _drawingsXml.CreateElement( "xdr", "to", ExcelPackage.schemaSheetDrawings); drawNode.AppendChild(toNode); toNode.InnerXml = "<xdr:col>10</xdr:col><xdr:colOff>0</xdr:colOff>" + "<xdr:row>10</xdr:row><xdr:rowOff>0</xdr:rowOff>"; } return drawNode; } 

然后我们在同一个文件里修改AddPicture两个方法:

 public ExcelPicture AddPicture(string Name, Image image, Uri Hyperlink) { if (image != null) { if (_drawingNames.ContainsKey(Name.ToLower())) { throw new Exception("Name already exists in the drawings collection"); } XmlElement drawNode = CreateDrawingXml(false); // Change: we need create element with dimensions // like: <xdr:ext cx="3857625" cy="1047750" /> XmlElement xdrext = _drawingsXml.CreateElement( "xdr", "ext", ExcelPackage.schemaSheetDrawings); xdrext.SetAttribute("cx", (image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString()); xdrext.SetAttribute("cy", (image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString()); drawNode.AppendChild(xdrext); // End of change, next part of method is the same: drawNode.SetAttribute("editAs", "oneCell"); ... } } 

而这个方法以FileInfo作为input参数:

 public ExcelPicture AddPicture(string Name, FileInfo ImageFile, Uri Hyperlink) { if (ImageFile != null) { if (_drawingNames.ContainsKey(Name.ToLower())) { throw new Exception("Name already exists in the drawings collection"); } XmlElement drawNode = CreateDrawingXml(false); // Change: First create ExcelPicture object and calculate EMU dimensions ExcelPicture pic = new ExcelPicture(this, drawNode, ImageFile, Hyperlink); XmlElement xdrext = _drawingsXml.CreateElement( "xdr", "ext", ExcelPackage.schemaSheetDrawings); xdrext.SetAttribute("cx", (pic.Image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString()); xdrext.SetAttribute("cy", (pic.Image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString()); drawNode.AppendChild(xdrext); // End of change, next part of method is the same (without create pic object) drawNode.SetAttribute("editAs", "oneCell"); ... } } 

所以,这都是重要的代码。 现在我们必须改变search节点的代码并保持元素的顺序。

private void AddDrawings()我们改变xpath从:

 XmlNodeList list = _drawingsXml.SelectNodes( "//xdr:twoCellAnchor", NameSpaceManager); 

对此

 XmlNodeList list = _drawingsXml.SelectNodes( "//(xdr:twoCellAnchor or xdr:oneCellAnchor)", NameSpaceManager); 

这一切都在这个文件,现在我们改变
ExcelPicture.cs ( 链接到这里的文件 )

原始代码查找节点用于在构造函数中追加下一个代码,如下所示:

 node.SelectSingleNode("xdr:to",NameSpaceManager); 

因为我们不总是创build<xdr:to>元素,所以我们改变这个代码:

 internal ExcelPicture(ExcelDrawings drawings, XmlNode node , Image image, Uri hyperlink) : base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name") { XmlElement picNode = node.OwnerDocument.CreateElement( "xdr", "pic", ExcelPackage.schemaSheetDrawings); // Edited: find xdr:to, or xdr:ext if xdr:to not exists XmlNode befor = node.SelectSingleNode("xdr:to",NameSpaceManager); if (befor != null && befor.Name == "xdr:to") node.InsertAfter(picNode, befor); else { befor = node.SelectSingleNode("xdr:ext", NameSpaceManager); node.InsertAfter(picNode, befor); } // End of change, next part of constructor is unchanged _hyperlink = hyperlink; ... } 

和FileInfo作为input参数的第二个构造函数一样:

 internal ExcelPicture(ExcelDrawings drawings, XmlNode node , FileInfo imageFile, Uri hyperlink) : base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name") { XmlElement picNode = node.OwnerDocument.CreateElement( "xdr", "pic", ExcelPackage.schemaSheetDrawings); // Edited: find xdr:to, or xdr:ext if xdr:to not exists XmlNode befor = node.SelectSingleNode("xdr:to", NameSpaceManager); if (befor != null && befor.Name == "xdr:to") node.InsertAfter(picNode, befor); else { befor = node.SelectSingleNode("xdr:ext", NameSpaceManager); node.InsertAfter(picNode, befor); } // End of change, next part of constructor is unchanged _hyperlink = hyperlink; ... 

现在,图片被创build为一个oneCellAnchor 。 如果你愿意,你可以为展位变体创build多个AddPicture方法。 最后一步是build立这个项目,并创build自己的自定义EPPlus.dll 。 然后closures你的项目,使用这个DLL和复制新的文件EPPlus.dllEPPlus.pdbEPPlus.XML在你的项目(备份和replace原来的dll文件)在同一个地方(所以你不需要做任何改变您的项目参考或设置)。
然后打开并重build您的项目,并尝试解决您的问题。

也许我太迟了,但是这是我的答案..你也可以在codeplex的问题上阅读它( https://epplus.codeplex.com/workitem/14846


我也遇到了这个问题。

经过一番研究,我找出了错误所在。

它位于149行代码( ExcelRow.cs文件)的ExcelRow类中。

有一个错误,当行的高度被改变时,它会重新调整所有的图片高度,但是使用图片宽度在高度,所以很容易修复。

只要改变一下

 var pos = _worksheet.Drawings.GetDrawingWidths(); 

 var pos = _worksheet.Drawings.GetDrawingHeight(); 

查看图像上的代码更改

PS实际版本4.0.4