アニメGIF ダウンロードサーバーとは
- フリーソフト9VAeをベースに開発された、PEASmotch! は、キッズプラザ大阪に5台設置され、毎日150から200本のアニメが作られている。
- 作成したベクトルアニメーションは、共有サーバーに保存され、専用プレーヤー 9view を使って、連続したアニメーションとして大型ディスプレイで上映されているが、かねてから、作ったアニメーションをスマホに入れて持ち帰りたいという要望があった。
- それを実現する方法として、共有サーバーのアニメーションをアニメGIFに変換する python プログラムを公開した。
- 今回、Flask を用いて、スマホからアクセスできるサーバープログラムを作成したので公開する。
- スマホにアニメをダウンロードできる
- サイトのURLアドレスをQRコードで表示する
- スマホアプリ(9VAe, PEASmotch)からアニメをアップロードできる
以下の記事も関連している
項目 | パソコン | スマホ |
---|---|---|
WiFiアクセスポイントの設置 | 〇 | 〇 |
共有フォルダにアニメを保存、連続上映 | 〇 | |
作成したアニメをスマホにダウンロード(本記事) | 〇 | |
スマホアプリからアニメをアップロード(本記事) | 〇 |
以下はプログラムの実行例。表示されているURLをスマホでアクセスすれば同じ画面が表示され、アニメーションをダウンロードできる。
Python のインストール
プログラムは python を使う。Windows と ラズベリーパイで作成してみた。
Windowsの場合
- Python.jpのフルインストーラ版から、ダウンロードするのが簡単。ここ(pythonlinks.python.jp)から32bit/64bitなどを選んでダウンロードできる。
Windowsの場合(仮想環境)
- こちらの記事の anaconda は、仮想環境で実行できる。アプリごとにライブラリを使い分けるときに便利。
- 日本語を使いたいので、Python Ver3をダウンロード。(anacondaインストール後の「anaconda-navigator」の実行はWindowsロゴから行う必要があったが、ほかは記事どおりに実行できた)
ラズベリーパイの場合
- python(Ver2), python3(Ver3) が最初からはいっている
Flask とQRコードライブラリのインストール
次のコマンドで、Flask とQRコード用ライブラリをインストールする。(ラズベリーパイの場合 pip3 、 python3 をつかう)pip が見つからない場合、pythonをインストールしたなかに、pip がはいっていると思われるので、そのフォルダに移動してから実行するとよい。
pip install Flask
pip install qrcode
pip install pillow
Linuxで上の命令で失敗した場合は、次の命令をためしてみてください
sudo apt-get install python-Flask
sudo apt-get install python-qrcode
sudo apt-get install python-pillow
アニメGIF ダウンロードサーバー
環境が整ったのであとはプログラム
フォルダ構成
Flask サンプルを参考に、以下のフォルダ構成とした。app.py がプログラム本体。ここに Flask を起動するコードがかかれている。templatesの中の設定データを利用して Web サイトの応答が行われる。
py
├──app.py (プログラム本体)
├──static
│ ├──qrcode.png(プログラムで作成される)
│ └──setpath.ini(プログラムで作成される)
└──templates
├──index.html
└──layout.html
python Flask ソースコード
- ソースコードは、すべて UTF-8 で作成すること
templates
Webサイトの内容が index.html に書かれている。
{% extends "layout.html" %}
{% block content %}
<img src="{{ url_for('static', filename='qrcode.png') }}" width="200">
<br>
画像を長押しすればダウンロードできます。<br>
Long press on the image to download.<br>
<div align="right">
{{ message }} <br>
<a href="{{ url_for('static', filename='setpath.ini') }}">setpath.ini</A>
</div>
{% if images %}
{% for path in images %}
{% if '.eva.gif##' in path %}
{% elif '.eva.gif' in path %}
<div>
<img src="images/{{ path }}" style="margin-top: 10px; vertical-align: bottom; width: 200px;">
{{ path }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
記述 | 意味 | 補足 |
---|---|---|
{% extends "layout.html" %} | ページレイアウトの設定ファイル | |
{% block content %}...{% endblock %} | この部分が中身 | |
<img src="{{ url_for('static', filename='qrcode.png') }}" | staticフォルダの中のQR画像を表示 | |
{{ message }} | 引数messageの文字列表示 | |
{% if images %} | 引数images(ファイル名リスト)があれば | |
{% for path in images %} | imagesリストの要素path(ファイル名)を順番に | |
{% if '.eva.gif' in path %} | .eva.gifが含まれるファイルだけ処理 | |
<img src="images/{{ path }}" | images/フォルダのファイル | |
{{ path }} | ファイル名も表示 | |
{% endif %} | ifの終わり | |
{% endfor %} | forの終わり |
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>9VAe Anime Post</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
記述 | 意味 | 補足 |
---|---|---|
{% block content %}{% endblock %} | この部分に中身がはいる |
app.py
以下の値は環境に応じて設定
定数 | 意味 | 補足 |
---|---|---|
EVA_FOLDER | アニメを保存するフォルダ | 例では「/home/pi/2018」 |
QVIEW_EXE | 9view.exe のフルパス | Windowsでもパスの区切りは'/' |
HTTP_URL | 公開するURLアドレス | 最初は'127.0.0.1'でテストする |
HTTP_PORT | 公開するポート | 最初は5000でテストする |
- アニメの保存フォルダについて、共有フォルダ直下でうまくいかない場合、共有フォルダの中のフォルダを指定してみてください。
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, make_response
import os # ファイル操作
import subprocess # プログラム実行
import time # 時間処理
import re # 文字置換,正規表現
import webbrowser # ブラウザ
import threading # multi thread
import qrcode # QRコード生成
EVA_FOLDER = '/home/pi/xxxxxx' #アニメを保存するフォルダ
QVIEW_EXE = '/home/pi/9va/9view' #9view.exe のフルパス
HTTP_URL = '192.168.99.1' #公開するURLアドレス
HTTP_PORT = 8080 #公開するポート
app = Flask(__name__)
inpFolder = EVA_FOLDER
class MyThread(threading.Thread):
def __init__(self):
super(MyThread, self).__init__()
def run(self):
loop(self,False)
@app.route('/')
def index():
global inpFolder
return render_template('index.html', images=sorted(os.listdir(inpFolder)[::-1], reverse=True), message = inpFolder)
@app.route('/images/<path:path>')
def send_js(path):
global inpFolder
return send_from_directory(inpFolder, path)
@app.route('/',methods=["POST"]) #アニメのアップロード
def save_eva():
global inpFolder
mno = -1
#print("Posted file: {}".format(request.files['file']))
file = request.files['file']
if(file.filename.endswith('.eva')):
files = [f for f in os.listdir(inpFolder)] #入力
for fn in files:
eva = os.path.join(inpFolder,fn)
if(not eva.endswith('.eva')):
continue
if( '_編集中' in eva): #自動保存ファイルは無視
continue
if( '_とちゅう' in eva):
continue
if( '_autosave' in eva):
continue
no = int(os.path.splitext(os.path.basename(fn))[0])
if(no > mno): #最終番号を探す
mno = no
savepath = os.path.join(inpFolder, '%04d.eva' % (mno+1))
file.save(savepath)
return str(mno+1) #保存した番号を返す
# GIF変換ループ
def loop(self,askFolder):
global inpFolder
drmax = '0000-0000'
while True:
dirs = [f for f in os.listdir(EVA_FOLDER)] #一番新しい日付を取得
drs = [s for s in dirs if re.match('[0-9]{4}-[0-9]{4}', s)]
for dr in drs:
if dr > drmax:
drmax = dr
inpFolder = EVA_FOLDER + '/' + drmax
if(askFolder):
return inpFolder
files = [f for f in os.listdir(inpFolder)] #入力
for fn in files:
if(os.path.splitext(fn)[1] != '.eva'):
continue
gif = fn + '.gif' #GIFファイル名
gif = os.path.join(inpFolder,gif)
eva = os.path.join(inpFolder,fn)
if( '_編集中' in eva): #自動保存ファイルは無視
continue
if( '_とちゅう' in eva):
continue
if( '_autosave' in eva):
continue
if(os.path.exists(gif)): #gifが存在,作成すみチェック
if(os.path.getmtime(gif) > os.path.getmtime(eva)):
continue
cmd = (QVIEW_EXE , eva , '-gif') #-gif オプションでGIFに変換
print(cmd) #変換したことを表示
subprocess.run(cmd) #gif作成
time.sleep(1.0) #sleep(秒指定)
return inpFolder
t = MyThread()
inpFolder = loop(t,True) #evaが修正されたらgif作成、新フォルダへの移動
t.start()
html = 'http://' + HTTP_URL + ':' + str(HTTP_PORT)
img = qrcode.make(html) #QR code作成
img.save('static/qrcode.png')
with open('static/setpath.ini', mode='w') as f:
f.write(html)
if __name__ == '__main__':
webbrowser.open(html) #ブラウザ起動
app.run(debug=True, host=HTTP_URL, port=HTTP_PORT)
記述 | 意味 | 補足 |
---|---|---|
from flask import Flask, ... | Flask用拡張 | |
import | 関数を使えるようにする | |
app = Flask(name) | 処理の名前 | |
class MyThread(threading.Thread): | マルチスレッド定義 | Flask内で同時実行する |
def run(self): | MyThreadで実行する処理 | |
@app.route('/') | ルートアクセスで表示される内容 | |
def: | 関数定義 | |
global inpFolder | 変数inpFolderは全体で共通 | |
render_template('index.html' | Flaskのtemplates/index.html を表示 | |
os.listdir(inpFolder)[::-1] | inpFolderのファイル全部 | -1は最後の意味 |
sorted(xxx, reverse=True) | リストを逆順でソート | |
@app.route('/images/path:path') | /images/のアクセスで表示される内容 | index.htmlから呼ばれる |
send_from_directory(inpFolder, path) | inpFolderフォルダのpathファイル | |
@app.route('/',methods=["POST"]) | POSTを受け取ったときの処理 | アップロード用 |
request.files['file'] | POSTされたファイル | |
if(file.filename.endswith('.eva')): | 拡張子が.evaの場合 | |
files = [f for f in os.listdir(inpFolder)] | inpFolderのファイルをリスト化 | |
os.path.splitext(os.path.basename(fn))[0] | 拡張子のないファイル名 | |
int(文字列) | 文字列を数値に変換 | |
'%04d.eva' % (mno+1) | 数値(mno+1)を文字列に変換 | |
savepath = os.path.join(inpFolder,ファイル名) | フォルダとファイル名の結合 | |
file.save(savepath) | ファイルをsavepathに保存 | POSTされたファイルを別名で保存 |
if re.match('[0-9]{4}-[0-9]{4}', s) | s が「数字4桁-数字4桁」の場合 | 正規表現 |
if(os.path.exists(gif)): | ファイルが存在した場合 | |
os.path.getmtime(gif) | ファイルの更新時間 | |
cmd = (QVIEW_EXE , eva , '-gif') | コマンド作成 | EVAアニメをGIFに変換 |
subprocess.run(cmd) | コマンド実行 | |
time.sleep(1.0) | 1秒停止 | |
t = MyThread() t.start() |
マルチスレッドの実行 | |
img = qrcode.make(html) | QRコード画像imgを作成 | |
img.save('static/qrcode.png') | 画像imgをstaticフォルダに保存 | |
with open('static/setpath.ini', mode='w') as f: | 書き込みファイルをオープン | |
f.write(html) | 文字列の書き込み | |
webbrowser.open(html) | ブラウザ起動 | |
app.run(debug=True, host=HTTP_URL, port=HTTP_PORT) | URL、Portを指定して実行 |
使い方
ラズベリーパイで実行した例を示す
- ラズベリーパイで WiFi アクセスポイントを作成し、URL「192.168.99.1」で公開した。やり方はこちら
- ターミナルでpyフォルダに移動。python3 app.py でプログラムを実行
- ブラウザが開き、以下のように表示される
スマホにアニメをダウンロードする方法
- スマホのWiFi設定で、ラズベリーパイアクセスポイントにWiFiをつなぐ
- スマホでQRコードをみてURLをひらく > 上と同じ画面が開く
- アニメーションを長押しし、メニューから「ダウンロード」を選べばGIFアニメをダウンロードできます。
スマホアプリ(PEASmotch!one)からアニメをアップロードする方法
- ラズベリーパイアクセスポイントにWiFiをつなぐ
- スマホでQRコードをみてURLをひらく > 上と同じ画面が開く
setpath.iniの設定
- setpath.ini を長押しし、「リンクをダウンロード」>setpath.ini ファイルをダウンロードする
- ファイルマネージャなどのアプリをつかって、setpath.ini ファイルを「PEASmotch」フォルダに入れる
- PEASmotchを起動し、PEASロゴをタッチ、メニューの一番下に「アップロード」が追加されていればOK。
- メニューの最後の「アップロード」項目は、スマホが、9VAeアニメGIF POSTと接続しており、保存用フォルダにアクセスできるときだけ表示される。
- アニメを作成し「アップロード」をタッチすればアニメが保存され、自動的に gif ファイルに変換される。(上の app.py プログラムの MyThread が新しいファイルを検出し、EVAからGIFに変換を行う)
- スマホ版のアップロード機能は、Ver.0.6.12(200110) 以降の PEASmotch!one に搭載された。なお、パソコン版の場合は、9va_dataフォルダの中の setpath.ini に共有フォルダのフルパスを記載しておき、直接保存する機能が従来から搭載されている。
問題点と改良版
上のシステムを実際にキッズプラザ大阪に設置したところ、以下のような問題があった。
問題点 | 修正 |
---|---|
Windows7の共有フォルダにfopenではアクセスできたが、statがアクセスできなかった | ファイルの存在チェックを、statを使わずにfopenを使う関数に変更 |
ラズパイで共有フォルダ上でEVA-GIF変換を行うと、ほかの端末から共有フォルダへの接続ができなくなった。Windowsの記憶域不足エラーが発生 | 共有フォルダからラズパイに1日分のフォルダを転送し、ラズパイ上でEVA-GIF変換、Flaskサーバー応答を行うように変更 |
上のプログラムだと、EVA-GIF変換が2つ起動してしまう | Flaskの応答とEVA-GIF変換を別プログラムにして起動する |
EVA-GIF変換の変換途中のファイルをFlaskサーバーが表示しようとしてエラー表示が出る | 変換途中の拡張子を、.gif##とし、変換終了後に.gifにリネームする |
EVAファイルを転送するときに、0バイトのファイルができることがある。 | 0バイトのファイルは削除する |
Macから共有フォルダをアクセスしたときに、隠しファイルがいくつも作成される。そのファイルを処理しようとしてエラー終了する | Macが作成する隠しファイルは読み飛ばす処理が必要 |
POSTしても応答がない | 2文字のPOSTに改行をつけないと、Linuxでは返事がこなかった。Windowsでは返事があった。 |
保存フォルダの読み書き属性。日付によってフォルダ変更する場合、外部端末によって日付フォルダを作成すると、POSTでデータが書けなくなった。 | Pythonで、日付がかわったら、日付フォルダを作成し、すべてのユーザーに読み書き可能にするよう設定する |
WindowsのPythonで動かすと、POSTの応答がうまくできない | セキュリティ設定が原因か?、firewall は、Pythonと Flask と両方許可したが、Webサイトは見えるが、POSTの応答がうまくいかない。Linuxだとちゃんと応答する。対策不明 |
改良版プログラム
上の問題を修正したプログラム app-2.py, gif-2.py が以下
ダウンロードサーバープログラム
サーバーは内部フォルダをみる。内部フォルダで、GIF変換を行う。内部フォルダを最新にするのは、GIF変換プログラム。
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, make_response
import os # ファイル操作
import shutil # ファイル操作
import subprocess # プログラム実行
import time # 時間処理
import re # 文字置換,正規表現
import webbrowser # ブラウザ
import threading # multi thread
import qrcode # QRコード生成
import datetime # 日付、時刻
EVA_FOLDER = '/home/share/xxxxxx' #アニメを保存する内部フォルダ(1日分)
HTTP_URL = '192.168.99.1' #公開するURLアドレス(例)
HTTP_PORT = 8080 #公開するポート
app = Flask(__name__)
inpFolder = EVA_FOLDER
class MyThread(threading.Thread):
def __init__(self):
super(MyThread, self).__init__()
def run(self):
loop(self,False)
@app.route('/')
def index():
global inpFolder
return render_template('index.html', images=sorted(os.listdir(inpFolder)[::-1], reverse=True), message = inpFolder)
@app.route('/images/<path:path>')
def send_js(path):
global inpFolder
return send_from_directory(inpFolder, path)
@app.route('/',methods=["POST"]) #アニメのアップロード
def save_eva():
global inpFolder
mno = -1
#print("Posted file: {}".format(request.files['file']))
file = request.files['file']
if(file.filename.endswith('.eva')):
files = [f for f in os.listdir(inpFolder)] #入力
for fn in files:
eva = os.path.join(inpFolder,fn)
if(not eva.endswith('.eva')):
continue
if( '_編集中' in eva): #自動保存ファイルは無視
continue
if( '_とちゅう' in eva):
continue
if( '_autosave' in eva):
continue
no = int(os.path.splitext(os.path.basename(fn))[0])
if(no > mno): #最終番号を探す
mno = no
savepath = os.path.join(inpFolder, '%04d.eva' % (mno+1))
file.save(savepath)
return str(mno+1) #保存した番号を返す
# 新しいフォルダができていないか確認するループ
def loop(self,askFolder):
global inpFolder
drmax = '0000-0000'
while True:
dirs = [f for f in os.listdir(EVA_FOLDER)] #一番新しい日付を取得
drs = [s for s in dirs if re.match('[0-9]{4}-[0-9]{4}', s)]
for dr in drs:
if dr > drmax:
drmax = dr
inpFolder = EVA_FOLDER + '/' + drmax
if(not os.path.exists(inpFolder)): #フォルダがなかったら作成
os.mkdir(inpFolder)
if(askFolder):
return inpFolder
dy = datetime.date.today()
nm = '{:04d}-{:02d}{:02d}'.format(dy.year,dy.month,dy.day)
dir = EVA_FOLDER + '/' + nm
if not os.path.exists(dir): #今日のフォルダがなければ作成、読み書き可能にする
os.mkdir(dir)
os.chmod(dir, 0o777)
inpFolder = dir
time.sleep(5.0) #sleep(秒指定)
return inpFolder
t = MyThread()
inpFolder = loop(t,True) #新フォルダへの移動
t.start()
html = 'http://' + HTTP_URL + ':' + str(HTTP_PORT)
img = qrcode.make(html) #QR code作成
img.save('static/qrcode.png')
with open('static/setpath.ini', mode='w') as f:
f.write(html)
if __name__ == '__main__':
webbrowser.open(html) #ブラウザ起動
app.run(debug=True, host=HTTP_URL, port=HTTP_PORT)
EVA→GIF変換プログラム
import os # ファイル操作
import shutil # ファイル操作
import subprocess # プログラム実行
import time # 時間処理
import re # 文字置換,正規表現
#ラズベリーパイ 例
ORG_FOLDER = '/home/pi/xxxxxx' #アニメを保存するフォルダ(オリジナルをmount)
EVA_FOLDER = '/home/share/xxxxxx' #アニメを保存する内部フォルダ(1日分)
QVIEW_EXE = '/home/pi/9va/9view' #9view.exe のフルパス
EVAorSVG = '.eva' #'.svg'
# Windows 例
#ORG_FOLDER = 'Q:/share/xxxxxx' #ネットワークドライブで指定
#EVA_FOLDER = 'C:/share/xxxxxx' #内部フォルダ
# Macintosh 例
#QVIEW_EXE = '/Volumes/9VAe1033a/9VAe.app/Contents/MacOS/9VAe' #ダウンロードした 9VAeの場合
orgFolder = ORG_FOLDER
inpFolder = EVA_FOLDER
# GIF変換ループ
drmax = '0000-0000'
while True:
dirs = [f for f in os.listdir(ORG_FOLDER)] #一番新しい日付を取得
drs = [s for s in dirs if re.match('[0-9]{4}-[0-9]{4}', s)]
for dr in drs:
if dr > drmax:
drmax = dr
orgFolder = ORG_FOLDER + '/' + drmax
inpFolder = EVA_FOLDER + '/' + drmax
#ORGとINPを比較してデータ取得
if(not os.path.exists(inpFolder)): #フォルダがなかったら作成
os.mkdir(inpFolder)
files = [f for f in os.listdir(orgFolder)] #入力
for fn in files:
eva = os.path.join(inpFolder,fn)
if(not os.path.exists(eva)): #ファイルがなかったら転送
org = os.path.join(orgFolder,fn)
shutil.copy(org, inpFolder)
#不要フォルダ削除
files = [f for f in os.listdir(EVA_FOLDER)]
for fn in files:
if( '.DS_Store' in fn): # Mac用システムフォルダは無視
continue
if(fn != drmax):
dr = os.path.join(EVA_FOLDER,fn)
shutil.rmtree(dr)
#サイズ0のEVAファイルは削除
files = [f for f in os.listdir(inpFolder)] #入力
for fn in files:
if(os.path.splitext(fn)[1] == EVAorSVG):
dr = os.path.join(inpFolder,fn)
if(os.path.getsize(dr)==0): #サイズが0のファイルは削除
os.remove(dr)
#GIF作成
files = [f for f in os.listdir(inpFolder)] #入力
for fn in files:
if(os.path.splitext(fn)[1] != EVAorSVG):
continue
gif = fn + '.gif' #GIFファイル名
gif = os.path.join(inpFolder,gif)
eva = os.path.join(inpFolder,fn)
if( '_編集中' in eva): #自動保存ファイルは無視
continue
if( '_とちゅう' in eva):
continue
if( '_autosave' in eva):
continue
if(os.path.exists(gif)): #gifが存在,作成すみチェック
if(os.path.getmtime(gif) > os.path.getmtime(eva)):
continue
cmd = (QVIEW_EXE , eva , '-gif') #-gif オプションでGIFに変換
#cmd = (QVIEW_EXE , eva , '-gif-trans') #-trans 背景透明にする場合
print(cmd) #変換したことを表示
subprocess.run(cmd) #gif作成
break;
time.sleep(1.0) #sleep(秒指定)
起動方法(ラズベリーパイ)
起動時に、以下のシェルスクリプトで、EVAアニメを保存する共有フォルダをマウントし、その後、GIF変換、ダウンロードサーバーを起動しています。
#!/bin/sh
sudo mount -t cifs //xx.xx.xx.xx/xx/xxxxxx /home/pi/xxxxxx -o user=xxxx,password=xxxx,sec=ntlmssp,nounix,noperm,rw
sleep 10
cd /home/share/py
python3 /home/share/py/gif-2.py &
python3 /home/share/py/app-2.py
起動方法(Windows)
- Windowsの場合、EVAアニメの共有フォルダをネットワークドライブに割り当てれば、Pythonからアクセスできます。(以下の例では gif.bat の中のnet use 命令で、Qドライブに割り当て)
- GIF変換とサーバーの2つを別々のバッチファイルで起動します。
GIF変換の起動
timeout /t 30
net use Q: \\xx.xx.xx.xx\xxxx パスワード /user:ユーザー名
cd C:\Users\xx\xx\xx\py
python gif.py
pause
ダウンロードサーバーの起動
timeout /t 50
cd C:\Users\xx\xx\xx\py
python app.py
pause
timeout は指定した時間(秒)待つ命令で、この2つをスタートアップフォルダに入れれば、先にGIF変換が起動し、そのあと、サーバーが起動します。
固定IPアドレスの割り当て
- ダウンロードサーバー用 WiFiアクセスポイントは、WiFiルーターを使用しました。
- Windows 機は、Wifi と、EVAアニメを保存する共有サーバーと2つのネットワークに接続します。それぞれ、固定IPアドレスを割り当てました。(コントロールパネル>ネットワークとインターネット>アダプターオプション>WiFiやLANアダプタアイコンの右ボタンメニュー>プロパティ>インターネットプロトコル(TCP/IPV4)>プロパティ>「IPアドレスを自動的に取得する」から「次のIPアドレスを使う」に変更)
- 設定した固定IPアドレスを、Pythonプログラムの記載と一致させます。
Macintoshの場合
ダウンロードしたドライブイメージをダブルクリックし、9VAe1033a というフォルダの中に、9VAe アプリがある場合
QVIEW_EXE = '/Volumes/9VAe1033a/9VAe.app/Contents/MacOS/9VAe'
のように書けばGIF変換できます。上のプログラムは、EVAファイルを変換しますが、EVAorSVG を'.svg'にすれば、SVGファイルを変換できます。(.evaのほうがサイズが小さいので、転送エラーがおこる場合は、EVAで運用したほうがよいでしょう)
設定例
- ここから 9VAeをダウンロード(右上のダウンロードボタン)
- ダブルクリックして展開。
- 9VAeを右ボタンクリックから「開く」(2回目に実行できる)
- ターミナルに9VAeをドラッグすると、9VAeのフルパスがわかります。
- デスクトップなどに、9VAeアニメを集めるフォルダを作成します。
- その中に、(1) 上の Python プログラム(gif-2.py)を作ります。
- (2) 年号-月日というフォルダ名を作ります。例「2023-0505」
- GIFを出力するフォルダをつくります。年号ー月日と同じ場所につくってもかまいません。
- gif-2.py プログラムの下の4行を修正します。
- ORG_FOLDER 年号-月日の親フォルダを指定します。
- EVA_FOLDER GIF出力するフォルダを指定します
- QVIEW_EXE 9VAeのパスを指定します(最後は9VAe.app/Contents/MacOS/9VAe)
- EVAorSVG SVGファイルを変換する場合は'.svg'にします
- ターミナルで、gif-2.py をいれたフォルダに移動(cd フォルダ)
- python3 gif-2.py
- 年号-月日フォルダが、ORG_FOLDER の中にある場合、その一番最後の月日が、EVA_FOLDERの中に作成され、データ入力待ちになります。最後の月日フォルダの中に、アニメが保存されると、自動的に変換フォルダにコピーされ、同じ名前のGIFファイルが作られます。