diff --git a/kivy/core/image/img_imageio.pyx b/kivy/core/image/img_imageio.pyx index b453b845a..861cef1d7 100644 --- a/kivy/core/image/img_imageio.pyx +++ b/kivy/core/image/img_imageio.pyx @@ -1,3 +1,5 @@ +# distutils: language = c++ + ''' ImageIO OSX framework ===================== @@ -140,6 +142,16 @@ cdef extern from "Accelerate/Accelerate.h" nogil: int flags) +cdef extern from "img_imageio_implem.mm": + cppclass KivyImageIOProviderSupportedExtensionList: + int count() + char* get(int index) + + cppclass KivyImageIOProvider: + KivyImageIOProvider() + KivyImageIOProviderSupportedExtensionList* supported_source_image_extensions + + def load_image_data(bytes _url, bytes _data=None): cdef size_t width, height cdef char *r_data = NULL @@ -310,19 +322,36 @@ def save_image(filenm, width, height, fmt, data, flipped): free(pixels) + +cdef class _ImageIOInterface: + cdef KivyImageIOProvider* _provider + + def __cinit__(self): + self._provider = new KivyImageIOProvider() + + def __dealloc__(self): + del self._provider + + cdef list get_supported_source_extensions(self): + cdef list ret = [] + for i in range(self._provider.supported_source_image_extensions.count()): + ret.append(self._provider.supported_source_image_extensions.get(i).decode('utf-8')) + return ret + +# A list of the supported source extensions is served by the static method +# extensions() of the ImageLoaderImageIO class. +# To avoid the creation of a new _ImageIOInterface object each time we need to +# get the list of supported extensions, we create a single use object and get +# the list of supported extensions at the module level. +cdef list _supported_source_extensions = _ImageIOInterface().get_supported_source_extensions() + class ImageLoaderImageIO(ImageLoaderBase): '''Image loader based on ImageIO OS X Framework ''' @staticmethod def extensions(): - # FIXME check which one are available on osx - return ('bmp', 'bufr', 'cur', 'dcx', 'fits', 'fl', 'fpx', 'gbr', - 'gd', 'grib', 'hdf5', 'ico', 'im', 'imt', 'iptc', - 'jpeg', 'jpg', 'jpe', 'mcidas', 'mic', 'mpeg', 'msp', - 'pcd', 'pcx', 'pixar', 'png', 'ppm', 'psd', 'sgi', - 'spider', 'tga', 'tiff', 'wal', 'wmf', 'xbm', 'xpm', - 'xv', 'icns') + return _supported_source_extensions def load(self, filename): # FIXME: if the filename is unicode, the loader is failing. diff --git a/kivy/core/image/img_imageio_implem.h b/kivy/core/image/img_imageio_implem.h new file mode 100644 index 000000000..380c71775 --- /dev/null +++ b/kivy/core/image/img_imageio_implem.h @@ -0,0 +1,23 @@ +#include +#include + +class KivyImageIOProviderSupportedExtensionList { + public: + KivyImageIOProviderSupportedExtensionList(); + ~KivyImageIOProviderSupportedExtensionList(); + void add(NSString* extension); + char* get(int index); + int count(); + void clear(); + private: + NSMutableArray* extensions; +}; + +class KivyImageIOProvider { + public: + KivyImageIOProvider(); + ~KivyImageIOProvider(); + KivyImageIOProviderSupportedExtensionList* supported_source_image_extensions; + private: + void load_supported_source_extensions(); +}; \ No newline at end of file diff --git a/kivy/core/image/img_imageio_implem.mm b/kivy/core/image/img_imageio_implem.mm new file mode 100644 index 000000000..4e8105365 --- /dev/null +++ b/kivy/core/image/img_imageio_implem.mm @@ -0,0 +1,84 @@ +#include "img_imageio_implem.h" + +/* +* KivyImageIOProviderSupportedExtensionList +*/ + +KivyImageIOProviderSupportedExtensionList::KivyImageIOProviderSupportedExtensionList() +{ + this->extensions = [[NSMutableArray alloc] init]; +} + +KivyImageIOProviderSupportedExtensionList::~KivyImageIOProviderSupportedExtensionList() +{ +} + +void KivyImageIOProviderSupportedExtensionList::add(NSString *extension) +{ + if (![this->extensions containsObject:extension]) + { + [this->extensions addObject:extension]; + } +} + +int KivyImageIOProviderSupportedExtensionList::count() +{ + return [this->extensions count]; +} + +char *KivyImageIOProviderSupportedExtensionList::get(int index) +{ + NSString *extension = [this->extensions objectAtIndex:index]; + return (char *)[extension UTF8String]; +} + +void KivyImageIOProviderSupportedExtensionList::clear() +{ + [this->extensions removeAllObjects]; +} + +/* +* KivyImageIOProvider +*/ + +KivyImageIOProvider::KivyImageIOProvider() +{ + this->supported_source_image_extensions = new KivyImageIOProviderSupportedExtensionList(); + this->load_supported_source_extensions(); +} + +KivyImageIOProvider::~KivyImageIOProvider() +{ + delete this->supported_source_image_extensions; +} + +void KivyImageIOProvider::load_supported_source_extensions() +{ + this->supported_source_image_extensions->clear(); + + CFArrayRef type_identifiers = CGImageSourceCopyTypeIdentifiers(); + + for (CFIndex i = 0; i < CFArrayGetCount(type_identifiers); i++) + { + CFStringRef uti = (CFStringRef)CFArrayGetValueAtIndex(type_identifiers, i); + NSArray *uti_extensions; + + if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)) + { + UTType *uttype = [UTType typeWithIdentifier:(NSString *)uti]; + uti_extensions = uttype.tags[@"public.filename-extension"]; + } + else + { + // UTTypeCopyAllTagsWithClass is deprecated, we're leaving this here + // for compatibility with older versions of macOS and iOS + uti_extensions = CFBridgingRelease( + UTTypeCopyAllTagsWithClass(uti, kUTTagClassFilenameExtension)); + } + + for (NSString *extension in uti_extensions) + { + this->supported_source_image_extensions->add(extension); + } + } +} \ No newline at end of file diff --git a/setup.py b/setup.py index b7cd5cfb9..a57f7010b 100644 --- a/setup.py +++ b/setup.py @@ -974,6 +974,7 @@ if platform in ('darwin', 'ios'): else: osx_flags = {'extra_link_args': [ '-framework', 'ApplicationServices']} + osx_flags['extra_compile_args'] = ['-ObjC++'] sources['core/image/img_imageio.pyx'] = merge( base_flags, osx_flags)