open officeopenxml escribir ejemplos desde combinar centrar celdas excel c#-4.0 epplus

excel - officeopenxml - Problema de imagen de Epplus SetPosition



escribir en excel desde c# (2)

Estoy usando la biblioteca Epplus para generar Excel 2010 y archivos compatibles en Asp.Net C #. Estoy usando la versión 3.1.2 que es la última en este momento.

Estoy configurando la altura de la fila primero, antes de agregar cualquier imagen como esta:

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 es mi DataTable con DataRows. Después de establecer la altura, vuelvo a recorrer las filas para agregar las imágenes

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

Esto funciona, pero esto no:

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

Esto da como resultado imágenes descentradas e imágenes sin restricciones. Y este código que está en el mismo ciclo:

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

Esto funciona a veces. las imágenes prodImgDm son imágenes de datamatrix con ancho y alto estáticos y no es necesario cambiar su tamaño porque siempre son pequeñas / pequeñas. Así que también sin SetSize en algunas filas, funciona y en algunas otras filas, no funciona. Realmente extraño porque el código es el mismo. Puede ser algo en la biblioteca y / o Excel. Tal vez lo estoy usando mal? ¿Algún experto en imágenes epplus?

¡¡Gracias por adelantado!!

edita a veces una imagen vale más que mil palabras, así que aquí está la captura de pantalla. Como puede ver, las imágenes del producto no están alineadas horizontal y verticalmente en la celda. Y la matriz de datos en el extremo derecho a veces se escala alrededor del 120% incluso cuando configuro SetSize(100) así que es realmente extraño para mí. Así que la última matriz de datos tiene el tamaño correcto ... Ya encontré este hilo SO, pero eso no me ayuda, creo.

editar 2013/04/09 Essenpillai me dio una pista para establecer

pck.DoAdjustDrawings = false;

pero eso me dio imágenes aún más extrañas:

la matriz de datos todavía está cambiando en la fila. en la fila está bien, el otro no. y el código ean13 es demasiado ancho.


Tengo el mismo problema con la biblioteca Epplus .
Después de que no encuentro una solución para resolver esto en mi código, verifiqué el código fuente de esta biblioteca. Epplus crea una imagen de Excel siempre como dibujo twoCellAnchor . En los archivos xlsx puede encontrar drawingXYZ.xml con este código:

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

Entonces, la imagen siempre está conectada a dos celdas, y esta no es una parte variable de la biblioteca de Epplus. Puede encontrar esta parte del código en el archivo ExcelDrawing.cs .

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

Puede crear fácilmente su propia copia de este dll. La buena noticia es que solo necesita modificar dos archivos para solucionar este problema. Asi que..

Descargue su copia de los códigos fuente para la biblioteca Epplus desde este sitio y ábrala en Visual Studio.

Necesitamos generar un código de drawing como oneCellAnchor , por lo que debemos eliminar el elemento <xdr:to> para las imágenes y crear el elemento <xdr:ext /> con las dimensiones de la imagen como parámetros.
Nueva estructura xml se verá así:

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

Ok, entonces, ¿cómo hacer esto?

Cambios en el código de Epplus

ExcelDrawings.cs ( enlace al archivo aquí )

  1. Al principio modificamos el método CreateDrawingXml() dentro de ExcelDrawings.cs . Para conservar la funcionalidad original, agregamos un parámetro opcional (si crea oneCellAnchor ) con el valor predeterminado. Y en el método, basado en este parámetro, creamos un anclado de celda o de arrastre y creamos o no elemento <xdr:to> .

Parte importante de este código de método:

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

Luego modificamos dos métodos para AddPicture dentro del mismo archivo:

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

Y este método con FileInfo como parámetro de entrada:

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

Entonces, este es un código importante. Ahora debemos cambiar el código para buscar nodos y conservar el orden en los elementos.

En private void AddDrawings() cambiamos xpath de:

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

Para esto :

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

Todo está en este archivo, ahora cambiamos
ExcelPicture.cs ( enlace al archivo aquí )

Original code find node para anexar el siguiente código en constructor como este:

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

Como no creamos siempre el elemento <xdr:to> , cambiamos este código:

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

Y lo mismo para el segundo constructor con FileInfo como parámetro de entrada:

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

Ahora, las imágenes se crean como oneCellAnchor . Si lo desea, puede crear varios métodos AddPicture para las variantes de cabina. El último paso es crear este proyecto y crear su propio EPPlus.dll personalizado. A continuación, cierre el proyecto que utiliza este dll y copie los nuevos archivos EPPlus.dll , EPPlus.pdb , EPPlus.XML dentro de su proyecto ( EPPlus.XML una copia de seguridad y reemplace sus archivos dll originales) en el mismo lugar (para que no necesite hacer ningún cambio en sus referencias o configuraciones del proyecto).
Luego abre y reconstruye tu proyecto y prueba si esto resuelve tu problema.


Tal vez sea demasiado tarde, pero esta es la respuesta mía ... también puedes leerla en codeplex ( https://epplus.codeplex.com/workitem/14846 )

También tengo este problema.

Y después de algunas investigaciones, descubrí dónde está el error.

Está en la clase ExcelRow en la línea 149 de código (archivo ExcelRow.cs ).

Hay un error, cuando se cambió la altura de la fila, recalcula todas las alturas de las imágenes, pero utiliza anchuras de las imágenes en el lugar de las alturas, por lo que es fácil de corregir.

Solo cambia la linea

var pos = _worksheet.Drawings.GetDrawingWidths();

a

var pos = _worksheet.Drawings.GetDrawingHeight();

Ver los cambios de código en la imagen

PS Actual para la versión 4.0.4