tifffile.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. # -*- coding: utf-8 -*-
  2. # imageio is distributed under the terms of the (new) BSD License.
  3. """Read/Write TIFF files.
  4. Backend: internal
  5. Provides support for a wide range of Tiff images using the tifffile
  6. backend.
  7. Parameters for reading
  8. ----------------------
  9. offset : int
  10. Optional start position of embedded file. By default this is
  11. the current file position.
  12. size : int
  13. Optional size of embedded file. By default this is the number
  14. of bytes from the 'offset' to the end of the file.
  15. multifile : bool
  16. If True (default), series may include pages from multiple files.
  17. Currently applies to OME-TIFF only.
  18. multifile_close : bool
  19. If True (default), keep the handles of other files in multifile
  20. series closed. This is inefficient when few files refer to
  21. many pages. If False, the C runtime may run out of resources.
  22. Parameters for saving
  23. ---------------------
  24. bigtiff : bool
  25. If True, the BigTIFF format is used.
  26. byteorder : {'<', '>'}
  27. The endianness of the data in the file.
  28. By default this is the system's native byte order.
  29. software : str
  30. Name of the software used to create the image.
  31. Saved with the first page only.
  32. Metadata for reading
  33. --------------------
  34. planar_configuration : {'contig', 'planar'}
  35. Specifies if samples are stored contiguous or in separate planes.
  36. By default this setting is inferred from the data shape.
  37. 'contig': last dimension contains samples.
  38. 'planar': third last dimension contains samples.
  39. resolution_unit : int
  40. The resolution unit stored in the TIFF tag. Usually 1 means no/unknown unit,
  41. 2 means dpi (inch), 3 means dpc (centimeter).
  42. resolution : (float, float, str)
  43. A tuple formatted as (X_resolution, Y_resolution, unit). The unit is a
  44. string representing one of the following units::
  45. NONE # No unit or unit unknown
  46. INCH # dpi
  47. CENTIMETER # cpi
  48. MILLIMETER
  49. MICROMETER
  50. compression : int
  51. Value indicating the compression algorithm used, e.g. 5 is LZW,
  52. 7 is JPEG, 8 is deflate.
  53. If 1, data are uncompressed.
  54. predictor : int
  55. Value 2 indicates horizontal differencing was used before compression,
  56. while 3 indicates floating point horizontal differencing.
  57. If 1, no prediction scheme was used before compression.
  58. orientation : {'top_left', 'bottom_right', ...}
  59. Oriented of image array.
  60. is_rgb : bool
  61. True if page contains a RGB image.
  62. is_contig : bool
  63. True if page contains a contiguous image.
  64. is_tiled : bool
  65. True if page contains tiled image.
  66. is_palette : bool
  67. True if page contains a palette-colored image and not OME or STK.
  68. is_reduced : bool
  69. True if page is a reduced image of another image.
  70. is_shaped : bool
  71. True if page contains shape in image_description tag.
  72. is_fluoview : bool
  73. True if page contains FluoView MM_STAMP tag.
  74. is_nih : bool
  75. True if page contains NIH image header.
  76. is_micromanager : bool
  77. True if page contains Micro-Manager metadata.
  78. is_ome : bool
  79. True if page contains OME-XML in image_description tag.
  80. is_sgi : bool
  81. True if page contains SGI image and tile depth tags.
  82. is_mdgel : bool
  83. True if page contains md_file_tag tag.
  84. is_mediacy : bool
  85. True if page contains Media Cybernetics Id tag.
  86. is_stk : bool
  87. True if page contains UIC2Tag tag.
  88. is_lsm : bool
  89. True if page contains LSM CZ_LSM_INFO tag.
  90. description : str
  91. Image description
  92. description1 : str
  93. Additional description
  94. is_imagej : None or str
  95. ImageJ metadata
  96. software : str
  97. Software used to create the TIFF file
  98. datetime : datetime.datetime
  99. Creation date and time
  100. Metadata for writing
  101. --------------------
  102. photometric : {'minisblack', 'miniswhite', 'rgb'}
  103. The color space of the image data.
  104. By default this setting is inferred from the data shape.
  105. planarconfig : {'contig', 'planar'}
  106. Specifies if samples are stored contiguous or in separate planes.
  107. By default this setting is inferred from the data shape.
  108. 'contig': last dimension contains samples.
  109. 'planar': third last dimension contains samples.
  110. resolution : (float, float) or ((int, int), (int, int))
  111. X and Y resolution in dots per inch as float or rational numbers.
  112. description : str
  113. The subject of the image. Saved with the first page only.
  114. compress : int
  115. Values from 0 to 9 controlling the level of zlib (deflate) compression.
  116. If 0, data are written uncompressed (default).
  117. compression : str, (int, int)
  118. Compression scheme used while writing the image. If omitted (default) the
  119. image is not uncompressed. Compression cannot be used to write contiguous
  120. series. Compressors may require certain data shapes, types or value ranges.
  121. For example, JPEG compression requires grayscale or RGB(A), uint8 or 12-bit
  122. uint16. JPEG compression is experimental. JPEG markers and TIFF tags may not
  123. match. Only a limited set of compression schemes are implemented. 'ZLIB' is
  124. short for ADOBE_DEFLATE. The value is written to the Compression tag.
  125. compressionargs:
  126. Extra arguments passed to compression codec, e.g., compression level. Refer
  127. to the Imagecodecs implementation for supported arguments.
  128. predictor : bool
  129. If True, horizontal differencing is applied before compression.
  130. Note that using an int literal 1 actually means no prediction scheme
  131. will be used.
  132. volume : bool
  133. If True, volume data are stored in one tile (if applicable) using
  134. the SGI image_depth and tile_depth tags.
  135. Image width and depth must be multiple of 16.
  136. Few software can read this format, e.g. MeVisLab.
  137. writeshape : bool
  138. If True, write the data shape to the image_description tag
  139. if necessary and no other description is given.
  140. extratags: sequence of tuples
  141. Additional tags as [(code, dtype, count, value, writeonce)].
  142. code : int
  143. The TIFF tag Id.
  144. dtype : str
  145. Data type of items in 'value' in Python struct format.
  146. One of B, s, H, I, 2I, b, h, i, f, d, Q, or q.
  147. count : int
  148. Number of data values. Not used for string values.
  149. value : sequence
  150. 'Count' values compatible with 'dtype'.
  151. writeonce : bool
  152. If True, the tag is written to the first page only.
  153. Notes
  154. -----
  155. Global metadata is stored with the first frame in a TIFF file.
  156. Thus calling :py:meth:`Format.Writer.set_meta_data` after the first frame
  157. was written has no effect. Also, global metadata is ignored if metadata is
  158. provided via the `meta` argument of :py:meth:`Format.Writer.append_data`.
  159. If you have installed tifffile as a Python package, imageio will attempt
  160. to use that as backend instead of the bundled backend. Doing so can
  161. provide access to new performance improvements and bug fixes.
  162. """
  163. import datetime
  164. from ..core import Format
  165. from ..core.request import URI_BYTES, URI_FILE
  166. import numpy as np
  167. import warnings
  168. try:
  169. import tifffile as _tifffile
  170. except ImportError:
  171. warnings.warn(
  172. "ImageIO's vendored tifffile backend is deprecated and will be"
  173. " removed in ImageIO v3. Install the tifffile directly:"
  174. " `pip install imageio[tifffile]`",
  175. DeprecationWarning,
  176. )
  177. from . import _tifffile
  178. TIFF_FORMATS = (".tif", ".tiff", ".stk", ".lsm")
  179. WRITE_METADATA_KEYS = (
  180. "photometric",
  181. "planarconfig",
  182. "resolution",
  183. "description",
  184. "compress",
  185. "compression",
  186. "compressionargs",
  187. "predictor",
  188. "volume",
  189. "writeshape",
  190. "extratags",
  191. "datetime",
  192. )
  193. READ_METADATA_KEYS = (
  194. "planar_configuration",
  195. "is_fluoview",
  196. "is_nih",
  197. "is_contig",
  198. "is_micromanager",
  199. "is_ome",
  200. "is_lsm",
  201. "is_palette",
  202. "is_reduced",
  203. "is_rgb",
  204. "is_sgi",
  205. "is_shaped",
  206. "is_stk",
  207. "is_tiled",
  208. "is_mdgel",
  209. "resolution_unit",
  210. "compression",
  211. "predictor",
  212. "is_mediacy",
  213. "orientation",
  214. "description",
  215. "description1",
  216. "is_imagej",
  217. "software",
  218. )
  219. class TiffFormat(Format):
  220. """Provides support for a wide range of Tiff images using the tifffile
  221. backend.
  222. Images that contain multiple pages can be read using ``imageio.mimread()``
  223. to read the individual pages, or ``imageio.volread()`` to obtain a
  224. single (higher dimensional) array.
  225. Note that global metadata is stored with the first frame in a TIFF file.
  226. Thus calling :py:meth:`Format.Writer.set_meta_data` after the first frame
  227. was written has no effect. Also, global metadata is ignored if metadata is
  228. provided via the `meta` argument of :py:meth:`Format.Writer.append_data`.
  229. If you have installed tifffile as a Python package, imageio will attempt
  230. to use that as backend instead of the bundled backend. Doing so can
  231. provide access to new performance improvements and bug fixes.
  232. Parameters for reading
  233. ----------------------
  234. offset : int
  235. Optional start position of embedded file. By default this is
  236. the current file position.
  237. size : int
  238. Optional size of embedded file. By default this is the number
  239. of bytes from the 'offset' to the end of the file.
  240. multifile : bool
  241. If True (default), series may include pages from multiple files.
  242. Currently applies to OME-TIFF only.
  243. multifile_close : bool
  244. If True (default), keep the handles of other files in multifile
  245. series closed. This is inefficient when few files refer to
  246. many pages. If False, the C runtime may run out of resources.
  247. Parameters for saving
  248. ---------------------
  249. bigtiff : bool
  250. If True, the BigTIFF format is used.
  251. byteorder : {'<', '>'}
  252. The endianness of the data in the file.
  253. By default this is the system's native byte order.
  254. software : str
  255. Name of the software used to create the image.
  256. Saved with the first page only.
  257. Metadata for reading
  258. --------------------
  259. planar_configuration : {'contig', 'planar'}
  260. Specifies if samples are stored contiguous or in separate planes.
  261. By default this setting is inferred from the data shape.
  262. 'contig': last dimension contains samples.
  263. 'planar': third last dimension contains samples.
  264. resolution_unit : (float, float) or ((int, int), (int, int))
  265. X and Y resolution in dots per inch as float or rational numbers.
  266. compression : int
  267. Value indicating the compression algorithm used, e.g. 5 is LZW,
  268. 7 is JPEG, 8 is deflate.
  269. If 1, data are uncompressed.
  270. predictor : int
  271. Value 2 indicates horizontal differencing was used before compression,
  272. while 3 indicates floating point horizontal differencing.
  273. If 1, no prediction scheme was used before compression.
  274. orientation : {'top_left', 'bottom_right', ...}
  275. Oriented of image array.
  276. is_rgb : bool
  277. True if page contains a RGB image.
  278. is_contig : bool
  279. True if page contains a contiguous image.
  280. is_tiled : bool
  281. True if page contains tiled image.
  282. is_palette : bool
  283. True if page contains a palette-colored image and not OME or STK.
  284. is_reduced : bool
  285. True if page is a reduced image of another image.
  286. is_shaped : bool
  287. True if page contains shape in image_description tag.
  288. is_fluoview : bool
  289. True if page contains FluoView MM_STAMP tag.
  290. is_nih : bool
  291. True if page contains NIH image header.
  292. is_micromanager : bool
  293. True if page contains Micro-Manager metadata.
  294. is_ome : bool
  295. True if page contains OME-XML in image_description tag.
  296. is_sgi : bool
  297. True if page contains SGI image and tile depth tags.
  298. is_stk : bool
  299. True if page contains UIC2Tag tag.
  300. is_mdgel : bool
  301. True if page contains md_file_tag tag.
  302. is_mediacy : bool
  303. True if page contains Media Cybernetics Id tag.
  304. is_stk : bool
  305. True if page contains UIC2Tag tag.
  306. is_lsm : bool
  307. True if page contains LSM CZ_LSM_INFO tag.
  308. description : str
  309. Image description
  310. description1 : str
  311. Additional description
  312. is_imagej : None or str
  313. ImageJ metadata
  314. software : str
  315. Software used to create the TIFF file
  316. datetime : datetime.datetime
  317. Creation date and time
  318. Metadata for writing
  319. --------------------
  320. photometric : {'minisblack', 'miniswhite', 'rgb'}
  321. The color space of the image data.
  322. By default this setting is inferred from the data shape.
  323. planarconfig : {'contig', 'planar'}
  324. Specifies if samples are stored contiguous or in separate planes.
  325. By default this setting is inferred from the data shape.
  326. 'contig': last dimension contains samples.
  327. 'planar': third last dimension contains samples.
  328. resolution : (float, float) or ((int, int), (int, int))
  329. X and Y resolution in dots per inch as float or rational numbers.
  330. description : str
  331. The subject of the image. Saved with the first page only.
  332. compress : int
  333. Values from 0 to 9 controlling the level of zlib (deflate) compression.
  334. If 0, data are written uncompressed (default).
  335. predictor : bool
  336. If True, horizontal differencing is applied before compression.
  337. Note that using an int literal 1 actually means no prediction scheme
  338. will be used.
  339. volume : bool
  340. If True, volume data are stored in one tile (if applicable) using
  341. the SGI image_depth and tile_depth tags.
  342. Image width and depth must be multiple of 16.
  343. Few software can read this format, e.g. MeVisLab.
  344. writeshape : bool
  345. If True, write the data shape to the image_description tag
  346. if necessary and no other description is given.
  347. extratags: sequence of tuples
  348. Additional tags as [(code, dtype, count, value, writeonce)].
  349. code : int
  350. The TIFF tag Id.
  351. dtype : str
  352. Data type of items in 'value' in Python struct format.
  353. One of B, s, H, I, 2I, b, h, i, f, d, Q, or q.
  354. count : int
  355. Number of data values. Not used for string values.
  356. value : sequence
  357. 'Count' values compatible with 'dtype'.
  358. writeonce : bool
  359. If True, the tag is written to the first page only.
  360. """
  361. def _can_read(self, request):
  362. try:
  363. _tifffile.TiffFile(request.get_file(), **request.kwargs)
  364. except ValueError:
  365. # vendored backend raises value exception
  366. return False
  367. except _tifffile.TiffFileError: # pragma: no-cover
  368. # current version raises custom exception
  369. return False
  370. finally:
  371. request.get_file().seek(0)
  372. return True
  373. def _can_write(self, request):
  374. if request._uri_type in [URI_FILE, URI_BYTES]:
  375. pass # special URI
  376. elif request.extension not in self.extensions:
  377. return False
  378. try:
  379. _tifffile.TiffWriter(request.get_file(), **request.kwargs)
  380. except ValueError:
  381. # vendored backend raises value exception
  382. return False
  383. except _tifffile.TiffFileError: # pragma: no-cover
  384. # current version raises custom exception
  385. return False
  386. finally:
  387. request.get_file().seek(0)
  388. return True
  389. # -- reader
  390. class Reader(Format.Reader):
  391. def _open(self, **kwargs):
  392. # Allow loading from http; tifffile uses seek, so download first
  393. if self.request.filename.startswith(("http://", "https://")):
  394. self._f = f = open(self.request.get_local_filename(), "rb")
  395. else:
  396. self._f = None
  397. f = self.request.get_file()
  398. self._tf = _tifffile.TiffFile(f, **kwargs)
  399. def _close(self):
  400. self._tf.close()
  401. if self._f is not None:
  402. self._f.close()
  403. def _get_length(self):
  404. return len(self._tf.series)
  405. def _get_data(self, index):
  406. if index < 0 or index >= self._get_length():
  407. raise IndexError("Index out of range while reading from tiff file")
  408. im = self._tf.asarray(series=index)
  409. meta = self._get_meta_data(index)
  410. return im, meta
  411. def _get_meta_data(self, index):
  412. meta = {}
  413. page = self._tf.pages[index or 0]
  414. for key in READ_METADATA_KEYS:
  415. try:
  416. meta[key] = getattr(page, key)
  417. except Exception:
  418. pass
  419. # tifffile <= 0.12.1 use datetime, newer use DateTime
  420. for key in ("datetime", "DateTime"):
  421. try:
  422. meta["datetime"] = datetime.datetime.strptime(
  423. page.tags[key].value, "%Y:%m:%d %H:%M:%S"
  424. )
  425. break
  426. except Exception:
  427. pass
  428. if 296 in page.tags:
  429. meta["resolution_unit"] = page.tags[296].value.value
  430. if 282 in page.tags and 283 in page.tags and 296 in page.tags:
  431. resolution_x = page.tags[282].value
  432. resolution_y = page.tags[283].value
  433. if resolution_x[1] == 0 or resolution_y[1] == 0:
  434. warnings.warn(
  435. "Ignoring resolution metadata, "
  436. "because at least one direction has a 0 denominator.",
  437. RuntimeWarning,
  438. )
  439. else:
  440. meta["resolution"] = (
  441. resolution_x[0] / resolution_x[1],
  442. resolution_y[0] / resolution_y[1],
  443. page.tags[296].value.name,
  444. )
  445. return meta
  446. # -- writer
  447. class Writer(Format.Writer):
  448. def _open(self, bigtiff=None, byteorder=None, software=None):
  449. try:
  450. self._tf = _tifffile.TiffWriter(
  451. self.request.get_file(),
  452. bigtiff=bigtiff,
  453. byteorder=byteorder,
  454. software=software,
  455. )
  456. self._software = None
  457. except TypeError:
  458. # In tifffile >= 0.15, the `software` arg is passed to
  459. # TiffWriter.save
  460. self._tf = _tifffile.TiffWriter(
  461. self.request.get_file(), bigtiff=bigtiff, byteorder=byteorder
  462. )
  463. self._software = software
  464. self._meta = {}
  465. self._frames_written = 0
  466. def _close(self):
  467. self._tf.close()
  468. def _append_data(self, im, meta):
  469. if meta is not None:
  470. meta = self._sanitize_meta(meta)
  471. else:
  472. # Use global metadata for first frame
  473. meta = self._meta if self._frames_written == 0 else {}
  474. if self._software is not None and self._frames_written == 0:
  475. meta["software"] = self._software
  476. # No need to check self.request.mode; tifffile figures out whether
  477. # this is a single page, or all page data at once.
  478. try:
  479. # TiffWriter.save has been deprecated in version 2020.9.30
  480. write_meth = self._tf.write
  481. except AttributeError:
  482. write_meth = self._tf.save
  483. write_meth(np.asanyarray(im), contiguous=False, **meta)
  484. self._frames_written += 1
  485. @staticmethod
  486. def _sanitize_meta(meta):
  487. ret = {}
  488. for key, value in meta.items():
  489. if key in WRITE_METADATA_KEYS:
  490. # Special case of previously read `predictor` int value
  491. # 1(=NONE) translation to False expected by TiffWriter.save
  492. if key == "predictor" and not isinstance(value, bool):
  493. ret[key] = value > 1
  494. elif key == "compress" and value != 0:
  495. warnings.warn(
  496. "The use of `compress` is deprecated. Use `compression` and `compressionargs` instead.",
  497. DeprecationWarning,
  498. )
  499. if _tifffile.__version__ < "2022":
  500. ret["compression"] = (8, value)
  501. else:
  502. ret["compression"] = "zlib"
  503. ret["compressionargs"] = {"level": value}
  504. else:
  505. ret[key] = value
  506. return ret
  507. def set_meta_data(self, meta):
  508. self._meta = self._sanitize_meta(meta)