Skip to content

Tighten geotiff accuracy: partial-tile validation, ModelTransformationTag rotation #1486

@brendancol

Description

@brendancol

Context

An accuracy pass over xrspatial/geotiff/ turned up two correctness gaps, both in the read path. Filing together since the fix surface is small.

Partial-tile shape validation

_decode_strip_or_tile decompresses tile/strip bytes and reshapes straight to (height, width). If a TIFF is corrupt (truncated deflate stream) or a compressor misbehaves and produces too few or too many bytes, numpy.reshape raises ValueError: cannot reshape array of size N into shape (h, w). That message tells you nothing about which tile broke or what size was expected.

Note the legitimate case this should NOT break: a valid edge tile decompresses to the full tile_height x tile_width and we slice the top-left actual_h x actual_w. That has to keep working.

Fix: check chunk.size == expected before reshape and raise a ValueError naming the size mismatch.

ModelTransformationTag rotation/skew

_extract_transform() reads tag 34264 (4x4 affine matrix) and pulls M[0], M[5] for pixel sizes and M[3], M[7] for origin. Fine for axis-aligned transforms, but rotation (M[1], M[4]) and 3D coupling (M[2], M[6]) get dropped silently. A rotated GeoTIFF round-trips with corrupted coordinates and no warning to the caller.

Fix: detect non-zero rotation/skew and raise NotImplementedError pointing at ModelTransformationTag. Axis-aligned case keeps working.

Out of scope

The audit also flagged a possible MinIsWhite + windowed-read interaction (inversion seeing padded pixels). On close reading, the windowing path clamps r0/c0/r1/c1 to image bounds before allocating the output, so the result shape always matches the in-bounds region. No padding reaches the inversion. Dropping it.

Tests

  • Truncated deflate stream raises ValueError with expected and actual sizes in the message.
  • ModelTransformationTag with rotation raises NotImplementedError.
  • Axis-aligned ModelTransformationTag (no PixelScale present) still extracts origin and pixel sizes correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions