Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/imageio-2.35.1-py3.8.egg/imageio/core/legacy_plugin_wrapper.py: 26%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

91 statements  

1from pathlib import Path 

2 

3import numpy as np 

4 

5from ..config import known_extensions 

6from .request import InitializationError, IOMode 

7from .v3_plugin_api import ImageProperties, PluginV3 

8 

9 

10def _legacy_default_index(format): 

11 if format._name == "FFMPEG": 

12 index = Ellipsis 

13 elif format._name == "GIF-PIL": 

14 index = Ellipsis 

15 else: 

16 index = 0 

17 

18 return index 

19 

20 

21class LegacyPlugin(PluginV3): 

22 """A plugin to make old (v2.9) plugins compatible with v3.0 

23 

24 .. depreciated:: 2.9 

25 `legacy_get_reader` will be removed in a future version of imageio. 

26 `legacy_get_writer` will be removed in a future version of imageio. 

27 

28 This plugin is a wrapper around the old FormatManager class and exposes 

29 all the old plugins via the new API. On top of this it has 

30 ``legacy_get_reader`` and ``legacy_get_writer`` methods to allow using 

31 it with the v2.9 API. 

32 

33 Methods 

34 ------- 

35 read(index=None, **kwargs) 

36 Read the image at position ``index``. 

37 write(image, **kwargs) 

38 Write image to the URI. 

39 iter(**kwargs) 

40 Iteratively yield images from the given URI. 

41 get_meta(index=None) 

42 Return the metadata for the image at position ``index``. 

43 legacy_get_reader(**kwargs) 

44 Returns the v2.9 image reader. (depreciated) 

45 legacy_get_writer(**kwargs) 

46 Returns the v2.9 image writer. (depreciated) 

47 

48 Examples 

49 -------- 

50 

51 >>> import imageio.v3 as iio 

52 >>> with iio.imopen("/path/to/image.tiff", "r", legacy_mode=True) as file: 

53 >>> reader = file.legacy_get_reader() # depreciated 

54 >>> for im in file.iter(): 

55 >>> print(im.shape) 

56 

57 """ 

58 

59 def __init__(self, request, legacy_plugin): 

60 """Instantiate a new Legacy Plugin 

61 

62 Parameters 

63 ---------- 

64 uri : {str, pathlib.Path, bytes, file} 

65 The resource to load the image from, e.g. a filename, pathlib.Path, 

66 http address or file object, see the docs for more info. 

67 legacy_plugin : Format 

68 The (legacy) format to use to interface with the URI. 

69 

70 """ 

71 self._request = request 

72 self._format = legacy_plugin 

73 

74 source = ( 

75 "<bytes>" 

76 if isinstance(self._request.raw_uri, bytes) 

77 else self._request.raw_uri 

78 ) 

79 if self._request.mode.io_mode == IOMode.read: 

80 if not self._format.can_read(request): 

81 raise InitializationError( 

82 f"`{self._format.name}`" f" can not read `{source}`." 

83 ) 

84 else: 

85 if not self._format.can_write(request): 

86 raise InitializationError( 

87 f"`{self._format.name}`" f" can not write to `{source}`." 

88 ) 

89 

90 def legacy_get_reader(self, **kwargs): 

91 """legacy_get_reader(**kwargs) 

92 

93 a utility method to provide support vor the V2.9 API 

94 

95 Parameters 

96 ---------- 

97 kwargs : ... 

98 Further keyword arguments are passed to the reader. See :func:`.help` 

99 to see what arguments are available for a particular format. 

100 """ 

101 

102 # Note: this will break thread-safety 

103 self._request._kwargs = kwargs 

104 

105 # safeguard for DICOM plugin reading from folders 

106 try: 

107 assert Path(self._request.filename).is_dir() 

108 except OSError: 

109 pass # not a valid path on this OS 

110 except AssertionError: 

111 pass # not a folder 

112 else: 

113 return self._format.get_reader(self._request) 

114 

115 self._request.get_file().seek(0) 

116 return self._format.get_reader(self._request) 

117 

118 def read(self, *, index=None, **kwargs): 

119 """ 

120 Parses the given URI and creates a ndarray from it. 

121 

122 Parameters 

123 ---------- 

124 index : {integer, None} 

125 If the URI contains a list of ndimages return the index-th 

126 image. If None, stack all images into an ndimage along the 

127 0-th dimension (equivalent to np.stack(imgs, axis=0)). 

128 kwargs : ... 

129 Further keyword arguments are passed to the reader. See 

130 :func:`.help` to see what arguments are available for a particular 

131 format. 

132 

133 Returns 

134 ------- 

135 ndimage : np.ndarray 

136 A numpy array containing the decoded image data. 

137 

138 """ 

139 

140 if index is None: 

141 index = _legacy_default_index(self._format) 

142 

143 if index is Ellipsis: 

144 img = np.stack([im for im in self.iter(**kwargs)]) 

145 return img 

146 

147 reader = self.legacy_get_reader(**kwargs) 

148 return reader.get_data(index) 

149 

150 def legacy_get_writer(self, **kwargs): 

151 """legacy_get_writer(**kwargs) 

152 

153 Returns a :class:`.Writer` object which can be used to write data 

154 and meta data to the specified file. 

155 

156 Parameters 

157 ---------- 

158 kwargs : ... 

159 Further keyword arguments are passed to the writer. See :func:`.help` 

160 to see what arguments are available for a particular format. 

161 """ 

162 

163 # Note: this will break thread-safety 

164 self._request._kwargs = kwargs 

165 return self._format.get_writer(self._request) 

166 

167 def write(self, ndimage, *, is_batch=None, metadata=None, **kwargs): 

168 """ 

169 Write an ndimage to the URI specified in path. 

170 

171 If the URI points to a file on the current host and the file does not 

172 yet exist it will be created. If the file exists already, it will be 

173 appended if possible; otherwise, it will be replaced. 

174 

175 Parameters 

176 ---------- 

177 ndimage : numpy.ndarray 

178 The ndimage or list of ndimages to write. 

179 is_batch : bool 

180 If True, treat the supplied ndimage as a batch of images. If False, 

181 treat the supplied ndimage as a single image. If None, try to 

182 determine ``is_batch`` from the ndimage's shape and ndim. 

183 metadata : dict 

184 The metadata passed to write alongside the image. 

185 kwargs : ... 

186 Further keyword arguments are passed to the writer. See 

187 :func:`.help` to see what arguments are available for a 

188 particular format. 

189 

190 

191 Returns 

192 ------- 

193 buffer : bytes 

194 When writing to the special target "<bytes>", this function will 

195 return the encoded image data as a bytes string. Otherwise it 

196 returns None. 

197 

198 Notes 

199 ----- 

200 Automatically determining ``is_batch`` may fail for some images due to 

201 shape aliasing. For example, it may classify a channel-first color image 

202 as a batch of gray images. In most cases this automatic deduction works 

203 fine (it has for almost a decade), but if you do have one of those edge 

204 cases (or are worried that you might) consider explicitly setting 

205 ``is_batch``. 

206 

207 """ 

208 

209 if is_batch or isinstance(ndimage, (list, tuple)): 

210 pass # ndimage is list of images 

211 elif is_batch is False: 

212 ndimage = [ndimage] 

213 else: 

214 # Write the largest possible block by guessing the meaning of each 

215 # dimension from the shape/ndim and then checking if any batch 

216 # dimensions are left. 

217 ndimage = np.asanyarray(ndimage) 

218 batch_dims = ndimage.ndim 

219 

220 # two spatial dimensions 

221 batch_dims = max(batch_dims - 2, 0) 

222 

223 # packed (channel-last) image 

224 if ndimage.ndim >= 3 and ndimage.shape[-1] < 5: 

225 batch_dims = max(batch_dims - 1, 0) 

226 

227 # format supports volumetric images 

228 ext_infos = known_extensions.get(self._request.extension, list()) 

229 for ext_info in ext_infos: 

230 if self._format.name in ext_info.priority and ext_info.volume_support: 

231 batch_dims = max(batch_dims - 1, 0) 

232 break 

233 

234 if batch_dims == 0: 

235 ndimage = [ndimage] 

236 

237 with self.legacy_get_writer(**kwargs) as writer: 

238 for image in ndimage: 

239 image = np.asanyarray(image) 

240 

241 if image.ndim < 2: 

242 raise ValueError( 

243 "The image must have at least two spatial dimensions." 

244 ) 

245 

246 if not np.issubdtype(image.dtype, np.number) and not np.issubdtype( 

247 image.dtype, bool 

248 ): 

249 raise ValueError( 

250 f"All images have to be numeric, and not `{image.dtype}`." 

251 ) 

252 

253 writer.append_data(image, metadata) 

254 

255 return writer.request.get_result() 

256 

257 def iter(self, **kwargs): 

258 """Iterate over a list of ndimages given by the URI 

259 

260 Parameters 

261 ---------- 

262 kwargs : ... 

263 Further keyword arguments are passed to the reader. See 

264 :func:`.help` to see what arguments are available for a particular 

265 format. 

266 """ 

267 

268 reader = self.legacy_get_reader(**kwargs) 

269 for image in reader: 

270 yield image 

271 

272 def properties(self, index=None): 

273 """Standardized ndimage metadata. 

274 

275 Parameters 

276 ---------- 

277 index : int 

278 The index of the ndimage for which to return properties. If the 

279 index is out of bounds a ``ValueError`` is raised. If ``None``, 

280 return the properties for the ndimage stack. If this is impossible, 

281 e.g., due to shape mismatch, an exception will be raised. 

282 

283 Returns 

284 ------- 

285 properties : ImageProperties 

286 A dataclass filled with standardized image metadata. 

287 

288 """ 

289 

290 if index is None: 

291 index = _legacy_default_index(self._format) 

292 

293 # for backwards compatibility ... actually reads pixel data :( 

294 if index is Ellipsis: 

295 image = self.read(index=0) 

296 n_images = self.legacy_get_reader().get_length() 

297 return ImageProperties( 

298 shape=(n_images, *image.shape), 

299 dtype=image.dtype, 

300 n_images=n_images, 

301 is_batch=True, 

302 ) 

303 

304 image = self.read(index=index) 

305 return ImageProperties( 

306 shape=image.shape, 

307 dtype=image.dtype, 

308 is_batch=False, 

309 ) 

310 

311 def get_meta(self, *, index=None): 

312 """Read ndimage metadata from the URI 

313 

314 Parameters 

315 ---------- 

316 index : {integer, None} 

317 If the URI contains a list of ndimages return the metadata 

318 corresponding to the index-th image. If None, behavior depends on 

319 the used api 

320 

321 Legacy-style API: return metadata of the first element (index=0) 

322 New-style API: Behavior depends on the used Plugin. 

323 

324 Returns 

325 ------- 

326 metadata : dict 

327 A dictionary of metadata. 

328 

329 """ 

330 

331 return self.metadata(index=index, exclude_applied=False) 

332 

333 def metadata(self, index=None, exclude_applied: bool = True): 

334 """Format-Specific ndimage metadata. 

335 

336 Parameters 

337 ---------- 

338 index : int 

339 The index of the ndimage to read. If the index is out of bounds a 

340 ``ValueError`` is raised. If ``None``, global metadata is returned. 

341 exclude_applied : bool 

342 This parameter exists for compatibility and has no effect. Legacy 

343 plugins always report all metadata they find. 

344 

345 Returns 

346 ------- 

347 metadata : dict 

348 A dictionary filled with format-specific metadata fields and their 

349 values. 

350 

351 """ 

352 

353 if index is None: 

354 index = _legacy_default_index(self._format) 

355 

356 return self.legacy_get_reader().get_meta_data(index=index) 

357 

358 def __del__(self) -> None: 

359 pass 

360 # turns out we can't close the file here for LegacyPlugin 

361 # because it would break backwards compatibility 

362 # with legacy_get_writer and legacy_get_reader 

363 # self._request.finish()