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)
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}
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}
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}
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
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"]:
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')
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: