【Pillow/Python】画像に透明な文字を描画する方法

画像に透明な文字を描画する方法の解説ページアイキャッチ

このページにはプロモーションが含まれています

このページでは、Python の画像処理ライブラリ Pillow (PIL) を利用した「画像への透明な文字」の描画方法について解説していきます。

透明な文字の描画方法

では、早速透明な文字を描画する方法について解説していきます。

3つの手順を追加すればよいだけ

Pillow で文字列を描画する方法さえ知っていれば、その時の手順に下記の3つの手順を加えることで透明な文字を描画することが可能となります。画像をファイルとして保存する場合のみ③が必要で、画像を表示するだけで良い場合は③も不要になります。

  • ①画像を 'RGBA' 形式に変換する
  • ②描画する文字の色の第4要素を 0 に設定する
  • ③文字描画後の画像を .png で保存する

画像への文字の描画自体は Pillow における ImgeDraw モジュールの text メソッドを利用することで実現できます。画像への文字列の描画や text メソッドについては下記ページでまとめていますので、詳しくは下記ページをご参照いただければと思います。

PIllowでの画像への文字列の描画の仕方の解説ページアイキャッチ 【Python/Pillow】画像に文字列を描画する(textメソッド)

そして、普通に文字列を描画する時のスクリプトに上記の3手順を加えてやることで画像への透明な文字列の描画可能となります。

スポンサーリンク

画像への透明な文字を描画するスクリプト

下記は image.jpg という画像に透明な文字列 ('Hello World!') を描画するスクリプトの例になります。

透明な文字の描画
from PIL import Image, ImageDraw

image = Image.open('image.jpg')
image = image.convert('RGBA') # ①画像を 'RGBA' 形式に変換する

drawer = ImageDraw.Draw(image)
drawer.text(
    xy=(image.width // 2, image.height // 2),
    text='Hello World!',
    fill=(0, 0, 0, 0), # ②描画する文字の色の第4要素を 0 に設定する
    anchor='mm',
    stroke_width=1,
    font_size=40
)

# ③文字描画後の画像を .png で保存する
image.save('transparent_text.png')

text メソッド実行時に指定している各種引数の意味合いについては、先ほども紹介した下記ページで解説していますので、詳しく知りたい方は下記ページをご参照いただければと思います。

PIllowでの画像への文字列の描画の仕方の解説ページアイキャッチ 【Python/Pillow】画像に文字列を描画する(textメソッド)

透明な文字を描画した画像

例えば、image.jpg が下記のような画像である場合、

オリジナルの画像

上記のスクリプトを実行することで下の図のような画像が transparent_text.png が保存されることになります。

透明な文字の描画結果

次は保存された画像を開いてコピーし、例えばパワポなどに貼り付けてみましょう!そして、その画像を色のついた図形の上に配置してみると…

文字が透明であることの確認1

下の図のように、背景の色に応じて文字の色が変化することが確認できます。これは、描画した文字が透明であるため、背景の色が透けて見えていることを示しています(画像を図形よりも前面に配置しておかないと画像が隠れてしまうので注意してください)。

文字が透明であることの確認2

こんな感じで、Pillow を利用することで透明な文字の画像への描画を行うことができます。

3つの手順とスクリプトの対応

そして、透明な文字の画像への描画は、いつも画像に文字列を描画するときに比べて下記の3つの手順を追加するだけで実現できます。

  • ①画像を 'RGBA' 形式に変換する
  • ②描画する文字の色の第4要素を 0 に設定する
  • ③文字描画後の画像を .png で保存する

先ほど示したスクリプトでコメントを記述していますが、①に関しては下記のように open 関数で生成した Image オブジェクトに convert('RGBA') を実行させることで実現できます。この①に関しては、Image オブジェクト生成直後 ~ Draw オブジェクト生成前に行えば良いです。

RGBAへの変換
image = image.convert('RGBA')

また②に関しては、下記のように text メソッドの fill 引数に指定するピクセル値の第4要素に 0 を指定することで実現できます。

色を透明に設定
drawer.text(
    # 略
    fill=(0, 0, 0, 0),
    # 略
)

さらに③に関しては、下記のように save メソッドの引数で指定するファイルパスの拡張子を .png にするだけで実現できます。この③に関しては画像をファイルとして保存する際に必要な手順であり、ファイルとして保存しない場合、例えば save メソッドで画像を表示するだけであれば不要な手順となります。

画像の保存
image.save('transparent_text.png')

そして、これらを行うことで、どんな画像に対しても透明な文字列が描画可能になります。

では、なぜ上記の3手順により透明な文字列が描画可能になるのでしょうか?

ここからは、オマケとして、上記の3手順を加えることで透明な文字列が描画されるようになる仕組みについて説明していきます。

スポンサーリンク

透明な文字が描画される仕組み

透明な文字の描画方法 で、通常の文字を描画する際の手順に対して下記の3つの手順を加えることで透明な文字が描画可能となることを説明しました。

  • ①画像を 'RGBA' 形式に変換する
  • ②描画する文字の色の第4要素を 0 に設定する
  • ③文字描画後の画像を .png で保存する

②によって透明な色で文字が描画される

この3つの手順の中で、実際に文字の色を透明に設定しているのは②の手順になります。

Pillow で扱う色は色名の文字列やカラーコードの形式で指定することが可能ですが、ピクセル値によって色を指定することも可能です。画像にもよりますが、ピクセル値としては (R, G, B) の3つの要素のタプルで指定するのが最も一般的で、R で赤色の強さ、G で緑色の強さ、B で青色の強さを指定することになります。そして、これらの3色の色の強さによって最終的な色が決まり、その色で文字が描画されることになります。

さらに、特定の画像に対してはピクセル値を (R, G, B) ではなく (R, G, B, A) の4つの要素のタプルで指定することが可能です。

MEMO

Aα で表されることも多く、これらはアルファチャンネルと呼ばれます

そして、A で色の透明度を指定することが出来ます。A に関しては 0255 の値を指定することができ、値に応じた透明度が設定されることになります。値が小さいほど透明に近くなり、完全な透明にしたいのであれば A0 を指定してやれば良いです。

下図は A の値によって描画する文字の透明度が変化する様子を示しています。A = 0 の場合は完全に透明になるため背景の色がそのまま透けて見えますが、A が大きくなると背景の色の透け度合いが小さくなっていくことが確認できると思います。

Aの値によって透明度が変化する様子

ここまでの説明のとおり、描画する文字の色を (R, G, B, A) の4つの要素のタプルのピクセル値として指定してやり、A0 を指定してやれば透明な文字が描画されることになります。

①によって色に透明度を指定できるようになる

であれば、②の手順だけ行えば透明な文字の描画は実現できそうなものですが、実はそうではありません。

実はピクセル値に透明度が設定可能な画像は限定されているのです。なので、文字の描画先の画像が透明度を設定可能なものでない場合、色に透明度は設定することはできず、当然透明な文字の描画も実現できないことになります。

mode と透明度の設定の関係

そして、色を表すピクセル値として指定可能な形式は、Pillow においては Image オブジェクトの mode によって決まります。この mode やピクセル値に関しては下記ページで詳しく説明していますので、興味があれば読んでみてください。

【Python/Pillow】画像のデータ構成とImageクラス

mode の代表例の1つは 'RGB' となります。mode'RGB' の場合、その Image オブジェクトではピクセル値が (R, G, B) の3つの要素のみのタプルの形式で扱われることになります。したがって、この Image オブジェクトでは透明な色を設定することが出来ません。それに対し、mode の代表例の1つに 'RGBA' があります。この場合、その Image オブジェクトではピクセル値が (R, G, B, A) の4つの要素のタプルの形式で扱われることになります。そして、この mode'RGBA' の Image オブジェクトでは透明な色を設定することが可能です。

modeによってピクセル値の構成が異なる様子

例えば、先ほど示した下図の画像のファイルパスを image.jpg とした時、

オリジナルの画像

下記によって image.jpg を読み込んで Image オブジェクトが生成されることになります。そして、この Image オブジェクトのデータ属性 mode を出力してみると RGB と出力されるはずです。

modeの出力
from PIL import Image

image = Image.open('image.jpg')
print(image.mode) # RGBが出力される

これは「この画像のピクセル値は (R, G, B) の3つの要素のタプルの形式であること」を示しています。そして、前述のとおり mode'RGB' の場合は透明度は設定不可です。つまり、mode'RGB' となっている Image オブジェクトに対し、色を (R, G, B, A) の4つの要素のタプルのピクセル値を指定して文字を描画したとしても A の要素は無視されることになります。

じゃあ、なぜ上記のスクリプト例によって生成された Image オブジェクトの mode'RGB' なのかというと、それは open 関数の第1引数で指定されたファイルパスの画像、すなわち、先ほど紹介した下図の画像の mode'RGB' だからになります。つまり、open 関数で Image オブジェクトを生成する場合、第1引数で指定したファイルパスの画像によって生成される Image オブジェクトの mode も決まることになります。さらに言えば、JPEG 画像などは透明度が設定不可な画像フォーマットととなります。したがって、open 関数の第1引数に JPEG ファイルのパスを指定すると、open 関数によって生成された Image オブジェクトに対しては基本的には透明な文字は描画不可となります。

open関数の第1引数に指定したパスのファイルによってmodeが決まることを示す図

mode の変換

じゃあ、JPEG 画像に透明な文字を描画することが絶対に不可能なのかというと実はそうではありません。正確に言えば、やっぱり JPEG 画像に透明な文字を描画することはできません。これは、JPEG 画像から生成される Imagemode が基本的に 'RGB' となるからになります。

なんですが、実は Pillow の Image クラスには convert メソッドが用意されており、この convert メソッドにより mode を変換することが可能となります。前述のとおり、mode'RGBA' の場合はピクセル値が (R, G, B, A) の4つの要素のタプルの形式で扱われることになり、A の値によって透明度が設定可能です。

したがって、Image オブジェクトの mode'RGB' であっても、convert メソッドにより mode'RGBA' に変換してやれば透明度が設定可能なピクセル値を色として指定することができるようになり、その後に②の手順で透明な文字を画像に描画することが可能となります。

つまり、①の手順で行っているのは、open 関数によって生成した Image オブジェクトの mode が 'RGBA' 以外の場合でも、透明度が扱えるように 'RGBA' に変換する処理を行っています。そして、これによって②の手順で透明な文字が描画することができるようになります。

透明度が扱えるmodeに変換してから透明な文字を描画する様子

ちなみに、JPEG 画像では透明度を扱うことが出来ず、JPEG 画像から open 関数で生成した Image オブジェクトの mode が  'RGBA' になることは無いはずです。それに対し、PNG 画像は透明度を扱うことが可能で、画像によっては PNG 画像から open 関数で生成した Image オブジェクトの mode が  'RGBA' となることがあります。この場合、convert メソッドによる mode の 'RGBA' への変換を行わなくても透明な文字の描画が可能となります。

MEMO

補足しておくと、JPEG 画像ではグレースケール画像や CMYK 画像も扱うことが可能であり、これらの画像から生成される Imagemode は、それぞれ 'L''CMYK' となります

が、このページでは最も一般的な 'RGB' であることを前提に解説しています

ちなみに、mode'L' の場合も 'CMYK' の場合も透明度の扱いは不可となっています

convert 以外での変換

先ほど透明度を扱うために convert メソッドで Image オブジェクトの mode を  'RGBA' に変換する必要があると説明しましたが、透明度を扱うための手段は他にもあって、その1つとして putalpha メソッドの実行が挙げられます。この putalpha メソッドを実行した Image オブジェクトの各ピクセルにはアルファチャンネルが追加されます。つまり、各ピクセルの元々のピクセル値に要素が1つ追加され、その追加された要素で透明度を扱うことが出来るようになります。

具体的に言えば、mode が  'RGB'Image オブジェクトの場合はピクセル値が (R, G, B) の3つの要素から構成されますが、この Image オブジェクトに putalpha メソッドを実行させればピクセル値に A が追加されて (R, G, B, A) の4つの要素から構成されるようになります。この A では、前述のとおり透明度を指定することが可能です。また、ピクセル値の構成は mode と連動しており、putalpha メソッドの実行によってピクセル値が (R, G, B, A) の4つの要素から構成されるようになることで mode も  'RGBA' に自動的に変換されることになります。

putalphaメソッドの実行によってアルファチャンネルが追加されて透明度が扱えるようになる様子

そして、これによって透明な文字を描画可能な Image オブジェクトに変換されることになります。

したがって、透明な文字の描画方法 で紹介したスクリプトにおける下記の convert メソッド実行部分を

image = image.convert('RGBA')

下記のように putalpha メソッドの実行に置き換えたとしても透明な文字は描画可能となります。

image.putalpha(255)

putalpha は実行したオブジェクトそのものが変化するメソッドであることに注意してください。convert メソッドの場合は実行したオブジェクトは変化せず、mode を変換した後の Image オブジェクトが新たに生成されて返却されることになります。putalpha の場合は実行したオブジェクトが変化し(A が追加される)、返却値は None となります。

また、追加された A の値は画像内の全ピクセルにおいて putalpha の引数で指定した整数の値となります。上記の例では 255 を指定しており、255 は不透明であることを指定する値であるため画像内の全ピクセルは不透明で元々の色を保持することになります。逆に 0 を指定した場合は画像全体が透明になることになります。今回は描画する文字だけを透明とすることを目的としているため 255 を指定していますが、画像全体を半透明などにしたいような場合は 128 などの中間値を指定しても良いです。

もともと mode'RGBA'Image オブジェクトの場合は、putalpha の実行によって全ピクセルの A の値が putalpha の引数に指定した値に置き換えられてしまうことになるので注意してください。

スポンサーリンク

③によって透明度が設定可能なフォーマットで保存される

さて、①と②によって透明な文字を画像に描画することが出来るようになったことになります。

では、すでに透明な文字を描画できているのに、なぜ③が必要なのでしょうか?

これは、透明度が設定可能な画像フォーマットでファイル保存するためになります。

Image オブジェクトの save メソッドで画像をファイル保存する際には、Image オブジェクトが特定の画像フォーマットに変換された状態でファイルに保存されることになります。有名な画像フォーマットには JPEG や PNG 等があります。そして、どのフォーマットに変換されるかは save メソッドの第1引数のファイルパスにおける拡張子(.jpg.png など)によって決まります。

この時に注意が必要なのは、画像フォーマットには透明度の設定に対応していないものがあるという点になります。そして、mode が 'RGBA'Image オブジェクトから save メソッドでファイル保存する際、透明度の設定が不可な画像フォーマットに変換されてしまうと例外が発生することになります。例えば、JPEG は透明度が設定不可な画像フォーマットであるため、mode が 'RGBA'Image オブジェクトから save メソッドを実行させる際に第1引数のファイルパスの拡張子が .jpg になっていると、JPEG は透明度の設定に対応していないため例外が発生します。

saveメソッド実行時に例外が発生する様子

具体的には、下記のような例外が発生すると思います。

OSError: cannot write mode RGBA as JPEG

このような例外を防ぐためには、 save メソッドの第1引数には透明度の設定が可能なフォーマットに対応する拡張子のファイルパスを指定する必要があります。そして、透明度の設定が可能なフォーマットの代表例の1つは PNG であり、.png の拡張子のファイルパスを指定してやれば例外を防ぐことが出来るようになります。そして、これが手順の③となります。

他にも透明度が設定可能なフォーマットは存在するのですが、一番ポピュラーなのは PNG だと思いますので、特にファイルをより小さくしたい等の特別な理由がなければ .png の拡張子のファイルパスを指定してやれば良いと思います。

以上が、透明な文字が描画される仕組みの説明となります。描画する文字の色に透明度を含めたピクセル値を指定すること、および、透明度を扱うことが可能な mode に変換し、さらに透明度が保持されるような画像フォーマットでファイル保存する必要がある点がポイントになると思います!

まとめ

このページでは、Python の画像処理ライブラリ Pillow (PIL) を利用した「画像への透明な文字」の描画方法について解説しました!

通常の Pillow を利用した画像への文字の描画時のスクリプトを下記の3つの手順を行うように変更してやることで画像への透明な文字の描画を実現することが出来ます。

  • ①画像を 'RGBA' 形式に変換する
  • ②描画する文字の色の第4要素を 0 に設定する
  • ③文字描画後の画像を .png で保存する

実際に透明な文字を描画するのは②になりますが、②で透明な文字を描画するために①が、②で透明な文字を描画した画像をファイルとして保存するために③が必要な手順となります。

透明な文字の描画手順を理解することで、目的となる透明な文字の描画を実現することは当然できますし、それだけでなく Pillow での画像の  mode についての理解も深まると思います。是非このページで開設した内容は覚えておきましょう!

また、このサイトでは Pillow での文字の描画に関するページを他にも公開しておりますので、是非これらのページも読んでみていただければと思います!

PIllowでの画像への文字列の描画の仕方の解説ページアイキャッチ 【Python/Pillow】画像に文字列を描画する(textメソッド) Pillowのtextメソッドで描画する文字列のフォントやサイズの変更方法の解説ページアイキャッチ 【Pillow/Python】textメソッドで描画する文字のフォントやサイズを変更する Pillowのtextメソッドで描画した日本語文字列の文字化けの解消方法 【Pillow/Python】textメソッドで描画した文字列が文字化けする問題の解決方法

同じカテゴリのページ一覧を表示

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です