sergey-tihon / Clippit

Fresh PowerTools for OpenXml
https://sergey-tihon.github.io/Clippit/
MIT License
50 stars 19 forks source link

PresentationBuilder doesn't add slide #24

Closed ashahabov closed 3 years ago

ashahabov commented 3 years ago

I am looking for a way to copy a slide from existing opened PresentationDocument document to another also already opened PresentationDocument document. To achieve it I added a new AppendSlide() method into PresentationBuilder. I tried re-use existing code without extra changes:

public static void AppendSlide(PresentationDocument sourceDoc, int sourceSlideNumber, PresentationDocument outputDoc)
{
    RelationshipMarkup ??= GetDefaultRelationshipMarkup();

    var images = new List<ImageData>();
    var mediaList = new List<MediaData>();
    int startIndex = sourceSlideNumber - 1;
    int count = 1;
    bool keepMaster = true;
    AppendSlides(sourceDoc, outputDoc, startIndex, count,
        keepMaster, true, null, images, mediaList);

    CleanupDocument(outputDoc);
}

Here is a sample running in PresentationBuilder01 project:

PresentationDocument sourcePreDoc = PresentationDocument.Open(@"source.pptx", true);
PresentationDocument outputDoc = PresentationDocument.Open(@"output.pptx", true);
// Do my business logic
// ...
var presentation = outputDoc.PresentationPart.Presentation; // it works if we delete this statement
// ...

PresentationBuilder.AppendSlide(sourcePreDoc, 1, outputDoc);

sourcePreDoc.Close();
outputDoc.Close();

Commit changes: https://github.com/adamshakhabov/Clippit/commit/d402e25a265e49fd2c8021c8045fc8881d551b0b


It does not work. But works (the first slide from source.pptx is added to output.pptx) if we delete outputDoc.PresentationPart.Presentation statement.

While debugging I can not detect how reading DocumentFormat.OpenXml.Presentation.Presentation affects on AppendSlide() flow.

Any ideas?

sergey-tihon commented 3 years ago

PresentationBuilder is not designed to work with already opened PresentationDocument. Original implementation rely on assumption that you always create new PresentationDocument using SlideSource.

You may want to take a look at FluentPresentationBuilder that wrap target PresentationDocument and provided API like AppendSlides

PresentationDocument that is released in 1.5.0-beta* packages uses FluentPresentationBuilder internally. But IIRC, it is may be slightly not ready for use case. It works well (even in production 😊) when FluentPresentationBuilder wrap empty presentation at the beginning, but it still not fully-enumerate internals of PresentationDocument that it wraps.

P.S. As workaround you always can create 3rd PresentationDocument and copy there slides from sourcePreDoc and from outputDoc.

ashahabov commented 3 years ago

Looks like FluentPresentationBuilder.AppendSlides() also rely on that PresentationDocument instance passed in constructor is empty.

Will see some workaround.

sergey-tihon commented 3 years ago

Why do not you like workaround to create 3rd PresentationDocument and copy all slides there?

ashahabov commented 3 years ago

For example, I wanna copy only the first slide from test1.pptx into test2.pptx. With this approach, I will touch one slide from the first presentation and all slides from the second. Even without considering performance issue, I think the chance of corruption is high.

In other words, you know that moving slide to an external presentation with its all references (layout, master, theme, chart, etc) is a tricky part, hence I'd like to avoid extra touching those references.

ashahabov commented 3 years ago

Today I made some implementation and it works for simple cases, but I do not know where it might go off :neutral_face:

ashahabov commented 3 years ago

I think the issue should be closed since PresentationBuilder designed as a builder that creates slides deck from scratch, as mentioned above.