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        # request.mode[1]: what kind of data the user expects: one of 'iIvV?'
104
105
106
107        if request.mode[1] in (self.modes + "?"):
108
109            if request.extension in self.extensions:
110
111                return True
112
113
114
115    def _can_write(self, request):
116
117        # This method is called when the format manager is searching
118
119        # for a format to write a certain image. It will first ask all
120
121        # formats that *seem* to be able to write it whether they can.
122
123        # If none can, it will ask the remaining formats if they can.
124
125        #
126
127        # Return True if the format can do it.
128
129
130
131        # In most cases, this code does suffice:
132
133        if request.mode[1] in (self.modes + "?"):
134
135            if request.extension in self.extensions:
136
137                return True
138
139
140
141    # -- reader
142
143
144
145    class Reader(Format.Reader):
146
147        def _open(self, some_option=False, length=1):
148
149            # Specify kwargs here. Optionally, the user-specified kwargs
150
151            # can also be accessed via the request.kwargs object.
152
153            #
154
155            # The request object provides two ways to get access to the
156
157            # data. Use just one:
158
159            #  - Use request.get_file() for a file object (preferred)
160
161            #  - Use request.get_local_filename() for a file on the system
162
163            self._fp = self.request.get_file()
164
165            self._length = length  # passed as an arg in this case for testing
166
167            self._data = None
168
169
170
171        def _close(self):
172
173            # Close the reader.
174
175            # Note that the request object will close self._fp
176
177            pass
178
179
180
181        def _get_length(self):
182
183            # Return the number of images. Can be np.inf
184
185            return self._length
186
187
188
189        def _get_data(self, index):
190
191            # Return the data and meta data for the given index
192
193            if index >= self._length:
194
195                raise IndexError("Image index %i > %i" % (index, self._length))
196
197            # Read all bytes
198
199            if self._data is None:
200
201                self._data = self._fp.read()
202
203            # Put in a numpy array
204
205            im = np.frombuffer(self._data, "uint8")
206
207            im.shape = len(im), 1
208
209            # Return array and dummy meta data
210
211            return im, {}
212
213
214
215        def _get_meta_data(self, index):
216
217            # Get the meta data for the given index. If index is None, it
218
219            # should return the global meta data.
220
221            return {}  # This format does not support meta data
222
223
224
225    # -- writer
226
227
228
229    class Writer(Format.Writer):
230
231        def _open(self, flags=0):
232
233            # Specify kwargs here. Optionally, the user-specified kwargs
234
235            # can also be accessed via the request.kwargs object.
236
237            #
238
239            # The request object provides two ways to write the data.
240
241            # Use just one:
242
243            #  - Use request.get_file() for a file object (preferred)
244
245            #  - Use request.get_local_filename() for a file on the system
246
247            self._fp = self.request.get_file()
248
249
250
251        def _close(self):
252
253            # Close the reader.
254
255            # Note that the request object will close self._fp
256
257            pass
258
259
260
261        def _append_data(self, im, meta):
262
263            # Process the given data and meta data.
264
265            raise RuntimeError("The dummy format cannot write image data.")
266
267
268
269        def set_meta_data(self, meta):
270
271            # Process the given meta data (global for all images)
272
273            # It is not mandatory to support this.
274
275            raise RuntimeError("The dummy format cannot write meta data.")
276
277
278
279
280
281# Register. You register an *instance* of a Format class. Here specify:
282
283format = DummyFormat(
284
285    "dummy",  # short name
286
287    "An example format that does nothing.",  # one line descr.
288
289    ".foobar .nonexistentext",  # list of extensions
290
291    "iI",  # modes, characters in iIvV
292
293)
294
295formats.add_format(format)