Open-XML-SDK
Open-XML-SDK copied to clipboard
Cloning sheet doesn't clone Drawing part
Describe the bug I have a template xlsx file, with template sheet, which in turn are cloned and their content is replaced ie. Cell values and images. After opening the file, the cell values are unique for each cloned Sheet except for the images which are the same, namely the last replaced image.
Screenshots
To Reproduce I have this code which clones a given Sheet:
public static async void CloneSheet(SpreadsheetDocument spreadSheet, string sheetName, string newSheetName) {
// Get the source sheet
var sheets = spreadSheet.WorkbookPart.Workbook.Sheets;
var sourceSheet = sheets.Elements<Sheet>().FirstOrDefault(s => s.Name == sheetName);
if (sourceSheet == null) {
throw new ArgumentException($"Sheet with name {sheetName} does not exist.");
}
// Get the source worksheet part
var sourceSheetPart = (WorksheetPart)spreadSheet.WorkbookPart.GetPartById(sourceSheet.Id);
// Create a new worksheet part
var newSheetPart = spreadSheet.WorkbookPart.AddNewPart<WorksheetPart>();
newSheetPart.Worksheet = (Worksheet)sourceSheetPart.Worksheet.Clone();
// Clone the relationships
foreach (var rel in sourceSheetPart.Parts) {
newSheetPart.AddPart(rel.OpenXmlPart, rel.RelationshipId);
}
// Clone DrawingsPart and its related ImageParts
if (sourceSheetPart.DrawingsPart != null) {
var sourceDrawingsPart = sourceSheetPart.DrawingsPart;
DrawingsPart newDrawingsPart;
if (newSheetPart.DrawingsPart == null) {
newDrawingsPart = newSheetPart.AddNewPart<DrawingsPart>();
} else {
newDrawingsPart = newSheetPart.DrawingsPart;
}
newDrawingsPart.WorksheetDrawing = (WorksheetDrawing)sourceDrawingsPart.WorksheetDrawing.Clone();
var imagePartsToClone = sourceDrawingsPart.ImageParts.ToList();
foreach (var imagePart in imagePartsToClone) {
var newImagePart = newDrawingsPart.AddImagePart(imagePart.ContentType);
using (var stream = imagePart.GetStream()) {
newImagePart.FeedData(stream);
}
// Update the BlipFill.Blip.Embed.Value to reference the new image part
foreach (var blip in newDrawingsPart.WorksheetDrawing.Descendants<DocumentFormat.OpenXml.Drawing.Blip>()) {
if (blip.Embed.Value == sourceDrawingsPart.GetIdOfPart(imagePart)) {
var newId = newDrawingsPart.GetIdOfPart(newImagePart);
blip.Embed.Value = newId;
}
}
}
}
// Create a new sheet and add it to the workbook
var newSheetId = spreadSheet.WorkbookPart.GetIdOfPart(newSheetPart);
var newSheet = new Sheet {
Id = newSheetId,
SheetId = sheets.Elements<Sheet>().Max(s => s.SheetId.Value) + 1,
Name = newSheetName // todo: Ensure the new sheet name is unique
};
sheets.Append(newSheet);
// Save the workbook
spreadSheet.WorkbookPart.Workbook.Save();
}
Observed behavior
What I discovered is that the Clone() method on the sourceDrawingsPart.WorksheetDrawing doesn't work and in effect, make all the cloned sheets share the DrawingsPart.
Expected behavior How can achieve DrawingsPart cloning to work?
Desktop (please complete the following information):
- OS: MacOS, Windows
- .NET Target: .NET Core, .NET Framework
- DocumentFormat.OpenXml Version: 3.1.0, 3.0.2