LoginSignup
10
9

More than 5 years have passed since last update.

PythonでアスキーアートのGIFアニメーションを作る

Posted at

サンプル

特に意味なく、複数の画像からアスキーアートのGIFアニメーションを作るPythonを書いたんで、使い道も特に無いんでここに書いとく。

上のサンプル画像は、頭が回るように8枚の写真を使って、「polikej#」の文字を使って生成しました。
タイル状に並べる画像の数、フォントの色・サイズなどを、スクリプト冒頭の大文字変数で指定してます。
(サンプル画像は、下のコードを少しいじって作ってます。)

フォントのパスは、OSXだとFont Bookとかで、等幅フォントを調べて、右クリックでFinder表示で分かる。

アスキーアート化にPillow、GIFアニ生成にImageMagickが必要です。
Mac使ってれんで、pipとbrewで、それぞれ、インストールしてます。

from PIL import Image, ImageDraw, ImageFont
import os.path
import os
import commands


FONT_SIZE = 12
GRID_SIZE = (3, 2)
FONT_COLOR_SET = ("#ffffff", "#000000")
FONT_PATH = 'フォント(等幅)のパス'
IMAGE_NAMES = [
    'f0.png',
    'f1.png',
    'f2.png',
    'f3.png',
    'f4.png',
    'f5.png',
    'f6.png',
    'f7.png',
]

FONT_COLOR, FONT_BACKGROUND_COLOR = FONT_COLOR_SET
COLUMNS, ROWS = GRID_SIZE


def image2ascii(input_image):

    original_width, original_height = input_image.size

    width = original_width * COLUMNS
    height = original_height * ROWS

    character, line = "", []
    font = ImageFont.truetype(FONT_PATH, FONT_SIZE, encoding="utf-8")
    input_pix = input_image.load()
    output_image = Image.new("RGBA", (width, height), FONT_BACKGROUND_COLOR)
    draw = ImageDraw.Draw(output_image)

    font_width, font_height = font.getsize("#")

    margin_width = width % font_width
    margin_height = height % font_height

    offset_x = int(round(margin_width / 2))
    offset_y = int(round(margin_height / 2))

    for row in range(ROWS):
        for y in range(offset_y, original_height - offset_y, font_height):
            line = []
            for column in range(COLUMNS):
                for x in range(offset_x, original_width - offset_x, font_width):
                    r, g, b, _ = input_pix[x - offset_x, y - offset_y]
                    gray = r * 0.2126 + g * 0.7152 + b * 0.0722
                    "polikeiji"
                    if gray > 130:
                        character = " "
                    elif gray > 100:
                        character = "i"
                    elif gray > 90:
                        character = "l"
                    elif gray > 80:
                        character = "j"
                    elif gray > 60:
                        character = "o"
                    elif gray > 50:
                        character = "e"
                    elif gray > 40:
                        character = "p"
                    elif gray > 30:
                        character = "k"
                    else:
                        character = "#"
                    line.append(character)
            draw.text((offset_x, y + row * original_height), "".join(line), font = font, fill = FONT_COLOR)
    return output_image

if __name__ == "__main__":
    directory_name = os.path.dirname(IMAGE_NAMES[0])
    if directory_name != '':
        directory_name = directory_name + "/"
    ascii_image_directory = "{0}ascii_{1}_{2}x{3}_{4}_{5}".format(
        directory_name, FONT_SIZE, ROWS, COLUMNS, FONT_COLOR, FONT_BACKGROUND_COLOR)

    for image_name in IMAGE_NAMES:
        print "Input image: {0}".format(image_name)

        with Image.open(image_name) as input_image:
            output_image = image2ascii(input_image)

            file_name, extension = os.path.splitext(os.path.basename(image_name))

            ascii_image_name = "{0}/ascii_{1}_{2}x{3}_{4}{5}".format(
                ascii_image_directory,
                FONT_SIZE, ROWS, COLUMNS, file_name, extension)

            ascii_image_directory = os.path.dirname(ascii_image_name)
            if not os.path.exists(ascii_image_directory):
                os.makedirs(ascii_image_directory)

            output_image.save(ascii_image_name)

            print "Output image: {0}".format(ascii_image_name)

    make_gif_animation_command = "convert -delay 10 -loop 0 {0}/*.png {0}/{1}.gif".format(
        ascii_image_directory, os.path.basename(ascii_image_directory))

    print commands.getoutput(make_gif_animation_command)

Pillowでアスキーアート生成

コードも含めてこちらを参考にしてます。
画像をピクセル単位で調べて、輝度に応じて文字を割り当てる感じ。

フォントによって、1文字のサイズが違うんで、事前に1文字のサイズを調べて、アスキーアートが中央寄せになるように調整してる。

あとで、ワイルドカードで画像を指定して、ImageMagickでGIFアニを作ってるんで、アスキーアート化した画像は一個のフォルダにまとめて保存してる。

ImageMagickでGifアニ生成

単にconvertコマンドで生成。

convert -delay 10 -loop 0 {フォルダ}/*.png {フォルダ}/output.gif

delayオプションでなんとなくスピードは変わるけど、ビューワーによって速度が違うっぽく、厳密にFPSとかは指定できないっぽい。

PythonでGIFアニ作れないのかな、と思ったけど、ライブラリが無い or 面倒臭そうだった。
stackoverflow

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9