Skip to content

Pillow-SIMD recipe? #2420

@podraco

Description

@podraco

Greetings i recently am testing some optimizations for my projects and i'm stuck trying to replace the normal pillow with pillow-SIMD for an android app.
Supposedly, pillow-simd is a drop and replace lib for pillow 7.0.0 but i'm stuck trying to perform the recipe for the lib.

the recipe should be a fork like from the current pillow recipe, as far as i understand.
yet, i'm stuck with this error:

myapp/PIL/Image.py:90: RuntimeWarning: The _imaging extension was built for another version of Pillow or PIL:

here are the files i'm using.
pythonforandroid/recipes/pillow-simd/__init__.py

from os.path import join

from pythonforandroid.recipe import CompiledComponentsPythonRecipe

class Pillow_SimdRecipe(CompiledComponentsPythonRecipe):
    """
    A recipe for Pillow (previously known as Pil).

    This recipe allow us to build the Pillow recipe with support for different
    types of images and fonts. But you should be aware, that in order to  use
    some of the features of  Pillow, we must build some libraries. By default
    we automatically trigger the build of below libraries::

        - freetype: rendering fonts support.
        - harfbuzz: a text shaping library.
        - jpeg: reading and writing JPEG image files.
        - png: support for PNG images.

    But you also could enable the build of some extra image types by requesting
    the build of some libraries via argument `requirements`::

        - libwebp: library to encode and decode images in WebP format.
    """

    version = 'master'
    url = 'https://github.com/uploadcare/pillow-simd/archive/simd/{version}.zip'
    site_packages_name = 'Pillow'
    depends = ['png', 'jpeg', 'freetype', 'setuptools']
    opt_depends = ['libwebp']
    patches = [join('patches', 'fix-setup.patch')]
    conflicts = ['pillow']

    call_hostpython_via_targetpython = False
    def get_recipe_env(self, arch=None, with_flags_in_cc=True):
        env = super().get_recipe_env(arch, with_flags_in_cc)

        env['ANDROID_ROOT'] = join(self.ctx.ndk_platform, 'usr')
        ndk_lib_dir = join(self.ctx.ndk_platform, 'usr', 'lib')
        ndk_include_dir = join(self.ctx.ndk_dir, 'sysroot', 'usr', 'include')

        png = self.get_recipe('png', self.ctx)
        png_lib_dir = join(png.get_build_dir(arch.arch), '.libs')
        png_inc_dir = png.get_build_dir(arch)

        jpeg = self.get_recipe('jpeg', self.ctx)
        jpeg_inc_dir = jpeg_lib_dir = jpeg.get_build_dir(arch.arch)

        freetype = self.get_recipe('freetype', self.ctx)
        free_lib_dir = join(freetype.get_build_dir(arch.arch), 'objs', '.libs')
        free_inc_dir = join(freetype.get_build_dir(arch.arch), 'include')

        # harfbuzz is a direct dependency of freetype and we need the proper
        # flags to successfully build the Pillow recipe, so we add them here.
        harfbuzz = self.get_recipe('harfbuzz', self.ctx)
        harf_lib_dir = join(harfbuzz.get_build_dir(arch.arch), 'src', '.libs')
        harf_inc_dir = harfbuzz.get_build_dir(arch.arch)

        # these below env variables are defined at Pillow's `setup.py`
        env['JPEG_ROOT'] = f'{jpeg_lib_dir}|{jpeg_inc_dir}'
        env['FREETYPE_ROOT'] = f'{free_lib_dir}|{free_inc_dir}'
        env['ZLIB_ROOT'] = f'{ndk_lib_dir}|{ndk_include_dir}'

        # libwebp is an optional dependency, so we add the
        # flags if we have it in our `ctx.recipe_build_order`
        build_with_webp_support = 'libwebp' in self.ctx.recipe_build_order
        if build_with_webp_support:
            webp = self.get_recipe('libwebp', self.ctx)
            webp_install = join(
                webp.get_build_dir(arch.arch), 'installation'
            )

        # Add libraries includes to CFLAGS
        cflags = f' -I{png_inc_dir}'
        cflags += f' -I{harf_inc_dir} -I{join(harf_inc_dir, "src")}'
        cflags += f' -I{free_inc_dir}'
        cflags += f' -I{jpeg_inc_dir}'
        if build_with_webp_support:
            cflags += f' -I{join(webp_install, "include")}'
        cflags += f' -I{ndk_include_dir}'

        # Link the basic Pillow libraries...no need to add webp's libraries
        # since it seems that the linkage is properly made without it :)
        env['LIBS'] = ' -lpng -lfreetype -lharfbuzz -ljpeg -lturbojpeg'

        # Add libraries locations to LDFLAGS
        env['LDFLAGS'] += f' -L{png_lib_dir}'
        env['LDFLAGS'] += f' -L{harf_lib_dir}'
        env['LDFLAGS'] += f' -L{jpeg_lib_dir}'
        if build_with_webp_support:
            env['LDFLAGS'] += f' -L{join(webp_install, "lib")}'
        env['LDFLAGS'] += f' -L{ndk_lib_dir}'
        if cflags not in env['CFLAGS']:
            env['CFLAGS'] += cflags + "cc -mavx2"
        return env


recipe = Pillow_SimdRecipe()

pythonforandroid/recipes/pillow-simd/patches/fix-setup.patch

--- Pillow-sidm/setup.py.orig	2020-01-02 06:19:26.000000000 +0100
+++ Pillow-simd/setup.py	2020-07-05 12:26:18.882948858 +0200
@@ -29,13 +29,13 @@ def get_version():

 NAME = "Pillow-SIMD"
 PILLOW_VERSION = get_version()
-FREETYPE_ROOT = None
+FREETYPE_ROOT = tuple(os.environ['FREETYPE_ROOT'].split('|')) if 'FREETYPE_ROOT' in os.environ else None
 IMAGEQUANT_ROOT = None
 JPEG2K_ROOT = None
-JPEG_ROOT = None
+JPEG_ROOT = tuple(os.environ['JPEG_ROOT'].split('|')) if 'JPEG_ROOT' in os.environ else None
 LCMS_ROOT = None
 TIFF_ROOT = None
-ZLIB_ROOT = None
+ZLIB_ROOT = tuple(os.environ['ZLIB_ROOT'].split('|')) if 'ZLIB_ROOT' in os.environ else None


 if sys.platform == "win32" and sys.version_info >= (3, 9):
@@ -317,7 +317,7 @@ class pil_build_ext(build_ext):
     )

     def initialize_options(self):
-        self.disable_platform_guessing = None
+        self.disable_platform_guessing = True
         self.add_imaging_libs = ""
         build_ext.initialize_options(self)
         for x in self.feature:
@@ -567,62 +567,6 @@ class pil_build_ext(build_ext):
                     feature.jpeg = "libjpeg"  # alternative name

         feature.openjpeg_version = None
-        if feature.want("jpeg2000"):
-            _dbg("Looking for jpeg2000")
-            best_version = None
-            best_path = None
-
-            # Find the best version
-            for directory in self.compiler.include_dirs:
-                _dbg("Checking for openjpeg-#.# in %s", directory)
-                try:
-                    listdir = os.listdir(directory)
-                except Exception:
-                    # WindowsError, FileNotFoundError
-                    continue
-                for name in listdir:
-                    if name.startswith("openjpeg-") and os.path.isfile(
-                        os.path.join(directory, name, "openjpeg.h")
-                    ):
-                        _dbg("Found openjpeg.h in %s/%s", (directory, name))
-                        version = tuple(int(x) for x in name[9:].split("."))
-                        if best_version is None or version > best_version:
-                            best_version = version
-                            best_path = os.path.join(directory, name)
-                            _dbg(
-                                "Best openjpeg version %s so far in %s",
-                                (best_version, best_path),
-                            )
-
-            if best_version and _find_library_file(self, "openjp2"):
-                # Add the directory to the include path so we can include
-                # <openjpeg.h> rather than having to cope with the versioned
-                # include path
-                # FIXME (melvyn-sopacua):
-                # At this point it's possible that best_path is already in
-                # self.compiler.include_dirs. Should investigate how that is
-                # possible.
-                _add_directory(self.compiler.include_dirs, best_path, 0)
-                feature.jpeg2000 = "openjp2"
-                feature.openjpeg_version = ".".join(str(x) for x in best_version)
-
-        if feature.want("imagequant"):
-            _dbg("Looking for imagequant")
-            if _find_include_file(self, "libimagequant.h"):
-                if _find_library_file(self, "imagequant"):
-                    feature.imagequant = "imagequant"
-                elif _find_library_file(self, "libimagequant"):
-                    feature.imagequant = "libimagequant"
-
-        if feature.want("tiff"):
-            _dbg("Looking for tiff")
-            if _find_include_file(self, "tiff.h"):
-                if _find_library_file(self, "tiff"):
-                    feature.tiff = "tiff"
-                if sys.platform in ["win32", "darwin"] and _find_library_file(
-                    self, "libtiff"
-                ):
-                    feature.tiff = "libtiff"

         if feature.want("freetype"):
             _dbg("Looking for freetype")
@@ -647,15 +591,6 @@ class pil_build_ext(build_ext):
                     if subdir:
                         _add_directory(self.compiler.include_dirs, subdir, 0)

-        if feature.want("lcms"):
-            _dbg("Looking for lcms")
-            if _find_include_file(self, "lcms2.h"):
-                if _find_library_file(self, "lcms2"):
-                    feature.lcms = "lcms2"
-                elif _find_library_file(self, "lcms2_static"):
-                    # alternate Windows name.
-                    feature.lcms = "lcms2_static"
-
         if feature.want("webp"):
             _dbg("Looking for webp")
             if _find_include_file(self, "webp/encode.h") and _find_include_file(
@@ -717,8 +652,8 @@ class pil_build_ext(build_ext):
             defs.append(("HAVE_LIBTIFF", None))
         if sys.platform == "win32":
             libs.extend(["kernel32", "user32", "gdi32"])
-        if struct.unpack("h", b"\0\1")[0] == 1:
-            defs.append(("WORDS_BIGENDIAN", None))
+        # if struct.unpack("h", b"\0\1")[0] == 1:
+        #     defs.append(("WORDS_BIGENDIAN", None))

         if sys.platform == "win32" and not (PLATFORM_PYPY or PLATFORM_MINGW):
             defs.append(("PILLOW_VERSION", '"\\"%s\\""' % PILLOW_VERSION))
@@ -769,16 +704,6 @@ class pil_build_ext(build_ext):
                 )
             )

-        tk_libs = ["psapi"] if sys.platform == "win32" else []
-        exts.append(
-            Extension(
-                "PIL._imagingtk",
-                ["src/_imagingtk.c", "src/Tk/tkImaging.c"],
-                include_dirs=["src/Tk"],
-                libraries=tk_libs,
-            )
-        )
-
         exts.append(Extension("PIL._imagingmath", ["src/_imagingmath.c"]))
         exts.append(Extension("PIL._imagingmorph", ["src/_imagingmorph.c"]))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions