I'm trying to add an image to an excel document that has been generated by closedxml using openxml after the spreadsheet has been generated (since closedxml has no way to insert images currently).
I can generate the excel file correctly and it opens up fine however when I try inserting the image in and try to open it in excel It gives an error.
I have used a small console app and found the error to be
Error 1
Description: The element has unexpected child element 'http://schemas.openxmlfor
mats.org/spreadsheetml/2006/main:drawing'.
Path: /x:worksheet[1]
Part: /xl/worksheets/sheet.xml
-------------------------------------------
The spreadsheet looks like this:
<?xml version="1.0" encoding="utf-8"?>
<x:worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:sheetPr>
<x:outlinePr summaryBelow="1" summaryRight="1" />
</x:sheetPr>
<x:dimension ref="A1:M4" />
<x:sheetViews>
<x:sheetView tabSelected="0" workbookViewId="0" />
</x:sheetViews>
<x:sheetFormatPr defaultRowHeight="15" />
<x:cols>
...
</x:cols>
<x:sheetData>
...
</x:sheetData>
<x:printOptions horizontalCentered="0" verticalCentered="0" headings="0" gridLines="0" />
<x:pageMargins left="0.75" right="0.75" top="0.75" bottom="0.5" header="0.5" footer="0.75" />
<x:pageSetup paperSize="1" scale="100" pageOrder="downThenOver" orientation="default" blackAndWhite="0" draft="0" cellComments="none" errors="displayed" />
<x:headerFooter />
<x:tableParts count="0" />
<x:drawing r:id="R701e4d0efd7143ee" />
</x:worksheet>
Taking the
section out seems to allow the file to validate correctly.
I have also tried creating a blank excel document manually and adding an image and it looks pretty similar:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
<dimension ref="A1"/>
<sheetViews>
<sheetView tabSelected="1" workbookViewId="0">
<selection activeCell="D14" sqref="D14"/>
</sheetView>
</sheetViews>
<sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
<sheetData/>
<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
<drawing r:id="rId1"/>
</worksheet>
One thing I notice is that they do not have a namespace (x) like the generated one does but I don't know if that is causing a problem or not.
Can anyone see what I'm missing?
The code im using to insert the image is as follows:
public static void InsertImage(this Worksheet ws, long x, long y, long? width, long? height, string sImagePath)
{
try
{
var wsp = ws.WorksheetPart;
var dp = default(DrawingsPart);
var imgp = default(ImagePart);
var wsd = default(WorksheetDrawing);
var ipt = default(ImagePartType);
switch (sImagePath.Substring(sImagePath.LastIndexOf('.') + 1).ToLower())
{
case "png":
ipt = ImagePartType.Png;
break; // TODO: might not be correct. Was : Exit Select
break;
case "jpg":
case "jpeg":
ipt = ImagePartType.Jpeg;
break; // TODO: might not be correct. Was : Exit Select
break;
case "gif":
ipt = ImagePartType.Gif;
break; // TODO: might not be correct. Was : Exit Select
break;
default:
return;
}
if (wsp.DrawingsPart == null)
{
//----- no drawing part exists, add a new one
dp = wsp.AddNewPart<DrawingsPart>();
imgp = dp.AddImagePart(ipt, wsp.GetIdOfPart(dp));
wsd = new WorksheetDrawing();
}
else
{
//----- use existing drawing part
dp = wsp.DrawingsPart;
imgp = dp.AddImagePart(ipt);
dp.CreateRelationshipToPart(imgp);
wsd = dp.WorksheetDrawing;
}
using (var fs = new FileStream(sImagePath, FileMode.Open))
{
imgp.FeedData(fs);
}
var imageNumber = 1;
if (imageNumber == 1)
{
var drawing = new Drawing();
drawing.Id = dp.GetIdOfPart(imgp);
ws.Append(drawing);
}
var nvdp = new NonVisualDrawingProperties();
nvdp.Id = new UInt32Value(Convert.ToUInt32(1024 + imageNumber));
nvdp.Name = "Picture " + imageNumber.ToString();
nvdp.Description = "Picture";
var picLocks = new PictureLocks();
picLocks.NoChangeAspect = true;
picLocks.NoChangeArrowheads = true;
var nvpdp = new NonVisualPictureDrawingProperties();
nvpdp.PictureLocks = picLocks;
var nvpp = new NonVisualPictureProperties();
nvpp.NonVisualDrawingProperties = nvdp;
nvpp.NonVisualPictureDrawingProperties = nvpdp;
var stretch = new Stretch();
stretch.FillRectangle = new FillRectangle();
var blipFill = new BlipFill();
var blip = new Blip();
blip.Embed = dp.GetIdOfPart(imgp);
blip.CompressionState = BlipCompressionValues.Print;
blipFill.Blip = blip;
blipFill.SourceRectangle = new SourceRectangle();
blipFill.Append(stretch);
var t2d = new Transform2D();
var offset = new Offset();
offset.X = 0;
offset.Y = 0;
t2d.Offset = offset;
var bm = new Bitmap(sImagePath);
var extents = new Extents();
if (width == null)
{
extents.Cx = Convert.ToInt64(bm.Width)*
Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.HorizontalResolution));
}
else
{
extents.Cx = width;
}
if (height == null)
{
extents.Cy = Convert.ToInt64(bm.Height)*
Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.VerticalResolution));
}
else
{
extents.Cy = height;
}
bm.Dispose();
t2d.Extents = extents;
var sp = new ShapeProperties();
sp.BlackWhiteMode = BlackWhiteModeValues.Auto;
sp.Transform2D = t2d;
var prstGeom = new PresetGeometry();
prstGeom.Preset = ShapeTypeValues.Rectangle;
prstGeom.AdjustValueList = new AdjustValueList();
sp.Append(prstGeom);
sp.Append(new NoFill());
var picture = new Picture();
picture.NonVisualPictureProperties = nvpp;
picture.BlipFill = blipFill;
picture.ShapeProperties = sp;
var pos = new Position();
pos.X = x;
pos.Y = y;
var ext = new Extent();
ext.Cx = extents.Cx;
ext.Cy = extents.Cy;
var anchor = new AbsoluteAnchor();
anchor.Position = pos;
anchor.Extent = ext;
anchor.Append(picture);
anchor.Append(new ClientData());
wsd.Append(anchor);
wsd.Save(dp);
}
catch (Exception ex)
{
// or do something more interesting if you want
throw ex;
}
}
public static void InsertImage(MemoryStream stream, long x, long y, string sImagePath)
{
using (var mySpreadsheet = SpreadsheetDocument.Open(stream, true))
{
var workbookPart = mySpreadsheet.WorkbookPart;
var sheets = mySpreadsheet.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
var relationshipId = sheets.First().Id.Value;
var worksheetPart = (WorksheetPart) mySpreadsheet.WorkbookPart.GetPartById(relationshipId);
var workSheet = worksheetPart.Worksheet;
//Dim sheets As worksheetpart = mySpreadsheet.WorkbookPart.Workbook.
// For each sheet, display the sheet information.
long width = 9525*193;
long height = 9525*80;
InsertImage(workSheet, x, y, width, height, sImagePath);
}
}