Skip to content

Commit 2014c6b

Browse files
authored
Merge pull request #1149 from EPPlusSoftware/bug/copy_fixes
Fix some issues when copying worksheets
2 parents 2fbb5e9 + 1f7bae2 commit 2014c6b

13 files changed

+265
-155
lines changed

src/EPPlus/Core/Worksheet/WorksheetCopyHelper.cs

+165-120
Large diffs are not rendered by default.

src/EPPlus/Drawing/ExcelPicture.cs

+20-12
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,19 @@ public sealed class ExcelPicture : ExcelDrawing, IPictureContainer
3232
{
3333
#region "Constructors"
3434
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, Uri hyperlink, ePictureType type) :
35-
base(drawings, node, "xdr:pic", "xdr:nvPicPr/xdr:cNvPr")
35+
base(drawings, node, "xdr:pic/", "xdr:nvPicPr/xdr:cNvPr")
3636
{
37+
Init();
3738
CreatePicNode(node,type);
3839
Hyperlink = hyperlink;
3940
Image = new ExcelImage(this);
4041
}
4142

4243
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, ExcelGroupShape shape = null) :
43-
base(drawings, node, "xdr:pic", "xdr:nvPicPr/xdr:cNvPr", shape)
44+
base(drawings, node, shape==null ? "xdr:pic/" : "", "xdr:nvPicPr/xdr:cNvPr", shape)
4445
{
45-
XmlNode picNode = node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip", drawings.NameSpaceManager);
46+
Init();
47+
XmlNode picNode = node.SelectSingleNode($"{_topPath}xdr:blipFill/a:blip", drawings.NameSpaceManager);
4648
if (picNode != null && picNode.Attributes["embed", ExcelPackage.schemaRelationships] != null)
4749
{
4850
IPictureContainer container = this;
@@ -78,14 +80,20 @@ internal ExcelPicture(ExcelDrawings drawings, XmlNode node, ExcelGroupShape shap
7880
container.ImageHash = ii.Hash;
7981
}
8082
}
83+
private void Init()
84+
{
85+
_lockAspectRatioPath = $"{_topPath}xdr:nvPicPr/xdr:cNvPicPr/a:picLocks/@noChangeAspect";
86+
_preferRelativeResizePath = $"{_topPath}xdr:nvPicPr/xdr:cNvPicPr/@preferRelativeResize";
87+
}
88+
8189
private void SetRelId(XmlNode node, ePictureType type, string relID)
8290
{
8391
//Create relationship
84-
node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relID;
92+
node.SelectSingleNode($"{_topPath}xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relID;
8593

8694
if (type == ePictureType.Svg)
8795
{
88-
node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip/@r:embed", NameSpaceManager).Value = relID;
96+
node.SelectSingleNode($"{_topPath}xdr:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip/@r:embed", NameSpaceManager).Value = relID;
8997
}
9098
}
9199

@@ -269,7 +277,7 @@ public ExcelDrawingFill Fill
269277
{
270278
if (_fill == null)
271279
{
272-
_fill = new ExcelDrawingFill(_drawings, NameSpaceManager, TopNode, "xdr:pic/xdr:spPr", SchemaNodeOrder);
280+
_fill = new ExcelDrawingFill(_drawings, NameSpaceManager, TopNode, $"{_topPath}xdr:spPr", SchemaNodeOrder);
273281
}
274282
return _fill;
275283
}
@@ -284,7 +292,7 @@ public ExcelDrawingBorder Border
284292
{
285293
if (_border == null)
286294
{
287-
_border = new ExcelDrawingBorder(_drawings, NameSpaceManager, TopNode, "xdr:pic/xdr:spPr/a:ln", SchemaNodeOrder);
295+
_border = new ExcelDrawingBorder(_drawings, NameSpaceManager, TopNode, $"{_topPath}xdr:spPr/a:ln", SchemaNodeOrder);
288296
}
289297
return _border;
290298
}
@@ -299,12 +307,12 @@ public ExcelDrawingEffectStyle Effect
299307
{
300308
if (_effect == null)
301309
{
302-
_effect = new ExcelDrawingEffectStyle(_drawings, NameSpaceManager, TopNode, "xdr:pic/xdr:spPr/a:effectLst", SchemaNodeOrder);
310+
_effect = new ExcelDrawingEffectStyle(_drawings, NameSpaceManager, TopNode, $"{_topPath}xdr:spPr/a:effectLst", SchemaNodeOrder);
303311
}
304312
return _effect;
305313
}
306314
}
307-
const string _preferRelativeResizePath = "xdr:pic/xdr:nvPicPr/xdr:cNvPicPr/@preferRelativeResize";
315+
string _preferRelativeResizePath;
308316
/// <summary>
309317
/// Relative to original picture size
310318
/// </summary>
@@ -319,7 +327,7 @@ public bool PreferRelativeResize
319327
SetXmlNodeBool(_preferRelativeResizePath, value);
320328
}
321329
}
322-
const string _lockAspectRatioPath = "xdr:pic/xdr:nvPicPr/xdr:cNvPicPr/a:picLocks/@noChangeAspect";
330+
string _lockAspectRatioPath;
323331
/// <summary>
324332
/// Lock aspect ratio
325333
/// </summary>
@@ -380,10 +388,10 @@ void IPictureContainer.RemoveImage()
380388
void IPictureContainer.SetNewImage()
381389
{
382390
var relId = ((IPictureContainer)this).RelPic.Id;
383-
TopNode.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relId;
391+
TopNode.SelectSingleNode($"{_topPath}xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relId;
384392
if (Image.Type == ePictureType.Svg)
385393
{
386-
TopNode.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip/@r:embed", NameSpaceManager).Value = relId;
394+
TopNode.SelectSingleNode($"{_topPath}xdr:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip/@r:embed", NameSpaceManager).Value = relId;
387395
}
388396
}
389397

src/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Date Author Change
1818
using OfficeOpenXml.Utils;
1919
using System.IO;
2020
using OfficeOpenXml.Constants;
21+
using OfficeOpenXml.Drawing.Interfaces;
22+
using OfficeOpenXml.Packaging;
2123

2224
namespace OfficeOpenXml.Drawing.Vml
2325
{

src/EPPlus/Drawing/Vml/ExcelVmlDrawingPicture.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -343,19 +343,19 @@ IPictureRelationDocument RelationDocument
343343
{
344344
get
345345
{
346-
return _worksheet.VmlDrawings;
346+
return _worksheet.HeaderFooter._vmlDrawingsHF;
347347
}
348348
}
349349

350350
string ImageHash { get; set; }
351351
Uri UriPic { get; set; }
352352
Packaging.ZipPackageRelationship RelPic { get; set; }
353353

354-
IPictureRelationDocument IPictureContainer.RelationDocument => throw new NotImplementedException();
354+
IPictureRelationDocument IPictureContainer.RelationDocument => _worksheet.HeaderFooter._vmlDrawingsHF;
355355

356-
string IPictureContainer.ImageHash { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
357-
Uri IPictureContainer.UriPic { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
358-
Packaging.ZipPackageRelationship IPictureContainer.RelPic { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
356+
string IPictureContainer.ImageHash { get; set; }
357+
Uri IPictureContainer.UriPic { get; set; }
358+
Packaging.ZipPackageRelationship IPictureContainer.RelPic { get; set; }
359359

360360
void IPictureContainer.RemoveImage()
361361
{

src/EPPlus/Drawing/Vml/ExcelVmlDrawingPictureCollection.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,18 @@ Date Author Change
1717
using System.Collections;
1818
using System.Globalization;
1919
using OfficeOpenXml.Utils;
20+
using OfficeOpenXml.Drawing.Interfaces;
21+
using OfficeOpenXml.Packaging;
2022

2123
namespace OfficeOpenXml.Drawing.Vml
2224
{
2325
/// <summary>
2426
/// A collection of vml drawings used for header and footer picturess
2527
/// </summary>
26-
public class ExcelVmlDrawingPictureCollection : ExcelVmlDrawingBaseCollection, IEnumerable
28+
public class ExcelVmlDrawingPictureCollection : ExcelVmlDrawingBaseCollection, IEnumerable, IPictureRelationDocument
2729
{
2830
internal List<ExcelVmlDrawingPicture> _images;
31+
Dictionary<string, HashInfo> _hashes = new Dictionary<string, HashInfo>();
2932
internal ExcelVmlDrawingPictureCollection(ExcelWorksheet ws, Uri uri) :
3033
base(ws, uri, "d:legacyDrawingHF/@r:id")
3134
{
@@ -149,5 +152,12 @@ IEnumerator IEnumerable.GetEnumerator()
149152
}
150153

151154
#endregion
155+
ExcelPackage IPictureRelationDocument.Package => _package;
156+
157+
Dictionary<string, HashInfo> IPictureRelationDocument.Hashes => _hashes;
158+
159+
ZipPackagePart IPictureRelationDocument.RelatedPart => Part;
160+
161+
Uri IPictureRelationDocument.RelatedUri => Uri;
152162
}
153163
}

src/EPPlus/EPPlus.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@
480480
</ItemGroup>
481481

482482
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
483-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.30" />
483+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.32" />
484484
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream">
485485
<Version>2.2.1</Version>
486486
</PackageReference>
@@ -496,7 +496,7 @@
496496
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream">
497497
<Version>2.2.1</Version>
498498
</PackageReference>
499-
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.3" />
499+
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.4" />
500500
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
501501
</ItemGroup>
502502

@@ -505,7 +505,7 @@
505505
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream">
506506
<Version>2.2.1</Version>
507507
</PackageReference>
508-
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="7.0.2" />
508+
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="7.0.3" />
509509
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
510510
</ItemGroup>
511511

src/EPPlus/ExcelHeaderFooter.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public ExcelVmlDrawingPicture InsertPicture(Stream PictureStream, ePictureType p
131131
var imgBytes=new byte[PictureStream.Length];
132132
PictureStream.Seek(0, SeekOrigin.Begin);
133133
PictureStream.Read(imgBytes,0, imgBytes.Length);
134-
var ii = _ws.Workbook._package.PictureStore.AddImage(imgBytes,null, pictureType);
134+
var ii = _ws.Workbook._package.PictureStore.AddImage(imgBytes, null, pictureType);
135135

136136
return AddImage(id, ii);
137137
}
@@ -429,7 +429,7 @@ public ExcelHeaderFooterText FirstFooter
429429
return _firstFooter;
430430
}
431431
}
432-
private ExcelVmlDrawingPictureCollection _vmlDrawingsHF = null;
432+
internal ExcelVmlDrawingPictureCollection _vmlDrawingsHF = null;
433433
/// <summary>
434434
/// Vml drawings. Underlaying object for Header footer images
435435
/// </summary>

src/EPPlus/ExcelPackage.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,8 @@ public void Dispose()
843843
{
844844
if (_isExternalStream==false && _stream != null && (_stream.CanRead || _stream.CanWrite))
845845
{
846-
CloseStream();
846+
_stream.Close();
847+
_stream.Dispose();
847848
}
848849
_zipPackage.Close();
849850
if(_workbook != null)
@@ -1228,7 +1229,7 @@ private void CheckNotDisposed()
12281229
/// </summary>
12291230
/// <param name="input">The input.</param>
12301231
public void Load(Stream input)
1231-
{
1232+
{
12321233
Load(input, RecyclableMemory.GetStream(), null);
12331234
}
12341235
/// <summary>
@@ -1248,6 +1249,7 @@ public void Load(Stream input, string Password)
12481249
/// <param name="Password"></param>
12491250
private void Load(Stream input, Stream output, string Password)
12501251
{
1252+
12511253
ReleaseResources();
12521254
if (input.CanSeek && input.Length == 0) // Template is blank, Construct new
12531255
{

src/EPPlus/ExcelWorksheet.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ internal string CodeModuleName
11101110
}
11111111
set
11121112
{
1113-
SetXmlNodeString(codeModuleNamePath, value);
1113+
SetXmlNodeString(codeModuleNamePath, value, true);
11141114
}
11151115
}
11161116
internal void CodeNameChange(string value)

src/EPPlus/ExcelWorksheets.cs

+4
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ private ExcelWorksheet AddSheet(string Name, bool isChart, eChartType? chartType
180180
_pck.Workbook.VbaProject.Modules.Add(new ExcelVBAModule(worksheet.CodeNameChange) { Name = name, Code = "", Attributes = _pck.Workbook.VbaProject.GetDocumentAttributes(Name, "0{00020820-0000-0000-C000-000000000046}"), Type = eModuleType.Document, HelpContext = 0 });
181181
worksheet.CodeModuleName = name;
182182
}
183+
else
184+
{
185+
worksheet.CodeModuleName = null;
186+
}
183187

184188
return worksheet;
185189
}

src/EPPlus/Packaging/ZipPackagePart.cs

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ internal Stream Stream
5050
}
5151
set
5252
{
53+
if(_stream!=null)
54+
{
55+
_stream.Close();
56+
_stream.Dispose();
57+
}
5358
_stream = value;
5459
}
5560
}

src/EPPlus/WorksheetZipStream.cs

+17-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Date Author Change
1717

1818
namespace OfficeOpenXml
1919
{
20-
internal class WorksheetZipStream : Stream
20+
internal class WorksheetZipStream : Stream, IDisposable
2121
{
2222
RollingBuffer _rollingBuffer = new RollingBuffer(8192 * 2); //Zip stream buffer is 8K, so we use the double here so we preserve any values from previous read.
2323
private Stream _stream;
@@ -43,7 +43,7 @@ public override void Flush()
4343
}
4444
public override int Read(byte[] buffer, int offset, int count)
4545
{
46-
if(_stream.Length > 0 && _stream.Position + count > _stream.Length)
46+
if (_stream.Length > 0 && _stream.Position + count > _stream.Length)
4747
{
4848
count = (int)(_stream.Length - _stream.Position);
4949
}
@@ -223,7 +223,7 @@ internal string ReadFromEndElement(string endElement, string startXml = "", stri
223223
WriteToBuffer = writeToBuffer;
224224
return startXml + xml;
225225
}
226-
internal string ReadToExt(string startXml, string uriValue, ref string lastElement, string lastUri="")
226+
internal string ReadToExt(string startXml, string uriValue, ref string lastElement, string lastUri = "")
227227
{
228228
Buffer.Flush();
229229
var xml = System.Text.Encoding.UTF8.GetString(((MemoryStream)Buffer.BaseStream).ToArray());
@@ -232,13 +232,13 @@ internal string ReadToExt(string startXml, string uriValue, ref string lastEleme
232232
{
233233
var lastExtStartIx = GetXmlIndex(xml, lastUri);
234234
int endExtIx;
235-
if(lastExtStartIx < 0)
235+
if (lastExtStartIx < 0)
236236
{
237237
endExtIx = FindElementPos(xml, "ext", false);
238238
}
239239
else
240240
{
241-
endExtIx = FindElementPos(xml, "ext", false, lastExtStartIx+4);
241+
endExtIx = FindElementPos(xml, "ext", false, lastExtStartIx + 4);
242242
}
243243
xml = xml.Substring(endExtIx);
244244
}
@@ -287,16 +287,16 @@ private int GetXmlIndex(string xml, string uriValue)
287287
private bool HasExtElementUri(string elementString, string uriValue)
288288
{
289289
if (elementString.StartsWith("</")) return false; //An endtag, return false;
290-
var ix=elementString.IndexOf("uri");
290+
var ix = elementString.IndexOf("uri");
291291
var pc = elementString[ix - 1];
292292
var nc = elementString[ix + 3];
293-
if(char.IsWhiteSpace(pc) && (char.IsWhiteSpace(nc) || nc=='='))
293+
if (char.IsWhiteSpace(pc) && (char.IsWhiteSpace(nc) || nc == '='))
294294
{
295295
ix = elementString.IndexOf('=', ix + 1);
296296
var ixAttrStart = elementString.IndexOf('"', ix + 1) + 1;
297297
var ixAttrEnd = elementString.IndexOf('"', ixAttrStart + 1) - 1;
298298

299-
var uri = elementString.Substring(ixAttrStart, ixAttrEnd - ixAttrStart+1);
299+
var uri = elementString.Substring(ixAttrStart, ixAttrEnd - ixAttrStart + 1);
300300
return uriValue.Equals(uri, StringComparison.OrdinalIgnoreCase);
301301
}
302302
return false;
@@ -310,7 +310,7 @@ private bool HasExtElementUri(string elementString, string uriValue)
310310
/// <param name="returnStartPos">If the position before the start element is returned. If false the end of the end element is returned.</param>
311311
/// <param name="ix">the index</param>
312312
/// <returns>The position of the element in the input xml</returns>
313-
private int FindElementPos(string xml, string element, bool returnStartPos = true, int ix=0)
313+
private int FindElementPos(string xml, string element, bool returnStartPos = true, int ix = 0)
314314
{
315315
while (true)
316316
{
@@ -347,5 +347,13 @@ private int FindElementPos(string xml, string element, bool returnStartPos = tru
347347
ix += element.Length;
348348
}
349349
}
350+
/// <summary>
351+
/// Disposes resources.
352+
/// </summary>
353+
public void Dispose()
354+
{
355+
base.Dispose();
356+
Buffer.BaseStream.Dispose();
357+
}
350358
}
351359
}

src/EPPlusTest/Issues.cs

+26
Original file line numberDiff line numberDiff line change
@@ -5504,5 +5504,31 @@ public void s542()
55045504
SaveAndCleanup(destinationpackage);
55055505
}
55065506
}
5507+
[TestMethod]
5508+
public void GroupDrawingIssue()
5509+
{
5510+
using (var p = OpenTemplatePackage("pic_shape_grouped2.xlsx"))
5511+
{
5512+
var ws = p.Workbook.Worksheets[0];
5513+
var grpSp = (ExcelGroupShape)ws.Drawings[0];
5514+
var d = grpSp.Drawings[0];
5515+
5516+
p.Workbook.Worksheets.Add("Sheet2", ws);
5517+
SaveAndCleanup(p);
5518+
}
5519+
}
5520+
[TestMethod]
5521+
public void i1146()
5522+
{
5523+
using (var p1 = OpenTemplatePackage("HeaderFooterTest.xlsx"))
5524+
{
5525+
using (var p2 = new ExcelPackage())
5526+
{
5527+
var ws = p1.Workbook.Worksheets[0];
5528+
p2.Workbook.Worksheets.Add("sheet1", ws);
5529+
SaveWorkbook("HeaderFooterSaved.xlsx", p2);
5530+
}
5531+
}
5532+
}
55075533
}
55085534
}

0 commit comments

Comments
 (0)