Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: reorder a slide #68

Open
scanny opened this issue Dec 10, 2013 · 17 comments
Open

feature: reorder a slide #68

scanny opened this issue Dec 10, 2013 · 17 comments
Labels
Milestone

Comments

@scanny
Copy link
Owner

scanny commented Dec 10, 2013

In order to repurpose an existing presentation
As a developer using python-pptx
I need the ability to change the ordering of slides in a deck

Candidate protocol:

>>> slides = prs.slides
>>> len(slides)
6
>>> slide = slides[2]
>>> slides.index(slide)
2
>>> slide.move_to(5)
>>> slides.index(slide)
5
@scanny
Copy link
Owner Author

scanny commented Apr 16, 2014

also inserting a slide rather than just adding it to the end of Presentation.slides would be very handy.

@scanny scanny added the slide label Jun 15, 2014
@scanny scanny modified the milestones: v0.4.0, later Nov 16, 2014
@PrivateStaticVoid
Copy link

This would be very useful for my application as well. I would like to auto-generate reports from my analysis program based on powerpoint templates. It would be ideal if I could provide the user with tools to insert and reorder slides within my report generation interface, rather than requiring them open the finished product and shuffle the slides around.

@NotSqrt
Copy link

NotSqrt commented Aug 7, 2015

👍

@NotSqrt
Copy link

NotSqrt commented Aug 7, 2015

@scanny Do you have any tips on how I could develop this ?

@blaze33
Copy link

blaze33 commented Aug 10, 2015

The following works fine for me:

def move_slide(self, presentation, old_index, new_index):
        xml_slides = presentation.slides._sldIdLst  # pylint: disable=W0212
        slides = list(xml_slides)
        xml_slides.remove(slides[old_index])
        xml_slides.insert(new_index, slides[old_index])

def delete_slide(self, presentation,  index):
        xml_slides = presentation.slides._sldIdLst  # pylint: disable=W0212
        slides = list(xml_slides)
        xml_slides.remove(slides[index])

@PrivateStaticVoid
Copy link

@blaze33 Those seem to be working for me as well. Thanks for sharing!

@smcpherson
Copy link

👍

@scanny
Copy link
Owner Author

scanny commented Apr 24, 2017

@blaze33 I think you'll find that even though a slide deleted this way doesn't appear in the UI, that it remains in the presentation package (although perhaps PowerPoint clears that up on a subsequent save; that's probably worth a quick experiment).

This could be verified with a quick unzip -l my.pptx before and after to observe the zip archive members.

To remove the actual slide{n}.xml "file" from the package (zip archive) you would also need to delete the relationship from the presentation to the slide in question. Something like this perhaps:

slide_rId = sldIdLst[slide_idx].rId
slide_part = slide.part
slide_part.drop_rel(slide_rId)

This would bear testing thoroughly with slides containing pictures, hyperlinks, etc. to make sure it worked in the general case. I don't believe a slide has any inbound relationships, but if it did you'd need to find and remove those as well. I suppose an internal jump link counts as one of those come to think of it.

On the other hand, if just getting it to not show does the trick for you, I can't argue with that :)

@blaze33
Copy link

blaze33 commented Apr 25, 2017

Indeed I'm aware that removing a slide ID from _sldIdLst won't really delete it from the presentation package but as it does the trick for me I can't complain ! :)

Obviously I'm not working with sensitive data that should really be deleted from the final presentation !

@khouryrami
Copy link

What happened with the above? Thanks

@natter1
Copy link

natter1 commented Jan 17, 2020

I understand the issue with deleting, but shouldn't moving work the way blaze33 suggested? I implemented something similar:

def move_slide(self, slide: Slide, new_index: int):
    """Moves the given slide to position new_index."""
    _sldIdLst = self.prs.slides._sldIdLst

    old_index = None
    for index, entry in enumerate((_sldIdLst.sldId_lst)):
        if entry.id == slide.slide_id:
            old_index = index

    if old_index is not None:
        to_move = _sldIdLst[old_index]
        list(_sldIdLst).pop(old_index)
        _sldIdLst.insert(new_index, to_move)

It seems to work so far, and moving slides around doesnt change filesize. Are there edge cases, that would need more testing?

@scanny
Copy link
Owner Author

scanny commented Jan 17, 2020

Because you're working with lxml.etree._Element objects there, the code can be a little simpler:

def move_slide(slides, slide, new_idx):
    slides._sldIdLst.insert(new_idx, slide._element)

The basic insight here is that lxml does not make copies unless you tell it to. If you stick an element somewhere else, it comes out of wherever it was before.

I can't think of any edge cases off the top of my head. This is the approach I would use if I was doing it myself.

@pguerrerop
Copy link

Hey!
I know this is old but I would be more than happy to contribute in implementing this.
How could I do it?

@bitknol
Copy link

bitknol commented May 8, 2020

is this still active? I see the issue open, but no contribution or update in 3 years

@nabeeltk
Copy link

Looks like its still open. I tried all these suggestions and it still doesn't reflect in the PPTX. Can someone help, please.

@Amazinzay
Copy link

Because you're working with lxml.etree._Element objects there, the code can be a little simpler:

def move_slide(slides, slide, new_idx):
    slides._sldIdLst.insert(new_idx, slide._element)

The basic insight here is that lxml does not make copies unless you tell it to. If you stick an element somewhere else, it comes out of wherever it was before.

I can't think of any edge cases off the top of my head. This is the approach I would use if I was doing it myself.

I was able to get this working with a slight modification.

def move_slide(slides, slide, new_idx):
        slides._sldIdLst.insert(new_idx, slides._sldIdLst[slides.index(slide)])

The slide element is not what is being moved, but rather the sldId Element.

@Ms-Ajith
Copy link

Could anyone show me how to actually call the function to move the slide? Any working small example code would really help. Thanks alot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests