mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	check run-time version numbers where available, add docs
This commit is contained in:
		
							parent
							
								
									a324f4a466
								
							
						
					
					
						commit
						6c1ff252d6
					
				|  | @ -8,6 +8,7 @@ The :py:mod:`PIL.features` module can be used to detect which Pillow features ar | |||
| 
 | ||||
| .. autofunction:: PIL.features.pilinfo | ||||
| .. autofunction:: PIL.features.check | ||||
| .. autofunction:: PIL.features.version | ||||
| .. autofunction:: PIL.features.get_supported | ||||
| 
 | ||||
| Modules | ||||
|  | @ -16,28 +17,31 @@ Modules | |||
| Support for the following modules can be checked: | ||||
| 
 | ||||
| * ``pil``: The Pillow core module, required for all functionality. | ||||
| * ``tkinter``: Tkinter support. | ||||
| * ``tkinter``: Tkinter support. Version number not available. | ||||
| * ``freetype2``: FreeType font support via :py:func:`PIL.ImageFont.truetype`. | ||||
| * ``littlecms2``: LittleCMS 2 support via :py:mod:`PIL.ImageCms`. | ||||
| * ``webp``: WebP image support. | ||||
| 
 | ||||
| .. autofunction:: PIL.features.check_module | ||||
| .. autofunction:: PIL.features.version_module | ||||
| .. autofunction:: PIL.features.get_supported_modules | ||||
| 
 | ||||
| Codecs | ||||
| ------ | ||||
| 
 | ||||
| These are only checked during Pillow compilation. | ||||
| Support for these is only checked during Pillow compilation. | ||||
| If the required library was uninstalled from the system, the ``pil`` core module may fail to load instead. | ||||
| Except for ``jpg``, the version number is checked at run-time. | ||||
| 
 | ||||
| Support for the following codecs can be checked: | ||||
| 
 | ||||
| * ``jpg``: (compile time) Libjpeg support, required for JPEG based image formats. | ||||
| * ``jpg``: (compile time) Libjpeg support, required for JPEG based image formats. Only compile time version number is available. | ||||
| * ``jpg_2000``: (compile time) OpenJPEG support, required for JPEG 2000 image formats. | ||||
| * ``zlib``: (compile time) Zlib support, required for zlib compressed formats, such as PNG. | ||||
| * ``libtiff``: (compile time) LibTIFF support, required for TIFF based image formats. | ||||
| 
 | ||||
| .. autofunction:: PIL.features.check_codec | ||||
| .. autofunction:: PIL.features.version_codec | ||||
| .. autofunction:: PIL.features.get_supported_codecs | ||||
| 
 | ||||
| Features | ||||
|  | @ -45,16 +49,18 @@ Features | |||
| 
 | ||||
| Some of these are only checked during Pillow compilation. | ||||
| If the required library was uninstalled from the system, the relevant module may fail to load instead. | ||||
| Feature version numbers are available only where stated. | ||||
| 
 | ||||
| Support for the following features can be checked: | ||||
| 
 | ||||
| * ``libjpeg_turbo``: (compile time) Whether Pillow was compiled against the libjpeg-turbo version of libjpeg. | ||||
| * ``libjpeg_turbo``: (compile time) Whether Pillow was compiled against the libjpeg-turbo version of libjpeg. Compile-time version number is available. | ||||
| * ``transp_webp``: Support for transparency in WebP images. | ||||
| * ``webp_mux``: (compile time) Support for EXIF data in WebP images. | ||||
| * ``webp_anim``: (compile time) Support for animated WebP images. | ||||
| * ``raqm``: Raqm library, required for ``ImageFont.LAYOUT_RAQM`` in :py:func:`PIL.ImageFont.truetype`. | ||||
| * ``libimagequant``: (compile time) ImageQuant quantization support in :py:func:`PIL.Image.Image.quantize`. | ||||
| * ``raqm``: Raqm library, required for ``ImageFont.LAYOUT_RAQM`` in :py:func:`PIL.ImageFont.truetype`. Run-time version number is available for Raqm 0.7.0 or newer. | ||||
| * ``libimagequant``: (compile time) ImageQuant quantization support in :py:func:`PIL.Image.Image.quantize`. Run-time version number is available. | ||||
| * ``xcb``: (compile time) Support for X11 in :py:func:`PIL.ImageGrab.grab` via the XCB library. | ||||
| 
 | ||||
| .. autofunction:: PIL.features.check_feature | ||||
| .. autofunction:: PIL.features.version_feature | ||||
| .. autofunction:: PIL.features.get_supported_features | ||||
|  |  | |||
|  | @ -8,11 +8,11 @@ import PIL | |||
| from . import Image | ||||
| 
 | ||||
| modules = { | ||||
|     "pil": ("PIL._imaging", None), | ||||
|     "pil": ("PIL._imaging", "PILLOW_VERSION"), | ||||
|     "tkinter": ("PIL._tkinter_finder", None), | ||||
|     "freetype2": ("PIL._imagingft", "freetype2"), | ||||
|     "littlecms2": ("PIL._imagingcms", "littlecms"), | ||||
|     "webp": ("PIL._webp", None), | ||||
|     "freetype2": ("PIL._imagingft", "freetype2_version"), | ||||
|     "littlecms2": ("PIL._imagingcms", "littlecms_version"), | ||||
|     "webp": ("PIL._webp", "webpdecoder_version"), | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ def check_module(feature): | |||
|     if not (feature in modules): | ||||
|         raise ValueError("Unknown module %s" % feature) | ||||
| 
 | ||||
|     module, lib = modules[feature] | ||||
|     module, ver = modules[feature] | ||||
| 
 | ||||
|     try: | ||||
|         __import__(module) | ||||
|  | @ -37,17 +37,21 @@ def check_module(feature): | |||
| 
 | ||||
| 
 | ||||
| def version_module(feature): | ||||
|     """ | ||||
|     :param feature: The module to check for. | ||||
|     :returns: | ||||
|         The loaded version number as a string, or ``None`` if unknown or not available. | ||||
|     :raises ValueError: If the module is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if not check_module(feature): | ||||
|         return None | ||||
| 
 | ||||
|     module, lib = modules[feature] | ||||
|     module, ver = modules[feature] | ||||
| 
 | ||||
|     if lib is None: | ||||
|     if ver is None: | ||||
|         return None | ||||
| 
 | ||||
|     attr = lib + "_version" | ||||
| 
 | ||||
|     return getattr(__import__(module, fromlist=[attr]), attr) | ||||
|     return getattr(__import__(module, fromlist=[ver]), ver) | ||||
| 
 | ||||
| 
 | ||||
| def get_supported_modules(): | ||||
|  | @ -82,6 +86,13 @@ def check_codec(feature): | |||
| 
 | ||||
| 
 | ||||
| def version_codec(feature): | ||||
|     """ | ||||
|     :param feature: The codec to check for. | ||||
|     :returns: | ||||
|         The version number as a string, or ``None`` if not available. | ||||
|         Checked at compile time for ``jpg``, run-time otherwise. | ||||
|     :raises ValueError: If the codec is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if not check_codec(feature): | ||||
|         return None | ||||
| 
 | ||||
|  | @ -103,13 +114,13 @@ def get_supported_codecs(): | |||
| 
 | ||||
| 
 | ||||
| features = { | ||||
|     "webp_anim": ("PIL._webp", "HAVE_WEBPANIM"), | ||||
|     "webp_mux": ("PIL._webp", "HAVE_WEBPMUX"), | ||||
|     "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"), | ||||
|     "raqm": ("PIL._imagingft", "HAVE_RAQM"), | ||||
|     "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"), | ||||
|     "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT"), | ||||
|     "xcb": ("PIL._imaging", "HAVE_XCB"), | ||||
|     "webp_anim": ("PIL._webp", "HAVE_WEBPANIM", None), | ||||
|     "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), | ||||
|     "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), | ||||
|     "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), | ||||
|     "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), | ||||
|     "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), | ||||
|     "xcb": ("PIL._imaging", "HAVE_XCB", None), | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -124,7 +135,7 @@ def check_feature(feature): | |||
|     if feature not in features: | ||||
|         raise ValueError("Unknown feature %s" % feature) | ||||
| 
 | ||||
|     module, flag = features[feature] | ||||
|     module, flag, ver = features[feature] | ||||
| 
 | ||||
|     try: | ||||
|         imported_module = __import__(module, fromlist=["PIL"]) | ||||
|  | @ -133,6 +144,23 @@ def check_feature(feature): | |||
|         return None | ||||
| 
 | ||||
| 
 | ||||
| def version_feature(feature): | ||||
|     """ | ||||
|     :param feature: The feature to check for. | ||||
|     :returns: The version number as a string, or ``None`` if not available. | ||||
|     :raises ValueError: If the feature is not defined in this version of Pillow. | ||||
|     """ | ||||
|     if not check_feature(feature): | ||||
|         return None | ||||
| 
 | ||||
|     module, flag, ver = features[feature] | ||||
| 
 | ||||
|     if ver is None: | ||||
|         return None | ||||
| 
 | ||||
|     return getattr(__import__(module, fromlist=[ver]), ver) | ||||
| 
 | ||||
| 
 | ||||
| def get_supported_features(): | ||||
|     """ | ||||
|     :returns: A list of all supported features. | ||||
|  | @ -142,9 +170,9 @@ def get_supported_features(): | |||
| 
 | ||||
| def check(feature): | ||||
|     """ | ||||
|     :param feature: A module, feature, or codec name. | ||||
|     :param feature: A module, codec, or feature name. | ||||
|     :returns: | ||||
|         ``True`` if the module, feature, or codec is available, | ||||
|         ``True`` if the module, codec, or feature is available, | ||||
|         ``False`` or ``None`` otherwise. | ||||
|     """ | ||||
| 
 | ||||
|  | @ -159,10 +187,18 @@ def check(feature): | |||
| 
 | ||||
| 
 | ||||
| def version(feature): | ||||
|     """ | ||||
|     :param feature: | ||||
|         The module, codec, or feature to check for. | ||||
|     :returns: | ||||
|         The version number as a string, or ``None`` if unknown or not available. | ||||
|     """ | ||||
|     if feature in modules: | ||||
|         return version_module(feature) | ||||
|     if feature in codecs: | ||||
|         return version_codec(feature) | ||||
|     if feature in features: | ||||
|         return version_feature(feature) | ||||
|     return None | ||||
| 
 | ||||
| 
 | ||||
|  | @ -228,12 +264,15 @@ def pilinfo(out=None, supported_formats=True): | |||
|         ("xcb", "XCB (X protocol)"), | ||||
|     ]: | ||||
|         if check(name): | ||||
|             if name == "jpg" and check_feature("libjpeg_turbo"): | ||||
|                 v = "libjpeg-turbo " + version_feature("libjpeg_turbo") | ||||
|             else: | ||||
|                 v = version(name) | ||||
|             if v is not None: | ||||
|                 support = "ok (version {})".format(v) | ||||
|                 t = "compiled for" if name in ("pil", "jpg") else "loaded" | ||||
|                 print("---", feature, "support ok,", t, "version", v, file=out) | ||||
|             else: | ||||
|                 support = "ok" | ||||
|             print("---", feature, "support", support, file=out) | ||||
|                 print("---", feature, "support ok", file=out) | ||||
|         else: | ||||
|             print("***", feature, "support not installed", file=out) | ||||
|     print("-" * 68, file=out) | ||||
|  |  | |||
|  | @ -4168,12 +4168,21 @@ setup_module(PyObject* m) { | |||
| 
 | ||||
| #ifdef LIBJPEG_TURBO_VERSION | ||||
|     PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_True); | ||||
|     #define tostr1(a) #a | ||||
|     #define tostr(a) tostr1(a) | ||||
|     PyDict_SetItemString(d, "libjpeg_turbo_version", PyUnicode_FromString(tostr(LIBJPEG_TURBO_VERSION))); | ||||
|     #undef tostr | ||||
|     #undef tostr1 | ||||
| #else | ||||
|     PyModule_AddObject(m, "HAVE_LIBJPEGTURBO", Py_False); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef HAVE_LIBIMAGEQUANT | ||||
|     PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_True); | ||||
|     { | ||||
|         extern const char* ImagingImageQuantVersion(void); | ||||
|         PyDict_SetItemString(d, "imagequant_version", PyUnicode_FromString(ImagingImageQuantVersion())); | ||||
|     } | ||||
| #else | ||||
|     PyModule_AddObject(m, "HAVE_LIBIMAGEQUANT", Py_False); | ||||
| #endif | ||||
|  |  | |||
|  | @ -1608,6 +1608,7 @@ static int | |||
| setup_module(PyObject* m) { | ||||
|     PyObject *d; | ||||
|     PyObject *v; | ||||
|     int vn; | ||||
| 
 | ||||
|     d = PyModule_GetDict(m); | ||||
| 
 | ||||
|  | @ -1622,7 +1623,8 @@ setup_module(PyObject* m) { | |||
| 
 | ||||
|     d = PyModule_GetDict(m); | ||||
| 
 | ||||
|     v = PyUnicode_FromFormat("%d.%d", LCMS_VERSION / 100, LCMS_VERSION % 100); | ||||
|     vn = cmsGetEncodedCMMversion(); | ||||
|     v = PyUnicode_FromFormat("%d.%d", vn / 100, vn % 100); | ||||
|     PyDict_SetItemString(d, "littlecms_version", v); | ||||
| 
 | ||||
|     return 0; | ||||
|  |  | |||
|  | @ -81,6 +81,7 @@ typedef struct { | |||
| 
 | ||||
| static PyTypeObject Font_Type; | ||||
| 
 | ||||
| typedef const char* (*t_raqm_version_string) (void); | ||||
| typedef bool (*t_raqm_version_atleast)(unsigned int major, | ||||
|                                        unsigned int minor, | ||||
|                                        unsigned int micro); | ||||
|  | @ -112,6 +113,7 @@ typedef void (*t_raqm_destroy) (raqm_t *rq); | |||
| typedef struct { | ||||
|     void* raqm; | ||||
|     int version; | ||||
|     t_raqm_version_string version_string; | ||||
|     t_raqm_version_atleast version_atleast; | ||||
|     t_raqm_create create; | ||||
|     t_raqm_set_text set_text; | ||||
|  | @ -173,6 +175,7 @@ setraqm(void) | |||
|     } | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
|     p_raqm.version_string = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_string"); | ||||
|     p_raqm.version_atleast = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast"); | ||||
|     p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create"); | ||||
|     p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text"); | ||||
|  | @ -206,6 +209,7 @@ setraqm(void) | |||
|         return 2; | ||||
|     } | ||||
| #else | ||||
|     p_raqm.version_string = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_string"); | ||||
|     p_raqm.version_atleast = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast"); | ||||
|     p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create"); | ||||
|     p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text"); | ||||
|  | @ -1251,6 +1255,9 @@ setup_module(PyObject* m) { | |||
|     setraqm(); | ||||
|     v = PyBool_FromLong(!!p_raqm.raqm); | ||||
|     PyDict_SetItemString(d, "HAVE_RAQM", v); | ||||
|     if (p_raqm.version_string) { | ||||
|         PyDict_SetItemString(d, "raqm_version", PyUnicode_FromString(p_raqm.version_string())); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										13
									
								
								src/_webp.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/_webp.c
									
									
									
									
									
								
							|  | @ -821,6 +821,16 @@ PyObject* WebPDecoderVersion_wrapper() { | |||
|     return Py_BuildValue("i", WebPGetDecoderVersion()); | ||||
| } | ||||
| 
 | ||||
| // Version as string
 | ||||
| const char* | ||||
| WebPDecoderVersion_str(void) | ||||
| { | ||||
|     static char version[20]; | ||||
|     int version_number = WebPGetDecoderVersion(); | ||||
|     sprintf(version, "%d.%d.%d", version_number >> 16, (version_number >> 8) % 0x100, version_number % 0x100); | ||||
|     return version; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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. | ||||
|  | @ -872,10 +882,13 @@ void addTransparencyFlagToModule(PyObject* m) { | |||
| } | ||||
| 
 | ||||
| static int setup_module(PyObject* m) { | ||||
|     PyObject* d = PyModule_GetDict(m); | ||||
|     addMuxFlagToModule(m); | ||||
|     addAnimFlagToModule(m); | ||||
|     addTransparencyFlagToModule(m); | ||||
| 
 | ||||
|     PyDict_SetItemString(d, "webpdecoder_version", PyUnicode_FromString(WebPDecoderVersion_str())); | ||||
| 
 | ||||
| #ifdef HAVE_WEBPANIM | ||||
|     /* Ready object types */ | ||||
|     if (PyType_Ready(&WebPAnimDecoder_Type) < 0 || | ||||
|  |  | |||
|  | @ -113,4 +113,13 @@ err: | |||
|     return result; | ||||
| } | ||||
| 
 | ||||
| const char* | ||||
| ImagingImageQuantVersion(void) | ||||
| { | ||||
|     static char version[20]; | ||||
|     int number = liq_version(); | ||||
|     sprintf(version, "%d.%d.%d", number / 10000, (number / 100) % 100, number % 100); | ||||
|     return version; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -373,7 +373,7 @@ ImagingZipEncodeCleanup(ImagingCodecState state) { | |||
| const char* | ||||
| ImagingZipVersion(void) | ||||
| { | ||||
|     return ZLIB_VERSION; | ||||
|     return zlibVersion(); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user