Read and write TIFF files for scientific and bioimaging applications with comprehensive format support
TIFF format constants, compression schemes, photometric interpretations, and other standardized values required for proper TIFF file creation and interpretation. These enums provide type-safe access to TIFF specification values and ensure compatibility across different TIFF implementations.
Core TIFF format identification and byte order constants.
class _TIFF:
"""Internal class containing TIFF format constants."""
# TIFF format signatures
CLASSIC_LE: bytes # b'II*\x00' - Classic TIFF, little-endian
CLASSIC_BE: bytes # b'MM\x00*' - Classic TIFF, big-endian
BIG_LE: bytes # b'II+\x00' - BigTIFF, little-endian
BIG_BE: bytes # b'MM\x00+' - BigTIFF, big-endian
# Version numbers
VERSION: int # 42 - Classic TIFF version
BIG_VERSION: int # 43 - BigTIFF version
TIFF = _TIFF() # Singleton instance containing TIFF constants# Check TIFF format
with open('image.tif', 'rb') as f:
header = f.read(4)
if header == tifffile.TIFF.CLASSIC_LE:
print("Classic TIFF, little-endian")
elif header == tifffile.TIFF.BIG_LE:
print("BigTIFF, little-endian")Compression algorithms supported in TIFF files.
class COMPRESSION(IntEnum):
NONE = 1 # No compression
CCITT_1D = 2 # CCITT Group 3 1-Dimensional Modified Huffman
CCITT_GROUP3 = 3 # CCITT Group 3 fax encoding
CCITT_GROUP4 = 4 # CCITT Group 4 fax encoding
LZW = 5 # Lempel-Ziv-Welch compression
JPEG_OLD = 6 # Old-style JPEG compression (deprecated)
JPEG = 7 # JPEG compression
ADOBE_DEFLATE = 8 # Adobe-style Deflate compression
JBIG_BW = 9 # JBIG bi-level compression
JBIG_COLOR = 10 # JBIG color compression
NEXT = 32766 # NeXT 2-bit RLE compression
CCITTRLEW = 32771 # CCITT RLE with word alignment
PACKBITS = 32773 # PackBits compression
THUNDERSCAN = 32809 # ThunderScan compression
IT8CTPAD = 32895 # IT8 CT w/padding compression
IT8LW = 32896 # IT8 Linework RLE compression
IT8MP = 32897 # IT8 Monochrome picture compression
IT8BL = 32898 # IT8 Binary line art compression
PIXARFILM = 32908 # Pixar companded 10bit LZW
PIXARLOG = 32909 # Pixar companded 11bit ZIP
DEFLATE = 32946 # PKZIP-style Deflate compression
DCS = 32947 # Kodak DCS encoding
JBIG = 34661 # ISO JBIG compression
SGILOG = 34676 # SGI Log Luminance RLE
SGILOG24 = 34677 # SGI Log 24-bit packed
JP2000 = 34712 # JPEG 2000 compression
LZMA = 34925 # LZMA compression
ZSTD = 50000 # Zstandard compression
WEBP = 50001 # WebP compression
PNG = 50002 # PNG compression
JPEGXR = 50003 # JPEG XR compression# Write compressed TIFF
tifffile.imwrite('lzw.tif', data, compression=tifffile.COMPRESSION.LZW)
tifffile.imwrite('deflate.tif', data, compression='deflate') # String also works
# Check compression of existing file
with tifffile.TiffFile('image.tif') as tif:
compression = tif.pages[0].compression
print(f"Compression: {compression.name} ({compression.value})")
if compression == tifffile.COMPRESSION.LZW:
print("Uses LZW compression")Color interpretation schemes for TIFF images.
class PHOTOMETRIC(IntEnum):
MINISWHITE = 0 # Min value is white (inverted grayscale)
MINISBLACK = 1 # Min value is black (normal grayscale)
RGB = 2 # RGB color model
PALETTE = 3 # Palette/indexed color
MASK = 4 # Transparency mask
SEPARATED = 5 # Color separations (CMYK)
YCBCR = 6 # YCbCr color space
CIELAB = 8 # CIE L*a*b* color space
ICCLAB = 9 # ICC L*a*b* color space
ITULAB = 10 # ITU L*a*b* color space
CFA = 32803 # Color Filter Array (Bayer pattern)
LOGL = 32844 # CIE Log2(L)
LOGLUV = 32845 # CIE Log2(L) (u',v')
LINEAR_RAW = 34892 # Linear Raw (Adobe DNG)# Write RGB image
rgb_data = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
tifffile.imwrite('rgb.tif', rgb_data, photometric=tifffile.PHOTOMETRIC.RGB)
# Write grayscale image
gray_data = np.random.randint(0, 256, (100, 100), dtype=np.uint8)
tifffile.imwrite('gray.tif', gray_data, photometric='minisblack')
# Check photometric interpretation
with tifffile.TiffFile('image.tif') as tif:
photometric = tif.pages[0].photometric
if photometric == tifffile.PHOTOMETRIC.RGB:
print("RGB color image")
elif photometric == tifffile.PHOTOMETRIC.MINISBLACK:
print("Grayscale image")TIFF tag data types for proper tag encoding and decoding.
class DATATYPE(IntEnum):
BYTE = 1 # 8-bit unsigned integer
ASCII = 2 # 8-bit byte containing ASCII character
SHORT = 3 # 16-bit unsigned integer
LONG = 4 # 32-bit unsigned integer
RATIONAL = 5 # Two 32-bit unsigned integers (numerator/denominator)
SBYTE = 6 # 8-bit signed integer
UNDEFINED = 7 # 8-bit byte with undefined content
SSHORT = 8 # 16-bit signed integer
SLONG = 9 # 32-bit signed integer
SRATIONAL = 10 # Two 32-bit signed integers (numerator/denominator)
FLOAT = 11 # 32-bit IEEE floating point
DOUBLE = 12 # 64-bit IEEE floating point
LONG8 = 16 # 64-bit unsigned integer (BigTIFF)
SLONG8 = 17 # 64-bit signed integer (BigTIFF)
IFD8 = 18 # 64-bit IFD offset (BigTIFF)Prediction algorithms used with compression.
class PREDICTOR(IntEnum):
NONE = 1 # No prediction
HORIZONTAL = 2 # Horizontal differencing
FLOATINGPOINT = 3 # Floating point horizontal differencing# Write with horizontal predictor (good for continuous-tone images)
tifffile.imwrite(
'predicted.tif',
data,
compression='lzw',
predictor=tifffile.PREDICTOR.HORIZONTAL
)
# Write floating point data with appropriate predictor
float_data = np.random.random((100, 100)).astype(np.float32)
tifffile.imwrite(
'float.tif',
float_data,
compression='deflate',
predictor='floatingpoint'
)Organization of samples within pixels.
class PLANARCONFIG(IntEnum):
CONTIG = 1 # Samples are contiguous (RGBRGBRGB...)
SEPARATE = 2 # Samples are in separate planes (RRR...GGG...BBB...)# Write RGB with separate planes
rgb_data = np.random.randint(0, 256, (3, 100, 100), dtype=np.uint8)
tifffile.imwrite(
'separate.tif',
rgb_data,
photometric='rgb',
planarconfig=tifffile.PLANARCONFIG.SEPARATE
)
# Write RGB with contiguous samples (default)
rgb_data = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
tifffile.imwrite(
'contiguous.tif',
rgb_data,
photometric='rgb',
planarconfig='contig'
)Interpretation of sample data values.
class SAMPLEFORMAT(IntEnum):
UINT = 1 # Unsigned integer
INT = 2 # Signed integer
IEEEFP = 3 # IEEE floating point
VOID = 4 # Undefined/void
COMPLEXINT = 5 # Complex integer
COMPLEXIEEEFP = 6 # Complex IEEE floating pointImage orientation relative to display.
class ORIENTATION(IntEnum):
TOPLEFT = 1 # Row 0 at top, column 0 at left
TOPRIGHT = 2 # Row 0 at top, column 0 at right
BOTRIGHT = 3 # Row 0 at bottom, column 0 at right
BOTLEFT = 4 # Row 0 at bottom, column 0 at left
LEFTTOP = 5 # Row 0 at left, column 0 at top
RIGHTTOP = 6 # Row 0 at right, column 0 at top
RIGHTBOT = 7 # Row 0 at right, column 0 at bottom
LEFTBOT = 8 # Row 0 at left, column 0 at bottomBit order within bytes.
class FILLORDER(IntEnum):
MSB2LSB = 1 # Most significant bit first
LSB2MSB = 2 # Least significant bit firstTIFF file type and subfile type indicators.
class FILETYPE(IntFlag):
UNDEFINED = 0 # Undefined
REDUCEDIMAGE = 1 # Reduced resolution version
PAGE = 2 # Single page of multi-page image
MASK = 4 # Transparency mask
DNG = 65536 # Adobe DNG format
class OFILETYPE(IntEnum):
IMAGE = 1 # Full resolution image
REDUCEDIMAGE = 2 # Reduced resolution version
PAGE = 3 # Single page of multi-page imageUnits for X and Y resolution values.
class RESUNIT(IntEnum):
NONE = 1 # No absolute unit
INCH = 2 # Inch
CENTIMETER = 3 # Centimeter# Write with resolution information
tifffile.imwrite(
'high_res.tif',
data,
resolution=(300, 300),
resolutionunit=tifffile.RESUNIT.INCH
)
# Write with metric resolution
tifffile.imwrite(
'metric.tif',
data,
resolution=(118.11, 118.11), # 300 DPI in dots per cm
resolutionunit='centimeter'
)Interpretation of additional samples beyond color channels.
class EXTRASAMPLE(IntEnum):
UNSPECIFIED = 0 # Unspecified data
ASSOCALPHA = 1 # Associated alpha (premultiplied)
UNASSALPHA = 2 # Unassociated alpha (separate)# Write RGBA with unassociated alpha
rgba_data = np.random.randint(0, 256, (100, 100, 4), dtype=np.uint8)
tifffile.imwrite(
'rgba.tif',
rgba_data,
photometric='rgb',
extrasamples=[tifffile.EXTRASAMPLE.UNASSALPHA]
)Strategies for reading large TIFF files in chunks.
class CHUNKMODE(IntEnum):
NONE = 0 # No chunking
PAGE = 1 # Chunk by pages
PLANE = 2 # Chunk by planes
TILE = 3 # Chunk by tiles
FRAME = 4 # Chunk by frames# Read large file with page-based chunking
large_data = tifffile.imread('huge.tif', chunkmode=tifffile.CHUNKMODE.PAGE)
# Use Zarr with tile-based chunking
zarr_store = tifffile.imread('tiled.tif', aszarr=True, chunkmode='tile')Helper functions for working with enums.
def enumarg(enum_class, arg):
"""
Convert argument to enum member.
Parameters:
- enum_class: Enum class
- arg: str, int, or enum member
Returns:
- Enum member
"""
def enumstr(enum_class, *args, **kwargs):
"""
Return string representation of enum values.
Parameters:
- enum_class: Enum class
- *args, **kwargs: enum values
Returns:
- str: Formatted enum string
"""# Convert strings to enums
compression = tifffile.enumarg(tifffile.COMPRESSION, 'lzw')
photometric = tifffile.enumarg(tifffile.PHOTOMETRIC, 'rgb')
# Get string representations
comp_str = tifffile.enumstr(tifffile.COMPRESSION, tifffile.COMPRESSION.LZW)
print(comp_str) # "LZW"# Determine appropriate settings based on data
data = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
if data.ndim == 3 and data.shape[2] == 3:
photometric = tifffile.PHOTOMETRIC.RGB
elif data.ndim == 3 and data.shape[2] == 4:
photometric = tifffile.PHOTOMETRIC.RGB
extrasamples = [tifffile.EXTRASAMPLE.UNASSALPHA]
else:
photometric = tifffile.PHOTOMETRIC.MINISBLACK
tifffile.imwrite('auto.tif', data, photometric=photometric)# Choose compression based on data type
if data.dtype in (np.uint8, np.uint16):
compression = tifffile.COMPRESSION.LZW
predictor = None
elif data.dtype in (np.float32, np.float64):
compression = tifffile.COMPRESSION.DEFLATE
predictor = tifffile.PREDICTOR.FLOATINGPOINT
else:
compression = tifffile.COMPRESSION.DEFLATE
predictor = tifffile.PREDICTOR.HORIZONTAL
tifffile.imwrite(
'optimized.tif',
data,
compression=compression,
predictor=predictor
)# Handle different input formats
def write_universal_tiff(filename, data, format_hint=None):
kwargs = {}
if format_hint == 'imagej':
kwargs.update({
'imagej': True,
'photometric': tifffile.PHOTOMETRIC.MINISBLACK
})
elif format_hint == 'ome':
kwargs.update({
'ome': True,
'compression': tifffile.COMPRESSION.LZW
})
elif format_hint == 'geotiff':
kwargs.update({
'photometric': tifffile.PHOTOMETRIC.RGB,
'compression': tifffile.COMPRESSION.DEFLATE
})
return tifffile.imwrite(filename, data, **kwargs)Install with Tessl CLI
npx tessl i tessl/pypi-tifffile