Skip to content

Commit

Permalink
feat: fluent API AddSlide
Browse files Browse the repository at this point in the history
  • Loading branch information
sergey-tihon committed Oct 6, 2024
1 parent 44bf4eb commit 598f8b1
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 70 deletions.
95 changes: 40 additions & 55 deletions Clippit/PowerPoint/Fluent/FluentPresentationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,79 +306,64 @@ private void EnsureDocumentInitialized(PresentationDocument sourceDocument)
_isDocumentInitialized = true;
}

public void AppendSlides(PresentationDocument sourceDocument, int start, int count) =>
AppendSlides(sourceDocument, start, count, false);

internal void AppendSlides(PresentationDocument sourceDocument, int start, int count, bool unHideSlides)
public SlidePart AddSlide(SlidePart slidePart)
{
var sourceDocument = (PresentationDocument)slidePart.OpenXmlPackage;
EnsureDocumentInitialized(sourceDocument);

var newPresentation = _newDocument.PresentationPart.GetXDocument();
var scaleFactor = GetScaleFactor(sourceDocument);

// TODO: Maintain it globally on the builder level, instead of calculating it for each slide add operation
var newPresentation = _newDocument.PresentationPart.GetXDocument();
uint newId = 256;
var ids = newPresentation.Root.Descendants(P.sldId).Select(f => (uint)f.Attribute(NoNamespace.id)).ToList();
if (ids.Count != 0)
newId = ids.Max() + 1;

var slideList = sourceDocument.PresentationPart.GetXDocument().Root.Descendants(P.sldId).ToList();
while (count > 0 && start < slideList.Count)
var newSlide = _newDocument.PresentationPart.AddNewPart<SlidePart>();
using (var sourceStream = slidePart.GetStream())
{
var slide = (SlidePart)
sourceDocument.PresentationPart.GetPartById(slideList.ElementAt(start).Attribute(R.id).Value);
var newSlide = _newDocument.PresentationPart.AddNewPart<SlidePart>();

using (var sourceStream = slide.GetStream())
{
newSlide.FeedData(sourceStream);
}

var slideDocument = newSlide.GetXDocument();
if (unHideSlides)
{
slideDocument.Root?.Attribute(NoNamespace.show)?.Remove();
}
newSlide.FeedData(sourceStream);
}

SlideLayoutData.ScaleShapes(slideDocument, scaleFactor);
var slideDocument = newSlide.GetXDocument();
SlideLayoutData.ScaleShapes(slideDocument, scaleFactor);

PBT.AddRelationships(slide, newSlide, [newSlide.GetXDocument().Root]);
CopyRelatedPartsForContentParts(slide, newSlide, [newSlide.GetXDocument().Root]);
CopyTableStyles(sourceDocument, newSlide);
PBT.AddRelationships(slidePart, newSlide, [newSlide.GetXDocument().Root]);
CopyRelatedPartsForContentParts(slidePart, newSlide, [newSlide.GetXDocument().Root]);
CopyTableStyles(sourceDocument, newSlide);

if (slide.NotesSlidePart is { } notesSlide)
{
if (_newDocument.PresentationPart.NotesMasterPart is null)
CopyNotesMaster(sourceDocument);
var newPart = newSlide.AddNewPart<NotesSlidePart>();
newPart.PutXDocument(notesSlide.GetXDocument());
newPart.AddPart(newSlide);
if (_newDocument.PresentationPart.NotesMasterPart is not null)
newPart.AddPart(_newDocument.PresentationPart.NotesMasterPart);
PBT.AddRelationships(notesSlide, newPart, [newPart.GetXDocument().Root]);
CopyRelatedPartsForContentParts(slide.NotesSlidePart, newPart, [newPart.GetXDocument().Root]);
}
if (slidePart.NotesSlidePart is { } notesSlide)
{
if (_newDocument.PresentationPart.NotesMasterPart is null)
CopyNotesMaster(sourceDocument);
var newPart = newSlide.AddNewPart<NotesSlidePart>();
newPart.PutXDocument(notesSlide.GetXDocument());
newPart.AddPart(newSlide);
if (_newDocument.PresentationPart.NotesMasterPart is not null)
newPart.AddPart(_newDocument.PresentationPart.NotesMasterPart);
PBT.AddRelationships(notesSlide, newPart, [newPart.GetXDocument().Root]);
CopyRelatedPartsForContentParts(slidePart.NotesSlidePart, newPart, [newPart.GetXDocument().Root]);
}

var slideLayoutData = GetOrAddSlideLayoutPart(sourceDocument, slide.SlideLayoutPart, scaleFactor);
newSlide.AddPart(slideLayoutData.Part);
var slideLayoutData = GetOrAddSlideLayoutPart(sourceDocument, slidePart.SlideLayoutPart, scaleFactor);
newSlide.AddPart(slideLayoutData.Part);

if (slide.SlideCommentsPart is not null)
CopyComments(sourceDocument, slide, newSlide);
if (slidePart.SlideCommentsPart is not null)
CopyComments(sourceDocument, slidePart, newSlide);

newPresentation = _newDocument.PresentationPart.GetXDocument();
newPresentation
.Root.Element(P.sldIdLst)
.Add(
new XElement(
P.sldId,
new XAttribute(NoNamespace.id, newId.ToString()),
new XAttribute(R.id, _newDocument.PresentationPart.GetIdOfPart(newSlide))
)
);
newPresentation = _newDocument.PresentationPart.GetXDocument();
newPresentation
.Root.Element(P.sldIdLst)
.Add(
new XElement(
P.sldId,
new XAttribute(NoNamespace.id, newId.ToString()),
new XAttribute(R.id, _newDocument.PresentationPart.GetIdOfPart(newSlide))
)
);

newId++;
start++;
count--;
}
return newSlide;
}

// Copies notes master and notesSz element from presentation
Expand Down
2 changes: 1 addition & 1 deletion Clippit/PowerPoint/IFluentPresentationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace Clippit.PowerPoint;
public interface IFluentPresentationBuilder : IDisposable
{
public void AddSlideMaster(SlideMasterPart slideMasterPart);
public void AppendSlides(PresentationDocument sourceDocument, int start, int count);
public SlidePart AddSlide(SlidePart slidePart);
}
50 changes: 36 additions & 14 deletions Clippit/PowerPoint/PresentationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,16 @@ public static IList<PmlDocument> PublishSlides(PmlDocument src)

public static IEnumerable<PmlDocument> PublishSlides(PresentationDocument srcDoc, string fileName)
{
var slidesCount = srcDoc.PresentationPart.GetXElement().Descendants(P.sldId).Count();
var slidesIds = GetSlidesInOrder(srcDoc);
var slideNameRegex = SlideNameRegex();
for (var slideNumber = 0; slideNumber < slidesCount; slideNumber++)
for (var slideNumber = 0; slideNumber < slidesIds.Count; slideNumber++)
{
var srcSlidePart = (SlidePart)srcDoc.PresentationPart.GetPartById(slidesIds[slideNumber]);

using var streamDoc = OpenXmlMemoryStreamDocument.CreatePresentationDocument();
using (var output = streamDoc.GetPresentationDocument(new OpenSettings { AutoSave = false }))
{
ExtractSlide(srcDoc, slideNumber, output);

var slides = output.PresentationPart.GetXElement().Descendants(P.sldId);
var slidePartId = slides.Single().Attribute(R.id)?.Value;
var slidePart = (SlidePart)output.PresentationPart.GetPartById(slidePartId);
var title = PresentationBuilderTools.GetSlideTitle(slidePart.GetXElement());

output.PackageProperties.Title = title;
ExtractSlide(srcSlidePart, output);
}

var slideDoc = streamDoc.GetModifiedPmlDocument();
Expand All @@ -121,17 +116,34 @@ public static IEnumerable<PmlDocument> PublishSlides(PresentationDocument srcDoc
}
}

private static void ExtractSlide(PresentationDocument srcDoc, int slideNumber, PresentationDocument output)
private static List<string> GetSlidesInOrder(PresentationDocument srcDoc)
{
return srcDoc
.PresentationPart.GetXElement()
.Descendants(P.sldId)
.Select(x => x.Attribute(R.id)!.Value)
.ToList();
}

private static void ExtractSlide(SlidePart slidePart, PresentationDocument output)
{
using var builder = new FluentPresentationBuilder(output);
try
{
builder.AppendSlides(srcDoc, slideNumber, 1, true);
var newSlidePart = builder.AddSlide(slidePart);

// Remove the show attribute from the slide element (if it exists)
var slideDocument = newSlidePart.GetXDocument();
slideDocument.Root?.Attribute(NoNamespace.show)?.Remove();

// Set the title of the new presentation to the title of the slide
var title = PresentationBuilderTools.GetSlideTitle(newSlidePart.GetXElement());
output.PackageProperties.Title = title;
}
catch (PresentationBuilderInternalException dbie)
{
if (dbie.Message.Contains("{0}"))
throw new PresentationBuilderException(string.Format(dbie.Message, slideNumber));
throw new PresentationBuilderException(string.Format(dbie.Message, slidePart.Uri));
throw;
}
}
Expand All @@ -155,7 +167,17 @@ private static void BuildPresentation(List<SlideSource> sources, PresentationDoc
builder.AddSlideMaster(slideMasterPart);
}
}
builder.AppendSlides(doc, source.Start, source.Count);

var slideIds = GetSlidesInOrder(doc);
var (count, start) = (source.Count, source.Start);
while (count > 0 && start < slideIds.Count)
{
var slidePart = (SlidePart)doc.PresentationPart.GetPartById(slideIds[start]);
builder.AddSlide(slidePart);

start++;
count--;
}
}
catch (PresentationBuilderInternalException dbie)
{
Expand Down

0 comments on commit 598f8b1

Please sign in to comment.