Source code for pyctools.components.io.imagefilepil

#  Pyctools - a picture processing algorithm development kit.
#  http://github.com/jim-easterbrook/pyctools
#  Copyright (C) 2014-20  Pyctools contributors
#
#  This program is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see
#  <http://www.gnu.org/licenses/>.

__all__ = ['ImageFileReaderPIL', 'ImageFileWriterPIL']
__docformat__ = 'restructuredtext en'

import io
import os

import PIL.Image

from pyctools.core.config import ConfigBool, ConfigPath, ConfigStr
from pyctools.core.base import Component, Transformer
from pyctools.core.frame import Frame, Metadata

[docs] class ImageFileReaderPIL(Component): """Read a still image file using Python Imaging Library. Reads an image file using :py:func:`PIL.Image.open`. This function cannot handle 16-bit data, so you may prefer to use :py:class:`~pyctools.components.io.imagefilecv.ImageFileReaderCV` instead. ======== === ==== Config ======== === ==== ``path`` str Path name of file to be read. ======== === ==== """ inputs = [] with_outframe_pool = False def initialise(self): self.config['path'] = ConfigPath() def on_start(self): # read file self.update_config() path = self.config['path'] out_frame = Frame() image = PIL.Image.open(path) image.load() # send output frame out_frame.data = image out_frame.type = image.mode out_frame.frame_no = 0 out_frame.metadata.from_file(path) out_frame.set_audit(self, 'data = {}\n'.format(os.path.basename(path)), with_config=self.config) self.send('output', out_frame) # shut down pipeline self.stop()
[docs] class ImageFileWriterPIL(Transformer): """Write a still image file using Python Imaging Library. This component saves the first frame it receives to file using :py:meth:`PIL.Image.Image.save`. See the `PIL documentation <http://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html>`_ for details of the available formats and options. The ``options`` configuration should be a comma separated list of colon separated names and values, for example a JPEG file might have these options: ``'quality': 95, 'progressive': True``. The ``set_thumbnail`` option allows you to store a DCF standard 160 x 120 (or 120 x 160) thumbnail in the Exif metadata. PIL cannot write 16-bit data, so you may prefer to use :py:class:`~pyctools.components.io.imagefilecv.ImageFileWriterCV` instead. ================= ==== ==== Config ================= ==== ==== ``path`` str Path name of file to be created. ``format`` str Over-ride the file format. This is normally derived from the ``path`` extension. ``options`` str A string of :py:meth:`PIL.Image.Image.save` options. ``set_thumbnail`` bool Create and add an Exif thumbnail. ================= ==== ==== """ def initialise(self): self.done = False self.config['path'] = ConfigPath(exists=False) self.config['format'] = ConfigStr() self.config['options'] = ConfigStr() self.config['set_thumbnail'] = ConfigBool(value=False) def transform(self, in_frame, out_frame): if self.done: return True self.update_config() path = self.config['path'] fmt = self.config['format'] or None options = eval('{' + self.config['options'] + '}') # save image image = in_frame.as_PIL() image.save(path, format=fmt, **options) # save metadata md = Metadata().copy(in_frame.metadata) md.set_audit(self, '{} = data\n'.format(os.path.basename(path)), with_date=True, with_config=self.config) if self.config['set_thumbnail']: w, h = image.size if w >= h: w, h = 160, 120 else: w, h = 120, 160 image.thumbnail((w, h), PIL.Image.ANTIALIAS) wt, ht = image.size if (wt, ht) != (w, h): # pad with black padded = PIL.Image.new(image.mode, (w, h)) padded.paste(image, ((w - wt) // 2, (h - ht) // 2)) image = padded buf = io.BytesIO() image.save(buf, format='JPEG', params={'quality': 95}) md.to_file(path, thumbnail=buf.getbuffer()) else: md.to_file(path) self.done = True return True