2013-03-26 76 views
7

我使用Epplus library产生在Asp.Net C#Excel 2010和高达兼容的文件。 我使用的是目前最新版本的3.1.2版本。Epplus SETPOSITION图片问题

我首先设置行高度,添加任何图片像在此之前:

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与数据行。 设置高度之后,我再通过行循环添加图片

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); 

这导致偏离中心的图片和影像unresized。然后这个代码在同一个循环中:

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

这有时会起作用。图片prodImgDm是一个静态的宽度和高度DataMatrix二维图像,不需要进行调整,因为他们总是小型/微型。因此,在某些行中没有SetSize,它也可以工作,而在其他一些行中,它不起作用。真的很奇怪,因为代码是一样的。它可能是图书馆和/或Excel中的东西。也许我使用它错了?任何epplus图片专家?

在此先感谢!

编辑有时候一张图片胜过千言万语,所以这里是截图。如您所见,产品图像在单元格中不是水平和垂直对齐的。而且甚至当我设置SetSize(100)最右边的是有时规模约120%的数据矩阵所以它是真的很奇怪我。所以最后一个datamatrix有正确的大小...我已经找到了this SO thread,但我认为这并没有帮助我。

epplus images

编辑 2013年4月9日Essenpillai给我提示设置

pck.DoAdjustDrawings = false; 

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

doadjustdrawings

数据矩阵依然在不断变化。在行是好的,另一个不是。并且ean13代码太宽。

回答

2

我有Epplus库同样的问题。
后,我发现没有解决如何在我的代码解决这个问题,我查了一下这个库的source code。 Epplus创建总是擅长的图片作为twoCellAnchor图。在xlsx文件,你可以用这个代码中找到drawingXYZ.xml

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

因此,画面总是连接到两个单元,这是不是Epplus库的可变部分。您可以在ExcelDrawing.cs文件中找到这部分代码。

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

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

this site下载Epplus库的源代码副本,并在Visual Studio中打开。

我们需要产生的drawing代码oneCellAnchor,所以我们必须删除图片<xdr:to>元素,创造元素<xdr:ext />与图片的尺寸作为参数。
新的XML结构是这样的:

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

好了,所以,如何做到这一点?

变化Epplus代码

ExcelDrawings.cslink to file here

  1. 起初,我们修改内部ExcelDrawings.cs方法CreateDrawingXml()。为了保留原有的功能,我们添加一个可选参数(如果创建oneCellAnchor)与默认值。并且在方法中,基于此参数,我们创建一个或两个单元格锚点并创建或不创建元素。

这种方法代码重要组成部分:

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作为输入参数:

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"); 
    ... 
    } 
} 

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

private void AddDrawings()我们改变xpath来自:

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

对此

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

这是所有在这个文件中,现在我们改变
ExcelPicture。CSlink to file here)进行追加下面的代码在构造函数中这样

原始代码中找到节点:

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

因为我们没有创造总是<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作为输入参数的第二个构造函数也是如此:

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; 
    ... 

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

+0

看起来像是一个很好的项目拉动请求。 https://epplus.codeplex.com/sourcecontrol/list/contributions – 2014-02-14 10:40:53

+1

ps。我发现这个资源https://epplus.codeplex.com/workitem/14675这表明,绘图应该有editas道具设置。那里你可以选择绝对的,一个单元,两个单元 – 2014-07-11 13:49:44

1

也许我太晚了,但这里是我的答案.. 你可以在CodePlex上发布阅读以及 (https://epplus.codeplex.com/workitem/14846


我得到了这个问题为好。

而且一些研究之后,我想通了其中的错误是。

它在ExcelRow类的行代码(ExcelRow.cs文件)。

有一个错误,当行的高度得到了改变它recalcs所有图片的高度,但使用图片宽度就地高度,所以很容易修复。

只需更改行

var pos = _worksheet.Drawings.GetDrawingWidths(); 

var pos = _worksheet.Drawings.GetDrawingHeight(); 

See the code changes on image

附:实际版本4.0.4