diff --git a/ClosedXML/Excel/Drawings/IXLMarker.cs b/ClosedXML/Excel/Drawings/IXLMarker.cs index 3f2bb92..d5c2ef4 100644 --- a/ClosedXML/Excel/Drawings/IXLMarker.cs +++ b/ClosedXML/Excel/Drawings/IXLMarker.cs @@ -1,15 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Drawing; namespace ClosedXML.Excel.Drawings { internal interface IXLMarker { - Int32 ColumnId { get; set; } - Int32 RowId { get; set; } - Double ColumnOffset { get; set; } - Double RowOffset { get; set; } + IXLAddress Address { get; set; } + Point Offset { get; set; } } } diff --git a/ClosedXML/Excel/Drawings/IXLPicture.cs b/ClosedXML/Excel/Drawings/IXLPicture.cs index a4e0c48..d059776 100644 --- a/ClosedXML/Excel/Drawings/IXLPicture.cs +++ b/ClosedXML/Excel/Drawings/IXLPicture.cs @@ -1,11 +1,12 @@ using System; +using System.Drawing; using System.IO; namespace ClosedXML.Excel.Drawings { public interface IXLPicture : IDisposable { - IXLCell BottomRightCell { get; } + IXLAddress BottomRightCellAddress { get; } /// /// Type of image. The supported formats are defined by OpenXML's ImagePartType. @@ -13,29 +14,42 @@ /// XLPictureFormat Format { get; } - long Height { get; set; } + Int32 Height { get; set; } MemoryStream ImageStream { get; } - long Left { get; set; } + Int32 Left { get; set; } String Name { get; set; } - long OriginalHeight { get; } - long OriginalWidth { get; } + Int32 OriginalHeight { get; } + Int32 OriginalWidth { get; } XLPicturePlacement Placement { get; set; } - long Top { get; set; } - IXLCell TopLeftCell { get; } - long Width { get; set; } + Int32 Top { get; set; } + IXLAddress TopLeftCellAddress { get; } + Int32 Width { get; set; } + IXLWorksheet Worksheet { get; } - IXLPicture AtPosition(long left, long top); + Point GetOffset(XLMarkerPosition position); - IXLPicture AtPosition(IXLCell cell); + IXLPicture MoveTo(Int32 left, Int32 top); - IXLPicture AtPosition(IXLCell fromCell, IXLCell toCell); + IXLPicture MoveTo(IXLAddress cell); - void ScaleHeight(Double factor, Boolean relativeToOriginal = false); + IXLPicture MoveTo(IXLAddress cell, Int32 xOffset, Int32 yOffset); - void ScaleWidth(Double factor, Boolean relativeToOriginal = false); + IXLPicture MoveTo(IXLAddress cell, Point offset); + + IXLPicture MoveTo(IXLAddress fromCell, IXLAddress toCell); + + IXLPicture MoveTo(IXLAddress fromCell, Int32 fromCellXOffset, Int32 fromCellYOffset, IXLAddress toCell, Int32 toCellXOffset, Int32 toCellYOffset); + + IXLPicture MoveTo(IXLAddress fromCell, Point fromOffset, IXLAddress toCell, Point toOffset); + + IXLPicture Scale(Double factor, Boolean relativeToOriginal = false); + + IXLPicture ScaleHeight(Double factor, Boolean relativeToOriginal = false); + + IXLPicture ScaleWidth(Double factor, Boolean relativeToOriginal = false); IXLPicture WithPlacement(XLPicturePlacement value); - IXLPicture WithSize(long width, long height); + IXLPicture WithSize(Int32 width, Int32 height); } } diff --git a/ClosedXML/Excel/Drawings/PictureEnums.cs b/ClosedXML/Excel/Drawings/PictureEnums.cs index 4cd1fcf..3d76e73 100644 --- a/ClosedXML/Excel/Drawings/PictureEnums.cs +++ b/ClosedXML/Excel/Drawings/PictureEnums.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace ClosedXML.Excel.Drawings { + public enum XLMarkerPosition + { + TopLeft, + BottomRight + } + public enum XLPictureFormat { Bmp = 0, diff --git a/ClosedXML/Excel/Drawings/XLMarker.cs b/ClosedXML/Excel/Drawings/XLMarker.cs index 4934cad..f48bf5c 100644 --- a/ClosedXML/Excel/Drawings/XLMarker.cs +++ b/ClosedXML/Excel/Drawings/XLMarker.cs @@ -1,48 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Diagnostics; +using System.Drawing; namespace ClosedXML.Excel.Drawings { + [DebuggerDisplay("{Address} {Offset}")] internal class XLMarker : IXLMarker { - private Int32 colId; - private Int32 rowId; + internal XLMarker(IXLAddress address) + : this(address, new Point(0, 0)) + { } - public Int32 ColumnId + internal XLMarker(IXLAddress address, Point offset) { - set - { - if (value < 1 || value > XLHelper.MaxColumnNumber) - throw new ArgumentOutOfRangeException(String.Format("Column number must be between 1 and {0}", - XLHelper.MaxColumnNumber)); - this.colId = value; - } - get - { - return this.colId; - } + this.Address = address; + this.Offset = offset; } - public Int32 RowId - { - set - { - if (value < 1 || value > XLHelper.MaxRowNumber) - throw new ArgumentOutOfRangeException(String.Format("Row number must be between 1 and {0}", - XLHelper.MaxRowNumber)); - this.rowId = value; - } - get - { - return this.rowId; - } - } + public IXLAddress Address { get; set; } - public Double ColumnOffset { get; set; } - - public Double RowOffset { get; set; } - + public Point Offset { get; set; } } } diff --git a/ClosedXML/Excel/Drawings/XLPicture.cs b/ClosedXML/Excel/Drawings/XLPicture.cs index 6cf81fc..d591f8f 100644 --- a/ClosedXML/Excel/Drawings/XLPicture.cs +++ b/ClosedXML/Excel/Drawings/XLPicture.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -8,16 +9,13 @@ namespace ClosedXML.Excel.Drawings { + [DebuggerDisplay("{Name}")] internal class XLPicture : IXLPicture { private readonly IXLWorksheet _worksheet; - private XLPicture(IXLWorksheet worksheet) - { - if (worksheet == null) throw new ArgumentNullException(nameof(worksheet)); - this._worksheet = worksheet; - this.Placement = XLPicturePlacement.MoveAndSize; - } + private Int32 height; + private Int32 width; internal XLPicture(IXLWorksheet worksheet, Stream stream, XLPictureFormat format) : this(worksheet) @@ -27,6 +25,7 @@ this.ImageStream = new MemoryStream(); { + stream.Position = 0; stream.CopyTo(ImageStream); ImageStream.Seek(0, SeekOrigin.Begin); @@ -60,43 +59,38 @@ this.Format = Enum.Parse(typeof(XLPictureFormat), formats.Single().Name, true).CastTo(); } - public IXLCell BottomRightCell + private XLPicture(IXLWorksheet worksheet) + { + if (worksheet == null) throw new ArgumentNullException(nameof(worksheet)); + this._worksheet = worksheet; + this.Placement = XLPicturePlacement.MoveAndSize; + this.Markers = new Dictionary() + { + [XLMarkerPosition.TopLeft] = null, + [XLMarkerPosition.BottomRight] = null + }; + } + + public IXLAddress BottomRightCellAddress { get { - if (this.Markers.Count > 1) - { - var marker = this.Markers.Skip(1).First(); - return _worksheet.Cell(marker.RowId, marker.ColumnId); - } - else - return null; + return Markers[XLMarkerPosition.BottomRight].Address; } private set { - while (this.Markers.Count > 1) - { - this.Markers.RemoveAt(this.Markers.Count - 1); - } - - this.Markers.Add(new XLMarker() - { - ColumnId = value.WorksheetColumn().ColumnNumber(), - RowId = value.WorksheetRow().RowNumber() - }); + if (!value.Worksheet.Equals(this._worksheet)) + throw new ArgumentOutOfRangeException(nameof(value.Worksheet)); + this.Markers[XLMarkerPosition.BottomRight] = new XLMarker(value); } } public XLPictureFormat Format { get; private set; } - private long height; - public long Height + public Int32 Height { - get - { - return height; - } + get { return height; } set { if (this.Placement == XLPicturePlacement.MoveAndSize) @@ -107,73 +101,54 @@ public MemoryStream ImageStream { get; private set; } - public long left; - - public long Left + public Int32 Left { - get { return left; } + get { return Markers[XLMarkerPosition.TopLeft]?.Offset.X ?? 0; } set { if (this.Placement != XLPicturePlacement.FreeFloating) throw new ArgumentException("To set the left-hand offset, the placement should be FreeFloating"); - left = value; + + Markers[XLMarkerPosition.TopLeft] = new XLMarker(_worksheet.Cell(1, 1).Address, new Point(value, this.Top)); } } - public IList Markers { get; private set; } = new List(); public String Name { get; set; } - public long OriginalHeight { get; private set; } - - public long OriginalWidth { get; private set; } - + public Int32 OriginalHeight { get; private set; } + public Int32 OriginalWidth { get; private set; } public XLPicturePlacement Placement { get; set; } - private long top; - public long Top + public Int32 Top { - get { return top; } + get { return Markers[XLMarkerPosition.TopLeft]?.Offset.Y ?? 0; } set { if (this.Placement != XLPicturePlacement.FreeFloating) throw new ArgumentException("To set the top offset, the placement should be FreeFloating"); - top = value; + + Markers[XLMarkerPosition.TopLeft] = new XLMarker(_worksheet.Cell(1, 1).Address, new Point(this.Left, value)); } } - public IXLCell TopLeftCell + public IXLAddress TopLeftCellAddress { get { - if (this.Markers.Any()) - { - var marker = this.Markers.First(); - return _worksheet.Cell(marker.RowId, marker.ColumnId); - } - else - return null; + return Markers[XLMarkerPosition.TopLeft].Address; } private set { - if (this.Markers.Any()) - this.Markers.RemoveAt(0); + if (!value.Worksheet.Equals(this._worksheet)) + throw new ArgumentOutOfRangeException(nameof(value.Worksheet)); - this.Markers.Insert(0, new XLMarker() - { - ColumnId = value.WorksheetColumn().ColumnNumber(), - RowId = value.WorksheetRow().RowNumber() - }); + this.Markers[XLMarkerPosition.TopLeft] = new XLMarker(value); } } - private long width; - - public long Width + public Int32 Width { - get - { - return width; - } + get { return width; } set { if (this.Placement == XLPicturePlacement.MoveAndSize) @@ -182,7 +157,24 @@ } } - public IXLPicture AtPosition(long left, long top) + public IXLWorksheet Worksheet + { + get { return _worksheet; } + } + + internal IDictionary Markers { get; private set; } + + public void Dispose() + { + this.ImageStream.Dispose(); + } + + public Point GetOffset(XLMarkerPosition position) + { + return Markers[position].Offset; + } + + public IXLPicture MoveTo(Int32 left, Int32 top) { this.Placement = XLPicturePlacement.FreeFloating; this.Left = left; @@ -190,39 +182,65 @@ return this; } - public IXLPicture AtPosition(IXLCell cell) + public IXLPicture MoveTo(IXLAddress cell) + { + return MoveTo(cell, 0, 0); + } + + public IXLPicture MoveTo(IXLAddress cell, Int32 xOffset, Int32 yOffset) + { + return MoveTo(cell, new Point(xOffset, yOffset)); + } + + public IXLPicture MoveTo(IXLAddress cell, Point offset) { if (cell == null) throw new ArgumentNullException(nameof(cell)); this.Placement = XLPicturePlacement.Move; - this.TopLeftCell = cell; + this.TopLeftCellAddress = cell; + this.Markers[XLMarkerPosition.TopLeft].Offset = offset; return this; } - public IXLPicture AtPosition(IXLCell fromCell, IXLCell toCell) + public IXLPicture MoveTo(IXLAddress fromCell, IXLAddress toCell) + { + return MoveTo(fromCell, 0, 0, toCell, 0, 0); + } + + public IXLPicture MoveTo(IXLAddress fromCell, Int32 fromCellXOffset, Int32 fromCellYOffset, IXLAddress toCell, Int32 toCellXOffset, Int32 toCellYOffset) + { + return MoveTo(fromCell, new Point(fromCellXOffset, fromCellYOffset), toCell, new Point(toCellXOffset, toCellYOffset)); + } + + public IXLPicture MoveTo(IXLAddress fromCell, Point fromOffset, IXLAddress toCell, Point toOffset) { if (fromCell == null) throw new ArgumentNullException(nameof(fromCell)); + if (toCell == null) throw new ArgumentNullException(nameof(toCell)); this.Placement = XLPicturePlacement.MoveAndSize; - this.TopLeftCell = fromCell; - if (toCell != null) - this.BottomRightCell = toCell; + this.TopLeftCellAddress = fromCell; + this.Markers[XLMarkerPosition.TopLeft].Offset = fromOffset; + + this.BottomRightCellAddress = toCell; + this.Markers[XLMarkerPosition.BottomRight].Offset = toOffset; return this; } - public void Dispose() + public IXLPicture Scale(Double factor, Boolean relativeToOriginal = false) { - this.ImageStream.Dispose(); + return this.ScaleHeight(factor, relativeToOriginal).ScaleWidth(factor, relativeToOriginal); } - public void ScaleHeight(Double factor, Boolean relativeToOriginal = false) + public IXLPicture ScaleHeight(Double factor, Boolean relativeToOriginal = false) { - this.Height = Convert.ToInt64((relativeToOriginal ? this.OriginalHeight : this.Height) * factor); + this.Height = Convert.ToInt32((relativeToOriginal ? this.OriginalHeight : this.Height) * factor); + return this; } - public void ScaleWidth(Double factor, Boolean relativeToOriginal = false) + public IXLPicture ScaleWidth(Double factor, Boolean relativeToOriginal = false) { - this.Width = Convert.ToInt64((relativeToOriginal ? this.OriginalWidth : this.Width) * factor); + this.Width = Convert.ToInt32((relativeToOriginal ? this.OriginalWidth : this.Width) * factor); + return this; } public IXLPicture WithPlacement(XLPicturePlacement value) @@ -231,7 +249,7 @@ return this; } - public IXLPicture WithSize(long width, long height) + public IXLPicture WithSize(Int32 width, Int32 height) { this.Width = width; this.Height = height; diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs index e74db1d..457ecbc 100644 --- a/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/Excel/XLWorkbook_Save.cs @@ -2590,22 +2590,22 @@ break; case Drawings.XLPicturePlacement.MoveAndSize: - var moveAndSizeFromMarker = pic.Markers.First(); + var moveAndSizeFromMarker = pic.Markers[Drawings.XLMarkerPosition.TopLeft]; fMark = new Xdr.FromMarker { - ColumnId = new Xdr.ColumnId((moveAndSizeFromMarker.ColumnId - 1).ToString()), - RowId = new Xdr.RowId((moveAndSizeFromMarker.RowId - 1).ToString()), - ColumnOffset = new Xdr.ColumnOffset((moveAndSizeFromMarker.ColumnOffset + pic.Left).ToString()), - RowOffset = new Xdr.RowOffset((moveAndSizeFromMarker.RowOffset + pic.Top).ToString()) + ColumnId = new Xdr.ColumnId((moveAndSizeFromMarker.Address.ColumnNumber - 1).ToString()), + RowId = new Xdr.RowId((moveAndSizeFromMarker.Address.RowNumber - 1).ToString()), + ColumnOffset = new Xdr.ColumnOffset(ConvertToEnglishMetricUnits(moveAndSizeFromMarker.Offset.X, GraphicsUtils.Graphics.DpiX).ToString()), + RowOffset = new Xdr.RowOffset(ConvertToEnglishMetricUnits(moveAndSizeFromMarker.Offset.Y, GraphicsUtils.Graphics.DpiY).ToString()) }; - var moveAndSizeToMarker = pic.Markers.Last(); + var moveAndSizeToMarker = pic.Markers[Drawings.XLMarkerPosition.BottomRight]; tMark = new Xdr.ToMarker { - ColumnId = new Xdr.ColumnId((moveAndSizeToMarker.ColumnId - 1).ToString()), - RowId = new Xdr.RowId((moveAndSizeToMarker.RowId - 1).ToString()), - ColumnOffset = new Xdr.ColumnOffset((moveAndSizeToMarker.ColumnOffset + pic.Left).ToString()), - RowOffset = new Xdr.RowOffset((moveAndSizeToMarker.RowOffset + pic.Top).ToString()) + ColumnId = new Xdr.ColumnId((moveAndSizeToMarker.Address.ColumnNumber - 1).ToString()), + RowId = new Xdr.RowId((moveAndSizeToMarker.Address.RowNumber - 1).ToString()), + ColumnOffset = new Xdr.ColumnOffset(ConvertToEnglishMetricUnits(moveAndSizeToMarker.Offset.X, GraphicsUtils.Graphics.DpiX).ToString()), + RowOffset = new Xdr.RowOffset(ConvertToEnglishMetricUnits(moveAndSizeToMarker.Offset.Y, GraphicsUtils.Graphics.DpiY).ToString()) }; var twoCellAnchor = new Xdr.TwoCellAnchor( @@ -2635,13 +2635,13 @@ break; case Drawings.XLPicturePlacement.Move: - var moveFromMarker = pic.Markers.First(); + var moveFromMarker = pic.Markers[Drawings.XLMarkerPosition.TopLeft]; fMark = new Xdr.FromMarker { - ColumnId = new Xdr.ColumnId((moveFromMarker.ColumnId - 1).ToString()), - RowId = new Xdr.RowId((moveFromMarker.RowId - 1).ToString()), - ColumnOffset = new Xdr.ColumnOffset((moveFromMarker.ColumnOffset + pic.Left).ToString()), - RowOffset = new Xdr.RowOffset((moveFromMarker.RowOffset + pic.Top).ToString()) + ColumnId = new Xdr.ColumnId((moveFromMarker.Address.ColumnNumber - 1).ToString()), + RowId = new Xdr.RowId((moveFromMarker.Address.RowNumber - 1).ToString()), + ColumnOffset = new Xdr.ColumnOffset(ConvertToEnglishMetricUnits(moveFromMarker.Offset.X + pic.Left, GraphicsUtils.Graphics.DpiX).ToString()), + RowOffset = new Xdr.RowOffset(ConvertToEnglishMetricUnits(moveFromMarker.Offset.Y + pic.Top, GraphicsUtils.Graphics.DpiY).ToString()) }; var oneCellAnchor = new Xdr.OneCellAnchor( diff --git a/ClosedXML_Examples/ClosedXML_Examples.csproj b/ClosedXML_Examples/ClosedXML_Examples.csproj index de7cb8e..16e493e 100644 --- a/ClosedXML_Examples/ClosedXML_Examples.csproj +++ b/ClosedXML_Examples/ClosedXML_Examples.csproj @@ -185,6 +185,9 @@ + + +