Skip to content

Commit 5f3043f

Browse files
committed
Allow plugins to specify their supported modes
1 parent 7ee1aa6 commit 5f3043f

6 files changed

Lines changed: 57 additions & 35 deletions

File tree

Tests/test_image.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
from PIL import Image, TiffImagePlugin
44
from PIL._util import py3
5+
6+
from io import BytesIO
57
import os
8+
import sys
69

710

811
class TestImage(PillowTestCase):
@@ -62,8 +65,7 @@ def test_width_height(self):
6265

6366
def test_invalid_image(self):
6467
if py3:
65-
import io
66-
im = io.BytesIO(b'')
68+
im = BytesIO(b'')
6769
else:
6870
import StringIO
6971
im = StringIO.StringIO('')
@@ -324,8 +326,29 @@ def test_registered_extensions(self):
324326
for ext in ['.cur', '.icns', '.tif', '.tiff']:
325327
self.assertIn(ext, extensions)
326328

327-
def test_no_convert_mode(self):
328-
self.assertTrue(not hasattr(TiffImagePlugin, '_convert_mode'))
329+
def test_supported_modes(self):
330+
for format in Image.MIME.keys():
331+
try:
332+
save_handler = Image.SAVE[format]
333+
except KeyError:
334+
continue
335+
plugin = sys.modules[save_handler.__module__]
336+
if not hasattr(plugin, '_supported_modes'):
337+
continue
338+
339+
# Check that the supported modes list is accurate
340+
supported_modes = plugin._supported_modes()
341+
for mode in ['1', 'L', 'P', 'RGB', 'RGBA', 'CMYK', 'YCbCr', 'LAB',
342+
'HSV', 'I', 'F', 'LA', 'La', 'RGBX', 'RGBa']:
343+
out = BytesIO()
344+
im = Image.new(mode, (100, 100))
345+
if mode in supported_modes:
346+
im.save(out, format)
347+
else:
348+
self.assertRaises(Exception, im.save, out, format)
349+
350+
def test_no_supported_modes_method(self):
351+
self.assertTrue(not hasattr(TiffImagePlugin, '_supported_modes'))
329352

330353
temp_file = self.tempfile("temp.tiff")
331354

src/PIL/GifImagePlugin.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -798,11 +798,8 @@ def write(self, data):
798798
return fp.data
799799

800800

801-
def _convert_mode(im):
802-
return {
803-
'LA':'P',
804-
'CMYK':'RGB'
805-
}.get(im.mode)
801+
def _supported_modes():
802+
return ['RGB', 'RGBA', 'P', 'I', 'F', 'LA', 'L', '1']
806803

807804

808805
# --------------------------------------------------------------------

src/PIL/Image.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,9 +1956,29 @@ def save(self, fp, format=None, **params):
19561956
fp.close()
19571957

19581958
def _convert_mode(self, plugin, params):
1959-
if not hasattr(plugin, '_convert_mode'):
1959+
if not hasattr(plugin, '_supported_modes'):
19601960
return
1961-
new_mode = plugin._convert_mode(self)
1961+
supported_modes = plugin._supported_modes()
1962+
if not supported_modes or self.mode in supported_modes:
1963+
return
1964+
if self.mode == 'P':
1965+
preferred_modes = []
1966+
if 'A' in self.im.getpalettemode():
1967+
preferred_modes.append('RGBA')
1968+
preferred_modes.append('RGB')
1969+
else:
1970+
preferred_modes = {
1971+
'RGBA': ['RGB'],
1972+
'LA': ['RGBA', 'P', 'L'],
1973+
'L': ['RGB'],
1974+
'I': ['L', 'RGB'],
1975+
'CMYK': ['RGB']
1976+
}.get(self.mode, [])
1977+
for new_mode in preferred_modes:
1978+
if new_mode in supported_modes:
1979+
break
1980+
else:
1981+
new_mode = supported_modes[0]
19621982
if self.mode == 'LA' and new_mode == 'P':
19631983
alpha = self.getchannel('A')
19641984
# Convert the image into P mode but only use 255 colors

src/PIL/JpegImagePlugin.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -792,15 +792,8 @@ def jpeg_factory(fp=None, filename=None):
792792
return im
793793

794794

795-
def _convert_mode(im):
796-
mode = im.mode
797-
if mode == 'P':
798-
return 'RGBA' if 'A' in im.im.getpalettemode() else 'RGB'
799-
return {
800-
'RGBA':'RGB',
801-
'LA':'L',
802-
'I':'L'
803-
}.get(mode)
795+
def _supported_modes():
796+
return ['RGB', 'CMYK', 'YCbCr', 'RGBX', 'L', '1']
804797

805798

806799
# -------------------------------------------------------------------q-

src/PIL/PngImagePlugin.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,8 @@ def append(fp, cid, *data):
859859
return fp.data
860860

861861

862-
def _convert_mode(im):
863-
return {
864-
'CMYK':'RGB'
865-
}.get(im.mode)
862+
def _supported_modes():
863+
return ['RGB', 'RGBA', 'P', 'I', 'LA', 'L', '1']
866864

867865

868866
# --------------------------------------------------------------------

src/PIL/WebPImagePlugin.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,8 @@ def _save(im, fp, filename):
308308
fp.write(data)
309309

310310

311-
def _convert_mode(im):
312-
mode = im.mode
313-
if mode == 'P':
314-
return 'RGBA' if 'A' in im.im.getpalettemode() else 'RGB'
315-
return {
316-
# Pillow doesn't support L modes for webp for now.
317-
'L':'RGB',
318-
'LA':'RGBA',
319-
'I':'RGB',
320-
'CMYK':'RGB'
321-
}.get(mode)
311+
def _supported_modes():
312+
return ['RGB', 'RGBA', 'RGBX', 'CMYK', 'YCbCr', 'HSV', 'I', 'F', 'P', 'LA', 'L', '1']
322313

323314

324315
Image.register_open(WebPImageFile.format, WebPImageFile, _accept)

0 commit comments

Comments
 (0)