Safer
The original code removed all slides which were not hidden to return to the previous state. Unfortunately, if you haven't yet run the AddElements script, that results in it deleting all your slides! Undo saves the day, but it would be nicer for RemElements to be a bit more considerate. This version tags all the slides it creates, then RemElements simply removes those with the appropriate tag - hopefully this removes the obvious "Doh!" moment from this tool.
Works with show/hide/reshow
The original code used the Shape.AnimationSettings properties to detect what happened to objects. Unfortunately, this property only records the first action associated with an object - I suspect in the past PowerPoint only allowed one action and this is merely here for compatibility. To get the full range of events you need to use the Slide.TimeLine property. Writing the code I ran into two issues: (1) objects with silly names; (2) mutability.
Objects With Silly Names
Some objects have properties which don't do what you might think! Effect.EffectType = msoAnimEffectAppear implies that the animation is to appear, but if Effect.Exit = msoTrue then this is the disappear effect! I was confused by this one for quite a while.
In order to solve all the naming problems, I made extensive use of the Visual Basic debugger included with Office, which puts many other debuggers to shame. It is at least 1000x better than any Haskell debugger I've ever seen, and equally far ahead of things like GDB. Microsoft's software may be maligned, but their debuggers are truly fantastic! It really does allow an entirely new style of development, and is particularly suited to dipping into a new API without having a large learning curve.
Mutability
Mutability is a bad idea. If you delete a shape, while you are iterating over a collection of shapes, you silently skip the element that comes after the deleted shape! If you delete a shape, and that shape is the subject of a transition, then that corresponding transition is deleted. If you change the Shape.AnimationSettings.Animate to msoFalse, this removes any associated transitions. All this means that to try and iterate over something starts to become a challenge!
The problem with mutability in this particular task is that it is unclear what is changing and when, leading to subtle bugs and lots of debugging. Again, the debugger helped, but not as much as before - having to single-step through quite deep properties is not a particularly fun task.
The Code
And here is the code, to be use as in the same way to the previous post.
Option Explicit
Sub AddElements()
Dim shp As Shape
Dim i As Integer, n As Integer
n = ActivePresentation.Slides.Count
For i = 1 To n
Dim s As Slide
Set s = ActivePresentation.Slides(i)
s.SlideShowTransition.Hidden = msoTrue
Dim max As Integer: max = AnimationElements(s)
Dim k As Integer, s2 As Slide
For k = 1 To max
Set s2 = s.Duplicate(1)
s2.Name = "AutoGenerated: " & s2.SlideID
s2.SlideShowTransition.Hidden = msoFalse
s2.MoveTo ActivePresentation.Slides.Count
Dim i2 As Integer, h As Shape
Dim Del As New Collection
For i2 = s2.Shapes.Count To 1 Step -1
Set h = s2.Shapes(i2)
If Not IsVisible(s2, h, k) Then Del.Add h
Next
Dim j As Integer
For j = s.TimeLine.MainSequence.Count To 1 Step -1
s2.TimeLine.MainSequence.Item(1).Delete
Next
For j = Del.Count To 1 Step -1
Del(j).Delete
Del.Remove j
Next
Next
Next
End Sub
'is the shape on this slide visible at point this time step (1..n)
Function IsVisible(s As Slide, h As Shape, i As Integer) As Boolean
'first search for a start state
Dim e As Effect
IsVisible = True
For Each e In s.TimeLine.MainSequence
If e.Shape Is h Then
IsVisible = Not (e.Exit = msoFalse)
Exit For
End If
Next
'now run forward animating it
Dim n As Integer: n = 1
For Each e In s.TimeLine.MainSequence
If e.Timing.TriggerType = msoAnimTriggerOnPageClick Then n = n + 1
If n > i Then Exit For
If e.Shape Is h Then IsVisible = (e.Exit = msoFalse)
Next
End Function
'How many animation steps are there
'1 for a slide with no additional elements
Function AnimationElements(s As Slide) As Integer
AnimationElements = 1
Dim e As Effect
For Each e In s.TimeLine.MainSequence
If e.Timing.TriggerType = msoAnimTriggerOnPageClick Then
AnimationElements = AnimationElements + 1
End If
Next
End Function
Sub RemElements()
Dim i As Integer, n As Integer
Dim s As Slide
n = ActivePresentation.Slides.Count
For i = n To 1 Step -1
Set s = ActivePresentation.Slides(i)
If s.SlideShowTransition.Hidden = msoTrue Then
s.SlideShowTransition.Hidden = msoFalse
ElseIf Left$(s.Name, 13) = "AutoGenerated" Then
s.Delete
End If
Next
End Sub
As before, no warranty, and please do backup first!
Great script! Exactly the functionality I have been looking for. If the script could handle appearing/disappearing bullets in a list WITHIN a text object as well there would be nothing left to ask for. Keep up the good work!
ReplyDeleteA great script indeed! I'd like to use it with work-related presentations, but since you did not mention any license, I'm not sure if it's OK to use it. Could you add the kind of license that you intended the script to be used with? (public domain i.e. free to use for anything, GPL, BSD, commercial, or something completely different)
ReplyDeleteRoger: I may extend it in such a direction, if it turns out not to be too hard. I'll probably put it on a proper web page and as a downloadable file, to make it a bit easier.
ReplyDeleteKari: BSD with no advertising - the source code is free, you are free to do what you want with it. If BSD doesn't meet your needs, let me know.
Hi Neil,
ReplyDeletejust another quick "thanks" for your code - it pretty much solves exactly the problem I was right now dealing with :-)
I will keep an eye on this page to not miss the new homepage for the VB Script...
Cheers,
Christian
It works fine except for:
ReplyDeleteWhen you add multi-step animations to a text block sentence by sentence, this coding cannot recognize that. It will treat the whole text block as 1 step animation.
Dear Neil,
ReplyDeleteis there any chance to modify the code such that the numbers of the slides are preserved? My use case is to provide slides for students on our web page, and it would be extremely useful to still be able to point them to a particular slide from the original talk after the conversion has been performed...
Thanks,
Christian (christian at uni-paderborn de)
Great Work.
ReplyDeleteWould be nice to hide objects that are hidden.
I might try and add it when I have some free time.
Worked nicely on Office 2007, BTW.
@Christian and Ophir: Quite a lot of people seem interested in this, so I'll set up a darcs repo, a web page, and attempt to make a proper release. Once I've got a proper source code repo for it, then it will be easier to add/accept features.
ReplyDeleteA great utility! Echo others in that the only thing I had to handle manually was bulleted items within a list.
ReplyDeleteI use that mode a lot. A list of itmes, each one revealed on a mouse click.
You sir, have just saved my day!
ReplyDeleteWonderful workaround to the pdf animation problem - thank you so much for sharing it with us less VBA savvy PP users :)
After copying AddElements into a module and tryin to run, I get an error "compile error: method or data member not found" running on mac word 2004. Is there something I'm missing?
ReplyDeleteThank you so much for the script.
ReplyDeleteI have an important presentation in a week and you help a lot!
Many many thanks also from me! The only thing I've done manually is move the hidden slides to the back so that the numbering starts with "1" in the pdf. Would be nice but by no means crucial if that would happen automatically.
ReplyDeleteThank you! I just used this with my pptx file (Microsoft Office 2007) and it worked beautifully!
ReplyDeleteThank you again!
Very useful script! Thank you. Marc
ReplyDeleteYou just saved my job!!!! When i needed to send a powerpoint with custom animations to a group of tech-challenged colleagues (it would be cruel to have them install powerpoint viewer) your code was a life saver. thank you. thank you. thank you.
ReplyDeleteThanks, its a nice script and works well for me
ReplyDeleteNeil,
ReplyDeleteThank you so much for sharing this script. It works great and saves me so much time!
Best,
Ram
Neil, Great work.
ReplyDeleteHere's is one more add-in. It works perfectly with 07.
http://www.dia.uniroma3.it/~rimondin/downloads.php
This is brilliant. Was looking for this and was thinking about contacting my IT to get this script written. Helped me a huge amount of time and effort.
ReplyDeleteThanks a mill!!!
Saved my day: thank you very very much! ;)
ReplyDeleteGreat script! Thanks! One problem is that page numbering is not retained. Any suggestions???
ReplyDeleteHi Neil.
ReplyDeleteI had difficulty to get this into Powerpoint2010. Cant find the button to paste this code.
Your assistance is highly appreciated
Hello,
ReplyDeleteThanks for this tip that is really useful.
Just a drawback: the incrementation of the slides numbers :-( (my final slide is slide # 99/15)
Do you have a trick to avoid this?
Thanks in advance ;-)
Hello,
ReplyDeleteThanks for this tip that is really useful.
Just a drawback: the incrementation of the slides numbers :-( (my final slide is slide # 99/15)
Do you have a trick to avoid this?
Thanks in advance ;-)
Hi,
ReplyDeleteI had a similar idea and cannot find why I have errors. The idea was to create a macro opening all my .pptx within a specified folder and create two kinds of pdfs from these.
Note: these pdf are password protected.
However I am now blocked as it works fine for the 1st powerpoint and then it crashes for the second telling me that the Exportasfixedformat does not work.
Would you have any tips for me, please?
Public wbPPT As Presentation
Public fPPT As String
Public fInput As String
Public fpath As String
Sub BatchBuilding_pdf_from_PPT()
Dim nfichier As String, nfichier2 As String, intpos As Byte
fInput = InputBox("Please enter the local address where are stored your PPT files (e.g. C:\... ) ")
If fInput = "" Then
MsgBox ("No path entered, the Importing process is cancelled")
Exit Sub
Else
If Right(fInput, 1) <> "\" Then
fInput = fInput & "\"
Else
fInput = fInput
End If
fpath = fInput
fPPT = Dir(fpath & "*.pptx")
Do While Len(fPPT) > 0
nfichier = fPPT
'find where is the extension in the name
intpos = InStrRev(nfichier, ".")
'replace the pptx by pdf
nfichier = Left(nfichier, intpos - 1)
nfichier2 = nfichier & ".pdf"
With ProtectedViewWindows.Open(fpath & fPPT, "password").Edit("password")
.ExportAsFixedFormat Path:=fpath & "Without notes\" & nfichier2, FixedFormatType:=ppFixedFormatTypePDF, Intent:=ppFixedFormatIntentPrint, FrameSlides:=msoTrue, PrintHiddenSlides:=msoTrue, OutputType:=ppPrintOutputSlides
.ExportAsFixedFormat Path:=fpath & "With notes\" & nfichier2, FixedFormatType:=ppFixedFormatTypePDF, Intent:=ppFixedFormatIntentPrint, FrameSlides:=msoTrue, PrintHiddenSlides:=msoTrue, OutputType:=ppPrintOutputNotesPages
.Close
End With
fPPT = Dir
'same code as before to prepare for the next file (just in case)
nfichier = fPPT
'find where is the extension in the name
intpos = InStrRev(nfichier, ".")
'replace the pptx by pdf
nfichier = Left(nfichier, intpos - 1)
nfichier2 = nfichier & ".pdf"
Loop
MsgBox ("All presentations have been PDFied")
End If
End Sub
Thanks in advance.
Sebastien, no idea I'm afraid - I don't even have PowerPoint installed on this machine anymore.
ReplyDelete8 years later, still works a charm! Thanks a lot!
ReplyDeleteMac users say: god bless you!
ReplyDeleteIt's amazing how 8 years later MS still haven't sorted this out (I think keynote has an option to break animations up when creating a PDF). In particular, the few scripts I could find out there are all for windows, so your script is a real life-saver for us OSX users.
Minor issue: when using text animations (i.e. just having bullet points appear one by one), the script will break the slide into multiple slides, but will keep all bullet points in every slide (rather than adding a new bullet point to each slide), requiring one to go and manually delete some bullet points. Still, small price to pay compared to having to do everything manually!
Thanks!!!!!!!!
p.s. - tested on OSX Yosemite running MS PowerPoint 2011 for mac.
Where do I paste the code? Please anyone describe exactly (Mac Yosemite; PPT 14.4.5 2011 for mac). Thx!
ReplyDeletePure Genius! thank you sooo much!!
ReplyDeleteFor those wondering. post the code into a VB module or open your macro menu, type in a AddElements to the Macro Name and click "create" then paste the code in the window the VB code editor window that comes up. Close and return, then you should see the two macros (addElements and RemElements) listed in your macro list.
ReplyDeleteThe script even works in PowerPoint 15 on macOS, however it is (like other commented) not able to split animated bullet point lists into single items. As a Mac user I just found out that (the meanwhile free) Apple Keynote can read PowerPoint pretty well and Keynote is able to export really reach animation to PDF. So lucky am I and others using a Mac.
ReplyDeleteAs it is always the case, there is still room for improvement.
ReplyDeleteOne thing that does not work with macro are page numbers. All added slides get new page numbers and don't retain the same numbers as they would have in the original.
Wow. I've never run a macro, used VBE etc. I had to hunt a bit through confusing crap on MS Support to stumble into what I should do to use your code on PowerPoint for Mac 2016. But it worked. Thank you so much.
ReplyDeleteThank you!!
ReplyDeleteHere is how you can use this code and retain the slide numbers from the old presentation:
ReplyDeletehttps://gist.github.com/pcmoritz/4b0e1be7f2dfcc4e51e2ace50426f67d
You need to deactivate the slide numbers, this will insert a text box per slide with the right number from the old slide.
Thanks Philipp - very cool! I would have updated the blog to include a link to your code, but unfortunately any edits to the page make it break (I guess something about blogger changed in the last decade...)
ReplyDeleteHi Neil,
ReplyDeleteI'm not a VBA expert (so apologies if these are dumb questions):
1. For your code to work, do you have to have an Adobe elements (or other) subscription? I.e. can anyone run this code, or do you have to have a subscription?
The reason I ask is, I just published a post on converting PowerPoint to PDF and one of my points was that animations do not carry over (which is something I'm often asked).
If this does work for anyone (which would be amazing), I would love to include a link back to your code or even expand on it for people who are not fluent in VBA so they can FINALLY make this a reality.
Below is the blog post I created for reference.
https://nutsandboltsspeedtraining.com/powerpoint-tutorials/ppt-to-pdf/
Would love to get your insight so I can refer people back to this assuming it works for everyone.
Thanks!
Taylor
Thanks Taylor - it doesn't require Adobe elements or anything beyond basic PowerPoint. I assume it still works, but don't use PowerPoint much anymore. Happy for you to take it and expand as you wish. https://github.com/ndmitchell/office/blob/master/PowerFlat.bas Is my latest version.
DeleteThanks Neil...
ReplyDeleteBy expand on it, I just meant advise people how to install and run VBA (which not a lot of people have done before).
Thanks for the confirmation, I will link to it from my post.
totally other random question, do you have a course on building macros in PowerPoint by chance? I get asked about this occasionally and don't know of anyone who really has one.
Thanks again,
Taylor
Taylor - no course of similar - I'm an ex VB5-6 programmer who got into it that way.
ReplyDeletehow to convert pdf to powerpont and enable edited file?
ReplyDeleteThank you so much, that was easy!
ReplyDeleteDear Sir, thank you so much !
ReplyDeleteThe only problem is that powerpoint keeps going into "program not responding any more"
I need to convert 108 slides into pdfs by tomorrow, you happen to have any experience why powerpoint becomes non responsive after launching the code? thank you
I just had to wait very long, it worked!
ReplyDelete