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