Source code for draugr.visualisation.pillow_utilities

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = "Christian Heider Nielsen"
__doc__ = r"""

           Created on 17/07/2020
           """

from enum import Enum
from typing import Tuple, Union

import numpy

__all__ = [
    "pil_merge_images",
    "pil_img_to_np_array",
    "np_array_to_pil_img",
    "pil_image_to_byte_array",
    "byte_array_to_pil_image",
]

import io

from PIL import Image
from sorcery import assigned_names


class PilModesEnum(Enum):
    """
      PIL pixel formats:

    RGB 24bits per pixel, 8-bit-per-channel RGB), 3 channels
    RGBA (8-bit-per-channel RGBA), 4 channels
    RGBa (8-bit-per-channel RGBA, remultiplied alpha), 4 channels
    1 - 1bpp, often for masks, 1 channel
    L - 8bpp, grayscale, 1 channel
    P - 8bpp, paletted, 1 channel
    I - 32-bit integers, grayscale, 1 channel
    F - 32-bit floats, grayscale, 1 channel
    CMYK - 8 bits per channel, 4 channels
    YCbCr - 8 bits per channel, 3 channels
    """

    OneBpp = "1"
    CMYK, F, HSV, I, L, LAB, P, RGB, RGBA, RGBX, YCbCr = assigned_names()


"""
1 (1-bit pixels, black and white, stored with one pixel per byte)

L (8-bit pixels, black and white)

P (8-bit pixels, mapped to any other mode using a color palette)

RGB (3x8-bit pixels, true color)

RGBA (4x8-bit pixels, true color with transparency mask)

CMYK (4x8-bit pixels, color separation)

YCbCr (3x8-bit pixels, color video format)

Note that this refers to the JPEG, and not the ITU-R BT.2020, standard

LAB (3x8-bit pixels, the L*a*b color space)

HSV (3x8-bit pixels, Hue, Saturation, Value color space)

I (32-bit signed integer pixels)

F (32-bit floating point pixels)

# Pillow also provides limited support for a few additional modes, including:

LA (L with alpha)

PA (P with alpha)

RGBX (true color with padding)

RGBa (true color with premultiplied alpha)

La (L with premultiplied alpha)

I;16 (16-bit unsigned integer pixels)

I;16L (16-bit little endian unsigned integer pixels)

I;16B (16-bit big endian unsigned integer pixels)

I;16N (16-bit native endian unsigned integer pixels)

BGR;15 (15-bit reversed true colour)

BGR;16 (16-bit reversed true colour)

BGR;24 (24-bit reversed true colour)

BGR;32 (32-bit reversed true colour)
"""


[docs]def pil_image_to_byte_array(image: Image.Image, *, coding: str = "PNG") -> bytes: """ PNG encoded by default :param coding: :param image: :return:""" buffer = io.BytesIO() image.save(buffer, coding) return buffer.getvalue()
[docs]def byte_array_to_pil_image(byte_array: bytes) -> Image.Image: """ :param byte_array: :return:""" return Image.open(io.BytesIO(byte_array))
[docs]def pil_img_to_np_array( data_path: Union[str, Image.Image], *, desired_size: Tuple[int, int] = None, expand: int = False ) -> numpy.ndarray: """ Util function for loading RGB image into a numpy array. Returns array of shape (1, H, W, C).""" img = Image.open(data_path) img = img.convert("RGB") if desired_size: img = img.resize((desired_size[1], desired_size[0])) x = numpy.asarray(img, dtype="float32") if expand: x = numpy.expand_dims(x, axis=0) return x / 255.0
[docs]def np_array_to_pil_img(x: numpy.ndarray) -> Image.Image: """ Util function for converting a numpy array to a PIL img. Returns PIL RGB img.""" x = numpy.asarray(x) x = x + max(-numpy.min(x), 0) x_max = numpy.max(x) if x_max != 0: x /= x_max return Image.fromarray((x * 255.0).astype("uint8"), "RGB")
[docs]def pil_merge_images(image1: Image.Image, image2: Image.Image) -> Image.Image: """Merge two images into one, displayed side by side.""" (width1, height1) = image1.size (width2, height2) = image2.size result_width = width1 + width2 result_height = max(height1, height2) result = Image.new("RGB", (result_width, result_height)) result.paste(im=image1, box=(0, 0)) result.paste(im=image2, box=(width1, 0)) return result