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:
|
Represents an implementation to read/write a particular file format |
|
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:
|
Initialize the Plugin. |
|
Check if Plugin can read from ImageResource. |
|
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 beinf
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)