LoginSignup
22
3

More than 3 years have passed since last update.

ApplescriptでKeynoteをハックしてみた

Last updated at Posted at 2020-12-09

概要

友達からプレゼン用のkeynoteにテロップを自動で挿入するプログラムが欲しいと言われたのでAppleScriptで作ってみた。

目次

  • AppleScriptとは
  • どんな感じのプログラム
  • 実装
  • おわりに
  • 参考URL

AppleScriptとは

https://en.wikipedia.org/wiki/AppleScript
名前から想像できる通り、Appleが作ったMac OS用のスクリプト言語で、macOSに同梱されている基本ソフトです。マウスやキーボードを使わずに、Macや外部のアプリを操作するすることができます。
実装してみると、構文が簡単で学習コストが低いかなと思います。一般敵にはmacOSに標準でインストールされているスクリプトエディタで記述すると思いますが、今回はAppleScriptのプラグインがあったのでVSCodeを使用しました。

どんな感じのプログラム

用意するもの

以下二点です。

  • テロップを入れたいkeyファイル
  • こんな感じのテキストファイル
telop.text
テロップ1
テロップ2
テロップ3

一行一行がスライドの1枚目から順番に挿入されて行きます。

実装内容は以下になります。

  • keynoteのスライドの指定した位置に予め用意したテキストファイルの文字列を貼り付ける
  • 実行時に文字の色選択ができる
  • スライドの枚数とテキストの行数が違う場合はバリデーションをかける
  • しゃべらせる

実装

それでは早速実装して行きましょう。
基本的な文法はこちらをご参照ください。

VSCodeの場合

まずAppleScriptのプラグインを入れましょう。
https://marketplace.visualstudio.com/items?itemName=idleberg.applescript

ファイル作成

applescriptの拡張子をつけてファイルを作成しましょう。
今回はtext_overlay.applescriptとしました。

パーツ作り

テキストのプロパティー

こちらを参考にテキストの色や大きさなどを変数に入れる。
今回はこんな感じ

-- OBJECT TEXT PROPERTIES
property textOverlayTypeface : "Arial Bold"
property textOverlayFontSize : 40
property textOverlayColorName : "WHITE"
property textOverlayRGBColorValues : {65535, 65535, 65535}

-- TEXT ITEM PROPERTIES
property textOverlayOpacityValue : 100
property textOverlayDefaultPosition : 3
property textItemOverlayOffset : 870
property textItemPointerOffset : 1012.5

Keynoteを開く

次にKeynoteを開きましょう。

tell application "Keynote"
        activate
end tell

Keyファイルを開く

次にテロップを入れたいkeyファイルを選択する。

tell application "Keynote"
    activate
    try
        set the chosenDocumentFile to ¬
            (choose file of type ¬
                {"com.apple.iwork.keynote.key", ¬
                    "com.apple.iwork.keynote.kth", ¬
                    "com.apple.iwork.keynote.sffkey", ¬
                    "com.apple.iwork.keynote.key-tef", ¬
                    "com.microsoft.powerpoint.ppt", ¬
                    "org.openxmlformats.presentationml.presentation", ¬
                    "org.openxmlformats.presentationml.presentation.macroenabled", ¬
                    "com.microsoft.powerpoint.pps", ¬
                    "org.openxmlformats.presentationml.slideshow", ¬
                    "org.openxmlformats.presentationml.slideshow.macroenabled", ¬
                    "com.microsoft.powerpoint.pot", ¬
                    "org.openxmlformats.presentationml.template", ¬
                    "org.openxmlformats.presentationml.template.macroenabled"} ¬
                    default location (path to documents folder) ¬
                with prompt "keynoteのドキュメントを選択してください。")
        open the chosenDocumentFile
    on error errorMessage number errorNumber
        if errorNumber is not -128 then
            display alert errorNumber message errorMessage
        else
            error number -128
        end if
    end try
end tell

テキストファイルから文字列を取得

    global text_file
    global text_lines

    set text_lines to {}
    set tmp_file to choose file of type {"Txt","Text"} with prompt "挿入する言葉が記載された.txtファイルを選んでください。"
    set text_file to POSIX path of (tmp_file)
    set tmp_data to do shell script "cat "  & quoted form of (POSIX path of tmp_file)

    repeat with nextLine in  paragraphs of tmp_data
        if length of nextLine is greater than 0 then
            copy nextLine to the end of text_lines
        end if
    end repeat

global変数を使ってる理由はこちらをご確認ください。

Tip:変数の中身をみたい時はlogが便利です
例: log text_lines

テロップ挿入

    set textOverlayDefaultPositionName to item

    set dialogText to "Overlay Text: " & POSIX path of tmp_file & return & ¬
        "Text Color: " & textOverlayColorName & return & ¬
        "Text Size: " & textOverlayFontSize & return & ¬
        "Typeface: " & textOverlayTypeface & return & ¬
        "Text Opacity: " & textOverlayOpacityValue & return & ¬
        "Text Position: " & textOverlayDefaultPositionName

    display dialog dialogText & return & return & "テキストの挿入を行いますか?" buttons ¬
        {"キャンセル", "実行"} default button 1
    set addDeleteOverlay to the button returned of the result
    tell the front document
        set documentWidth to its width
        set documentHeight to its height

        if addDeleteOverlay is not "キャンセル" then
            repeat with i from 1 to the count of slides
                set thisSlide to item i of slides
                set the presenter notes of thisSlide to item i of text_lines
                tell slide i
                    set thisTextItem to ¬
                        make new text item with properties {object text:item i of text_lines as text}
                    tell thisTextItem
                        tell object text
                            set font to textOverlayTypeface
                            set size to textOverlayFontSize
                            set color of it to textOverlayRGBColorValues
                        end tell
                        set textItemWidth to its width
                        set textItemHeight to its height
                        set opacity to textOverlayOpacityValue
                        if textOverlayDefaultPosition is 0 then
                            -- center
                            set x to (documentWidth - textItemWidth) div 2
                            set y to (documentHeight - textItemHeight) div 2
                        else if textOverlayDefaultPosition is 1 then
                            -- top left
                            set x to textItemOverlayOffset
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 2 then
                            -- top right
                            set x to documentWidth - textItemWidth - textItemOverlayOffset
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 3 then
                            -- bottom ceter
                            set x to (documentWidth - textItemWidth ) div 2
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 4 then
                            -- bottom right
                            set x to documentWidth - textItemWidth - textItemOverlayOffset
                            set y to documentHeight - textItemHeight - textItemOverlayOffset
                        end if
                        set position to {x, y}
                    end tell
                end tell
            end repeat
        else
            delete (every text item of every slide whose object text of it is text_lines)
        end if
    end tell

少しコードが長くなりましたが、行っていることは以下です。

  • 実行ダイアログに各プロパティーの表示
  • キャンセル/実行ボタンの設置
  • 実行する場合各プロパティーに前に定義した値を入れて、テロップをスライドに挿入

テキストカラー選択の追加

{"キャンセル", "実行", "色の変更"} default button 1

ボタンの項目に色の変更を追加

if addDeleteOverlay is "色の変更" then
  set textOverlayRGBColorValues to choose color default color textOverlayRGBColorValues
end if

色の変更がクリックされた時の処理を追加

バリデーションの追加

    tell the front document
        if count of slides is not length of paragraphs of tmp_data then
            display dialog dialogText & return & return & "スライドの数とテキストの行数が違いますが、実行しますか?" buttons ¬
            {"キャンセル", "実行", "色の変更"} default button 1
        else
            display dialog dialogText & return & return & "テキストの挿入を行いますか?" buttons ¬
            {"キャンセル", "実行", "色の変更"} default button 1
        end if
    end tell

しゃべらせる

say "処理が正常に終了しました。今日もお仕事頑張ってください。"

sayを使えばなんでもしゃべってくれます。

最終コード

-- OBJECT TEXT PROPERTIES
property textOverlayTypeface : "Arial Bold"
property textOverlayFontSize : 40
property textOverlayColorName : "WHITE"
property textOverlayRGBColorValues : {65535, 65535, 65535}

-- TEXT ITEM PROPERTIES
property textOverlayOpacityValue : 100
property textOverlayDefaultPosition : 3
property textItemOverlayOffset : 870
property textItemPointerOffset : 1012.5

tell application "Keynote"
    activate
    try
        set the chosenDocumentFile to ¬
            (choose file of type ¬
                {"com.apple.iwork.keynote.key", ¬
                    "com.apple.iwork.keynote.kth", ¬
                    "com.apple.iwork.keynote.sffkey", ¬
                    "com.apple.iwork.keynote.key-tef", ¬
                    "com.microsoft.powerpoint.ppt", ¬
                    "org.openxmlformats.presentationml.presentation", ¬
                    "org.openxmlformats.presentationml.presentation.macroenabled", ¬
                    "com.microsoft.powerpoint.pps", ¬
                    "org.openxmlformats.presentationml.slideshow", ¬
                    "org.openxmlformats.presentationml.slideshow.macroenabled", ¬
                    "com.microsoft.powerpoint.pot", ¬
                    "org.openxmlformats.presentationml.template", ¬
                    "org.openxmlformats.presentationml.template.macroenabled"} ¬
                    default location (path to documents folder) ¬
                with prompt "keynoteのドキュメントを選択してください。")
        open the chosenDocumentFile
    on error errorMessage number errorNumber
        if errorNumber is not -128 then
            display alert errorNumber message errorMessage
        else
            error number -128
        end if
    end try

    global text_file
    global text_lines

    set text_lines to {}
    set tmp_file to choose file of type {"Txt","Text"} with prompt "挿入する言葉が記載された.txtファイルを選んでください。"
    set text_file to POSIX path of (tmp_file)
    set tmp_data to do shell script "cat "  & quoted form of (POSIX path of tmp_file)

    repeat with nextLine in  paragraphs of tmp_data
        if length of nextLine is greater than 0 then
            copy nextLine to the end of text_lines
        end if
    end repeat

    set textOverlayDefaultPositionName to item

    set dialogText to "Overlay Text: " & POSIX path of tmp_file & return & ¬
        "Text Color: " & textOverlayColorName & return & ¬
        "Text Size: " & textOverlayFontSize & return & ¬
        "Typeface: " & textOverlayTypeface & return & ¬
        "Text Opacity: " & textOverlayOpacityValue & return & ¬
        "Text Position: " & textOverlayDefaultPositionName

    tell the front document
        if count of slides is not length of paragraphs of tmp_data then
            display dialog dialogText & return & return & "スライドの数とテキストの行数が違いますが、実行しますか?" buttons ¬
            {"キャンセル", "実行", "色の変更"} default button 1
        else
            display dialog dialogText & return & return & "テキストの挿入を行いますか?" buttons ¬
            {"キャンセル", "実行", "色の変更"} default button 1
        end if
    end tell
    set addDeleteOverlay to the button returned of the result
        tell the front document
        set documentWidth to its width
        set documentHeight to its height

        if addDeleteOverlay is "色の変更" then
            set textOverlayRGBColorValues to choose color default color textOverlayRGBColorValues
        end if


        if addDeleteOverlay is not "キャンセル" then
            repeat with i from 1 to the count of slides
                set thisSlide to item i of slides
                set the presenter notes of thisSlide to item i of text_lines
                tell slide i
                    set thisTextItem to ¬
                        make new text item with properties {object text:item i of text_lines as text}
                    tell thisTextItem
                        tell object text
                            set font to textOverlayTypeface
                            set size to textOverlayFontSize
                            set color of it to textOverlayRGBColorValues
                        end tell
                        set textItemWidth to its width
                        set textItemHeight to its height
                        set opacity to textOverlayOpacityValue
                        if textOverlayDefaultPosition is 0 then
                            -- center
                            set x to (documentWidth - textItemWidth) div 2
                            set y to (documentHeight - textItemHeight) div 2
                        else if textOverlayDefaultPosition is 1 then
                            -- top left
                            set x to textItemOverlayOffset
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 2 then
                            -- top right
                            set x to documentWidth - textItemWidth - textItemOverlayOffset
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 3 then
                            -- bottom ceter
                            set x to (documentWidth - textItemWidth ) div 2
                            set y to textItemOverlayOffset
                        else if textOverlayDefaultPosition is 4 then
                            -- bottom right
                            set x to documentWidth - textItemWidth - textItemOverlayOffset
                            set y to documentHeight - textItemHeight - textItemOverlayOffset
                        end if
                        set position to {x, y}
                    end tell
                end tell
            end repeat
        else
            delete (every text item of every slide whose object text of it is text_lines)
        end if
    end tell
    say "処理が正常に終了しました。今日もお仕事頑張ってください。"
end tell

おわりに

普段は業務でRailsとVueを使っているのですが、全く違う言語を触るのもたまにはいいなと感じました。
Macユーザーなら割とAppleScript使っていろいろ面白そうなことできそうなので、また機会があれば触ってみたいです。

参考URL

keynoteを開く
https://iworkautomation.com/keynote/document-open.html

テキストを作成して記載する
https://iworkautomation.com/keynote/text-item-overlay.html

プレゼンテータノート
https://iworkautomation.com/keynote/slide-presenter-notes.html

テキストを読み込む(文字化け対応)
http://underwoodmac.cocolog-nifty.com/blog/2011/07/applescriptread.html

グローバル変数
http://www.script-factory.net/history/2012/06/27_1832.xhtml

基本文法
https://qiita.com/MMRN/items/5e622eee5c736a42ee38

22
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
3