MarginNote 是 Mac 和 iOS 上的一个非常强大的学习工具,知乎上有很多人推荐。可惜在多设备同步等功能上 bug 非常多,导致我一直对它爱不起来,但奈何它的功能确实比较强大,市面上并没有替代的工具。这段时间我尝试使用 MarginNote 来阅读老师的 PPT 以准备考试。MarginNote 并不能直接使用 PPT 格式的文档,而是需要先转换成其他格式,比如 PDF。

然而,PPT 在转换为 PDF 的时候会丢失动画。而有的老师很喜欢在一页 PPT 上加很多动画,使得元素会重叠,转换为 PDF 之后底层的内容被挡住。有没有办法可以让 PPT 中的重叠元素自动分页,使得底层的元素在转换为 PDF 之后也可见呢?

经过搜索,我发现我们可以使用 VBA 脚本来将 PPT 的动画进行分页,然后再导出为 PDF 的话就不会出现元素的重叠了。而且非常幸运的是,VBA 脚本并不是只有 Windows 可以使用,Mac 也可以使用。以下演示以 Office for Mac 2016 为例:

打开 PPT 的“工具->宏>Visual Basic 编辑器”

打开 PPT 的“工具->宏>Visual Basic 编辑器”,然后选择“插入->模块”。

在新打开的窗口中粘贴以下代码:

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

然后我们关闭这个窗口,在 Powerpoint 的主窗口中选择“工具->宏->宏”。

选择“AddElements”,然后点击“运行”。

运行之后,你原来的页面将会变成隐藏的状态(左上角有个符号),而新增的页面为动画分页后的版本。

这时候在从菜单中选择“文件->另存为”,选择 PDF 保存即可。

如果你使用的 Office 是其他版本,可以在这里查看如何使用 VBA 脚本。本文所使用的 VBA 脚本来自 Neil Mitchell’s Haskell Blog