--PEASmotch!, which was developed based on the free software 9VAe, has been installed in Kids Plaza Osaka, and 150 to 200 pieces daily. An anime is being made. --The created vector animation is saved on the shared server and shown on a large display as a continuous animation using Dedicated Player 9view. However, for some time, there was a request to put the created animation in a smartphone and take it home. --As a way to achieve that, we have released the python program that converts animation to animated GIF on the shared server. --This time, I created a server program that can be accessed from a smartphone using Flask, so I will publish it. --You can download anime to your smartphone --Display the URL address of the site with a QR code --You can upload anime from your smartphone app (9VAe, PEASmotch)
The following articles are also relevant
item | computer | smartphone |
---|---|---|
Installation of WiFi access point | 〇 | 〇 |
Save animation in shared folder, continuous screening | 〇 | |
Download the created animation to your smartphone (this article) | 〇 | |
Upload anime from your smartphone app (this article) | 〇 |
The following is an example of program execution. If you access the displayed URL with your smartphone, the same screen will be displayed and you can download the animation.
The program uses python. I made it with Windows and Raspberry Pi.
For Windows
--There are various versions and libraries of python, but I used anaconda that can install virtual environment. ――I want to use Japanese, so download Python Ver3. (It was necessary to execute "anaconda-navigator" after installing anaconda from the Windows logo, but other things could be executed as described in the article)
For Raspberry Pi
--python (Ver2), python3 (Ver3) are included from the beginning
Install Flask and the library for QR code with the following command. (For Raspberry Pi, use pip3 and python3)
pip install Flask
pip install qrcode
pip install pillow
The environment is ready and the program
The following folder structure was used with reference to the Flask sample. app.py is the main body of the program. Here is the code that launches Flask. The website responds using the configuration data in the templates.
py
├──app.py (program body)
├──static
│ ├──qrcode.png(Created programmatically)
│ └──setpath.ini(Created programmatically)
└──templates
├──index.html
└──layout.html
--All source code should be written in UTF-8
templates
The content of the website is written in index.html.
index.html
{% extends "layout.html" %}
{% block content %}
<img src="{{ url_for('static', filename='qrcode.png') }}" width="200">
<br>
You can download it by long-pressing the image.<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 %}
<div>
<img src="images/{{ path }}" style="margin-top: 10px; vertical-align: bottom; width: 200px;">
{{ path }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
Description | meaning | Supplement |
---|---|---|
{% extends "layout.html" %} | Page layout configuration file | |
{% block content %}...{% endblock %} | This part is the contents | |
<img src="{{ url_for('static', filename='qrcode.png') }}" | Display QR image in static folder | |
{{ message }} | String display of argument message | |
{% if images %} | If there is an argument images (file name list) | |
{% for path in images %} | The element path (file name) of the images list is ordered | |
{% if '.eva.gif' in path %} | .eva.Process only files containing gifs | |
<img src="images/{{ path }}" | images/Folder files | |
{{ path }} | Also display the file name | |
{% endif %} | end of if | |
{% endfor %} | End of for |
layout.html
<!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>
Description | meaning | Supplement |
---|---|---|
{% block content %}{% endblock %} | There is content in this part |
app.py
The following values are set according to the environment
constant | meaning | Supplement |
---|---|---|
EVA_FOLDER | Folder to save anime | In the example, "/home/pi/2018」 |
QVIEW_EXE | 9view.Full path of exe | Even in Windows, the path delimiter'/' |
HTTP_URL | URL address to publish | Initially'127.0.0.1'Test with |
HTTP_PORT | Port to publish | First test at 5000 |
app.py
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, make_response
import os #File operations
import subprocess #Program execution
import time #Time processing
import re #Character replacement,Regular expressions
import webbrowser #browser
import threading # multi thread
import qrcode #QR code generation
EVA_FOLDER = '/home/pi/xxxxxx' #Folder to save anime
QVIEW_EXE = '/home/pi/9va/9view' #9view.Full path of exe
HTTP_URL = '192.168.99.1' #URL address to publish
HTTP_PORT = 8080 #Port to publish
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"]) #Anime upload
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)] #input
for fn in files:
eva = os.path.join(inpFolder,fn)
if(not eva.endswith('.eva')):
continue
if( '_While editing' in eva): #Ignore autosave files
continue
if( '_Tochu' in eva):
continue
if( '_autosave' in eva):
continue
no = int(os.path.splitext(os.path.basename(fn))[0])
if(no > mno): #Find the final number
mno = no
savepath = os.path.join(inpFolder, '%04d.eva' % (mno+1))
file.save(savepath)
return str(mno+1) #Returns the saved number
#GIF conversion loop
def loop(self,askFolder):
global inpFolder
drmax = '0000-0000'
while True:
dirs = [f for f in os.listdir(EVA_FOLDER)] #Get the latest date
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)] #input
for fn in files:
if(os.path.splitext(fn)[1] != '.eva'):
continue
gif = fn + '.gif' #GIF file name
gif = os.path.join(inpFolder,gif)
eva = os.path.join(inpFolder,fn)
if( '_While editing' in eva): #Ignore autosave files
continue
if( '_Tochu' in eva):
continue
if( '_autosave' in eva):
continue
if(os.path.exists(gif)): #gif exists,Creation corner check
if(os.path.getmtime(gif) > os.path.getmtime(eva)):
continue
cmd = (QVIEW_EXE , eva , '-gif') #-Convert to GIF with gif option
print(cmd) #Show that it has been converted
subprocess.run(cmd) #gif creation
time.sleep(1.0) #sleep(Specify seconds)
return inpFolder
t = MyThread()
inpFolder = loop(t,True) #Create gif when eva is fixed, move to new folder
t.start()
html = 'http://' + HTTP_URL + ':' + str(HTTP_PORT)
img = qrcode.make(html) #QR code creation
img.save('static/qrcode.png')
with open('static/setpath.ini', mode='w') as f:
f.write(html)
if __name__ == '__main__':
webbrowser.open(html) #Launch browser
app.run(debug=True, host=HTTP_URL, port=HTTP_PORT)
Description | meaning | Supplement |
---|---|---|
from flask import Flask, ... | Extensions for Flask | |
import | Make functions available | |
app = Flask(name) | The name of the process | |
class MyThread(threading.Thread): | Multithreaded definition | Run concurrently in Flask |
def run(self): | Processing to be executed by MyThread | |
@app.route('/') | What is displayed by route access | |
def: | Function definition | |
global inpFolder | The variable impFolder is common throughout | |
render_template('index.html' | Flask templates/index.Show html | |
os.listdir(inpFolder)[::-1] | All inpFolder files | -1 is the last meaning |
sorted(xxx, reverse=True) | Sort the list in reverse order | |
@app.route('/images/path:path') | /images/What is displayed by accessing | index.Called from html |
send_from_directory(inpFolder, path) | path file in the inpFolder folder | |
@app.route('/',methods=["POST"]) | Processing when POST is received | For upload |
request.files['file'] | POSTed file | |
if(file.filename.endswith('.eva')): | The extension is.For eva | |
files = [f for f in os.listdir(inpFolder)] | List inpFolder files | |
os.path.splitext(os.path.basename(fn))[0] | File name without extension | |
int(String) | Stringを数値に変換 | |
'%04d.eva' % (mno+1) | Numerical value(mno+1)To a string | |
savepath = os.path.join(inpFolder,file name) | フォルダとfile nameの結合 | |
file.save(savepath) | Save the file to savepath | Save the POSTed file with a different name |
if re.match('[0-9]{4}-[0-9]{4}', s) | s is "4 digits-In the case of "4 digits" | Regular expressions |
if(os.path.exists(gif)): | If the file exists | |
os.path.getmtime(gif) | File update time | |
cmd = (QVIEW_EXE , eva , '-gif') | Command creation | Convert EVA anime to GIF |
subprocess.run(cmd) | Command execution | |
time.sleep(1.0) | Stop for 1 second | |
t = MyThread() t.start() |
Multithreaded execution | |
img = qrcode.make(html) | Create QR code image img | |
img.save('static/qrcode.png') | Save image img in static folder | |
with open('static/setpath.ini', mode='w') as f: | Open write file | |
f.write(html) | Writing a string | |
webbrowser.open(html) | Launch browser | |
app.run(debug=True, host=HTTP_URL, port=HTTP_PORT) | Execute by specifying URL and Port |
Here is an example of running on a Raspberry Pi
--I created a WiFi access point with Raspberry Pi and published it at the URL "192.168.99.1". Click here for how to do --Move to the py folder in the terminal. Run the program with python3 app.py --The browser will open and you will see the following![Ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0 /67734/3bed0f33-3ccb-1236-1d82-fe8d7bce0b62.gif)
setpath.ini settings
--The "Upload" item at the end of the menu is displayed only when the smartphone is connected to the 9VAe anime GIF POST and the save folder can be accessed. --Create an animation and touch "Upload" to save the animation and automatically convert it to a gif file. (MyThread of the above app.py program detects a new file and converts it from EVA to GIF) --The smartphone version upload function has been installed in PEASmotch! One since Ver.0.6.12 (200110). In the case of the PC version, the function to write the full path of the shared folder in setpath.ini in the 9va_data folder and save it directly has been installed.
Recommended Posts