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 theuser-provided keyword arguments here.
Implement
_close()to clean up.
- Implement
_get_length()to provide a suitable length based on whatthe user expects. Can be
inffor 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 indexis 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 theuser-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)