'''
PIL: PIL image loader
'''

__all__ = ('ImageLoaderPIL', )

try:
    from PIL import Image as PILImage
except:
    import Image as PILImage

from kivy.logger import Logger
from kivy.core.image import ImageLoaderBase, ImageData, ImageLoader


class ImageLoaderPIL(ImageLoaderBase):
    '''Image loader based on the PIL library.

    .. versionadded:: 1.0.8

    Support for GIF animation added.

    Gif animation has a lot of issues(transparency/color depths... etc).
    In order to keep it simple, what is implemented here is what is
    natively supported by the PIL library.

    As a general rule, try to use gifs that have no transparency.
    Gif's with transparency will work but be prepared for some
    artifacts until transparency support is improved.

    '''

    @staticmethod
    def can_save():
        return True

    @staticmethod
    def can_load_memory():
        return True

    @staticmethod
    def extensions():
        '''Return accepted extensions for this loader'''
        # See http://www.pythonware.com/library/pil/handbook/index.htm
        return ('bmp', 'bufr', 'cur', 'dcx', 'fits', 'fl', 'fpx', 'gbr',
                'gd', 'gif', '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')

    def _img_correct(self, _img_tmp):
        '''Convert image to the correct format and orientation.
        '''
        # image loader work only with rgb/rgba image
        if _img_tmp.mode.lower() not in ('rgb', 'rgba'):
            try:
                imc = _img_tmp.convert('RGBA')
            except:
                Logger.warning(
                    'Image: Unable to convert image to rgba (was %s)' %
                    (_img_tmp.mode.lower()))
                raise
            _img_tmp = imc

        return _img_tmp

    def _img_read(self, im):
        '''Read images from an animated file.
        '''
        im.seek(0)

        # Read all images inside
        try:
            img_ol = None
            while True:
                img_tmp = im
                img_tmp = self._img_correct(img_tmp)
                if img_ol and (hasattr(im, 'dispose') and not im.dispose):
                    # paste new frame over old so as to handle
                    # transparency properly
                    img_ol.paste(img_tmp, (0, 0), img_tmp)
                    img_tmp = img_ol
                img_ol = img_tmp
                yield ImageData(img_tmp.size[0], img_tmp.size[1],
                                img_tmp.mode.lower(), img_tmp.tobytes())
                im.seek(im.tell() + 1)
        except EOFError:
            pass

    def load(self, filename):
        try:
            im = PILImage.open(filename)
        except:
            Logger.warning('Image: Unable to load image <%s>' % filename)
            raise
        # update internals
        if not self._inline:
            self.filename = filename
        # returns an array of type ImageData len 1 if not a sequence image
        return list(self._img_read(im))

    @staticmethod
    def save(filename, width, height, fmt, pixels, flipped=False):
        image = PILImage.fromstring(fmt.upper(), (width, height), pixels)
        if flipped:
            image = image.transpose(PILImage.FLIP_TOP_BOTTOM)
        image.save(filename)
        return True


# register
ImageLoader.register(ImageLoaderPIL)

kivy/core/image/img_pil.py
'''
PIL: PIL image loader
'''

__all__ = ('ImageLoaderPIL', )

try:
    from PIL import Image as PILImage
except:
    import Image as PILImage

from kivy.logger import Logger
from kivy.core.image import ImageLoaderBase, ImageData, ImageLoader


class ImageLoaderPIL(ImageLoaderBase):
    '''Image loader based on the PIL library.

    .. versionadded:: 1.0.8

    Support for GIF animation added.

    Gif animation has a lot of issues(transparency/color depths... etc).
    In order to keep it simple, what is implemented here is what is
    natively supported by the PIL library.

    As a general rule, try to use gifs that have no transparency.
    Gif's with transparency will work but be prepared for some
    artifacts until transparency support is improved.

    '''

    @staticmethod
    def can_save():
        return True

    @staticmethod
    def can_load_memory():
        return True

    @staticmethod
    def extensions():
        '''Return accepted extensions for this loader'''
        # See http://www.pythonware.com/library/pil/handbook/index.htm
        return ('bmp', 'bufr', 'cur', 'dcx', 'fits', 'fl', 'fpx', 'gbr',
                'gd', 'gif', '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')

    def _img_correct(self, _img_tmp):
        '''Convert image to the correct format and orientation.
        '''
        # image loader work only with rgb/rgba image
        if _img_tmp.mode.lower() not in ('rgb', 'rgba'):
            try:
                imc = _img_tmp.convert('RGBA')
            except:
                Logger.warning(
                    'Image: Unable to convert image to rgba (was %s)' %
                    (_img_tmp.mode.lower()))
                raise
            _img_tmp = imc

        return _img_tmp

    def _img_read(self, im):
        '''Read images from an animated file.
        '''
        im.seek(0)

        # Read all images inside
        try:
            img_ol = None
            while True:
                img_tmp = im
                img_tmp = self._img_correct(img_tmp)
                if img_ol and (hasattr(im, 'dispose') and not im.dispose):
                    # paste new frame over old so as to handle
                    # transparency properly
                    img_ol.paste(img_tmp, (0, 0), img_tmp)
                    img_tmp = img_ol
                img_ol = img_tmp
                yield ImageData(img_tmp.size[0], img_tmp.size[1],
                                img_tmp.mode.lower(), img_tmp.tobytes())
                im.seek(im.tell() + 1)
        except EOFError:
            pass

    def load(self, filename):
        try:
            im = PILImage.open(filename)
        except:
            Logger.warning('Image: Unable to load image <%s>' % filename)
            raise
        # update internals
        if not self._inline:
            self.filename = filename
        # returns an array of type ImageData len 1 if not a sequence image
        return list(self._img_read(im))

    @staticmethod
    def save(filename, width, height, fmt, pixels, flipped=False):
        image = PILImage.frombytes(fmt.upper(), (width, height), pixels)

        if flipped:
            image = image.transpose(PILImage.FLIP_TOP_BOTTOM)
        image.save(filename)
        return True


# register
ImageLoader.register(ImageLoaderPIL)

kivy/core/image/img_pil.py
diff --git a/kivy/core/image/img_pil.py b/kivy/core/image/img_pil.py
index 139ff81219..93067516a3 100644
--- a/kivy/core/image/img_pil.py
+++ b/kivy/core/image/img_pil.py
@@ -102,7 +102,8 @@ def load(self, filename):
 
     @staticmethod
     def save(filename, width, height, fmt, pixels, flipped=False):
-        image = PILImage.fromstring(fmt.upper(), (width, height), pixels)
+        image = PILImage.frombytes(fmt.upper(), (width, height), pixels)
+
         if flipped:
             image = image.transpose(PILImage.FLIP_TOP_BOTTOM)
         image.save(filename)

Error: fromstring() in core/image/img_pil.py
Platform: Linux (OpenSuse, Ubuntu)

[INFO   ] [Kivy        ] v1.9.1
[INFO   ] [Python      ] v2.7.12 (default, Jul 01 2016, 15:36:53) [GCC]

Error:
  File "/usr/lib64/python2.7/site-packages/kivy/core/image/img_pil.py", line 105, in save
    image = PILImage.fromstring(fmt.upper(), (width, height), pixels)
  File "/usr/lib64/python2.7/site-packages/PIL/Image.py", line 2063, in fromstring
    "Please call frombytes() instead.")
Exception: fromstring() has been removed. Please call frombytes() instead.


In File "/usr/lib64/python2.7/site-packages/kivy/core/image/img_pil.py"
Line 105:
image = PILImage.fromstring(fmt.upper(), (width, height), pixels)

use...

image = PILImage.frombytes(fmt.upper(), (width, height), pixels)
