DESIGN / CODE / INFRA / AI

解説

透明PNGを白背景のJPEGへ。半透明の縁まで合成して保存しよう

透明PNGを白背景のJPEGへ変換する手順。半透明の縁の合成と、保存後の寸法・モード・色を生成画像で検証する。

透明PNGを白背景のJPEGへ。半透明の縁まで合成して保存しよう
保存リストを見る →
この記事の道しるべ 4項目

透明なロゴをJPEGで納品したいとき、背景色も決めて書き出したい。PythonのPillowで白い下地を用意し、透明度を使って合成する手順を試してみよう。

ここで完成させるのは、元PNGを残したまま作る白背景のJPEG。形式選びの基本はPNGとJPEGの透過の違いにまとめている。今回は、変換を繰り返す制作作業向けに、コードとピクセルの値で確認するよ。

まずは練習用の画像を作る

Python 3とPillowが使える環境で、空の練習用フォルダを用意する。このページのPythonコードは、そこへスクリプトとして保存し、ターミナルから実行する。編集部の検証環境はPython 3・Pillow 11.3.0。実際の顧客画像は使わず、次の三色を横に並べた画像を作った。

from PIL import Image, ImageDraw

sample = Image.new("RGBA", (180, 60), (0, 0, 0, 0))
draw = ImageDraw.Draw(sample)
draw.rectangle((60, 0, 119, 59), fill=(255, 0, 0, 128))
draw.rectangle((120, 0, 179, 59), fill=(0, 0, 255, 255))
sample.save("sample.png")

RGBAは赤・緑・青に透明度を加えた形式。この作例では左が透明、中央が約半透明の赤、右が不透明の青になる。透明度の値は0で透明、255で不透明だよ。

同じ大きさの白い下地へ合成する

次のコードを、同じフォルダで実行する。出力先に同名のファイルがないことを先に確認しよう。

from PIL import Image

with Image.open("sample.png") as source:
    foreground = source.convert("RGBA")
    background = Image.new("RGBA", foreground.size, (255, 255, 255, 255))
    flattened = Image.alpha_composite(background, foreground).convert("RGB")
    flattened.save("white-background.jpg", quality=95, subsampling=0)

    print("size", flattened.size)
    for x in (30, 90, 150):
        print(x, flattened.getpixel((x, 30)))

alpha_compositeは二枚目を一枚目の上へ合成する関数。同じ大きさ・同じモードの画像を渡す必要があるため、前景をRGBAにそろえ、前景の寸法から下地を作っている。[Pillowのalpha_composite仕様]

白い下地へ合成したあと、RGBへ変換してJPEGに保存する。quality=95とsubsampling=0はこの検証で使った保存設定。容量と見た目を比べ、自分の用途に合わせて選んでね。[PillowのJPEG保存オプション]

保存前の値と、開き直した結果を比べる

編集部の作例では、上のコードで次の値が得られた。

size (180, 60)
30 (255, 255, 255)
90 (255, 127, 127)
150 (0, 0, 255)

透明だった左側は白に、中央の半透明の赤は白と混ざった淡い赤になった。単に透明度を取り除くだけの処理も比較したところ、左は黒、中央は赤のままだった。保存したJPEGも開き直して確認しよう。

from PIL import Image

with Image.open("white-background.jpg") as result:
    print(result.format, result.mode, result.size)
    for x in (30, 90, 150):
        print(x, result.getpixel((x, 30)))

確認できた形式・モード・寸法は JPEG RGB (180, 60)。各領域の中央は、白が (255, 255, 255)、淡い赤が (255, 127, 126)、青が (0, 0, 254) だった。JPEGは圧縮で値が変わるので、保存前のピクセルと完全一致することを合格条件にしないでね。

同じ透明・半透明・不透明の三領域を、透明度だけ除去した場合と白へ合成した場合で比較

上段は透明度だけ除去、下段は白い下地へ合成した保存前の画像。PNGの透明領域に入っていた黒や、半透明の赤の扱いが違うことを、同じ位置で比較しているよ。

本物の画像へ置き換える前に

確認するところ 合わないときに戻る場所
出力の背景が白か 下地の色と、合成の順序
薄い縁が意図した色か 元PNGの透明度と、合成後の画像
幅・高さが想定どおりか 元画像と変換後のsize
JPEGとして開けるか 保存先のファイル名と、開き直したformat

実画像には細かな文字や輪郭もあるので、実際の表示サイズでも読む。試した結果を戻したいときは、元PNGのコピーからやり直し、合成済みJPEGを何度も再圧縮する流れを避けよう。

色管理の指定がある納品では、ICCプロファイルなどの条件も別途そろえる。この作例は生成したRGBの色を合成する検証で、印刷向けの色変換は行っていないよ。向き情報付きの写真も扱う場合は、Exifの向き補正を先に確認してね。

参考・出典

  1. Pillow Image.alpha_compositeの仕様

    資料の確認日:

  2. Pillow JPEG保存オプション

    資料の確認日:

公開と変更の記録
  • :初回公開

日時は日本時間です。記載のある変更は、確認できた編集記録に基づきます。更新日の違いだけから変更内容を推測して載せることはありません。

更新・訂正の方針 →

みんなのコメント 0

感想や、試してみたことを聞かせてね。コメント・返信は承認後に公開されます。

最初のコメントをどうぞ。