Skip to content

Panic on TIFFs that omit the SamplesPerPixel tag (spec default is 1) #318

Description

@TomNicholas

Summary

Parsing a TIFF that omits the SamplesPerPixel tag (277) panics with samples_per_pixel not found instead of applying the spec default.

The TIFF 6.0 specification defines a default value of 1 for SamplesPerPixel (tag 277 reference). Many single-channel grayscale TIFFs omit the tag entirely — notably the PerkinElmer/Phenix microscopy images in the Cell Painting Gallery open dataset.

Where

src/ifd.rs:

let samples_per_pixel = samples_per_pixel.expect("samples_per_pixel not found");

Because this is an .expect() inside the async IFD parse, it surfaces (via virtual_tiff/pyo3-async-runtimes) as an uncatchable Rust panic:

thread 'tokio-rt-worker' panicked at .../async-tiff/src/ifd.rs:375:51:
samples_per_pixel not found

Reproduce

Any TIFF lacking tag 277 triggers it. A public example (single-channel 16-bit LZW grayscale, no SamplesPerPixel tag):

s3://cellpainting-gallery/cpg0000-jump-pilot/source_4/images/2020_11_04_CPJUMP1/images/BR00116991__2020-11-05T19_51_35-Measurement1/Images/r01c01f01p01-ch1sk1fk1fl1.tiff

(publicly readable with --no-sign-request).

Confirmed absent via tifffile:

import tifffile
p = tifffile.TiffFile("r01c01f01p01-ch1sk1fk1fl1.tiff").pages[0]
assert 277 not in [t.code for t in p.tags]  # SamplesPerPixel omitted

Suggested fix

Fall back to the spec default of 1:

let samples_per_pixel = samples_per_pixel.unwrap_or(1);

The existing PlanarConfiguration logic just below already handles the samples_per_pixel == 1 case, so this is a self-contained change. Happy to open a PR (with a minimal regression fixture).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions