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)