Create an animated GIF local server with Python + Flask

What is an anime GIF local server?

--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.

サーバーを実行した図

Python installation

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 QR code library

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

Anime GIF local server

The environment is ready and the program

Folder structure

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    

python Flask source code

--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

How to use

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)

How to download anime to your smartphone

  1. Connect WiFi to the Raspberry Pi access point with your smartphone's WiFi settings
  2. Look at the QR code on your smartphone and open the URL > The same screen as above opens
  3. You can download the GIF animation by long-pressing the animation and selecting "Download" from the menu.

How to upload anime from your smartphone app (PEASmotch! One)

  1. Connect WiFi to the Raspberry Pi access point
  2. Look at the QR code on your smartphone and open the URL > The same screen as above opens

setpath.ini settings

  1. Press and hold setpath.ini and select "Download Link"> download the setpath.ini file
  2. Use an app such as a file manager to put the setpath.ini file in the "PEASmotch" folder
  3. Start PEASmotch, touch the PEAS logo, and if "Upload" is added at the bottom of the menu, it's OK.

--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

Create an animated GIF local server with Python + Flask
[Python] Quickly create an API with Flask
Local server with python
Create an API server quickly with Python + Falcon
Create 3d gif with python3
Create an Excel file with Python3
Quickly create an excel file with Python #python
Create an English word app with python
Create an app that guesses students with python
Create an image composition app with Flask + Pillow
Create an image with characters in python (Japanese)
Launch a web server with Python and Flask
Programming with Python Flask
Create an animated time series map of coronavirus infection status with python + plotly
[Python] How to create a local web server environment with SimpleHTTPServer and CGIHTTPServer
A server that echoes data POSTed with flask / python
[Python] I tried running a local server using flask
Create a fake Minecraft server in Python with Quarry
Create an environment with virtualenv
Create an API with Django
Create gif video in Python
Creating an egg with python
Easy HTTP server with Python
Web application with Python + Flask ② ③
Create a directory with python
Web application with Python + Flask ④
Create an LCD (16x2) game with Raspberry Pi and Python
Create Heroku, Flask, Python, Nyanko bulletin boards with "csv files"
[Python Kivy] How to create an exe file with pyinstaller
Cut out an image with python
Create plot animation with Python + Matplotlib
SNS Python basics made with Flask
Create Awaitable with Python / C API
Create folders from '01' to '12' with python
Creating a Flask server with Docker
Write an HTTP / 2 server in Python
Persist Flask API server with forever
[Python] Use Basic/Digest authentication with Flask
Create a virtual environment with Python!
How to create a heatmap with an arbitrary domain in Python
I sent an SMS with Python
Load gif images with Python + OpenCV
Create an age group with pandas
Draw an illustration with Python + OpenCV
[Python] Send an email with outlook
Application development with Docker + Python + Flask
Rock-paper-scissors with Python Let's run on a Windows local server for beginners
Create an application by classifying with Pygame
[Python] Building an environment with Anaconda [Mac]
Competitive programming with python Local environment settings
Create a Python function decorator with Class
Automatically create Python API documentation with Sphinx
Create wordcloud from your tweet with python3
[In-Database Python Analysis Tutorial with SQL Server 2017]
Build a blockchain with Python ① Create a class
Create an image processing viewer with PySimpleGUI
Create a dummy image with Python + PIL.
Create your own DNS server with Twisted
Note when creating an environment with python
[Python] Create a virtual environment with Anaconda
Let's create a free group with Python