Skip to main content
`Ctrl`+`K`

# The ImageIO Plugin API

Here you can find documentation on how to write your own plugin to allow ImageIO to access a new backend. Plugins are quite object oriented, and the relevant classes and their interaction are documented here:

`imageio.core.Format`(name, description[, ...]) | Represents an implementation to read/write a particular file format
`imageio.core.Request`(uri, mode, *[, ...]) | ImageResource handling utility.

Note

You can always check existing plugins if you want to see examples.

## What methods to implement

To implement a new plugin, create a new class that inherits from `imageio.core.Format`. and implement the following functions:

`imageio.core.Format.__init__`(name, description) | Initialize the Plugin.
`imageio.core.Format._can_read`(request) | Check if Plugin can read from ImageResource.
`imageio.core.Format._can_write`(request) | Check if Plugin can write to ImageResource.

Further, each format contains up to two nested classes; one for reading and one for writing. To support reading and/or writing, the respective classes need to be defined.

For reading, create a nested class that inherits from `imageio.core.Format.Reader` and that implements the following functions:

> - Implement `_open(**kwargs)` to initialize the reader. Deal with the

>     user-provided keyword arguments here.

> - Implement `_close()` to clean up.

> - Implement `_get_length()` to provide a suitable length based on what

>     the user expects. Can be `inf` for streaming data.

> - Implement `_get_data(index)` to return an array and a meta-data dict.

> - Implement `_get_meta_data(index)` to return a meta-data dict. If index

>     is None, it should return the ‘global’ meta-data.

For writing, create a nested class that inherits from `imageio.core.Format.Writer` and implement the following functions:

> - Implement `_open(**kwargs)` to initialize the writer. Deal with the

>     user-provided keyword arguments here.

> - Implement `_close()` to clean up.

> - Implement `_append_data(im, meta)` to add data (and meta-data).

> - Implement `_set_meta_data(meta)` to set the global meta-data.

## Example / template plugin

      1# -*- coding: utf-8 -*-
      2
      3# imageio is distributed under the terms of the (new) BSD License.
      4
      5
      6
      7""" Example plugin. You can use this as a template for your own plugin.
      8
      9"""
     10
     11
     12
     13import numpy as np
     14
     15
     16
     17from .. import formats
     18
     19from ..core import Format
     20
     21
     22
     23
     24
     25class DummyFormat(Format):
     26
     27    """The dummy format is an example format that does nothing.
     28
     29    It will never indicate that it can read or write a file. When
     30
     31    explicitly asked to read, it will simply read the bytes. When
     32
     33    explicitly asked to write, it will raise an error.
     34
     35
     36
     37    This documentation is shown when the user does ``help('thisformat')``.
     38
     39
     40
     41    Parameters for reading
     42
     43    ----------------------
     44
     45    Specify arguments in numpy doc style here.
     46
     47
     48
     49    Parameters for saving
     50
     51    ---------------------
     52
     53    Specify arguments in numpy doc style here.
     54
     55
     56
     57    """
     58
     59
     60
     61    def _can_read(self, request):
     62
     63        # This method is called when the format manager is searching
     64
     65        # for a format to read a certain image. Return True if this format
     66
     67        # can do it.
     68
     69        #
     70
     71        # The format manager is aware of the extensions and the modes
     72
     73        # that each format can handle. It will first ask all formats
     74
     75        # that *seem* to be able to read it whether they can. If none
     76
     77        # can, it will ask the remaining formats if they can: the
     78
     79        # extension might be missing, and this allows formats to provide
     80
     81        # functionality for certain extensions, while giving preference
     82
     83        # to other plugins.
     84
     85        #
     86
     87        # If a format says it can, it should live up to it. The format
     88
     89        # would ideally check the request.firstbytes and look for a
     90
     91        # header of some kind.
     92
     93        #
     94
     95        # The request object has:
     96
     97        # request.filename: a representation of the source (only for reporting)
     98
     99        # request.firstbytes: the first 256 bytes of the file.
    100
    101        # request.mode[0]: read or write mode
    102
    103
    104
    105        if request.extension in self.extensions:
    106
    107            return True
    108
    109
    110
    111    def _can_write(self, request):
    112
    113        # This method is called when the format manager is searching
    114
    115        # for a format to write a certain image. It will first ask all
    116
    117        # formats that *seem* to be able to write it whether they can.
    118
    119        # If none can, it will ask the remaining formats if they can.
    120
    121        #
    122
    123        # Return True if the format can do it.
    124
    125
    126
    127        # In most cases, this code does suffice:
    128
    129        if request.extension in self.extensions:
    130
    131            return True
    132
    133
    134
    135    # -- reader
    136
    137
    138
    139    class Reader(Format.Reader):
    140
    141        def _open(self, some_option=False, length=1):
    142
    143            # Specify kwargs here. Optionally, the user-specified kwargs
    144
    145            # can also be accessed via the request.kwargs object.
    146
    147            #
    148
    149            # The request object provides two ways to get access to the
    150
    151            # data. Use just one:
    152
    153            #  - Use request.get_file() for a file object (preferred)
    154
    155            #  - Use request.get_local_filename() for a file on the system
    156
    157            self._fp = self.request.get_file()
    158
    159            self._length = length  # passed as an arg in this case for testing
    160
    161            self._data = None
    162
    163
    164
    165        def _close(self):
    166
    167            # Close the reader.
    168
    169            # Note that the request object will close self._fp
    170
    171            pass
    172
    173
    174
    175        def _get_length(self):
    176
    177            # Return the number of images. Can be np.inf
    178
    179            return self._length
    180
    181
    182
    183        def _get_data(self, index):
    184
    185            # Return the data and meta data for the given index
    186
    187            if index >= self._length:
    188
    189                raise IndexError("Image index %i > %i" % (index, self._length))
    190
    191            # Read all bytes
    192
    193            if self._data is None:
    194
    195                self._data = self._fp.read()
    196
    197            # Put in a numpy array
    198
    199            im = np.frombuffer(self._data, "uint8")
    200
    201            im.shape = len(im), 1
    202
    203            # Return array and dummy meta data
    204
    205            return im, {}
    206
    207
    208
    209        def _get_meta_data(self, index):
    210
    211            # Get the meta data for the given index. If index is None, it
    212
    213            # should return the global meta data.
    214
    215            return {}  # This format does not support meta data
    216
    217
    218
    219    # -- writer
    220
    221
    222
    223    class Writer(Format.Writer):
    224
    225        def _open(self, flags=0):
    226
    227            # Specify kwargs here. Optionally, the user-specified kwargs
    228
    229            # can also be accessed via the request.kwargs object.
    230
    231            #
    232
    233            # The request object provides two ways to write the data.
    234
    235            # Use just one:
    236
    237            #  - Use request.get_file() for a file object (preferred)
    238
    239            #  - Use request.get_local_filename() for a file on the system
    240
    241            self._fp = self.request.get_file()
    242
    243
    244
    245        def _close(self):
    246
    247            # Close the reader.
    248
    249            # Note that the request object will close self._fp
    250
    251            pass
    252
    253
    254
    255        def _append_data(self, im, meta):
    256
    257            # Process the given data and meta data.
    258
    259            raise RuntimeError("The dummy format cannot write image data.")
    260
    261
    262
    263        def set_meta_data(self, meta):
    264
    265            # Process the given meta data (global for all images)
    266
    267            # It is not mandatory to support this.
    268
    269            raise RuntimeError("The dummy format cannot write meta data.")
    270
    271
    272
    273
    274
    275# Register. You register an *instance* of a Format class. Here specify:
    276
    277format = DummyFormat(
    278
    279    "dummy",  # short name
    280
    281    "An example format that does nothing.",  # one line descr.
    282
    283    ".foobar .nonexistentext",  # list of extensions
    284
    285    "iI",  # modes, characters in iIvV
    286
    287)
    288
    289formats.add_format(format)