Source code for image_utils.nodes.image

"""
============
Read Node
============

- **Read**:
- **Constant**:
- **Checker**:
"""
from __future__ import print_function
# __all__ = ['Read', 'constant', 'checker']

import os

import OpenImageIO as OIIO
from OpenImageIO import ImageBuf
from OpenImageIO import ImageSpec
from OpenImageIO import ImageBufAlgo

from image_utils.pixel_type import PixelType
from image_utils.nodes import merge

from image_utils import extention


def constant(width, height, color=(1, 1, 1, 0), data_type=PixelType().float):
    """Create constant image with specific dimension and color

    .. code-block::  python

       >>> # import the required module
       >>> from image_utils.nodes import image

       >>> # create a red 4k by 3k constant image in red
       >>> constant_image = image.constant(4000, 3000, (1, 0, 0, 0))

       >>> # save it as png
       >>> constant_image.write('foo.png')

    :type width: int
    :param width: image width
    :type height: int
    :param height: image height
    :type color: tuple
    :param color: rgba color
    :type data_type: OpenImageIO.BASETYPE
    :param data_type: type of image
    :rtype: OpenImageIO.ImageBuf
    :return: constant image
    """
    constant_image = Read(width=width,
                          height=height,
                          channels=4,
                          pixel_type=data_type)
    ImageBufAlgo.fill(constant_image, color, constant_image.roi_full)
    return constant_image


def checker(width,
            height,
            color_a=(1, 1, 1),
            color_b=(0, 0, 0),
            cells=10,
            data_type=PixelType().float):
    """Create checker image. default is black and white checker color

    .. code-block::  python

       >>> # import the checker module
       >>> from image_utils.nodes import image

       >>> # create a 4k checker, red by blue color, with 10 cells
       >>> checker_image = image.checker(4000, 4000, (1, 0, 0), (0, 0, 1), 10)
       >>> checker_image.write('check_me.png')

    Result

    .. image:: ./_static/images/output_examples/check_me.png
       :scale: 5%
       :alt: checker example image
       :align: center

    :type width: int
    :param width: image width
    :type height: int
    :param height: image height
    :type color_a: tuple
    :param color_a: color A
    :type color_b: tuple
    :param color_b: color B
    :type cells: int
    :param cells: number of cell rows
    :type data_type: OpenImageIO.BASETYPE
    :param data_type: type of image
    :rtype: OpenImageIO.ImageBuf
    :return: checker image
    """
    checker_image = ImageBuf(ImageSpec(width, height, 3, data_type))
    ImageBufAlgo.checker(checker_image,
                         width / cells,
                         height / cells,
                         1,
                         color_a,
                         color_b)

    return checker_image


[docs]class Read(ImageBuf): """Read an existing image Example: .. code-block:: python >>> # import the Read module >>> from image_utils.nodes import image >>> # read an EXR image >>> read_node = image.Read('input.exr') >>> # pre-multiply it by its alpha >>> read_node.premult() >>> # save it as tiff >>> read_node.write('output.tif') """ def __init__(self, image_path='', width=100, height=100, channels=4, pixel_type=PixelType().float): # construct an image with image path if image_path: # make sure the path is correct and it exists if not os.path.exists(image_path): raise UserWarning("Can't locate the input image: " "{}".format(image_path)) self.__image_path = image_path super(Read, self).__init__(image_path) # construct an image with image size else: new_spec = OIIO.ImageSpec(width, height, channels, pixel_type) super(Read, self).__init__(new_spec) self.__spec = self.spec() # add file format specific attributes if self.file_format: attribute_data = getattr(extention, self.file_format, None) if attribute_data: image_extension_attr = attribute_data.items() for attr_name, attr_value in image_extension_attr: image_attr_value = self.spec().getattribute(attr_value) setattr(self, attr_name, image_attr_value) def __repr__(self): return "Image Read node from {}".format(self.path) def __str__(self): return "image_utils.nodes.image.Read({})".format(self.path) def __add__(self, other): """Merge with the input image using the 'add' function :type other: Read :param other: secondary image to add to this image :rtype: Read :return: the image as a result of the add process """ print(type(other)) # merge.add(self, other) # raise NotImplementedError("This method is not implemented!")
[docs] def premult(self): """pre-multiply the channels by alpha""" ImageBufAlgo.premult(self, self)
[docs] def unpremult(self): """un-premultiply the channels by alpha""" ImageBufAlgo.unpremult(self, self)
@property def path(self): """Path to the source image :rtype: str """ return self.__image_path @property def data_width(self): """Width of the source image's data window :rtype: int """ return self.__spec.width @property def data_height(self): """Height of the source image's data window :rtype: int """ return self.__spec.height @property def width(self): """Image width :rtype: int """ return self.roi_full.width @property def height(self): """Image height :rtype: int """ return self.roi_full.height @property def channels(self): """A tuple of strings containing the names of each color channel .. code-block:: python >>> # import the checker module >>> from image_utils.nodes import image >>> read_image = image.Read('grid-overscan.exr') >>> print(read_image.channels) ... ('R', 'G', 'B', 'A') :rtype: tuple :return: list of existing channel """ return self.__spec.channelnames @property def has_alpha(self): """Whether or not the image has alpha :rtype: bool :return: True or False """ return bool(self.__spec.alpha_channel > 0) @property def file_format(self): """Returns the file format of the image" .. code-block:: python >>> from image_utils.nodes import image >>> image_node = image.Read('foo.exr') >>> print(image_node.file_format) ... openexr :rtype: str """ return self.file_format_name @property def data_window_coordinate(self): """X and Y coordinate of data window (a.k.a. display window) .. code-block:: python >>> # import the checker module >>> from image_utils.nodes import image >>> read_image = image.Read('grid-overscan.exr') >>> print(read_image.data_window_coordinate) ... (-250, -250, 1250, 1250) .. image:: ./_static/images/output_examples/grid_overscan_exr.png :scale: 30 :align: center :rtype: tuple """ return (self.xbegin, self.ybegin, self.xend, self.yend)
[docs] def set_data_window(self, x1, y1, x2, y2): """set data window (a.k.a. display window) :type x1: int :param x1: x begin :type y1: int :param y1: y begin :type x2: int :param x2: x end :type y2: int :param y2: y end """ self.set_full(x1, x2, y1, y2, 0, 0)
[docs] def duplicate(self, pixel_type=None): """make a exact copy of this image. If a file_format is provided, this will get the specified pixel data type rather than using the same pixel file_format as the source ImageBuf. Example: >>> from image_utils.nodes import image >>> from image_utils.pixel_type import PixelType >>> # create an image instance >>> A = image.Read('foo.exr') >>> # make a copy of it >>> B = A.duplicate(PixelType().bit8) :rtype pixel_type: OpenImageIO.BASETYPE :param pixel_type: new image type. i.e, float, half, 8bit :rtype: Image :return: duplicate of this image """ # use the same pixel type as the source image if not specified if not pixel_type: pixel_type = self.pixeltype # Create an empty image with the same specs as the source image copy_image = Read(width=self.width, height=self.height, channels=len(self.channels), pixel_type=pixel_type) copy_image.copy(self, pixel_type) return copy_image
if __name__ == '__main__': print(__doc__)