diff --git a/.travis/install.sh b/.travis/install.sh index 259d33e55..d5f190619 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -3,7 +3,7 @@ set -e sudo apt-get update -sudo apt-get -qq install libfreetype6-dev liblcms2-dev\ +sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk \ python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick pip install cffi pip install nose diff --git a/PIL/features.py b/PIL/features.py index fb8e4371b..e01a32193 100644 --- a/PIL/features.py +++ b/PIL/features.py @@ -2,45 +2,26 @@ from . import Image modules = { "pil": "PIL._imaging", - "tkinter": "PIL._imagingtk", + "tkinter": "PIL._tkinter_finder", "freetype2": "PIL._imagingft", "littlecms2": "PIL._imagingcms", "webp": "PIL._webp", - "transp_webp": ("WEBP", "WebPDecoderBuggyAlpha") } - def check_module(feature): - if feature not in modules: + if not (feature in modules): raise ValueError("Unknown module %s" % feature) module = modules[feature] - method_to_call = None - if isinstance(module, tuple): - module, method_to_call = module - try: imported_module = __import__(module) - except ImportError: - # If a method is being checked, None means that - # rather than the method failing, the module required for the method - # failed to be imported first - return None if method_to_call else False - - if method_to_call: - method = getattr(imported_module, method_to_call) - return method() is True - else: return True - + except ImportError: + return False def get_supported_modules(): - supported_modules = [] - for feature in modules: - if check_module(feature): - supported_modules.append(feature) - return supported_modules + return [f for f in modules if check_module(f)] codecs = { "jpg": "jpeg", @@ -49,7 +30,6 @@ codecs = { "libtiff": "libtiff" } - def check_codec(feature): if feature not in codecs: raise ValueError("Unknown codec %s" % feature) @@ -60,8 +40,38 @@ def check_codec(feature): def get_supported_codecs(): - supported_codecs = [] - for feature in codecs: - if check_codec(feature): - supported_codecs.append(feature) - return supported_codecs + return [f for f in codecs if check_codec(f)] + +features = { + "webp_mux": ("PIL._webp", 'HAVE_WEBPMUX'), + "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"), +} + +def check_feature(feature): + if feature not in features: + raise ValueError("Unknown feature %s" % feature) + + module, flag = features[feature] + + try: + imported_module = __import__(module, fromlist=['PIL']) + return getattr(imported_module, flag) + except ImportError: + return None + + +def get_supported_features(): + return [f for f in features if check_feature(f)] + + +def check(feature): + return (feature in modules and check_module(feature) or \ + feature in codecs and check_codec(feature) or \ + feature in features and check_feature(feature)) + +def get_supported(): + ret = get_supported_modules() + ret.extend(get_supported_features()) + ret.extend(get_supported_codecs()) + return ret + diff --git a/Tests/test_features.py b/Tests/test_features.py index eacf807db..d14aaca69 100644 --- a/Tests/test_features.py +++ b/Tests/test_features.py @@ -2,19 +2,50 @@ from helper import unittest, PillowTestCase from PIL import features +try: + from PIL import _webp + HAVE_WEBP = True +except: + HAVE_WEBP = False + class TestFeatures(PillowTestCase): - def test_check_features(self): + def test_check(self): + # Check the correctness of the convenience function + for module in features.modules: + self.assertEqual(features.check_module(module), + features.check(module)) + for codec in features.codecs: + self.assertEqual(features.check_codec(codec), + features.check(codec)) + for feature in features.features: + self.assertEqual(features.check_feature(feature), + features.check(feature)) + + @unittest.skipUnless(HAVE_WEBP, True) + def check_webp_transparency(self): + self.assertEqual(features.check('transp_webp'), + not _webp.WebPDecoderBuggyAlpha()) + self.assertEqual(features.check('transp_webp'), + _webp.HAVE_TRANSPARENCY) + + @unittest.skipUnless(HAVE_WEBP, True) + def check_webp_mux(self): + self.assertEqual(features.check('webp_mux'), + _webp.HAVE_WEBPMUX) + + def test_check_modules(self): for feature in features.modules: - self.assertIn( - features.check_module(feature), [True, False, None]) + self.assertIn(features.check_module(feature), [True, False]) for feature in features.codecs: self.assertIn(features.check_codec(feature), [True, False]) - def test_supported_features(self): + def test_supported_modules(self): self.assertIsInstance(features.get_supported_modules(), list) self.assertIsInstance(features.get_supported_codecs(), list) + self.assertIsInstance(features.get_supported_features(), list) + self.assertIsInstance(features.get_supported(), list) def test_unsupported_codec(self): # Arrange diff --git a/_webp.c b/_webp.c index 70830ec8b..421f49957 100644 --- a/_webp.c +++ b/_webp.c @@ -247,8 +247,12 @@ PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){ * The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well. * Files that are valid with 0.3 are reported as being invalid. */ +int WebPDecoderBuggyAlpha() { + return WebPGetDecoderVersion()==0x0103; +} + PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){ - return Py_BuildValue("i", WebPGetDecoderVersion()==0x0103); + return Py_BuildValue("i", WebPDecoderBuggyAlpha()); } static PyMethodDef webpMethods[] = @@ -268,6 +272,11 @@ void addMuxFlagToModule(PyObject* m) { #endif } +void addTransparencyFlagToModule(PyObject* m) { + PyModule_AddObject(m, "HAVE_TRANSPARENCY", + PyBool_FromLong(!WebPDecoderBuggyAlpha())); +} + #if PY_VERSION_HEX >= 0x03000000 PyMODINIT_FUNC @@ -284,6 +293,7 @@ PyInit__webp(void) { m = PyModule_Create(&module_def); addMuxFlagToModule(m); + addTransparencyFlagToModule(m); return m; } #else @@ -292,5 +302,6 @@ init_webp(void) { PyObject* m = Py_InitModule("_webp", webpMethods); addMuxFlagToModule(m); + addTransparencyFlagToModule(m); } #endif diff --git a/selftest.py b/selftest.py index 067db4d79..f6e8e5ed8 100755 --- a/selftest.py +++ b/selftest.py @@ -178,25 +178,14 @@ if __name__ == "__main__": ("freetype2", "FREETYPE2"), ("littlecms2", "LITTLECMS2"), ("webp", "WEBP"), - ("transp_webp", "Transparent WEBP") - ]: - supported = features.check_module(name) - - if supported is None: - # A method was being tested, but the module required - # for the method could not be correctly imported - pass - elif supported: - print("---", feature, "support ok") - else: - print("***", feature, "support not installed") - for name, feature in [ + ("transp_webp", "Transparent WEBP"), + ("webp_mux", "WEBPMUX"), ("jpg", "JPEG"), ("jpg_2000", "OPENJPEG (JPEG2000)"), ("zlib", "ZLIB (PNG/ZIP)"), ("libtiff", "LIBTIFF") ]: - if features.check_codec(name): + if features.check(name): print("---", feature, "support ok") else: print("***", feature, "support not installed")