Pythonの画像処理ライブラリPillowの13.0.0が公開されました。PyPIの記録によると、日本時間では2026年10月17日の朝に配布が始まっています。
今回の目玉は、とても多くのセキュリティ修正です。公式のリリースノートには、深刻度が最も高いCriticalの問題が2件、次に高いHighの問題が13件も並んでいます。
画像を扱うアプリでPillowを使っている方は、できるだけ早く更新しておきたい版です。今回は、何が直ったのか、ほかに何が変わったのかを順番に見ていきます。
まずは何が変わったのかを整理しよう¶
最初に、今回の変更を大きく分けて表にまとめます。内容は、Pillowの公式リポジトリにある13.0.0のリリースノートにもとづいています。
| 分類 | 主な中身 |
|---|---|
| セキュリティ | Criticalを含む多数の脆弱性を修正 |
| Pythonの対応範囲 | 3.10のサポートを終了し、3.15に正式対応 |
| 速度 | importにかかる時間が12.3.0のおよそ半分に |
| 新機能 | 新しい縮小フィルター、パレット画像の色反転など |
| 互換性のない変更 | 一部の古い機能の削除や、保存時の動きの変更 |
PyPIの記録によると、13.0.0が必要とするPythonは3.11以上です。3.10のままpip installすると、13.0.0ではなく、それより前の版が入ります。
Pillowそのものがまだよくわからない方は、先にこちらを読んでおくと話がつながります。【関連記事】PythonのPillowとは?
多数のセキュリティ修正が入った¶
リリースノートでは、修正された脆弱性が深刻度ごとに並べられています。それぞれの件数を数えると、次のようになりました。
| 深刻度 | 件数 | 主な例 |
|---|---|---|
| Critical | 2 | 画像の形式を変えたあとに古い領域が再利用される問題、JPEGの読み込みでのバッファオーバーフロー |
| High | 13 | TIFFやPDF、WMF/EMFの読み書きでの範囲外アクセスなど |
| Medium | 20 | 圧縮爆弾の検出をすり抜ける問題、処理が終わらなくなる問題など |
| Low | 3 | GIFやEPSの圧縮爆弾の検出の不備など |
件数は、リリースノートに箇条書きされた項目の数です。1つの項目に複数の識別番号がまとめられているものもあります。
画像ファイルは攻撃の入口になりやすい¶
画像を開くだけで危ないの?と思うかもしれません。けれども、画像の読み込みは、ファイルの中身を細かく解釈する、とても複雑な処理です。
わざと壊した画像を読み込ませて、メモリの範囲外を読み書きさせるのは、古くからある攻撃の手口です。利用者が画像をアップロードできるWebアプリでは、特に影響が大きくなります。
圧縮爆弾とは¶
リストに何度も出てくる圧縮爆弾、英語でdecompression bombとは、小さなファイルが展開すると膨大な大きさになる仕掛けのことです。読み込んだだけでメモリを使い果たし、サーバーを止めてしまうおそれがあります。
Pillowには、もともと大きすぎる画像を検出して止める仕組みがあります。今回は、seek()を使うなどしてその検出をすり抜けられる問題が、いくつもの形式で見つかり、まとめて直されました。
私は10年ほどエンジニアとして開発に関わってきましたが、画像のアップロード機能は、作るのは簡単でも守るのが難しい機能だと感じています。外から受け取ったファイルを扱うライブラリは、いちばん優先して更新するのが鉄則です。
ライブラリの脆弱性をまとめて調べるには、pip-auditが便利です。【関連記事】pip-auditとは?
Python 3.10のサポート終了と、3.15への正式対応¶
リリースノートによると、Pillowは13.0.0でPython 3.10のサポートを終えました。理由は、3.10が2026年10月にサポート期間を終えたためと説明されています。
一方で、Python 3.15には正式に対応しました。12.3.0の時点でも3.15のベータ版向けの配布物が用意されていて、正式版の公開と同時に使えるよう準備されていたそうです。
主要なライブラリが3.10を外していく流れは、先日の記事でもまとめました。Pillowもその流れに加わった形です。【関連記事】Python 3.10のサポート終了から2週間、主要ライブラリの対応状況
importが速くなった¶
13.0.0では、Pillowの読み込みにかかる時間が大きく縮みました。リリースノートには、12.3.0のおよそ半分の時間で読み込めるようになったと書かれています。
なぜ速くなったのか¶
リリースノートによると、PIL.Imageがloggingを読み込まなくなりました。また、一部の操作でしか使わないtempfileのようなモジュールは、初めて使うときに読み込むようになっています。
さらにPython 3.15では、__lazy_modules__という仕組みで、残りの標準ライブラリの読み込みも後回しにしています。これは、3.15で入ったlazy importの仕組みを使ったものです。
lazy importそのものについては、Python 3.15の記事で実際に動かしながら紹介しました。【関連記事】Python 3.15が正式リリース
手元で測ってみた¶
実際に、12.3.0と13.0.0を別々の仮想環境に入れ、from PIL import Imageにかかる時間を比べました。Pythonの-X importtimeという仕組みで、15回ずつ測った中央値です。
| 版 | 読み込みにかかった時間(中央値) |
|---|---|
| Pillow 12.3.0 | 約20.5ミリ秒 |
| Pillow 13.0.0 | 約13.2ミリ秒 |
手元のPython 3.11では、およそ3分の1ほど短くなりました。リリースノートの半分という数字は、Apple製のMacで測ったものなので、環境によって差が出るのは自然です。
1回あたりはわずかな差ですが、コマンドラインのツールのように何度も起動するプログラムでは、積み重なって効いてきます。
画像の読み書きそのものも速くなった¶
リリースノートによると、macOSとLinux向けの配布物に同梱されたいくつかのライブラリが、これまで最適化なしでビルドされていました。13.0.0ではこれが直り、12.3.0と比べてJPEG 2000の読み込みは2〜3倍、文字の描画は最大3倍速くなったと説明されています。
Windows向けの配布物は、もともとこの問題の影響を受けていなかったそうです。
新機能を12.3.0と比べてみた¶
続いて、新しく加わった機能を試してみましょう。今回は、パレット画像の色反転と、新しい縮小フィルターの2つを確かめます。
パレット画像とは、使う色の一覧を持ち、各画素がその番号で色を表す形式のことです。GIF画像などでよく使われ、PillowではPモードと呼ばれます。
import PIL
from PIL import Image, ImageOps
print("Pillow", PIL.__version__)
# パレット(Pモード)の画像を作る
img = Image.new("RGB", (64, 64), (200, 30, 30)).convert("P")
try:
inverted = ImageOps.invert(img)
print("invert:", inverted.convert("RGB").getpixel((0, 0)))
except NotImplementedError as e:
print("NotImplementedError:", e)
# 新しい縮小フィルター
filters = [name for name in ("MKS2013", "MKS2021") if hasattr(Image.Resampling, name)]
print("new filters:", filters)
まずは12.3.0で実行した結果です。
Pillow 12.3.0
NotImplementedError: mode P support coming soon
new filters: []
続いて13.0.0です。同じコードで、色の反転がうまくいき、新しいフィルターも見つかりました。
Pillow 13.0.0
invert: (51, 204, 204)
new filters: ['MKS2013', 'MKS2021']
12.3.0では、パレット画像の反転はまだ対応していないというエラーになりました。13.0.0では、赤っぽい色が反転して、青緑っぽい色に変わっています。
新しいMKS2013とMKS2021は、Magic Kernel Sharpと呼ばれる縮小フィルターです。resize()やthumbnail()で、ほかのフィルターと同じように指定できます。
今後削除される予定の機能¶
リリースノートには、将来取り除かれる予定の機能も書かれています。日付まで明記されているので、表にまとめておきます。
| 機能 | 削除の予定 |
|---|---|
| JpegImageFile.load_djpeg | Pillow 14(2027年10月15日) |
| IM形式の画像 | Pillow 15.0.0(2028年10月15日) |
| ImageQt.align8to32() | 非推奨。内部向けの関数のため代わりはなし |
日付を見ると、Pillowは毎年10月にメジャーバージョンを上げる予定で動いているようです。次の大きな変更が来る時期を前もって知っておけるのは、使う側にとってありがたいことです。
load_djpegを使っている場合は、リリースノートのとおり、組み込みのJPEGデコーダーを使うか、djpegを直接呼んで結果をPillowで読む形に切り替えましょう。IM形式は使う人の少ない形式なので、多くの方には関係ないはずです。
自分の環境のPillowを確かめる¶
最後に、手元のPillowのバージョンを確かめておきましょう。ターミナルでpip show pillowと打つか、Pythonの中でimport PIL; print(PIL.__version__)と書けば表示されます。
13.0.0より前の版だった場合は、pip install --upgrade pillowで更新します。Python 3.10を使っている場合は13.0.0が入らないので、Python本体の更新もあわせて考えてください。
上げる前に確かめたいこと¶
13.0.0には、互換性のない変更もいくつか含まれています。リリースノートから、初心者にも関係しそうなものを表にまとめます。
| 変更 | 中身 |
|---|---|
| Iモードの画像をPNGで保存 | これまでは値を黙って切り詰めていたが、それをやめた。保存前に変換が必要 |
| 小さなICOの保存 | 16×16より小さい画像は、その大きさのまま保存されるように |
| get_child_images()の移動 | ImageFileのメソッドへ移った |
| 古い属性の削除 | ExifTags.IFD.Makernoteなどを削除 |
リリースノートによると、32ビットのIモードの画像をPNGで保存するときは、im.convert("I;16").save("out.png")のように、先に変換するよう案内されています。
以前、画像の変換処理でライブラリを上げたら、エラーは出ないのに一部の画像だけ色が変わっていて、気づくまで時間がかかったことがあります。更新の前後で、代表的な画像を何枚か変換して見比べると安心です。
まとめ¶
Pillow 13.0.0が公開されました。Criticalを含む多数のセキュリティ修正が入り、Python 3.10のサポートを終えて3.15に正式対応し、importも速くなっています。
利用者から画像を受け取るアプリでPillowを使っている方は、できるだけ早く更新してください。そのうえで、互換性のない変更に当てはまる箇所がないかを確かめておきましょう。
ここまでお読みいただきありがとうございました。