Source code for dgenerate.imageprocessors.imageops

# Copyright (c) 2023, Teriks
#
# dgenerate is distributed under the following BSD 3-Clause License
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import PIL.Image
import PIL.ImageOps

import dgenerate.imageprocessors.imageprocessor as _imageprocessor
import dgenerate.types as _types


[docs] class MirrorFlipProcessor(_imageprocessor.ImageProcessor): """ Implements the "mirror" and "flip" PIL.ImageOps operations as an image imageprocessor """ NAMES = ['mirror', 'flip']
[docs] @staticmethod def help(loaded_by_name): if loaded_by_name == 'mirror': return 'Mirror the input image horizontally.' if loaded_by_name == 'flip': return 'Flip the input image vertically.'
[docs] def __init__(self, **kwargs): """ :param kwargs: forwarded to base class """ super().__init__(**kwargs) if self.loaded_by_name == 'flip': self._func = PIL.ImageOps.flip elif self.loaded_by_name == 'mirror': self._func = PIL.ImageOps.mirror
[docs] def impl_pre_resize(self, image: PIL.Image.Image, resize_resolution: _types.OptionalSize): """ Mirrors or flips the image depending on what name was used to invoke this imageprocessor implementation. :param image: image to process :param resize_resolution: purely informational, is unused by this imageprocessor :return: the mirrored or flipped image. """ return self._func(image)
[docs] def impl_post_resize(self, image: PIL.Image.Image): """ Post resize, for this imageprocessor nothing happens post-resize. :param image: image to process :return: the same image """ return image
[docs] class SimpleColorProcessor(_imageprocessor.ImageProcessor): """ Implements the "grayscale" and "invert" PIL.ImageOps operations as an image imageprocessor. """ NAMES = ['grayscale', 'invert']
[docs] @staticmethod def help(loaded_by_name): if loaded_by_name == 'grayscale': return 'Convert the input image to grayscale.' if loaded_by_name == 'invert': return 'Invert the colors of the input image.'
[docs] def __init__(self, **kwargs): """ :param kwargs: forwarded to base class """ super().__init__(**kwargs) if self.loaded_by_name == 'grayscale': self._func = PIL.ImageOps.grayscale elif self.loaded_by_name == 'invert': self._func = PIL.ImageOps.invert
[docs] def impl_pre_resize(self, image: PIL.Image.Image, resize_resolution: _types.OptionalSize): """ Pre resize, for this imageprocessor nothing happens pre-resize. :param image: image to process :param resize_resolution: purely informational, is unused by this imageprocessor :return: the same image """ return image
[docs] def impl_post_resize(self, image: PIL.Image.Image): """ Invert or grayscale the image depending on which name was used to invoke this imageprocessor. :param image: image to process :return: the inverted or grayscale image """ return self._func(image)
[docs] class PosterizeProcessor(_imageprocessor.ImageProcessor): """ Posterize the input image with PIL.ImageOps.posterize. Accepts the argument 'bits', an integer value from 1 to 8. """ NAMES = ['posterize']
[docs] def __init__(self, bits: int, **kwargs): """ :param bits: required argument, integer value from 1 to 8 :param kwargs: forwarded to base class """ super().__init__(**kwargs) self._bits = bits if self._bits < 1 or self._bits > 8: raise self.argument_error( f'Argument "bits" must be an integer value from 1 to 8, received {self._bits}.')
[docs] def impl_pre_resize(self, image: PIL.Image.Image, resize_resolution: _types.OptionalSize): """ Posterize operation is preformed by this method. :param image: image to process :param resize_resolution: purely informational, is unused by this imageprocessor :return: the posterized image """ return PIL.ImageOps.posterize(image, self._bits)
[docs] def impl_post_resize(self, image: PIL.Image.Image): """ Post resize, for this imageprocessor nothing happens post-resize. :param image: image to process :return: the same image """ return image
[docs] class SolarizeProcessor(_imageprocessor.ImageProcessor): """ Solarize the input image with PIL.ImageOps.solarize. Accepts the argument "threshold" which is an integer value from 0 to 255. """ NAMES = ['solarize']
[docs] def __init__(self, threshold: int = 128, **kwargs): """ :param threshold: integer value from 0 to 255, default is 128 :param kwargs: forwarded to base class """ super().__init__(**kwargs) self._threshold = threshold if self._threshold < 0 or self._threshold > 255: raise self.argument_error( f'Argument "threshold" must be an integer value from 0 to 255, received {self._threshold}.')
[docs] def impl_pre_resize(self, image: PIL.Image.Image, resize_resolution: _types.OptionalSize): """ Solarize operation is preformed by this method. :param image: image to process :param resize_resolution: purely informational, is unused by this imageprocessor :return: the solarized image """ return PIL.ImageOps.solarize(image, self._threshold)
[docs] def impl_post_resize(self, image: PIL.Image.Image): """ Post resize, for this imageprocessor nothing happens post-resize. :param image: image to process :return: the same image """ return image
__all__ = _types.module_all()