Я использую OpenXml (версия 3.0.1) для вставки изображения в ячейку. Хотя код выполняется без ошибок, когда я экспортирую файл Excel и открываю его, я получаю сообщение об ошибке, и изображение не появляется в ожидаемой ячейке (A2).
Я сослался на эту msdn-code-gallery, но этот код, похоже, не работает или, возможно, устарел в последней версии OpenXml.
Вот мой код
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
using A = DocumentFormat.OpenXml.Drawing;
public byte[] AddImageToExcel(SheetExport sheetExport)
{
using var memoryStream = new MemoryStream();
var spreadSheetDocument = SpreadsheetDocument.Create(memoryStream, SpreadsheetDocumentType.Workbook);
var workbookPart = spreadSheetDocument.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
var sheetToAppend = new Sheet()
{ Name = sheetExport.SheetName, SheetId = 1, Id = workbookPart.GetIdOfPart(worksheetPart) };
sheets.Append(sheetToAppend);
// Adding image to the worksheet
InsertImageInCell(worksheetPart);
workbookPart.Workbook.Save();
spreadSheetDocument.Dispose();
return memoryStream.ToArray();
}
private (long Width, long Height) GetImageExtents(string imagePath)
{
using System.Drawing.Image image = System.Drawing.Image.FromFile(imagePath);
long width = (long)((image.Width / image.HorizontalResolution) * 914400L);
long height = (long)((image.Height / image.VerticalResolution) * 914400L);
return (width, height);
}
private void InsertImageInCell(WorksheetPart worksheetPart)
{
DrawingsPart drawingsPart;
if (worksheetPart.DrawingsPart == null)
{
drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
worksheetPart.Worksheet.Append(new Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });
worksheetPart.Worksheet.Save();
}
else
{
drawingsPart = worksheetPart.DrawingsPart;
}
var imagePath = Path.Combine(Directory.GetCurrentDirectory(), "Resources", "Banner.png");
var imageExtents = GetImageExtents(imagePath);
// Add the image
ImagePart imagePart = drawingsPart.AddImagePart(ImagePartType.Png);
using (var imageFileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
imagePart.FeedData(imageFileStream);
}
// Create the drawing elements
var nvdp = new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)1025U,
Name = "Picture 1"
};
var nvpd = new PIC.NonVisualPictureDrawingProperties(new A.PictureLocks() { NoChangeAspect = true });
var nvpp = new PIC.NonVisualPictureProperties()
{
NonVisualDrawingProperties = nvdp,
NonVisualPictureDrawingProperties = nvpd
};
var blip = new A.Blip()
{
Embed = drawingsPart.GetIdOfPart(imagePart),
CompressionState = A.BlipCompressionValues.Print
};
var blipFill = new PIC.BlipFill()
{
Blip = blip,
SourceRectangle = new A.SourceRectangle()
};
blipFill.Append(new A.Stretch() { FillRectangle = new A.FillRectangle() });
var sp = new PIC.ShapeProperties()
{
BlackWhiteMode = A.BlackWhiteModeValues.Auto
};
var transform2D = new A.Transform2D();
var offset = new A.Offset() { X = 0L, Y = 0L };
var extents = new A.Extents() { Cx = imageExtents.Width, Cy = imageExtents.Height };
transform2D.Append(offset);
transform2D.Append(extents);
sp.Append(transform2D);
sp.Append(new A.PresetGeometry(new A.AdjustValueList())
{
Preset = A.ShapeTypeValues.Rectangle
});
var picture = new PIC.Picture()
{
NonVisualPictureProperties = nvpp,
BlipFill = blipFill,
ShapeProperties = sp
};
var position = new Position() { X = 0L, Y = 0L };
var extent = new Extent() { Cx = imageExtents.Width, Cy = imageExtents.Height };
var absoluteAnchor = new AbsoluteAnchor()
{
Position = position,
Extent = extent
};
absoluteAnchor.Append(picture);
absoluteAnchor.Append(new ClientData());
WorksheetDrawing worksheetDrawing = drawingsPart.WorksheetDrawing;
if (worksheetDrawing == null)
{
worksheetDrawing = new WorksheetDrawing();
drawingsPart.WorksheetDrawing = worksheetDrawing;
}
worksheetDrawing.Append(absoluteAnchor);
drawingsPart.WorksheetDrawing.Save();
}
Внутренний xml drawingPart.WorkSheetDrawing
<xdr:absoluteAnchor
xmlns:xdr = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">
<xdr:pos x = "0" y = "0" />
<xdr:ext cx = "1781423" cy = "628737" />
<pic:pic
xmlns:pic = "http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:nvPicPr>
<pic:cNvPr id = "1025" name = "Picture 1" />
<pic:cNvPicPr>
<a:picLocks noChangeAspect = "1"
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main" />
</pic:cNvPicPr>
</pic:nvPicPr>
<pic:blipFill>
<a:blip r:embed = "R3a1e7131d49045f5" cstate = "print"
xmlns:r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main" />
<a:srcRect
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main" />
<a:stretch
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main">
<a:fillRect />
</a:stretch>
</pic:blipFill>
<pic:spPr bwMode = "auto">
<a:xfrm
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main">
<a:off x = "0" y = "0" />
<a:ext cx = "1781423" cy = "628737" />
</a:xfrm>
<a:prstGeom prst = "rect"
xmlns:a = "http://schemas.openxmlformats.org/drawingml/2006/main">
<a:avLst />
</a:prstGeom>
</pic:spPr>
</pic:pic>
<xdr:clientData />
</xdr:absoluteAnchor>
Я не могу использовать какие-либо третьи стороны, такие как EPPlus или ClosedXml, это нужно делать через OpenXml.
Вы используете using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
Я думаю, что это неправильное пространство имен.
Например:var nvdp = new PIC.NonVisualDrawingProperties()
должно быть var nvpp = new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureProperties()
Проверьте, где вы используете PIC, и используйте DocumentFormat.OpenXml.Drawing.Spreadsheet
Это был недостающий фрагмент. Я добавлю еще один ответ на свой вопрос, который объяснит, что я сделал, чтобы добавить изображение. Инструменты повышения производительности OpenXml помогли мне выбрать правильное направление.