PythonでコマンドラインにGIFを表示させる(Python&乃木坂)
この前こんなのを書いた
コマンドラインで画像を表示させる(Python&乃木坂46) - Terasannのチラ裏
コンソール画面に画像を表示できるようになった!
ってことでこんどはGIFを表示できないか考えてみる。
で、実装してみた。
するとこんな感じで表示される。あらまぁ便利
かわいい。
アニメーションであるのでできればファイルダウンロードのプログレスバーのように標準出力を上書きしていきたいところ。
プログレスバーとかは標準出力のCR(キャリッジリターン)っていう先頭を指すポインタみたいのを使っているらしい。ってかキャリッジリターンていうの!? ちなみにLFはラインフィード!
pythonで実装した例が検索したら、ちらほら発見できた。
しかし複数行で行ってるという記事は見当たらなかった。
参考サイトからまずカウントダウンのコードを入手。
参考 : コンソールへの出力を上書きしてゆく方法
うむ。いい感じに動いている。
つづいて改行コードを忍ばせる。
失敗。
どうやら改行コードが入ってしまうとダメ。
CRで戻れるのはその行の先頭らしい。
これはスペースをコンソール目一杯に埋めて改行っぽくしてもダメだった。(試してみた)
どうしよう
ってことでclearコマンドを使うことにした。
os.system("clear")
こんな感じでコンソールをクリアできる。 クリアって言っても消すわけではないみたい。 消したわけではないのでスクロールすると見えてきます笑
つづいてgifの見れるコードを。
#!/usr/bin/env python # -*- coding: utf-8 -*- """ created by keiichi """ from PIL import Image from PIL import ImageOps import os import sys, time def ascii(pmatrix, sx, sy, columns): tab = "" tablen = 0 if columns <= sx: sx = columns columns = 0 else: tablen = columns - sx*2 for i in xrange(tablen): tab = tab + " " line = "" for y in xrange(sy): sentence = "" for x in xrange(sx*2): gray = pmatrix.getpixel((x,y)) """ if gray > 250: character = " " elif gray > 230: character = "." elif gray > 200: character = ":" elif gray > 175: character = "+" elif gray > 150: character = "*" elif gray > 125: character = "#" elif gray > 50: character = "@" if gray > 250: character = " " elif gray > 230: character = "." elif gray > 210: character = ":" elif gray > 190: character = "|" elif gray > 170: character = "/" elif gray > 150: character = "+" elif gray > 130: character = "*" elif gray > 110: character = "¥" elif gray > 90: character = "&" elif gray > 70: character = "$" elif gray > 50: character = "@" """ if gray > 250: character = "@" elif gray > 230: character = "$" elif gray > 210: character = "&" elif gray > 190: character = "¥" elif gray > 170: character = "*" elif gray > 150: character = "+" elif gray > 130: character = "/" elif gray > 110: character = "|" elif gray > 90: character = ":" elif gray > 70: character = "." elif gray > 50: character = " " sentence = sentence + character line = line + sentence + tab return line if __name__ == '__main__': try: param = sys.argv filename = 'logo.gif' if param[1] != None: filename = param[1] try: src = Image.open(filename) except IOError: print "Cant load", filename sys.exit(1) rows, columns = os.popen('stty size', 'r').read().split() size = 60 sx = src.size[0] sy = src.size[1] if param[2] != None: size = int(param[2]) gif = [] if (src.format == 'GIF'): try: while 1: try : image = src.resize((size*2, size), Image.ANTIALIAS) output_image = ImageOps.grayscale(image) gif.append(ascii(output_image, int(size) , int(size), int(columns))) except ValueError,UnboundLocalError: pass src.seek(src.tell()+1) # 各フレーム毎の処理をする except EOFError: pass print len(gif) count = 2 for i in xrange(count): for tgif in gif: #sys.stdout.write("\r"+tgif) os.system("clear") sys.stdout.write('\r%s' % str(tgif)) sys.stdout.flush() time.sleep(0.1) else: image = src.resize((size*2, size), Image.ANTIALIAS) #image.show() output_image = ImageOps.grayscale(image) print ascii(output_image, int(size), int(size), int(columns)) except Exception as e: print '=== エラー内容 ===' print 'type:' + str(type(e)) print 'args:' + str(e.args) print 'message:' + e.message print 'e自身:' + str(e)
PILにはGIFを分解できる関数があるのでそれを使いました!
参考 : Pillow/PIL/GifImagePlugin.py
ところがぎっちょん!あまりに高速なgifだとうまく抽出できなかった! こういうGIFたち↓
なんでかなーっておもってちょっと調べて見たんだけど、GIFってframeの速度の設定があるらしい。そりゃそうだ。
Pillow/PIL/GifImagePlugin.pyの110行目のところで
if frame != self.__frame + 1:
raise ValueError("cannot seek to frame %d" % frame)
が起こっているっぽい。よくわかんないけど! ついでにPILが今現在対応しているGIFはGIF87 and GIF89ってことなのでそれ以外のGIFは再生できない。
GIFってこんなに種類のあるものなのね。
ちなみにPNGが登場したことで静止画用途でのGIFはほぼ消滅したそうな。
なかなか勉強になりました!
Gifが表示できるようになったからTerminalの起動もかっこよくなるできるかも!
目指すはアイアンマン2のディスプレイにハッキングをするシーン 58秒辺りから!
Iron Man 2 Hacking Scene - YouTube
Arch Linuxだとこんなかんじの表示だよね。いいなぁ〜。
作ってみようかな〜なんて笑
今日も良いPythonライフを!