|  | /******************************************************************************* | 
|  | * You may amend and distribute as you like, but don't remove this header! | 
|  | * | 
|  | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
|  | * See http://www.codeplex.com/EPPlus for details. | 
|  | * | 
|  | * Copyright (C) 2011  Jan Källman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | * See the GNU Lesser General Public License for more details. | 
|  | * | 
|  | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
|  | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
|  | * | 
|  | * All code and executables are provided "as is" with no warranty either express or implied. | 
|  | * The author accepts no liability for any damage or loss of business that this product may cause. | 
|  | * | 
|  | * Code change notes: | 
|  | * | 
|  | * Author							Change						Date | 
|  | * ****************************************************************************** | 
|  | * Jan Källman		                Initial Release		        2009-12-22 | 
|  | * Jan Källman		License changed GPL-->LGPL 2011-12-16 | 
|  | *******************************************************************************/ | 
|  | using System; | 
|  | using System.Collections.Generic; | 
|  | using System.Text; | 
|  | using System.Xml; | 
|  | using System.Collections; | 
|  | using System.IO; | 
|  | using System.Drawing; | 
|  | using System.Linq; | 
|  | using OfficeOpenXml.Drawing.Chart; | 
|  | using OfficeOpenXml.Table.PivotTable; | 
|  | using OfficeOpenXml.Utils; | 
|  | namespace OfficeOpenXml.Drawing | 
|  | { | 
|  | /// <summary> | 
|  | /// Collection for Drawing objects. | 
|  | /// </summary> | 
|  | public class ExcelDrawings : IEnumerable<ExcelDrawing>, IDisposable | 
|  | { | 
|  | private XmlDocument _drawingsXml=new XmlDocument(); | 
|  | private Dictionary<string, int> _drawingNames; | 
|  | private List<ExcelDrawing> _drawings; | 
|  | internal class ImageCompare | 
|  | { | 
|  | internal byte[] image { get; set; } | 
|  | internal string relID { get; set; } | 
|  |  | 
|  | internal bool Comparer(byte[] compareImg) | 
|  | { | 
|  | if (compareImg.Length != image.Length) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < image.Length; i++) | 
|  | { | 
|  | if (image[i] != compareImg[i]) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; //Equal | 
|  | } | 
|  | } | 
|  | //internal List<ImageCompare> _pics = new List<ImageCompare>(); | 
|  | internal Dictionary<string, string> _hashes = new Dictionary<string, string>(); | 
|  | internal ExcelPackage _package; | 
|  | internal Packaging.ZipPackageRelationship _drawingRelation = null; | 
|  | internal ExcelDrawings(ExcelPackage xlPackage, ExcelWorksheet sheet) | 
|  | { | 
|  | _drawingsXml = new XmlDocument(); | 
|  | _drawingsXml.PreserveWhitespace = false; | 
|  | _drawings = new List<ExcelDrawing>(); | 
|  | _drawingNames = new Dictionary<string,int>(StringComparer.InvariantCultureIgnoreCase); | 
|  | _package = xlPackage; | 
|  | Worksheet = sheet; | 
|  | XmlNode node = sheet.WorksheetXml.SelectSingleNode("//d:drawing", sheet.NameSpaceManager); | 
|  | CreateNSM(); | 
|  | if (node != null) | 
|  | { | 
|  | _drawingRelation = sheet.Part.GetRelationship(node.Attributes["r:id"].Value); | 
|  | _uriDrawing = UriHelper.ResolvePartUri(sheet.WorksheetUri, _drawingRelation.TargetUri); | 
|  |  | 
|  | _part = xlPackage.Package.GetPart(_uriDrawing); | 
|  | XmlHelper.LoadXmlSafe(_drawingsXml, _part.GetStream()); | 
|  |  | 
|  | AddDrawings(); | 
|  | } | 
|  | } | 
|  | internal ExcelWorksheet Worksheet { get; set; } | 
|  | /// <summary> | 
|  | /// A reference to the drawing xml document | 
|  | /// </summary> | 
|  | public XmlDocument DrawingXml | 
|  | { | 
|  | get | 
|  | { | 
|  | return _drawingsXml; | 
|  | } | 
|  | } | 
|  | private void AddDrawings() | 
|  | { | 
|  | // Look inside all children for the drawings because they could be inside | 
|  | // Markup Compatibility AlternativeContent/Choice or AlternativeContent/Fallback nodes. | 
|  | // The code below currently pretends that loading all Choice alternative drawings doesn't cause a problem | 
|  | // elsewhere. This seems to be ok for the time being as encountered drawing files so far only seem to have | 
|  | // one Choice node (and no Fallback) underneath the AlternativeContent node. (Excel 2013 that is.) | 
|  | // This change prevents CodePlex issue #15028 from occurring. | 
|  | // (the drawing xml part (that ONLY contained AlternativeContent nodes) was incorrectly being garbage collected when the package was saved) | 
|  | XmlNodeList list = _drawingsXml.SelectNodes("//*[self::xdr:twoCellAnchor or self::xdr:oneCellAnchor or self::xdr:absoluteAnchor]", NameSpaceManager); | 
|  |  | 
|  | foreach (XmlNode node in list) | 
|  | { | 
|  |  | 
|  | ExcelDrawing dr; | 
|  | switch(node.LocalName) | 
|  | { | 
|  | case "oneCellAnchor": | 
|  | dr = new ExcelDrawing(this, node, "xdr:sp/xdr:nvSpPr/xdr:cNvPr/@name"); | 
|  | break; | 
|  | case "twoCellAnchor": | 
|  | dr = ExcelDrawing.GetDrawing(this, node); | 
|  | break; | 
|  | case "absoluteAnchor": | 
|  | dr = ExcelDrawing.GetDrawing(this, node); | 
|  | break; | 
|  | default: //"absoluteCellAnchor": | 
|  | dr = null; | 
|  | break; | 
|  | } | 
|  | if (dr != null) | 
|  | { | 
|  | _drawings.Add(dr); | 
|  | if (!_drawingNames.ContainsKey(dr.Name)) | 
|  | { | 
|  | _drawingNames.Add(dr.Name, _drawings.Count - 1); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #region NamespaceManager | 
|  | /// <summary> | 
|  | /// Creates the NamespaceManager. | 
|  | /// </summary> | 
|  | private void CreateNSM() | 
|  | { | 
|  | NameTable nt = new NameTable(); | 
|  | _nsManager = new XmlNamespaceManager(nt); | 
|  | _nsManager.AddNamespace("a", ExcelPackage.schemaDrawings); | 
|  | _nsManager.AddNamespace("xdr", ExcelPackage.schemaSheetDrawings); | 
|  | _nsManager.AddNamespace("c", ExcelPackage.schemaChart); | 
|  | _nsManager.AddNamespace("r", ExcelPackage.schemaRelationships); | 
|  | } | 
|  | /// <summary> | 
|  | /// Provides access to a namespace manager instance to allow XPath searching | 
|  | /// </summary> | 
|  | XmlNamespaceManager _nsManager=null; | 
|  | public XmlNamespaceManager NameSpaceManager | 
|  | { | 
|  | get | 
|  | { | 
|  | return _nsManager; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | #region IEnumerable Members | 
|  |  | 
|  | public IEnumerator GetEnumerator() | 
|  | { | 
|  | return (_drawings.GetEnumerator()); | 
|  | } | 
|  | #region IEnumerable<ExcelDrawing> Members | 
|  |  | 
|  | IEnumerator<ExcelDrawing> IEnumerable<ExcelDrawing>.GetEnumerator() | 
|  | { | 
|  | return (_drawings.GetEnumerator()); | 
|  | } | 
|  |  | 
|  | #endregion | 
|  |  | 
|  | /// <summary> | 
|  | /// Returns the drawing at the specified position. | 
|  | /// </summary> | 
|  | /// <param name="PositionID">The position of the drawing. 0-base</param> | 
|  | /// <returns></returns> | 
|  | public ExcelDrawing this[int PositionID] | 
|  | { | 
|  | get | 
|  | { | 
|  | return (_drawings[PositionID]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Returns the drawing matching the specified name | 
|  | /// </summary> | 
|  | /// <param name="Name">The name of the worksheet</param> | 
|  | /// <returns></returns> | 
|  | public ExcelDrawing this[string Name] | 
|  | { | 
|  | get | 
|  | { | 
|  | if (_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | return _drawings[_drawingNames[Name]]; | 
|  | } | 
|  | else | 
|  | { | 
|  | return null; | 
|  | } | 
|  | } | 
|  | } | 
|  | public int Count | 
|  | { | 
|  | get | 
|  | { | 
|  | if (_drawings == null) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | return _drawings.Count; | 
|  | } | 
|  | } | 
|  | } | 
|  | Packaging.ZipPackagePart _part=null; | 
|  | internal Packaging.ZipPackagePart Part | 
|  | { | 
|  | get | 
|  | { | 
|  | return _part; | 
|  | } | 
|  | } | 
|  | Uri _uriDrawing=null; | 
|  | public Uri UriDrawing | 
|  | { | 
|  | get | 
|  | { | 
|  | return _uriDrawing; | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | #region Add functions | 
|  | /// <summary> | 
|  | /// Add a new chart to the worksheet. | 
|  | /// Do not support Bubble-, Radar-, Stock- or Surface charts. | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="ChartType">Type of chart</param> | 
|  | /// <param name="PivotTableSource">The pivottable source for a pivotchart</param> | 
|  | /// <returns>The chart</returns> | 
|  | public ExcelChart AddChart(string Name, eChartType ChartType, ExcelPivotTable PivotTableSource) | 
|  | { | 
|  | if(_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | throw new Exception("Name already exists in the drawings collection"); | 
|  | } | 
|  |  | 
|  | if (ChartType == eChartType.StockHLC || | 
|  | ChartType == eChartType.StockOHLC || | 
|  | ChartType == eChartType.StockVOHLC) | 
|  | { | 
|  | throw(new NotImplementedException("Chart type is not supported in the current version")); | 
|  | } | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Chart Worksheets can't have more than one chart"); | 
|  | } | 
|  | XmlElement drawNode = CreateDrawingXml(); | 
|  |  | 
|  | ExcelChart chart = ExcelChart.GetNewChart(this, drawNode, ChartType, null, PivotTableSource); | 
|  | chart.Name = Name; | 
|  | _drawings.Add(chart); | 
|  | _drawingNames.Add(Name, _drawings.Count - 1); | 
|  | return chart; | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a new chart to the worksheet. | 
|  | /// Do not support Bubble-, Radar-, Stock- or Surface charts. | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="ChartType">Type of chart</param> | 
|  | /// <returns>The chart</returns> | 
|  | public ExcelChart AddChart(string Name, eChartType ChartType) | 
|  | { | 
|  | return AddChart(Name, ChartType, null); | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a picure to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="image">An image. Allways saved in then JPeg format</param> | 
|  | /// <returns></returns> | 
|  | public ExcelPicture AddPicture(string Name, Image image) | 
|  | { | 
|  | return AddPicture(Name, image, null); | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a picure to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="image">An image. Allways saved in then JPeg format</param> | 
|  | /// <param name="Hyperlink">Picture Hyperlink</param> | 
|  | /// <returns></returns> | 
|  | public ExcelPicture AddPicture(string Name, Image image, Uri Hyperlink) | 
|  | { | 
|  | if (image != null) | 
|  | { | 
|  | if (_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | throw new Exception("Name already exists in the drawings collection"); | 
|  | } | 
|  | XmlElement drawNode = CreateDrawingXml(); | 
|  | drawNode.SetAttribute("editAs", "oneCell"); | 
|  | ExcelPicture pic = new ExcelPicture(this, drawNode, image, Hyperlink); | 
|  | pic.Name = Name; | 
|  | _drawings.Add(pic); | 
|  | _drawingNames.Add(Name, _drawings.Count - 1); | 
|  | return pic; | 
|  | } | 
|  | throw (new Exception("AddPicture: Image can't be null")); | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a picure to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="ImageFile">The image file</param> | 
|  | /// <returns></returns> | 
|  | public ExcelPicture AddPicture(string Name, FileInfo ImageFile) | 
|  | { | 
|  | return AddPicture(Name, ImageFile, null); | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a picure to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name"></param> | 
|  | /// <param name="ImageFile">The image file</param> | 
|  | /// <param name="Hyperlink">Picture Hyperlink</param> | 
|  | /// <returns></returns> | 
|  | public ExcelPicture AddPicture(string Name, FileInfo ImageFile, Uri Hyperlink) | 
|  | { | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Chart worksheets can't have more than one drawing"); | 
|  | } | 
|  | if (ImageFile != null) | 
|  | { | 
|  | if (_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | throw new Exception("Name already exists in the drawings collection"); | 
|  | } | 
|  | XmlElement drawNode = CreateDrawingXml(); | 
|  | drawNode.SetAttribute("editAs", "oneCell"); | 
|  | ExcelPicture pic = new ExcelPicture(this, drawNode, ImageFile, Hyperlink); | 
|  | pic.Name = Name; | 
|  | _drawings.Add(pic); | 
|  | _drawingNames.Add(Name, _drawings.Count - 1); | 
|  | return pic; | 
|  | } | 
|  | throw (new Exception("AddPicture: ImageFile can't be null")); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Add a new shape to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name">Name</param> | 
|  | /// <param name="Style">Shape style</param> | 
|  | /// <returns>The shape object</returns> | 
|  |  | 
|  | public ExcelShape AddShape(string Name, eShapeStyle Style) | 
|  | { | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Chart worksheets can't have more than one drawing"); | 
|  | } | 
|  | if (_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | throw new Exception("Name already exists in the drawings collection"); | 
|  | } | 
|  | XmlElement drawNode = CreateDrawingXml(); | 
|  |  | 
|  | ExcelShape shape = new ExcelShape(this, drawNode, Style); | 
|  | shape.Name = Name; | 
|  | shape.Style = Style; | 
|  | _drawings.Add(shape); | 
|  | _drawingNames.Add(Name, _drawings.Count - 1); | 
|  | return shape; | 
|  | } | 
|  | /// <summary> | 
|  | /// Add a new shape to the worksheet | 
|  | /// </summary> | 
|  | /// <param name="Name">Name</param> | 
|  | /// <param name="Source">Source shape</param> | 
|  | /// <returns>The shape object</returns> | 
|  | public ExcelShape AddShape(string Name, ExcelShape Source) | 
|  | { | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Chart worksheets can't have more than one drawing"); | 
|  | } | 
|  | if (_drawingNames.ContainsKey(Name)) | 
|  | { | 
|  | throw new Exception("Name already exists in the drawings collection"); | 
|  | } | 
|  | XmlElement drawNode = CreateDrawingXml(); | 
|  | drawNode.InnerXml = Source.TopNode.InnerXml; | 
|  |  | 
|  | ExcelShape shape = new ExcelShape(this, drawNode); | 
|  | shape.Name = Name; | 
|  | shape.Style = Source.Style; | 
|  | _drawings.Add(shape); | 
|  | _drawingNames.Add(Name, _drawings.Count - 1); | 
|  | return shape; | 
|  | } | 
|  | private XmlElement CreateDrawingXml() | 
|  | { | 
|  | if (DrawingXml.OuterXml == "") | 
|  | { | 
|  | DrawingXml.LoadXml(string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><xdr:wsDr xmlns:xdr=\"{0}\" xmlns:a=\"{1}\" />", ExcelPackage.schemaSheetDrawings, ExcelPackage.schemaDrawings)); | 
|  | _uriDrawing = new Uri(string.Format("/xl/drawings/drawing{0}.xml", Worksheet.SheetID),UriKind.Relative); | 
|  |  | 
|  | Packaging.ZipPackage package = Worksheet._package.Package; | 
|  | _part = package.CreatePart(_uriDrawing, "application/vnd.openxmlformats-officedocument.drawing+xml", _package.Compression); | 
|  |  | 
|  | StreamWriter streamChart = new StreamWriter(_part.GetStream(FileMode.Create, FileAccess.Write)); | 
|  | DrawingXml.Save(streamChart); | 
|  | streamChart.Close(); | 
|  | package.Flush(); | 
|  |  | 
|  | _drawingRelation = Worksheet.Part.CreateRelationship(UriHelper.GetRelativeUri(Worksheet.WorksheetUri, _uriDrawing), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/drawing"); | 
|  | XmlElement e = Worksheet.WorksheetXml.CreateElement("drawing", ExcelPackage.schemaMain); | 
|  | e.SetAttribute("id",ExcelPackage.schemaRelationships, _drawingRelation.Id); | 
|  |  | 
|  | Worksheet.WorksheetXml.DocumentElement.AppendChild(e); | 
|  | package.Flush(); | 
|  | } | 
|  | XmlNode colNode = _drawingsXml.SelectSingleNode("//xdr:wsDr", NameSpaceManager); | 
|  | XmlElement drawNode; | 
|  | if (this.Worksheet is ExcelChartsheet) | 
|  | { | 
|  | drawNode = _drawingsXml.CreateElement("xdr", "absoluteAnchor", ExcelPackage.schemaSheetDrawings); | 
|  | XmlElement posNode = _drawingsXml.CreateElement("xdr", "pos", ExcelPackage.schemaSheetDrawings); | 
|  | posNode.SetAttribute("y", "0"); | 
|  | posNode.SetAttribute("x", "0"); | 
|  | drawNode.AppendChild(posNode); | 
|  | XmlElement extNode = _drawingsXml.CreateElement("xdr", "ext", ExcelPackage.schemaSheetDrawings); | 
|  | extNode.SetAttribute("cy", "6072876"); | 
|  | extNode.SetAttribute("cx", "9299263"); | 
|  | drawNode.AppendChild(extNode); | 
|  | colNode.AppendChild(drawNode); | 
|  | } | 
|  | else | 
|  | { | 
|  | drawNode = _drawingsXml.CreateElement("xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings); | 
|  | colNode.AppendChild(drawNode); | 
|  | //Add from position Element; | 
|  | XmlElement fromNode = _drawingsXml.CreateElement("xdr", "from", ExcelPackage.schemaSheetDrawings); | 
|  | drawNode.AppendChild(fromNode); | 
|  | fromNode.InnerXml = "<xdr:col>0</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>0</xdr:row><xdr:rowOff>0</xdr:rowOff>"; | 
|  |  | 
|  | //Add to position Element; | 
|  | XmlElement toNode = _drawingsXml.CreateElement("xdr", "to", ExcelPackage.schemaSheetDrawings); | 
|  | drawNode.AppendChild(toNode); | 
|  | toNode.InnerXml = "<xdr:col>10</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>10</xdr:row><xdr:rowOff>0</xdr:rowOff>"; | 
|  | } | 
|  |  | 
|  | return drawNode; | 
|  | } | 
|  | #endregion | 
|  | #region Remove methods | 
|  | /// <summary> | 
|  | /// Removes a drawing. | 
|  | /// </summary> | 
|  | /// <param name="Index">The index of the drawing</param> | 
|  | public void Remove(int Index) | 
|  | { | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Can' remove charts from chart worksheets"); | 
|  | } | 
|  | RemoveDrawing(Index); | 
|  | } | 
|  |  | 
|  | internal void RemoveDrawing(int Index) | 
|  | { | 
|  | var draw = _drawings[Index]; | 
|  | draw.DeleteMe(); | 
|  | for (int i = Index + 1; i < _drawings.Count; i++) | 
|  | { | 
|  | _drawingNames[_drawings[i].Name]--; | 
|  | } | 
|  | _drawingNames.Remove(draw.Name); | 
|  | _drawings.Remove(draw); | 
|  | } | 
|  | /// <summary> | 
|  | /// Removes a drawing. | 
|  | /// </summary> | 
|  | /// <param name="Drawing">The drawing</param> | 
|  | public void Remove(ExcelDrawing Drawing) | 
|  | { | 
|  | Remove(_drawingNames[Drawing.Name]); | 
|  | } | 
|  | /// <summary> | 
|  | /// Removes a drawing. | 
|  | /// </summary> | 
|  | /// <param name="Name">The name of the drawing</param> | 
|  | public void Remove(string Name) | 
|  | { | 
|  | Remove(_drawingNames[Name]); | 
|  | } | 
|  | /// <summary> | 
|  | /// Removes all drawings from the collection | 
|  | /// </summary> | 
|  | public void Clear() | 
|  | { | 
|  | if (Worksheet is ExcelChartsheet && _drawings.Count > 0) | 
|  | { | 
|  | throw new InvalidOperationException("Can' remove charts from chart worksheets"); | 
|  | } | 
|  | ClearDrawings(); | 
|  | } | 
|  |  | 
|  | internal void ClearDrawings() | 
|  | { | 
|  | while (Count > 0) | 
|  | { | 
|  | RemoveDrawing(0); | 
|  | } | 
|  | } | 
|  | #endregion | 
|  | internal void AdjustWidth(int[,] pos) | 
|  | { | 
|  | var ix = 0; | 
|  | //Now set the size for all drawings depending on the editAs property. | 
|  | foreach (OfficeOpenXml.Drawing.ExcelDrawing d in this) | 
|  | { | 
|  | if (d.EditAs != Drawing.eEditAs.TwoCell) | 
|  | { | 
|  | if (d.EditAs == Drawing.eEditAs.Absolute) | 
|  | { | 
|  | d.SetPixelLeft(pos[ix, 0]); | 
|  | } | 
|  | d.SetPixelWidth(pos[ix, 1]); | 
|  |  | 
|  | } | 
|  | ix++; | 
|  | } | 
|  | } | 
|  | internal void AdjustHeight(int[,] pos) | 
|  | { | 
|  | var ix = 0; | 
|  | //Now set the size for all drawings depending on the editAs property. | 
|  | foreach (OfficeOpenXml.Drawing.ExcelDrawing d in this) | 
|  | { | 
|  | if (d.EditAs != Drawing.eEditAs.TwoCell) | 
|  | { | 
|  | if (d.EditAs == Drawing.eEditAs.Absolute) | 
|  | { | 
|  | d.SetPixelTop(pos[ix, 0]); | 
|  | } | 
|  | d.SetPixelHeight(pos[ix, 1]); | 
|  |  | 
|  | } | 
|  | ix++; | 
|  | } | 
|  | } | 
|  | internal int[,] GetDrawingWidths() | 
|  | { | 
|  | int[,] pos = new int[Count, 2]; | 
|  | int ix = 0; | 
|  | //Save the size for all drawings | 
|  | foreach (ExcelDrawing d in this) | 
|  | { | 
|  | pos[ix, 0] = d.GetPixelLeft(); | 
|  | pos[ix++, 1] = d.GetPixelWidth(); | 
|  | } | 
|  | return pos; | 
|  | } | 
|  | internal int[,] GetDrawingHeight() | 
|  | { | 
|  | int[,] pos = new int[Count, 2]; | 
|  | int ix = 0; | 
|  | //Save the size for all drawings | 
|  | foreach (ExcelDrawing d in this) | 
|  | { | 
|  | pos[ix, 0] = d.GetPixelTop(); | 
|  | pos[ix++, 1] = d.GetPixelHeight(); | 
|  | } | 
|  | return pos; | 
|  | } | 
|  |  | 
|  | public void Dispose() | 
|  | { | 
|  | _drawingsXml = null; | 
|  | _hashes.Clear(); | 
|  | _hashes = null; | 
|  | _part = null; | 
|  | _drawingNames.Clear(); | 
|  | _drawingNames = null; | 
|  | _drawingRelation = null; | 
|  | foreach (var d in _drawings) | 
|  | { | 
|  | d.Dispose(); | 
|  | } | 
|  | _drawings.Clear(); | 
|  | _drawings = null; | 
|  | } | 
|  | } | 
|  | } |