Pillow で大きい解像度の画像を開くには Image.MAX_IMAGE_PIXELS の値を変える

試した環境

本題

Pillow では開く画像ファイルのピクセル数の制限が設定されています。 このことはリファレンスのPIL.Image.open()の Warning コラムに詳しく書かれています。

pillow.readthedocs.io

To protect against potential DOS attacks caused by “decompression bombs” (i.e. malicious files which decompress into a huge amount of data and are designed to crash or cause disruption by using up a lot of memory), Pillow will issue a DecompressionBombWarning if the number of pixels in an image is over a certain limit, PIL.Image.MAX_IMAGE_PIXELS.

This threshold can be changed by setting PIL.Image.MAX_IMAGE_PIXELS. It can be disabled by setting Image.MAX_IMAGE_PIXELS = None.

If desired, the warning can be turned into an error with warnings.simplefilter('error', Image.DecompressionBombWarning) or suppressed entirely with warnings.simplefilter('ignore', Image.DecompressionBombWarning). See also the logging documentation to have warnings output to the logging facility instead of stderr.

If the number of pixels is greater than twice PIL.Image.MAX_IMAGE_PIXELS, then a DecompressionBombError will be raised instead.

ピクセル数の制限はImage.MAX_IMAGE_PIXELSで設定されており、私の環境では89478485でした。

Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
>>> Image.MAX_IMAGE_PIXELS
89478485

この解像度より大きいファイルを開くとき、Image.MAX_IMAGE_PIXELSの2倍までなら警告が表示されるものの開くことができますが、2倍より大きい場合はエラーになり開くことができません。 以下はImage.MAX_IMAGE_PIXELSの丁度2倍の解像度の画像を開いた例です。 警告が表示されます。

>>> Image.new('1', (140911, 1270)).save('img1.png')
>>> img1 = Image.open('img1.png')
E:\work\tips\20220327_pillow_image_size\.venv\lib\site-packages\PIL\Image.py:2896: DecompressionBombWarning: Image size (178956970 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
  warnings.warn(
>>> img1
<PIL.PngImagePlugin.PngImageFile image mode=1 size=140911x1270 at 0x22E8D24A470>

以下は、Image.MAX_IMAGE_PIXELSの2倍より大きい解像度の画像を開こうとしてエラーになり開けない例です。 ちなみに、Image.new()Image.MAX_IMAGE_PIXELSを超えたサイズで使用出来ます。

>>> Image.new(mode='1', size=(16384, 16384)).save('img.png')
>>> img = Image.open('img.png')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "E:\work\tips\20220327_pillow_image_size\.venv\lib\site-packages\PIL\Image.py", line 2994, in open
    im = _open_core(fp, filename, prefix, formats)
  File "E:\work\tips\20220327_pillow_image_size\.venv\lib\site-packages\PIL\Image.py", line 2981, in _open_core
    _decompression_bomb_check(im.size)
  File "E:\work\tips\20220327_pillow_image_size\.venv\lib\site-packages\PIL\Image.py", line 2890, in _decompression_bomb_check
    raise DecompressionBombError(
PIL.Image.DecompressionBombError: Image size (268435456 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack.
>>> img
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'img' is not defined

大きい解像度の画像を開くには、Image.MAX_IMAGE_PIXELS = Noneとしてこの制限を無効化します。 もしくは開こうとするファイルのピクセル数以上の値(警告が出てもいいなら半分の値以上でも可)をImage.MAX_IMAGE_PIXELSに設定することでも開くことができます。

>>> Image.MAX_IMAGE_PIXELS = 16384 * 16384
>>> img = Image.open('img.png')
>>> img
<PIL.PngImagePlugin.PngImageFile image mode=1 size=16384x16384 at 0x1FF20513EB0>

この制限はDOS攻撃対策のための制限なので、解除する際にはそういった攻撃の可能性がない場面に限った方がいいでしょう。

参考

https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.open