素材動画や静止画にテキストを読み上げソフトで作成された音声ファイル割り当てて一本の動画に仕立て上げるるソフト「ゆっくりMoviemaker3」。
このソフト、特徴的な音声読み上げキャラクターのおかげでYoutubeなどの動画投稿サイトで、このソフトで作成されたと思われる動画がすぐ見つかります。
昔からテキストの読み上げソフトに興味があり、それを組合せて動画というコンテンツを手軽に作成出来るソフトを無償で公開している作者様には頭が下がる思いです。素晴らしいソフトではありますが、興味はあっても動画投稿向けのコンテンツ作成をする人間では無いので、これまで触れる機会がありませんでした。
あるときパワーポイントでプレゼン資料を作っていて、台本を打ち込んでいる際「台本通りしゃべるだけなら、別に自分がプレゼンターでなくてもいいんじゃないか?」と、プレゼン資料を作るたびにおきる思考ループが始まりかけていた時でした。次に、パワーポイントに動画作成機能を見ながら「事前に台本吹き込んでおけば、プレゼン当日は動画を流しておけば・・・?」とか考えます。
それで済むプレゼンかどうかは別として。結局自分が台本をしゃべらなくてはならないのは変わらないので、労力をかけて事前に吹き込むのは無しだなと。次考えることは「台本作るのめんどくさい。事前台本を用意するのはやめて自分がしゃべるんだったら全部アドリブにしよう!!」とこうなります。
その日の自分は違いました。テキストの読み上げソフトを使えば自分で音声を吹き込むことなく用意した台本のテキストを音声化することが出来ることに気づいたのです。
でも、読み上げソフトで出来上がった音声ファイルをプレゼン資料に割り当てるのは結構面倒です。それも多数の音声ファイルをタイミングよく資料に割り当てるには、何らかの方法で音声ファイルの内容を視覚化する必要があります。大概ファイル名に内容を入力するわけですが、これが大変面倒。適当なファイル名にすると出来上がる動画が悲惨な事になります。
思いつきは悪くないですが、相当忍耐が必要な作業になります。
この面倒さを何とかしてくれるソフトは無いのかと調べること幾星霜、「ゆっくりMoviemaker3」に巡り合うわけです。
結局プレゼンには使ったことは無いのですが。
使ってみるとタイムライン(時間軸)のウィンドウに画像ファイルをドラック&ドロップすると画像1つで10秒程の動画になります。必要な枚数分ドラック&ドロップを繰り返します。
画像ファイルを複数選択してドラック&ドロップしてみると、縦方向に画像が並びます。普通、同じ時間軸の動画、静止画、音声を編集することになりますので、縦に並んだほうが都合がよいので縦に並ぶわけです。
しかし、私の場合、同一時間軸に必要となるアイテムは画像ファイル1つだけなので、ドラック&ドロップをするとタイムラインの横軸にに画像アイテムが並んで欲しい。少量のファイルであれば縦に並んだアイテムをマウスで移動させれば良いですが、多量にあるとさすがに・・・。色々試行錯誤してみましたが良い方法は見つけられませんでした。
操作で無理であれば、あらかじめ画像アイテムの読み込み位置を指定したプロジェクトファイル(.ymmp)を作ってしまえば良いのではと考えた次第です。
ここからやっと本題
プロジェクトファイル(.ymmp)をテキストエディタで開いてみると中身はxmlでした。ということはスクリプトで作ることが出来るはずです。
それで、使われているxmlの要素を調べてみました。
各要素
- TimelineItems
- タイムライン(アイテムを配置する場所)
- CommonItems xsi:type=”ImageItem”
- 画像アイテム。
- TimelineY
- Layer番号、タイムラインのY軸
- DoubleItemEnd
- 画像の表示時間、単位ミリ秒
- HeadColor
- アイテムの開始色
- FootColor
- アイテムの終了色
- FilePath
- 画像ファイルのパス
- DoubleTimeX
- アイテムの表示開始位置、単位ミリ秒、タイムラインのX軸
画像の追加に必要そうな要素を調べました。
あとはスクリプトを組んでいきます。
<#
.SYNOPSIS
ゆっくりMoviemaker3のプロジェクトに画像を追加するスクリプト
#>
using namespace System.Xml
using namespace System.Drawing
param(
[string]$SrcPath = ".\empty.ymmp",
[string]$ImgDir = "画像のディレクトリ",
[string]$DestPath = ".\new.ymmp",
[int]$ItemTime = 10000
)
$ErrorActionPreference = "STOP"
Add-Type -AssemblyName System.Drawing
function Main
{
param([string]$SrcPath, [string]$ImgDir, [string]$DestPath, [int]$ItemTime)
# ImageItemの生成
function AppendImageItem
{
param(
[xml]$xml,
[int]$line_y,
[int]$line_x,
[int]$item_end,
[string]$file_name
)
$element = $xml.CreateElement("CommonItem")
$element.SetAttribute("type","http://www.w3.org/2001/XMLSchema-instance" ,"ImageItem") | Out-Null
if ($line_x -gt 0)
{
$dtlx = $xml.CreateElement("DoubleTimelineX")
$dtlx.InnerText = $line_x
$element.AppendChild($dtlx) | Out-Null
}
$tly = $xml.CreateElement("TimelineY")
$tly.InnerText = $line_y
$element.AppendChild($tly) | Out-Null
$die = $xml.CreateElement("DoubleItemEnd")
$die.InnerText = $item_end
$element.AppendChild($die) | Out-Null
$hc = $xml.CreateElement("HeadColor")
$hc_a = $xml.CreateElement("A")
$hc_a.InnerText = 255
$hc.AppendChild($hc_a) | Out-Null
$hc_r = $xml.CreateElement("R")
$hc_r.InnerText = 0
$hc.AppendChild($hc_r) | Out-Null
$hc_g = $xml.CreateElement("G")
$hc_g.InnerText = 0
$hc.AppendChild($hc_g) | Out-Null
$hc_b = $xml.CreateElement("B")
$hc_b.InnerText = 139
$hc.AppendChild($hc_b) | Out-Null
$hc_sca = $xml.CreateElement("ScA")
$hc_sca.InnerText = 1
$hc.AppendChild($hc_sca) | Out-Null
$hc_scr = $xml.CreateElement("ScR")
$hc_scr.InnerText = 0
$hc.AppendChild($hc_scr) | Out-Null
$hc_scg = $xml.CreateElement("ScG")
$hc_scg.InnerText = 0
$hc.AppendChild($hc_scg) | Out-Null
$hc_scb = $xml.CreateElement("ScB")
$hc_scb.InnerText = 0.258182853
$hc.AppendChild($hc_scb) | Out-Null
$element.AppendChild($hc) | Out-Null
$fc = $xml.CreateElement("FootColor")
$fc_a = $xml.CreateElement("A")
$fc_a.InnerText = 255
$fc.AppendChild($fc_a) | Out-Null
$fc_r = $xml.CreateElement("R")
$fc_r.InnerText = 0
$fc.AppendChild($fc_r) | Out-Null
$fc_g = $xml.CreateElement("G")
$fc_g.InnerText = 0
$fc.AppendChild($fc_g) | Out-Null
$fc_b = $xml.CreateElement("B")
$fc_b.InnerText = 255
$fc.AppendChild($fc_b) | Out-Null
$fc_sca = $xml.CreateElement("ScA")
$fc_sca.InnerText = 1
$fc.AppendChild($fc_sca) | Out-Null
$fc_scr = $xml.CreateElement("ScR")
$fc_scr.InnerText = 0
$fc.AppendChild($fc_scr) | Out-Null
$fc_scg = $xml.CreateElement("ScG")
$fc_scg.InnerText = 0
$fc.AppendChild($fc_scg) | Out-Null
$fc_scb = $xml.CreateElement("ScB")
$fc_scb.InnerText = 1
$fc.AppendChild($fc_scb) | Out-Null
$element.AppendChild($fc) | Out-Null
$fp = $xml.CreateElement("FilePath")
$fp.InnerText = $file_name
$element.AppendChild($fp) | Out-Null
$element
}
# 動画サイズの計算
$file = (Get-ChildItem $ImgDir -File -Filter "*.png" | select -First 1).FullName
$bmp = [Bitmap]::FromFile($file)
$Width = $bmp.Width
$Height = $bmp.Height
$bmp.Dispose()
$xml = [xml](Get-Content -Encoding UTF8 -Path $SrcPath)
$w = $xml.GetElementsByTagName("Width").Item(0)
$w.InnerText = $Width
$h = $xml.GetElementsByTagName("Height").Item(0)
$h.InnerText = $Height
$t = $xml.GetElementsByTagName("TimelineItems").Item(0)
Get-ChildItem $ImgDir -File -Filter "*.png" | % -Begin {
$i = 0
} -Process {
$file = $_.FullName
$len = [int]$ItemTime
$c = AppendImageItem $xml 0 ($i * $ItemTime) $len $file
$t.AppendChild($c) | Out-Null
$i++
}
$xml.Save($DestPath)
}
Main $SrcPath $ImgDir $DestPath $ItemTime
使い方
一度ゆっくりMoviemaker3を起動しプロジェクトを「empty.ymmp」で保存。
スクリプト内のempty.ymmpのパスをプロジェクトを保存した場所に合わせて$SrcPath
をセットする。
スクリプト内の追加したい画像ファイルのディレクトリのパスを$ImgDir
へセットする。
ディレクトリには追加したいファイルのみを置くこと。
余分なファイルの除外や並び替えをしたい場合スクリプトを修正。
スクリプトを実行すると画像ファイルが追加された「new.ymmp」が作成される。
出来上がった「new.ymmp」をMoviemaker3で読み込むと、画像ファイルのアイテムがタイムラインの横軸に並んでいれば成功です。
あとはお好きなように。
注).ymmpを自己解析したものであり公式の情報ではありません。今のところ問題なく動きますが、仕様変更などがあった場合確実に動かなくなると思われます。
コメント