はじめに
nana musicでサーバサイドエンジニアをやっている@xKxAxKxです
この記事はnana music Advent Calendar 2018の19日目の記事です
nanaのTwitterカードの画像が変更されたぞ!
nanaのサウンドへのリンクをTwitterに投稿した時、以前は投稿ユーザのアイコンが表示されているだけだったんだけど、以下のように投稿ユーザのアイコン、再生ボタン画像、投稿パート毎の背景色画像、投稿楽曲タイトル、投稿楽曲アーティスト名、投稿ユーザ名の組み合わせで画像を生成し、それがTwitterカードの画像として使用されるようになった
画像ファイルを色々といじるの、割とカジュアルにやることができたので、どのような処理をやっているかについて書いていく
用意するもの
アイコン画像
いらすとや様から借りた
中二病(厨二病)の女の子が自分で考えたかっこいいポーズを取っているイラストです
再生ボタン画像
パート毎の画像
ベースとなる画像
この画像に対してアイコン画像を貼っていったり、文字を入れたりする
今回はギターパートを投稿した場合の画像です
その他必要なもの
- Python3系(実際の環境は3.6.5)
- 画像を生成するぞ、という気持ち(重要)
手順
各種ライブラリのインストール
Pythonの画像処理ライブラリ Pillow をインストールする
公式ドキュメントはこちら
$ pip install Pillow
再生ボタン画像とアイコンを合成する
まずは再生ボタン画像と、アイコンをそれぞれ Image.open()
でpath/urlから画像データとして読み込みを行う
from PIL import Image
play_path = '再生ボタン画像のpath/url'
play = Image.open(play_path).copy()
icon_path = 'アイコンのpath/url'
icon = Image.open(icon_path).copy()
次にアイコン画像を適切なサイズに縮小する
nanaでは全てのアイコン画像は正方形で保存されているので以下の処理だけでいいけれどp、仮に正方形じゃない画像を扱う場合だと、画像を正方形にトリミングしないと、縦横比が変な画像になってしまう
icon = icon.resize(size=(252, 252), resample=Image.ANTIALIAS)
resize関数で resample=Image.ANTIALIAS
というように指定しておかないと、大きい画像を縮小する時にジャギジャギしたような感じに処理されてしまう
最後に再生ボタンとアイコンの合成
アイコンに再生ボタンを貼り付けるという、イメージ
icon.paste(play, (51, 51), play)
第一引数が貼り付ける画像
第二引数が左端からのwidth/height
第三引数がマスクとなる画像を指定
今回の場合、再生ボタン画像は円形の背景透過であるため、透過部分がそのままマスクとなる
アイコンを円形に切り出し、背景を透過にする
Twitterカードの画像を見てもらえばわかるとおり、アイコンは円形で貼り付けられているのでアイコンを円形に切り出して、背景をとうかにするひつようがある
まずは、円形に切り取るためのマスクを生成する
from PIL import ImageDraw
mask = Image.new("L", icon.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, icon.size[0], icon.size[1]), fill=255)
mask = mask.filter(ImageFilter.GaussianBlur(1))
これにより以下のようなアイコンの画像のサイズに合わせた円形で、背景が透過の画像が生成される
このマスクを putalpha()
を使ってアイコン+再生ボタンの画像にかぶせる
icon.putalpha(mask)
背景画像にアイコンを貼り付ける
ここは非常に簡単で、アイコンと再生ボタンの合成と同じ要領でやるだけで良い
base_image_path = '背景画像のpath/url'
base_img = Image.open(base_image_path).copy()
base_img.paste(icon, (80, 134), icon)
文字の入力
最後に文字を入力していく
ここは、まずは文字を入力するための関数で説明していきたい
from PIL import ImageFont
def add_text_to_image(img, text, font_path, font_size, font_color, height, width, max_length=740):
position = (width, height)
font = ImageFont.truetype(font_path, font_size)
draw = ImageDraw.Draw(img)
if draw.textsize(text, font=font)[0] > max_length:
while draw.textsize(text + '…', font=font)[0] > max_length:
text = text[:-1]
text = text + '…'
draw.text(position, text, font_color, font=font)
return img
第1引数に画像データ
第2引数に入れる文字列
第3引数に使用するフォントのpath
第4引数に文字の大きさ
第5引数に文字の色
第6、第7引数にそれぞれ、文字を入れる位置
第8引数に文字列の最大の長さ
引数が多い関数だけれど、このような感じ
文字列の長さがmax_lengthを超えた場合は以下省略する、という感じになっている
最後にImageクラスの text()
で文字入力を行なっていく
この関数を以下のようにそれぞれ呼び出していく
song_title = "There Is A Light That Never Goes Out"
font_path = "フォントファイルのpath"
font_size = 57
font_color = (255, 255, 255)
height = 155
width = 380
img = add_text_to_image(base_img, song_title, font_path, font_size, font_color, height, width)
song_artist = "The Smiths"
font_path = "フォントファイルのpath"
font_size = 40
font_color = (255, 255, 255)
height = 244
width = 380
img = add_text_to_image(base_img, song_artist, font_path, font_size, font_color, height, width)
user_name = 'by xKxAxKx'
font_path = "フォントファイルのpath"
font_size = 40
font_color = (20, 23, 26)
height = 328
width = 380
img = add_text_to_image(base_img, user_name, font_path, font_size, font_color, height, width)
img.save('ファイルのパス')
すると、実際に使用しているtwitterカードの画像のようになる
最後に
実際は様々な部分を関数化したり、アイコン画像に対しても処理を追加したりしている
また、絵文字対応なども行なったりしているんだけれど、ざっとした流れとしては以上のような感じになっている
自分自身、Pythonで画像をどうのこうのする、という経験がほとんどなかったのだが、何かと需要はありそうではあるし、視覚的に成果が見えやすいのでやってて楽しかったっす