Skip to content

TIFF: refuse zero-size continuation pages - #10080

Closed
akx wants to merge 2 commits into
python-pillow:mainfrom
akx:ziff
Closed

akx wants to merge 2 commits into
python-pillow:mainfrom
akx:ziff

Conversation

@akx

@akx akx commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

While zero-dimension images (touched upon in #9673, #9997, #9856) are creatable in Pillow, they were generally refused from input files, except when seeking into a non-first IFD of a TIFF file.

This PR:

  • adds an explicit check and SyntaxError raise for zero-dimensioned pages in the TIFF plugin
  • ImageFile-level fixes to refuse using mmap for cases where it would be erroneous

@radarhere

Copy link
Copy Markdown
Member

I don't necessarily mind this, but should we take a minute to consider why we reject zero-dimension images?

The behaviour started in PIL. I imagine the initial thinking was that it was a sanity check - surely the plugin must have missed a step, because who would want a zero-dimension image?

Well, it turns out that Pillow can save ICNS, ICO and SGI images as (0, 0), and someone has actually tried saving zero-dimension images. If Image.new("L", (0, 0)) can work, then what is fundamentally wrong about opening an empty image?

The simple response that 'this is still a sanity check, and no one actually wants to load zero-dimension images' may be a valid answer, I just wanted to raise the question.

@akx

akx commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

I don't necessarily mind this, but should we take a minute to consider why we reject zero-dimension images?

From a mathematical standpoint, there's no great reason not to (in fact, zero-dimension arrays are fine in NumPy, and Image.fromarray(np.zeros((80000000,0), dtype=np.uint8)) will happily work)... but I think there are places in Pillow where zero-dimension images aren't handled gracefully.

For instance, the whole zero-width-but-tall-image allocation surprise, #9957 (review) etc. isn't very graceful in my books, but fixing it (namely that no image data pointers are allocated whatsoever for zero-dimension images) is a larger change.

then what is fundamentally wrong about opening an empty image?

I think that's often against the specs (or reference decoders) of said image formats, so such a file in those formats shouldn't exist to begin with.

A quick look at some common formats' specs:

  • PNG: "Zero is an invalid value."
  • WebP specifies width/height as 1-based, so a value of zero there means 1x1 px (so 0x0 is simply impossible)
  • the QOI reference decoder refuses zero-size images
  • libtiff (which doesn't get used in Pillow for raw uncompressed data, which is the issue here) would refuse in TIFFTileRowSize64 or TIFFStartStrip
  • JPEG specifies width has to be 1-65535; height can be zero there in the header, but that means it'll be specified later by the DNL marker.

and so on. On the other hand, e.g. HDF5 explicitly allows zero-sized datasets, but notes that no data would be written.

The simple response that 'this is still a sanity check, and no one actually wants to load zero-dimension images' may be a valid answer, I just wanted to raise the question.

I think that's a good enough answer, because e.g. ImageMagick also refuses to work with the new test TIFFs' second IFDs:

$ identify Tests/images/zero_height_frame.tif
Tests/images/zero_height_frame.tif TIFF 8x8 8x8+0+0 8-bit Grayscale Gray 300B 0.000u 0:00.001
identify: Cannot handle zero number of strips. `TIFFReadDirectory' @ error/tiff.c/TIFFErrors/571.

$ identify Tests/images/zero_width_frame.tif
Tests/images/zero_width_frame.tif TIFF 8x8 8x8+0+0 8-bit Grayscale Gray 300B 0.000u 0:00.000
identify: Bogus "StripByteCounts" field, ignoring and calculating from imagelength. `TIFFReadDirectory' @ warning/tiff.c/TIFFWarnings/924.
identify: Computed scanline size is zero. `TIFFScanlineSize64' @ error/tiff.c/TIFFErrors/571.
identify: Cannot handle zero scanline size. `TIFFReadDirectory' @ error/tiff.c/TIFFErrors/571.

@aclark4life aclark4life added Bug Any unexpected behavior, until confirmed feature. TIFF labels Oct 11, 2026
@radarhere

Copy link
Copy Markdown
Member

When opening a new image, the default size is

self._size = (0, 0)

So it makes more sense that something should be done by the plugin in that scenario.

When seeking to another frame, if the plugin didn't do anything, the size would stay the same as the first frame, not be set to (0, 0).

So the 'sanity check' argument doesn't quite play out in the same way, and I'd rather not introduce a constraint just because we can.

@radarhere radarhere closed this Oct 12, 2026
@akx

akx commented Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

@radarhere The plugin refuses a TIFF whose first IFD is 0x0 though.

@radarhere

Copy link
Copy Markdown
Member

We reject the first frame if it is (0, 0), yes. If we were starting from scratch, perhaps we would not do that. I'm not saying that the behaviour is consistent, or that Pillow is perfect. I'm saying that I don't think this is a move in the right direction.

@akx

akx commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

the mmap fixes here should probably be merged anyhow. I can't open a new PR for that.

@radarhere

Copy link
Copy Markdown
Member

When you say 'mmap fixes', you're referring to 1857cc2. #10239 should cover zero-size.

So you're just referring to extents that do not exactly match the size, yes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Any unexpected behavior, until confirmed feature. TIFF

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants