File: tifffile.py

package info (click to toggle)
python-imageio 2.4.1-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 4,824 kB
  • sloc: python: 18,306; makefile: 145
file content (328 lines) | stat: -rw-r--r-- 11,182 bytes parent folder | download | duplicates (3)
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
# -*- coding: utf-8 -*-
# imageio is distributed under the terms of the (new) BSD License.

""" Storage of image data in tiff format.
"""

from __future__ import absolute_import, print_function, division

import sys
import datetime

from .. import formats
from ..core import Format

import numpy as np

_tifffile = None  # Defer loading to lib() function.


def load_lib():
    if sys.version_info < (3,):
        try:
            import enum  # noqa - needs enum34
            import concurrent.futures  # noqa - needs futures
        except ImportError:
            raise ImportError(
                "The Imageio TIFF format has extra dependencies "
                "on Python 2.7. Install these using e.g. "
                '"pip install enum34 futures".'
            )

    global _tifffile
    try:
        import tifffile as _tifffile
    except ImportError:
        from . import _tifffile
    return _tifffile


TIFF_FORMATS = (".tif", ".tiff", ".stk", ".lsm")
WRITE_METADATA_KEYS = (
    "photometric",
    "planarconfig",
    "resolution",
    "description",
    "compress",
    "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",
    "is_mediacy",
    "orientation",
    "description",
    "description1",
    "is_imagej",
    "software",
)


class TiffFormat(Format):
    """ Provides support for a wide range of Tiff images.
    
    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.

    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
        Values from 0 to 9 indicating the level of zlib compression.
        If 0, data is uncompressed.
    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 compression.
        If 0, data are written uncompressed (default).
    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):
        # We support any kind of image data
        return request.extension in self.extensions

    def _can_write(self, request):
        # We support any kind of image data
        return request.extension in self.extensions

    # -- reader

    class Reader(Format.Reader):
        def _open(self, **kwargs):
            if not _tifffile:
                load_lib()
            # Allow loading from http; tiffile 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)

            # metadata is the same for all images
            self._meta = {}

        def _close(self):
            self._tf.close()
            if self._f is not None:
                self._f.close()

        def _get_length(self):
            if self.request.mode[1] in "vV":
                return 1  # or can there be pages in pages or something?
            else:
                return len(self._tf.pages)

        def _get_data(self, index):
            if self.request.mode[1] in "vV":
                # Read data as single 3D (+ color channels) array
                if index != 0:
                    raise IndexError('Tiff support no more than 1 "volume" per file')
                im = self._tf.asarray()  # request as singleton image
                meta = self._meta
            else:
                # Read as 2D image
                if index < 0 or index >= self._get_length():
                    raise IndexError("Index out of range while reading from tiff file")
                im = self._tf.pages[index].asarray()
                meta = self._meta or self._get_meta_data(index)
            # Return array and empty meta data
            return im, meta

        def _get_meta_data(self, index):
            page = self._tf.pages[index or 0]
            for key in READ_METADATA_KEYS:
                try:
                    self._meta[key] = getattr(page, key)
                except Exception:
                    pass

            # tifffile <= 0.12.1 use datetime, newer use DateTime
            for key in ("datetime", "DateTime"):
                try:
                    self._meta["datetime"] = datetime.datetime.strptime(
                        page.tags[key].value, "%Y:%m:%d %H:%M:%S"
                    )
                    break
                except Exception:
                    pass

            return self._meta

    # -- writer
    class Writer(Format.Writer):
        def _open(self, bigtiff=None, byteorder=None, software=None):
            if not _tifffile:
                load_lib()

            try:
                self._tf = _tifffile.TiffWriter(
                    self.request.get_local_filename(),
                    bigtiff,
                    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_local_filename(), bigtiff, byteorder
                )
                self._software = software

            self._meta = {}

        def _close(self):
            self._tf.close()

        def _append_data(self, im, meta):
            if meta:
                self.set_meta_data(meta)
            # No need to check self.request.mode; tiffile figures out whether
            # this is a single page, or all page data at once.
            if self._software is None:
                self._tf.save(np.asanyarray(im), **self._meta)
            else:
                # tifffile >= 0.15
                self._tf.save(np.asanyarray(im), software=self._software, **self._meta)

        def set_meta_data(self, meta):
            self._meta = {}
            for (key, value) in meta.items():
                if key in WRITE_METADATA_KEYS:
                    self._meta[key] = value


# Register
format = TiffFormat("tiff", "TIFF format", TIFF_FORMATS, "iIvV")
formats.add_format(format)