tag:crieit.net,2005:https://crieit.net/tags/Pillow/feed
「Pillow」の記事 - Crieit
Crieitでタグ「Pillow」に投稿された最近の記事
2021-05-23T19:26:23+09:00
https://crieit.net/tags/Pillow/feed
tag:crieit.net,2005:PublicArticle/17235
2021-05-23T18:18:06+09:00
2021-05-23T19:26:23+09:00
https://crieit.net/posts/pillow-vertical-writing
📝 Pillow を使って画像に縦書きテキストを埋め込む
<h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2>
<p>縦書きテキストを画像に埋め込みたいと頼まれたので、<br />
Python 製の画像処理ライブラリ <a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/">Pillow</a> を使ってサクッと実装してみました。</p>
<p>一応ソースコードは Gist にもアップ済みです ✍️<br />
<a target="_blank" rel="nofollow noopener" href="https://gist.github.com/nikaera/c1049708ff548b06cab0ae377adc4ac7">https://gist.github.com/nikaera/c1049708ff548b06cab0ae377adc4ac7</a></p>
<h2 id="動作環境"><a href="#%E5%8B%95%E4%BD%9C%E7%92%B0%E5%A2%83">動作環境</a></h2>
<ul>
<li>Python 3.9.5</li>
<li>Pillow 8.2.0</li>
</ul>
<h2 id="画像に縦書きテキストを埋め込む"><a href="#%E7%94%BB%E5%83%8F%E3%81%AB%E7%B8%A6%E6%9B%B8%E3%81%8D%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%92%E5%9F%8B%E3%82%81%E8%BE%BC%E3%82%80">画像に縦書きテキストを埋め込む</a></h2>
<p>まずは今回利用する <a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/">Pillow</a> を予めインストールしておきます。</p>
<pre><code class="bash">pip install Pillow
</code></pre>
<p>その後 <code>main.py</code> を作成して下記を入力します。<br />
テキストを埋め込みたい画像を <code>main.py</code> と同じフォルダに <code>sample.jpeg</code> という名前で配置しておきます。</p>
<pre><code class="python"># main.py
# Pillow の利用するモジュールのみをインポートする
from PIL import Image, ImageDraw, ImageFont
# 読み込みたいフォント情報を入力する
font_name = "/System/Library/Fonts/ヒラギノ角ゴシック W0.ttc"
font_size = 48
font = ImageFont.truetype(font_name, font_size)
# テキストを埋め込みたい画像 sample.jpeg を読み込む
im = Image.open('sample.jpeg')
d = ImageDraw.Draw(im)
# 画像に埋め込みたいテキスト情報を入力する
# (後述するが、改行コードには未対応)
text = "bifdLcFCKXtFJZmPZhzdefjhhYTtuJPAYsR"
# 文章を改行するまでの文字数を入力する
split_number = 11
# split_number で指定した文字数ごとに分割され配列に格納される
# ref: https://qiita.com/yasunori/items/551a7c20ef9b81474e2a
splits = [text[i: i+split_number] for i in range(0, len(text), split_number)]
# 画像の width を読み込み、画像の右端の座標を取得する
# top_right_margin には余白を設定する (描画領域の端が画像の端と被ってしまうため)
w, _ = im.size
top_right_margin = 13
right_edge = w - top_right_margin
# テキストの入力領域に端が赤い四角形を描画する
d.rectangle((right_edge, top_right_margin, right_edge - font_size * len(splits), font_size * split_number + top_right_margin), fill=(255, 255, 255), outline=(255, 0, 0))
# 分割した文章を上記四角形内に左にずらしながら縦書き入力する
for index, item in enumerate(splits):
d.text((right_edge - (font_size / 2) - font_size * index, top_right_margin), item, fill="black", anchor="mt", font=font, direction="ttb")
# 縦書きテキストを埋め込んだ画像を test.png として出力する
im.save("test.png")
</code></pre>
<p>上記ソースコード内で特筆すべき事項として <code>d.text</code> があります。<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup><br />
まず <a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/handbook/text-anchors.html"><code>anchor</code> オプション</a> で文字を横中央に寄せて、縦を上端に寄せるよう設定しています。</p>
<p>更に <a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.text"><code>direction</code> オプション</a> を利用することで、文字列を縦に入力しています。縦に入力するためのオプションとして <code>ttb</code> を入力しています。</p>
<p>実際に <code>main.py</code> を実行した際に生成される画像は下記のとおりです。</p>
<p><img src="https://i.gyazo.com/a51851cded2f1d4bf2da6ff1e98df912.jpg" alt="テキストを埋め込む前の画像" /><br />
<strong>テキストを埋め込む前の画像</strong></p>
<p><img src="https://i.gyazo.com/7908dd812db36afeee315ae5bd287406.png" alt="<code>main.py</code> を実行してテキストを埋め込んだ画像" /><br />
<strong><code>main.py</code> を実行してテキストを埋め込んだ画像</strong></p>
<h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2>
<p>今回は Pillow を用いて縦書きテキストの画像埋め込みを実装しましたが、<br />
ブラウザベースで埋め込みをやりたい場合は <a target="_blank" rel="nofollow noopener" href="https://html2canvas.hertzen.com/">html2canvas</a> からの png 出力ダウンロードで実装できそうでした。(ただその場合は各種ブラウザ対応とかモバイル対応が大変そう。。 👀)</p>
<h2 id="参考リンク"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF">参考リンク</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/">Pillow — Pillow (PIL Fork) 8.2.0 documentation</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/handbook/text-anchors.html">Text anchors — Pillow (PIL Fork) 8.2.0 documentation</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.text">ImageDraw Module — Pillow (PIL Fork) 8.2.0 documentation</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/masushin/items/fbeb9018c9b17fe4d244">Pillow を日本語縦書きに対応させる - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://gist.github.com/nikaera/c1049708ff548b06cab0ae377adc4ac7">Embedding Japanese vertical writing characters into an image using Pillow.</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn:1" role="doc-endnote">
<p>当初は <a target="_blank" rel="nofollow noopener" href="https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html#PIL.ImageDraw.ImageDraw.multiline_text"><code>multiline_text</code> 関数</a> を用いて改行にも対応した形でテキスト埋め込みを実装する予定でした。しかし、<code>ValueError: ttb direction is unsupported for multiline text</code> というエラーが発生してしまい <code>multiline_text</code> 関数の利用は断念しました。。😭 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
nikaera