Created
May 18, 2011 00:19
-
-
Save maffoo/977752 to your computer and use it in GitHub Desktop.
Macro to expand animations in a LibreOffice/OpenOffice.org presentation into separate slides, suitable for pdf export.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
' ExpandAnimations | |
' Copyright 2010 Matthew Neeley. | |
' This program is free software: you can redistribute it and/or modify | |
' it under the terms of the GNU Lesser General Public License as published by | |
' the Free Software Foundation, either version 3 of the License, or | |
' (at your option) any later version. | |
' This program is distributed in the hope that it will be useful, | |
' but WITHOUT ANY WARRANTY; without even the implied warranty of | |
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
' GNU Lesser General Public License for more details. | |
' You should have received a copy of the GNU Lesser General Public License | |
' along with this program. If not, see <http://www.gnu.org/licenses/>. | |
' future enhancements: | |
' - delete unnecessary animations from expanded slides | |
' - turn appear/disappear animations or fades into slide transitions | |
' - add progress dialog and make the operation modal | |
' - use the standard presenter machinery to "play" anims and grab frames. | |
' in particular, this would let us handle other types of animation like | |
' objects moving, resizing, changing colors, etc. | |
Private ANIMSET as String | |
Private ENUMACCESS as String | |
Private VISATTR as String | |
sub ExpandAnimations | |
ANIMSET = "com.sun.star.animations.XAnimateSet" | |
ENUMACCESS = "com.sun.star.container.XEnumerationAccess" | |
VISATTR = "Visibility" | |
doc = thisComponent | |
numSlides = doc.getDrawPages().getCount() | |
' go through pages in reverse order | |
for i = numSlides-1 to 0 step -1 | |
slide = doc.drawPages(i) | |
if hasAnimation(slide) then | |
n = countAnimationSteps(slide) | |
if n > 1 then | |
origName = slide.Name | |
replicateSlide(doc, slide, n) | |
visArray = getShapeVisibility(slide, n) | |
for frame = 0 to n-1 | |
currentSlide = doc.drawPages(i + frame) | |
currentSlide.Name = origName & " (" & CStr(frame+1) & ")" | |
removeInvisibleShapes(currentSlide, visArray, frame) | |
next | |
end if | |
end if | |
next | |
finalSlides = doc.getDrawPages().getCount() | |
MsgBox("Done! Expanded " & CStr(numSlides) & " slides to " & CStr(finalSlides) & ".") | |
end sub | |
' get a list of all shapes whose visibility is changed during the animation | |
function getAnimatedShapes(slide as Object) | |
shapes = Array() ' start with an empty array | |
if not hasAnimation(slide) then | |
getAnimatedShapes = shapes | |
exit function | |
end if | |
mainSequence = getMainSequence(slide) | |
clickNodes = mainSequence.createEnumeration() | |
while clickNodes.hasMoreElements() | |
clickNode = clickNodes.nextElement() | |
groupNodes = clickNode.createEnumeration() | |
while groupNodes.hasMoreElements() | |
groupNode = groupNodes.nextElement() | |
effectNodes = groupNode.createEnumeration() | |
while effectNodes.hasMoreElements() | |
effectNode = effectNodes.nextElement() | |
animNodes = effectNode.createEnumeration() | |
while animNodes.hasMoreElements() | |
animNode = animNodes.nextElement() | |
if isVisibilityAnimation(animNode) then | |
target = animNode.target | |
' if we haven't seen this shape yet, add it to the array | |
if not containsObject(shapes, target) then | |
newUBound = UBound(shapes) + 1 | |
reDim preserve shapes(newUBound) | |
shapes(newUBound) = target | |
end if | |
end if | |
wend | |
wend | |
wend | |
wend | |
getAnimatedShapes = shapes | |
end function | |
' create a 2-D array giving the visibility of each animated | |
' shape for each frame in the expanded animation | |
function getShapeVisibility(slide as Object, nFrames as Integer) | |
shapes = getAnimatedShapes(slide) | |
dim visibility(UBound(shapes), nFrames-1) as Boolean | |
' loop over all animated shapes | |
for n = 0 to UBound(shapes) | |
shape = shapes(n) | |
visKnown = false | |
visCurrent = false | |
' iterate over the animations for this slide, | |
' looking for those that change the visibility | |
' of the current shape | |
mainSequence = getMainSequence(slide) | |
if HasUnoInterfaces(mainSequence, ENUMACCESS) then | |
clickNodes = mainSequence.createEnumeration() | |
currentFrame = 0 | |
while clickNodes.hasMoreElements() | |
clickNode = clickNodes.nextElement() | |
groupNodes = clickNode.createEnumeration() | |
while groupNodes.hasMoreElements() | |
groupNode = groupNodes.nextElement() | |
effectNodes = groupNode.createEnumeration() | |
while effectNodes.hasMoreElements() | |
effectNode = effectNodes.nextElement() | |
animNodes = effectNode.createEnumeration() | |
while animNodes.hasMoreElements() | |
animNode = animNodes.nextElement() | |
if isVisibilityAnimation(animNode) then | |
target = animNode.target | |
' if this is the shape we want, check the visibility | |
if EqualUnoObjects(shape, target) then | |
visCurrent = animNode.To | |
' if this is the first time we've seen this | |
' shape, set the visibility on the previous frames | |
if visKnown = false then | |
for i = 0 to currentFrame | |
visibility(n, i) = not visCurrent | |
next | |
visKnown = true | |
end if | |
end if | |
end if | |
wend | |
wend | |
wend | |
currentFrame = currentFrame + 1 | |
visibility(n, currentFrame) = visCurrent | |
wend | |
end if | |
next | |
getShapeVisibility = visibility | |
end function | |
' remove from the given slide all shapes that are invisible in the specified frame | |
sub removeInvisibleShapes(slide as Object, visibility, frame as Integer) | |
shapes = getAnimatedShapes(slide) | |
for n = 0 to UBound(shapes) | |
if visibility(n, frame) = false then | |
slide.remove(shapes(n)) | |
end if | |
next | |
end sub | |
' checks if the given animation node changes a shape's visibility | |
function isVisibilityAnimation(animNode as Object) as Boolean | |
isVisibilityAnimation = HasUnoInterfaces(animNode, ANIMSET) and _ | |
(animNode.AttributeName = VISATTR) | |
end function | |
' check if an object (needle) is contained in an array (haystack) | |
function containsObject(haystack as Object, needle as Object) as Boolean | |
containsObject = false | |
for each item in haystack | |
if EqualUnoObjects(item, needle) then | |
containsObject = true | |
exit function | |
end if | |
next item | |
end function | |
' determine whether the given drawPage has animations attached | |
function hasAnimation(slide as Object) as Boolean | |
mainSequence = getMainSequence(slide) | |
hasAnimation = HasUnoInterfaces(mainSequence, ENUMACCESS) | |
end function | |
' count the number of frames in the animation for the given slide | |
function countAnimationSteps(slide as Object) as Integer | |
mainSequence = getMainSequence(slide) | |
countAnimationSteps = countElements(mainSequence) + 1 | |
end function | |
' count the number of elements in an enumerable object | |
function countElements(enumerable as Object) as Integer | |
oEnum = enumerable.createEnumeration() | |
n = 0 | |
while oEnum.hasMoreElements() | |
n = n + 1 | |
oEnum.nextElement() | |
wend | |
countElements = n | |
end function | |
' make n-1 copies of the given slide in the given doc | |
' when done, the slide will appear a total of n times | |
' note that doc.duplicate adds copies immediately after | |
' the page being copied | |
function replicateSlide(doc, slide, n) | |
for i = 1 to n-1 | |
doc.duplicate(slide) | |
next | |
end function | |
' get the main sequence from the given draw page | |
function getMainSequence(oPage as Object) as Object | |
on error resume next | |
mainSeq = com.sun.star.presentation.EffectNodeType.MAIN_SEQUENCE | |
oNodes = oPage.AnimationNode.createEnumeration() | |
while oNodes.hasMoreElements() | |
oNode = oNodes.nextElement() | |
if getNodeType(oNode) = mainSeq then | |
getMainSequence = oNode | |
exit function | |
end if | |
wend | |
end function | |
' get the type of a node | |
function getNodeType(oNode as Object) as Integer | |
on error resume next | |
for each oData in oNode.UserData | |
if oData.Name = "node-type" then | |
getNodeType = oData.Value | |
exit function | |
end if | |
next oData | |
end function | |
' get the class of an effect | |
function getEffectClass(oEffectNode as Object) as String | |
on error resume next | |
for each oData in oEffectNode.UserData | |
if oData.Name = "preset-class" then | |
getEffectId = oData.Value | |
exit function | |
end if | |
next oData | |
End Function | |
' get the id of an effect | |
function getEffectId(oEffectNode as Object) as String | |
on error resume next | |
for each oData in oEffectNode.UserData | |
if oData.Name = "preset-id" then | |
getEffectId = oData.Value | |
exit function | |
end if | |
next oData | |
end function |
Hi,
I'd just like to select a text in Impress and add a simple "ooo-entrance-fade-in" effect (duration: 1second) to all the text on the current slide that have no effect attached. May I ask you to help me on this (or maybe a link to a tutorial specific to Impress because all I can find is about Calc or Word)
Thank you very much
Olivier Pons
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
I have a presentation which could not be parsed with the given macro. May I send it to You?
Best regards,
zirneklitis