developmentseed / developmentseed/async-tiff
Panic on TIFFs that omit the SamplesPerPixel tag (spec default is 1)
- Dominant language
- Rust
- Stars
- 120
- Forks
- 15
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 9
Description
## 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](https://download.osgeo.org/libtiff/doc/TIFF6.pdf)). Many single-channel grayscale TIFFs omit the tag entirely — notably the PerkinElmer/Phenix microscopy images in the [Cell Painting Gallery](https://registry.opendata.aws/cellpainting-gallery/) open dataset.
## Where
`src/ifd.rs`:
```rust
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`:
```python
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:
```rust
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).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in src/ifd.rs at the SamplesPerPixel expect() shown in the issue, then read the nearby PlanarConfiguration logic. Reproduce with a TIFF that omits tag 277, such as the referenced Cell Painting Gallery image, and add a minimal regression fixture. Done means the file parses without a panic and uses the TIFF default of one sample per pixel.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- data
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100