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是具有静态宽度和高度的数据矩阵图像,不需要调整大小,因为它们总是很小/很小。 所以在一些行中没有SetSize情况下,它也可以工作,而在其他一些行中,它不起作用。 真的很奇怪,因为代码是一样的。 它可能是图书馆和/或Excel中的东西。 也许我使用它错了? 任何epplus图片专家?

提前致谢!!

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

epplus图像

编辑 2013/04/09 Essenpillai给了我一个提示设置

pck.DoAdjustDrawings = false;

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

doadjustdrawings

数据矩阵仍然按行进行更改。 在行是好的,另一个不是。 并且ean13代码太宽。


我与Epplus库有相同的问题。
在我的代码中找不到解决方案如何解决这个问题之后,我检查了这个库的源代码。 Epplus始终以twoCellAnchor绘图创建excel图片。 在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的副本。 好消息是你只需要修改两个文件来解决这个问题。 所以..

从本网站下载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.cs(链接到这里的文件)

  • 起初,我们修改方法CreateDrawingXml()ExcelDrawings.cs 。 为了保留原有的功能,我们添加一个可选参数(如果创建oneCellAnchor ),并使用默认值。 在方法中,基于这个参数,我们创建一个或两个单元格锚点并创建或不创建<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作为输入参数:

    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.cs(链接到这里的文件)

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

    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文件)(因此你不需要做任何改变)您的项目参考或设置)。
    然后打开并重建您的项目,并尝试解决您的问题。


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


    我也遇到了这个问题。

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

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

    有一个错误,当行的高度发生变化时,它会重新调整所有图片高度,但是使用图片宽度替换高度,因此很容易修复。

    只要改变一下

    var pos = _worksheet.Drawings.GetDrawingWidths();
    

    var pos = _worksheet.Drawings.GetDrawingHeight();
    

    查看图像上的代码更改

    版本4.0.4的 PS实际值

    链接地址: http://www.djcxy.com/p/12491.html

    上一篇: Epplus SetPosition picture issue

    下一篇: webapp2 with python3