I am able to add in an image to an excel spreadsheet by using OpenXML. However for the rest of the program I use ClosedXML to add data. I can add data at a specific cell using the column and row index. If I can add an image to an excel (It currently is a separate layer it seems, hovering over cells), how can I add it to a cell using ClosedXML?
//Adds an image to the excel file
public void AddImageToExcel(SpreadsheetDocument sd, MemoryStream imagestream)
{
DrawingsPart dp = sd.WorkbookPart.WorksheetParts.First().AddNewPart<DrawingsPart>();
ImagePart imgp = dp.AddImagePart(ImagePartType.Jpeg, sd.WorkbookPart.WorksheetParts.First().GetIdOfPart(dp));
MemoryStream bmstream = new MemoryStream(imagestream.ToArray());
bmstream.Seek(0, SeekOrigin.Begin);
MemoryStream fs;
using (fs = imagestream)
{
fs.Position = 0;
imgp.FeedData(fs);
}
DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties nvdp = new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties();
nvdp.Id = 1025;
nvdp.Name = "Chart Image";
nvdp.Description = "Image";
DocumentFormat.OpenXml.Drawing.PictureLocks piclocks = new DocumentFormat.OpenXml.Drawing.PictureLocks();
piclocks.NoChangeAspect = true;
piclocks.NoChangeArrowheads = true;
DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureDrawingProperties nvpdp = new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureDrawingProperties();
nvpdp.PictureLocks = piclocks;
DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureProperties nvpp = new DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureProperties();
nvpp.NonVisualDrawingProperties = nvdp;
nvpp.NonVisualPictureDrawingProperties = nvpdp;
DocumentFormat.OpenXml.Drawing.Stretch stretch = new DocumentFormat.OpenXml.Drawing.Stretch();
stretch.FillRectangle = new DocumentFormat.OpenXml.Drawing.FillRectangle();
DocumentFormat.OpenXml.Drawing.Spreadsheet.BlipFill blipfill = new DocumentFormat.OpenXml.Drawing.Spreadsheet.BlipFill();
DocumentFormat.OpenXml.Drawing.Blip blip = new DocumentFormat.OpenXml.Drawing.Blip();
blip.Embed = dp.GetIdOfPart(imgp);
blip.CompressionState = DocumentFormat.OpenXml.Drawing.BlipCompressionValues.Print;
blipfill.Blip = blip;
blipfill.SourceRectangle = new DocumentFormat.OpenXml.Drawing.SourceRectangle();
blipfill.Append(stretch);
DocumentFormat.OpenXml.Drawing.Transform2D t2d = new DocumentFormat.OpenXml.Drawing.Transform2D();
DocumentFormat.OpenXml.Drawing.Offset offset = new DocumentFormat.OpenXml.Drawing.Offset();
offset.X = 0;
offset.Y = 0;
t2d.Offset = offset;
Bitmap bm = new Bitmap(bmstream);
DocumentFormat.OpenXml.Drawing.Extents extents = new DocumentFormat.OpenXml.Drawing.Extents();
extents.Cx = ((long)bm.Width * (long)((float)914400 / bm.HorizontalResolution));
extents.Cy = ((long)bm.Height * (long)((float)914400 / bm.VerticalResolution));
bm.Dispose();
t2d.Extents = extents;
DocumentFormat.OpenXml.Drawing.Spreadsheet.ShapeProperties sp = new DocumentFormat.OpenXml.Drawing.Spreadsheet.ShapeProperties();
sp.BlackWhiteMode = DocumentFormat.OpenXml.Drawing.BlackWhiteModeValues.Auto;
sp.Transform2D = t2d;
DocumentFormat.OpenXml.Drawing.PresetGeometry prstgeom = new DocumentFormat.OpenXml.Drawing.PresetGeometry();
prstgeom.Preset = DocumentFormat.OpenXml.Drawing.ShapeTypeValues.Rectangle;
prstgeom.AdjustValueList = new DocumentFormat.OpenXml.Drawing.AdjustValueList();
sp.Append(prstgeom);
sp.Append(new DocumentFormat.OpenXml.Drawing.NoFill());
DocumentFormat.OpenXml.Drawing.Spreadsheet.Picture picture = new DocumentFormat.OpenXml.Drawing.Spreadsheet.Picture();
picture.NonVisualPictureProperties = nvpp;
picture.BlipFill = blipfill;
picture.ShapeProperties = sp;
DocumentFormat.OpenXml.Drawing.Spreadsheet.Position pos = new DocumentFormat.OpenXml.Drawing.Spreadsheet.Position();
//The position corrosponds these numbers. X= 600000 & y = 200000 adds up to 1 cell
pos.X = 600000;
pos.Y = 200000;
Extent ext = new Extent();
ext.Cx = extents.Cx;
ext.Cy = extents.Cy;
AbsoluteAnchor anchor = new AbsoluteAnchor();
Xdr.Position pp = new Xdr.Position();
pp.X = 0;
pp.Y = 0;
anchor.Position = pp;
anchor.Position = pos;
anchor.Extent = ext;
anchor.Append(picture);
anchor.Append(new ClientData());
WorksheetDrawing wsd = new WorksheetDrawing();
wsd.Append(anchor);
Drawing drawing = new Drawing();
drawing.Id = dp.GetIdOfPart(imgp);
wsd.Save(dp);
sd.WorkbookPart.WorksheetParts.First().Worksheet.Append(drawing);
MessageBox.Show("Excel File created");
}
This is the code I used, which I found here on stack overflow somewhere. I modified it to use a MemoryStream for the image. So firstly one of the problems I have is that I pass a spreadsheet document to the method, however I'm not sure what I can do in ClosedXML to fix this Really appreciate any help with how I could go about this. Ideally I would love to simply say
ws.Cell(colnum, rownum).Value = AddImageToExcel(wb, ImageToMemoryStream(imagelocation));
Thanks for any help!
I little bit late here, but in case someone else comes looking I've added (limited) image support to ClosedXML.
Fork can be found at https://closedxml.codeplex.com/SourceControl/network/forks/ajwhiteway/ClosedXMLImageSupport
EDIT: Adding some detail to how it works.
New classes, XLPicture and XLMarker, have been added.
Picture can be created by
As of now it only accepts streams, not files, and it only spits out JPEGs. This can be changed if there is demand.
Once your picture is created you create a marker for where it goes
If you add a single marker it will embed the image directly into the cell. If you add 2 markers it will span the image across the two markers.
Then to add it to the sheet just
Cheers guys.