Source code for imagefactory.imagefactory

import logging
import os
import shutil
from io import BytesIO, StringIO, TextIOBase

from PIL import Image, ImageDraw

logger = logging.getLogger(__name__)


# FIXME: Text size
# TODO: Caching?
# TODO: Image size choises: Icon, ...
# TODO: Width and height units (cm, mm, em, px, pt, pc, in, ...) default: px
# TODO: Background color


def _create_bitmap(name, width, height, filetype, text):
    """
    Create bitmap image.

    Returns:
        BytesIO:
    """
    file = BytesIO()
    file.name = name + '.' + filetype
    image = Image.new('RGBA', size=(width, height), color=(128, 128, 128))
    draw = ImageDraw.Draw(image)
    size = draw.textsize(text)
    draw.text(((width - size[0]) / 2, (height - size[1]) / 2), text)
    image.save(file, format=filetype)
    file.seek(0)
    return file


def _create_svg(name, width, height, text):
    """
    Create svg image.

    Returns:
        StringIO:
    """
    import svgwrite
    file = StringIO()
    file.name = name + '.svg'
    center = (width / 2, height / 2)
    image = svgwrite.Drawing(file.name, profile='tiny', height=height,
                             width=width)
    image.add(image.rect(insert=(0, 0), size=(width, height), fill='gray'))
    # TODO: Test if text fits inside rectangle
    # image.add(image.text(text, insert=center))
    image.write(file)
    file.seek(0)
    return file


def _save_image(image, filedir, overwrite):
    """
    Save in memory image to a file.

    Args:
        image (io.IOBase):
            In memory image.

        filedir (str):
            Path to the directory where `image` should be saved

    Raises:
        TypeError: If `image` is not correct type.
        FileExistsError: If file with name `image.name` exists in `filedir`.
    """
    if isinstance(image, TextIOBase):
        # Write as text file
        mode = 'wt'
    else:
        # Write as binary file
        mode = 'wb'

    filepath = os.path.join(filedir, image.name)
    if os.path.exists(filepath) and not overwrite:
        raise FileExistsError(
            'File with name "{name}" already exists in path "{filepath}".'
            ''.format(name=image.name, filepath=filepath)
        )
    with open(filepath, mode) as file:
        shutil.copyfileobj(image, file)


[docs]def create_image(name='untitled', filetype='png', width=48, height=48, text=None, savedir=None, overwrite=False): """ Creates in memory images for testing [#]_. Bitmap images are created >>> from imagefactory import create_image >>> create_image() <_io.BytesIO object at ...> Vector graphic images can be created >>> from imagefactory import create_image >>> create_image(filetype='svg') <_io.StringIO object at ...> Args: name (str): - ``name`` Name of the file. - ``name.ext`` If extension is supplied it overwrites any supplied filetype. width (int): Positive integer height (int): Positive integer filetype (str): Filetype is extension string: ``jpeg, png, gif, svg`` text (str, optional): - Default: ``None`` uses ``{width}x{height}`` - Otherwise supplied ``text`` string is used. savedir (str, optional): - Default: ``None`` doesn't save the image - Otherwise save image to ``savedir`` directory overwrite (Boolean): Boolean flag for toggling if existing file in the same filepath should be overwritten. Returns: BytesIO|StringIO: Image as ``BytesIO`` or ``StringIO`` object. It can be used in same fashion as file object created by opening a file. References: .. [#] http://wildfish.com/blog/2014/02/27/generating-in-memory-image-for-tests-python/ """ logging.info("") name, ext = os.path.splitext(name) if ext: filetype = ext if text is None: text = "{width}x{height}".format(width=width, height=height) if filetype == 'svg': try: image = _create_svg(name, width, height, text) except ImportError as error: raise Exception( 'You need to install svgwrite to create vector graphics.' '{msg}'.format(msg=error) ) else: image = _create_bitmap(name, width, height, filetype, text) if savedir is not None: _save_image(image, savedir, overwrite) return image