Exemple #1
0
def affine(img, angle, translate, scale, shear, resample=0, fillcolor=None):
    """Apply affine transformation on the image keeping image center invariant

    Args:
        img (PIL Image): PIL Image to be rotated.
        angle (float or int): rotation angle in degrees between -180 and 180, clockwise direction.
        translate (list or tuple of integers): horizontal and vertical translations (post-rotation translation)
        scale (float): overall scale
        shear (float or tuple or list): shear angle value in degrees between -180 to 180, clockwise direction.
        If a tuple of list is specified, the first value corresponds to a shear parallel to the x axis, while
        the second value corresponds to a shear parallel to the y axis.
        resample (``PIL.Image.NEAREST`` or ``PIL.Image.BILINEAR`` or ``PIL.Image.BICUBIC``, optional):
            An optional resampling filter.
            See `filters`_ for more information.
            If omitted, or if the image has mode "1" or "P", it is set to ``PIL.Image.NEAREST``.
        fillcolor (int): Optional fill color for the area outside the transform in the output image. (Pillow>=5.0.0)
    """
    if not _is_pil_image(img):
        raise TypeError('img should be PIL Image. Got {}'.format(type(img)))

    assert isinstance(translate, (tuple, list)) and len(translate) == 2, \
        "Argument translate should be a list or tuple of length 2"

    assert scale > 0.0, "Argument scale should be positive"

    output_size = img.size
    center = (img.size[0] * 0.5 + 0.5, img.size[1] * 0.5 + 0.5)
    matrix = _get_inverse_affine_matrix(center, angle, translate, scale, shear)
    kwargs = {
        "fillcolor": fillcolor
    } if int(PILLOW_VERSION.split('.')[0]) >= 5 else {}
    return img.transform(output_size, Image.AFFINE, matrix, resample, **kwargs)
Exemple #2
0
def _parse_fill(fill, img, min_pil_version):
    """Helper function to get the fill color for rotate and perspective transforms.

    Args:
        fill (n-tuple or int or float): Pixel fill value for area outside the transformed
            image. If int or float, the value is used for all bands respectively.
            Defaults to 0 for all bands.
        img (PIL Image): Image to be filled.
        min_pil_version (str): The minimum PILLOW version for when the ``fillcolor`` option 
            was first introduced in the calling function. (e.g. rotate->5.2.0, perspective->5.0.0)

    Returns:
        dict: kwarg for ``fillcolor``
    """
    major_found, minor_found = (int(v) for v in PILLOW_VERSION.split('.')[:2])
    major_required, minor_required = (int(v) for v in min_pil_version.split('.')[:2])
    if major_found < major_required or (major_found == major_required and minor_found < minor_required):
        if fill is None:
            return {}
        else:
            msg = ("The option to fill background area of the transformed image, "
                   "requires pillow>={}")
            raise RuntimeError(msg.format(min_pil_version))

    num_bands = len(img.getbands())
    if fill is None:
        fill = 0
    if isinstance(fill, (int, float)) and num_bands > 1:
        fill = tuple([fill] * num_bands)
    if not isinstance(fill, (int, float)) and len(fill) != num_bands:
        msg = ("The number of elements in 'fill' does not match the number of "
               "bands of the image ({} != {})")
        raise ValueError(msg.format(len(fill), num_bands))

    return {"fillcolor": fill}
Exemple #3
0
def _parse_fill(fill, img, min_pil_version, name="fillcolor"):
    # Process fill color for affine transforms
    major_found, minor_found = (int(v) for v in PILLOW_VERSION.split('.')[:2])
    major_required, minor_required = (int(v)
                                      for v in min_pil_version.split('.')[:2])
    if major_found < major_required or (major_found == major_required
                                        and minor_found < minor_required):
        if fill is None:
            return {}
        else:
            msg = (
                "The option to fill background area of the transformed image, "
                "requires pillow>={}")
            raise RuntimeError(msg.format(min_pil_version))

    num_bands = len(img.getbands())
    if fill is None:
        fill = 0
    if isinstance(fill, (int, float)) and num_bands > 1:
        fill = tuple([fill] * num_bands)
    if isinstance(fill, (list, tuple)):
        if len(fill) != num_bands:
            msg = (
                "The number of elements in 'fill' does not match the number of "
                "bands of the image ({} != {})")
            raise ValueError(msg.format(len(fill), num_bands))

        fill = tuple(fill)

    return {name: fill}
Exemple #4
0
def _parse_fill(fill, img, min_pil_version, name="fillcolor"):
    """PRIVATE METHOD. Helper function to get the fill color for rotate, perspective transforms, and pad.

    .. warning::

        Module ``transforms.functional_pil`` is private and should not be used in user application.
        Please, consider instead using methods from `transforms.functional` module.

    Args:
        fill (n-tuple or int or float): Pixel fill value for area outside the transformed
            image. If int or float, the value is used for all bands respectively.
            Defaults to 0 for all bands.
        img (PIL Image): Image to be filled.
        min_pil_version (str): The minimum PILLOW version for when the ``fillcolor`` option
            was first introduced in the calling function. (e.g. rotate->5.2.0, perspective->5.0.0)
        name (str): Name of the ``fillcolor`` option in the output. Defaults to ``"fillcolor"``.

    Returns:
        dict: kwarg for ``fillcolor``
    """
    major_found, minor_found = (int(v) for v in PILLOW_VERSION.split('.')[:2])
    major_required, minor_required = (int(v)
                                      for v in min_pil_version.split('.')[:2])
    if major_found < major_required or (major_found == major_required
                                        and minor_found < minor_required):
        if fill is None:
            return {}
        else:
            msg = (
                "The option to fill background area of the transformed image, "
                "requires pillow>={}")
            raise RuntimeError(msg.format(min_pil_version))

    num_bands = len(img.getbands())
    if fill is None:
        fill = 0
    if isinstance(fill, (int, float)) and num_bands > 1:
        fill = tuple([fill] * num_bands)
    if isinstance(fill, (list, tuple)):
        if len(fill) != num_bands:
            msg = (
                "The number of elements in 'fill' does not match the number of "
                "bands of the image ({} != {})")
            raise ValueError(msg.format(len(fill), num_bands))

        fill = tuple(fill)

    return {name: fill}
Exemple #5
0
def _check_pil():
    from sys import platform
    if platform != 'win32':
        return True

    from PIL import __version__ as pil_version
    major, minor, rest = pil_version.split('.', 2)
    major, minor = int(major), int(minor)
    if major > 6 or (major == 6 and minor >= 1):
        return True

    warning = 'Your version of PIL or Pillow ({}) has a problem with Unicode on Windows. ' \
              'Please update Pillow using the script in the "Pillow-update" directory.'.format(pil_version)

    from warnings import warn
    warn(warning, UserWarning, source=__name__)

    nulano_warn('Pillow bug', warning)

    return False
Exemple #6
0
    encode_png,
    write_png,
    write_file,
    ImageReadMode,
    read_image,
    _read_png_16,
)

IMAGE_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets")
FAKEDATA_DIR = os.path.join(IMAGE_ROOT, "fakedata")
IMAGE_DIR = os.path.join(FAKEDATA_DIR, "imagefolder")
DAMAGED_JPEG = os.path.join(IMAGE_ROOT, "damaged_jpeg")
ENCODE_JPEG = os.path.join(IMAGE_ROOT, "encode_jpeg")
INTERLACED_PNG = os.path.join(IMAGE_ROOT, "interlaced_png")
IS_WINDOWS = sys.platform in ("win32", "cygwin")
PILLOW_VERSION = tuple(int(x) for x in PILLOW_VERSION.split("."))


def _get_safe_image_name(name):
    # Used when we need to change the pytest "id" for an "image path" parameter.
    # If we don't, the test id (i.e. its name) will contain the whole path to the image, which is machine-specific,
    # and this creates issues when the test is running in a different machine than where it was collected
    # (typically, in fb internal infra)
    return name.split(os.path.sep)[-1]


def get_images(directory, img_ext):
    assert os.path.isdir(directory)
    image_paths = glob.glob(directory + f"/**/*{img_ext}", recursive=True)
    for path in image_paths:
        if path.split(os.sep)[-2] not in ["damaged_jpeg", "jpeg_write"]:
Exemple #7
0
from PIL import Image, __version__ as pil_version
from tests.base import TestCase, main, assets

from ocrd_models import OcrdExif

pil_version_major, pil_version_minor  = [int(x) for x in pil_version.split('.')][:2]
pil_below_83 = pil_version_major < 8 or (pil_version_major == 8 and pil_version_minor < 3)

# pylint: disable=no-member
class TestOcrdExif(TestCase):

    def test_str(self):
        with Image.open(assets.path_to('SBB0000F29300010000/data/OCR-D-IMG/FILE_0001_IMAGE.tif')) as img:
            exif = OcrdExif(img)
        print(str(exif.to_xml()))
        # XXX not platform-independent/stable
        #  self.assertEqual(
        #      exif.to_xml(),
        #      '<exif><width>2875</width><height>3749</height><photometricInterpretation>RGB</photometricInterpretation><compression>jpeg</compression><photometric_interpretation>None</photometric_interpretation><xResolution>300.0</xResolution><yResolution>300.0</yResolution><resolutionUnit>inches</resolutionUnit></exif>'
        #  )


    def test_tiff(self):
        with Image.open(assets.path_to('SBB0000F29300010000/data/OCR-D-IMG/FILE_0001_IMAGE.tif')) as img:
            exif = OcrdExif(img)
        self.assertEqual(exif.width, 2875)
        self.assertEqual(exif.height, 3749)
        self.assertEqual(exif.xResolution, 300)
        self.assertEqual(exif.yResolution, 300)
        self.assertEqual(exif.resolution, 300)
        self.assertEqual(exif.compression, 'jpeg')
Exemple #8
0
        print('A Pillow update is only necessary on Windows!')
        sys.exit(0)

    platform = 'win' + platform.architecture()[0][:2]

    py_major, py_minor, rest = sys.version.split('.', 2)
    py_major, py_minor = int(py_major), int(py_minor)
    py_version = '{}.{}'.format(py_major, py_minor)

    if py_major == 2:
        print('There is no fix for Python 2.x!')
        sys.exit(2)

    try:
        from PIL import __version__ as PIL_VERSION
        pil_major, pil_minor, rest = PIL_VERSION.split('.', 2)
        pil_major, pil_minor = int(pil_major), int(pil_minor)
        pil_version = '{}.{}'.format(pil_major, pil_minor)
    except ImportError:
        pil_major, pil_minor, pil_version = 0, 0, '???'

    print('Detected system: {}, Python {}, Pillow {}'.format(
        platform, py_version, pil_version))
    print()

    if pil_major > 6 or (pil_major == 6 and pil_minor >= 1):
        print('No need to update Pillow!')
        sys.exit(0)

    package = packages.get('{}-{}'.format(platform, py_version))
    if package is None: