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