diff --git a/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML.csproj
index d5ddc65..0539fcd 100644
--- a/ClosedXML/ClosedXML.csproj
+++ b/ClosedXML/ClosedXML.csproj
@@ -72,6 +72,10 @@
+
+
+
+
@@ -343,4 +347,4 @@
-->
-
\ No newline at end of file
+
diff --git a/ClosedXML/Excel/Drawings/IXLMarker.cs b/ClosedXML/Excel/Drawings/IXLMarker.cs
new file mode 100644
index 0000000..048020b
--- /dev/null
+++ b/ClosedXML/Excel/Drawings/IXLMarker.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ClosedXML.Excel.Drawings
+{
+ public interface IXLMarker
+ {
+ Int32 ColumnId { get; set; }
+ Int32 RowId { get; set; }
+ Double ColumnOffset { get; set; }
+ Double RowOffset { get; set; }
+ }
+}
diff --git a/ClosedXML/Excel/Drawings/IXLPicture.cs b/ClosedXML/Excel/Drawings/IXLPicture.cs
new file mode 100644
index 0000000..96a9eb6
--- /dev/null
+++ b/ClosedXML/Excel/Drawings/IXLPicture.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace ClosedXML.Excel.Drawings
+{
+ public interface IXLPicture
+ {
+ Stream ImageStream { get; set; }
+
+ List GetMarkers();
+ void AddMarker(IXLMarker marker);
+
+ long MaxHeight { get; set; }
+ long MaxWidth { get; set; }
+ long Width { get; set; }
+ long Height { get; set; }
+ long PaddingX { get; set; }
+ long PaddingY { get; set; }
+ long EMUOffsetX { get; set; }
+ long EMUOffsetY { get; set; }
+
+ String Name { get; set; }
+ }
+}
diff --git a/ClosedXML/Excel/Drawings/XLMarker.cs b/ClosedXML/Excel/Drawings/XLMarker.cs
new file mode 100644
index 0000000..a523677
--- /dev/null
+++ b/ClosedXML/Excel/Drawings/XLMarker.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace ClosedXML.Excel.Drawings
+{
+ public class XLMarker : IXLMarker
+ {
+ private Int32 colId;
+ private Int32 rowId;
+ private Double colOffset;
+ private Double rowOffset;
+
+ public Int32 ColumnId
+ {
+ set
+ {
+ this.colId = value;
+ }
+ get
+ {
+ return this.colId - 1;
+ }
+ }
+
+ public Int32 RowId
+ {
+ set
+ {
+ this.rowId = value;
+ }
+ get
+ {
+ return this.rowId - 1;
+ }
+ }
+
+ public Double ColumnOffset
+ {
+ set
+ {
+ this.colOffset = value;
+ }
+ get
+ {
+ return this.colOffset;
+ }
+ }
+
+ public Double RowOffset
+ {
+ set
+ {
+ this.rowOffset = value;
+ }
+ get
+ {
+ return this.rowOffset;
+ }
+ }
+ }
+}
diff --git a/ClosedXML/Excel/Drawings/XLPicture.cs b/ClosedXML/Excel/Drawings/XLPicture.cs
new file mode 100644
index 0000000..2419568
--- /dev/null
+++ b/ClosedXML/Excel/Drawings/XLPicture.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace ClosedXML.Excel.Drawings
+{
+ public class XLPicture : IXLPicture
+ {
+ private MemoryStream imgStream;
+ private List Markers;
+ private String name;
+ public bool NoChangeAspect;
+ public bool NoMove;
+ public bool NoResize;
+
+ private long iMaxWidth = 500;
+ private long iMaxHeight = 500;
+
+ private long iWidth;
+ private long iHeight;
+
+ private long iOffsetX;
+ private long iOffsetY;
+
+ private float iVerticalResolution;
+ private float iHorizontalResolution;
+
+ private bool isResized = false;
+
+ private void Resize()
+ {
+ if (iWidth > iMaxHeight || iHeight > iMaxWidth)
+ {
+ var scaleX = (double)iWidth / (double)iMaxWidth;
+ var scaleY = (double)iHeight / (double)iMaxHeight;
+ var scale = Math.Max(scaleX, scaleY);
+ iWidth = (int)((double)iWidth / scale);
+ iHeight = (int)((double)iHeight / scale);
+ }
+ isResized = true;
+ }
+
+ public long MaxWidth
+ {
+ get
+ {
+ return ConvertToEmu(iMaxWidth, iHorizontalResolution);
+ }
+ set
+ {
+ iMaxWidth = value;
+ isResized = false;
+ }
+ }
+
+
+ public long MaxHeight
+ {
+ get
+ {
+ return ConvertToEmu(iMaxHeight, iVerticalResolution);
+ }
+ set
+ {
+ iMaxHeight = value;
+ isResized = false;
+ }
+ }
+
+ public long Width
+ {
+ get
+ {
+ if (!isResized)
+ {
+ Resize();
+ }
+ return ConvertToEmu(iWidth, iHorizontalResolution);
+ }
+ set { }
+ }
+
+ public long Height
+ {
+ get
+ {
+ if (!isResized)
+ {
+ Resize();
+ }
+ return ConvertToEmu(iHeight, iVerticalResolution);
+ }
+ set { }
+ }
+
+ public long RawHeight
+ {
+ get { return (long)iHeight; }
+ }
+ public long RawWidth
+ {
+ get { return (long)iWidth; }
+ }
+
+ public long PaddingX
+ {
+ get { return ConvertToEmu(iOffsetX, iHorizontalResolution); }
+ set { iOffsetX = value; }
+ }
+ public long PaddingY
+ {
+ get { return ConvertToEmu(iOffsetY, iVerticalResolution); }
+ set { iOffsetY = value; }
+ }
+
+ public long EMUOffsetX
+ {
+ get
+ {
+ return iOffsetX;
+ }
+ set
+ {
+ iOffsetX = value;
+ }
+ }
+
+ public long EMUOffsetY
+ {
+ get
+ {
+ return iOffsetY;
+ }
+ set
+ {
+ iOffsetY = value;
+ }
+ }
+
+ private long ConvertToEmu(long pixels, float resolution)
+ {
+ return (long)(914400 * pixels / resolution);
+ }
+
+ public Stream ImageStream
+ {
+ get
+ {
+ return imgStream;
+ }
+ set
+ {
+ if (imgStream == null)
+ {
+ imgStream = new MemoryStream();
+ }
+ else
+ {
+ imgStream.Dispose();
+ imgStream = new MemoryStream();
+ }
+ value.CopyTo(imgStream);
+ imgStream.Seek(0, SeekOrigin.Begin);
+
+ using (var bitmap = new System.Drawing.Bitmap(imgStream))
+ {
+ iWidth = (long)bitmap.Width;
+ iHeight = (long)bitmap.Height;
+ iHorizontalResolution = bitmap.HorizontalResolution;
+ iVerticalResolution = bitmap.VerticalResolution;
+ }
+ imgStream.Seek(0, SeekOrigin.Begin);
+ }
+ }
+
+ public List GetMarkers()
+ {
+ return Markers;
+ }
+ public void AddMarker(IXLMarker marker)
+ {
+ if (Markers == null)
+ {
+ Markers = new List();
+ }
+ Markers.Add(marker);
+ }
+
+ public String Name
+ {
+ get
+ {
+ return name;
+ }
+ set
+ {
+ name = value;
+ }
+ }
+ }
+}
diff --git a/ClosedXML/Excel/IXLWorksheet.cs b/ClosedXML/Excel/IXLWorksheet.cs
index 0d9dcd6..897e694 100644
--- a/ClosedXML/Excel/IXLWorksheet.cs
+++ b/ClosedXML/Excel/IXLWorksheet.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace ClosedXML.Excel
{
@@ -285,7 +286,7 @@
IXLTables Tables { get; }
///
- /// Copies the
+ /// Copies the
///
///
///
@@ -368,5 +369,9 @@
Object Evaluate(String expression);
String Author { get; set; }
+
+ List Pictures();
+
+ void AddPicture(Drawings.XLPicture pic);
}
}
diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs
index 9a99f83..457a474 100644
--- a/ClosedXML/Excel/XLWorkbook_Save.cs
+++ b/ClosedXML/Excel/XLWorkbook_Save.cs
@@ -14,6 +14,8 @@
using DocumentFormat.OpenXml.Vml.Office;
using DocumentFormat.OpenXml.Vml.Spreadsheet;
using Vml = DocumentFormat.OpenXml.Vml;
+using A = DocumentFormat.OpenXml.Drawing;
+using Xdr = DocumentFormat.OpenXml.Drawing.Spreadsheet;
using BackgroundColor = DocumentFormat.OpenXml.Spreadsheet.BackgroundColor;
using BottomBorder = DocumentFormat.OpenXml.Spreadsheet.BottomBorder;
using Break = DocumentFormat.OpenXml.Spreadsheet.Break;
@@ -2501,6 +2503,99 @@
return stroke;
}
+ private static void AddPictureAnchor(WorksheetPart worksheetPart, Drawings.IXLPicture picture)
+ {
+ var drawingsPart = worksheetPart.DrawingsPart ?? worksheetPart.AddNewPart();
+
+ if (drawingsPart.WorksheetDrawing == null)
+ {
+ drawingsPart.WorksheetDrawing = new Xdr.WorksheetDrawing();
+ }
+
+ var worksheetDrawing = drawingsPart.WorksheetDrawing;
+
+ var imagePart = drawingsPart.AddImagePart(ImagePartType.Jpeg);
+
+ using (Stream stream = new MemoryStream())
+ {
+ picture.ImageStream.CopyTo(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+ imagePart.FeedData(stream);
+ }
+
+ var extentsCx = picture.Width;
+ var extentsCy = picture.Height;
+
+ var nvps = worksheetDrawing.Descendants();
+ var nvpId = nvps.Count() > 0 ?
+ (UInt32Value)worksheetDrawing.Descendants().Max(p => p.Id.Value) + 1 :
+ 1U;
+ var markers = picture.GetMarkers();
+ Xdr.TwoCellAnchor twoCellAnchor;
+ Xdr.FromMarker fMark;
+ Xdr.ToMarker tMark;
+
+ if (markers.Count == 2)
+ {
+ fMark = new Xdr.FromMarker
+ {
+ ColumnId = new Xdr.ColumnId(markers[0].ColumnId.ToString()),
+ RowId = new Xdr.RowId(markers[0].RowId.ToString()),
+ ColumnOffset = new Xdr.ColumnOffset((markers[0].ColumnOffset + picture.PaddingX).ToString()),
+ RowOffset = new Xdr.RowOffset((markers[0].RowOffset + picture.PaddingY).ToString())
+ };
+ tMark = new Xdr.ToMarker
+ {
+ ColumnId = new Xdr.ColumnId(markers[1].ColumnId.ToString()),
+ RowId = new Xdr.RowId(markers[1].RowId.ToString()),
+ ColumnOffset = new Xdr.ColumnOffset((markers[1].ColumnOffset + picture.PaddingX).ToString()),
+ RowOffset = new Xdr.RowOffset((markers[1].RowOffset + picture.PaddingY).ToString())
+ };
+ }
+ else
+ {
+ fMark = new Xdr.FromMarker
+ {
+ ColumnId = new Xdr.ColumnId(markers[0].ColumnId.ToString()),
+ RowId = new Xdr.RowId(markers[0].RowId.ToString()),
+ ColumnOffset = new Xdr.ColumnOffset((markers[0].ColumnOffset + picture.PaddingX).ToString()),
+ RowOffset = new Xdr.RowOffset((markers[0].RowOffset + picture.PaddingY).ToString())
+ };
+
+ tMark = new Xdr.ToMarker
+ {
+ ColumnId = new Xdr.ColumnId(markers[0].ColumnId.ToString()),
+ RowId = new Xdr.RowId(markers[0].RowId.ToString()),
+ ColumnOffset = new Xdr.ColumnOffset((markers[0].ColumnOffset + extentsCx + picture.PaddingX).ToString()),
+ RowOffset = new Xdr.RowOffset((markers[0].RowOffset + extentsCy + picture.PaddingY).ToString())
+ };
+ }
+
+ twoCellAnchor = new Xdr.TwoCellAnchor(
+ fMark, tMark,
+ new Xdr.Picture(
+ new Xdr.NonVisualPictureProperties(
+ new Xdr.NonVisualDrawingProperties { Id = nvpId, Name = picture.Name },
+ new Xdr.NonVisualPictureDrawingProperties(new A.PictureLocks { NoChangeAspect = true, NoMove = true, NoResize = true })
+ ),
+ new Xdr.BlipFill(
+ new A.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = A.BlipCompressionValues.Print },
+ new A.Stretch(new A.FillRectangle())
+ ),
+ new Xdr.ShapeProperties(
+ new A.Transform2D(
+ new A.Offset { X = 0, Y = 0 },
+ new A.Extents { Cx = extentsCx, Cy = extentsCy }
+ ),
+ new A.PresetGeometry { Preset = A.ShapeTypeValues.Rectangle }
+ )
+ ),
+ new Xdr.ClientData()
+ );
+
+ worksheetDrawing.Append(twoCellAnchor);
+ }
+
private static Vml.TextBox GetTextBox(IXLDrawingStyle ds)
{
var sb = new StringBuilder();
@@ -4564,19 +4659,6 @@
#endregion
- #region Drawings
-
- //worksheetPart.Worksheet.RemoveAllChildren();
- //{
- // OpenXmlElement previousElement = cm.GetPreviousElementFor(XLWSContentManager.XLWSContents.Drawing);
- // worksheetPart.Worksheet.InsertAfter(new Drawing() { Id = String.Format("rId{0}", 1) }, previousElement);
- //}
-
- //Drawing drawing = worksheetPart.Worksheet.Elements().First();
- //cm.SetElement(XLWSContentManager.XLWSContents.Drawing, drawing);
-
- #endregion
-
#region Tables
worksheetPart.Worksheet.RemoveAllChildren();
@@ -4596,6 +4678,36 @@
#endregion
+ #region Drawings
+
+ //worksheetPart.Worksheet.RemoveAllChildren();
+ //{
+ // OpenXmlElement previousElement = cm.GetPreviousElementFor(XLWSContentManager.XLWSContents.Drawing);
+ // worksheetPart.Worksheet.InsertAfter(new Drawing() { Id = String.Format("rId{0}", 1) }, previousElement);
+ //}
+
+ //Drawing drawing = worksheetPart.Worksheet.Elements().First();
+ //cm.SetElement(XLWSContentManager.XLWSContents.Drawing, drawing);
+
+ var pics = xlWorksheet.Pictures();
+ if (pics != null)
+ {
+ foreach (Drawings.IXLPicture pic in pics)
+ {
+ AddPictureAnchor(worksheetPart, pic);
+ }
+ }
+
+ if (xlWorksheet.Pictures().Count > 0)
+ {
+ Drawing worksheetDrawing = new Drawing { Id = worksheetPart.GetIdOfPart(worksheetPart.DrawingsPart) };
+ worksheetDrawing.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
+ worksheetPart.Worksheet.InsertBefore(worksheetDrawing, tableParts);
+ //worksheetPart.Worksheet.Append(worksheetDrawing);
+ }
+
+ #endregion
+
#region LegacyDrawing
if (xlWorksheet.LegacyDrawingIsNew)
diff --git a/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/Excel/XLWorksheet.cs
index 227ee49..12cce27 100644
--- a/ClosedXML/Excel/XLWorksheet.cs
+++ b/ClosedXML/Excel/XLWorksheet.cs
@@ -96,6 +96,7 @@
public Boolean LegacyDrawingIsNew;
private Double _columnWidth;
public XLWorksheetInternals Internals { get; private set; }
+ private List pictures;
public override IEnumerable Styles
{
@@ -1491,5 +1492,19 @@
}
public String Author { get; set; }
+
+ public List Pictures()
+ {
+ return pictures;
+ }
+
+ public void AddPicture(Drawings.XLPicture pic)
+ {
+ if (pictures == null)
+ {
+ pictures = new List();
+ }
+ pictures.Add(pic);
+ }
}
}