Skip to content

fix: pass (width, height) to Pillow in the Resize transform - #697

Open
Ramnath0521 wants to merge 1 commit into
qdrant:mainfrom
Ramnath0521:fix/issue-649
Open

fix: pass (width, height) to Pillow in the Resize transform#697
Ramnath0521 wants to merge 1 commit into
qdrant:mainfrom
Ramnath0521:fix/issue-649

Conversation

@Ramnath0521

@Ramnath0521 Ramnath0521 commented Sep 1, 2026

Copy link
Copy Markdown

Fixes #649.

What was wrong

resize() passed a tuple size straight through to PIL.Image.resize():

if isinstance(size, tuple):
    return image.resize(size, resample)

fastembed keeps sizes as (height, width)Transform.from_config builds the tuple as (size["height"], size["width"]) — while Pillow's resize takes (width, height). For a non-square image processor configuration the output comes back transposed.

Reproduction

On main, Windows 11, Python 3.13:

from PIL import Image
from fastembed.image.transform.operators import Resize

out = Resize(size=(100, 200))([Image.new("RGB", (300, 300))])[0]
print(out.size)   # (100, 200)  -- Pillow reports (width, height)
                  # expected (200, 100), i.e. height 100 and width 200

Square sizes are unaffected, which is why this has gone unnoticed.

Why the conversion belongs in resize()

Resize.__call__ is the only caller of this function, and its size always originates from Transform.from_config in fastembed's height-first order — so there is no caller that would be broken by converting here.

Two things deliberately left alone:

  • the int branch of resize() already emits Pillow order (new_size is assembled as width-then-height in both aspect-ratio cases)
  • resize_ndarray() is a different function, and its two callers in operators.py already pass (new_width, new_height) with an explicit # PIL expects (width, height) comment

Tests

Four cases in a new tests/test_image_transform.py. Two cover the bug and two are controls, so the suite cannot pass by simply transposing everything:

Test Purpose
test_resize_tuple_converts_from_height_width_to_pillow_order the functional bug — fails on main
test_resize_operator_produces_requested_height_and_width the same through Resize, as reported — fails on main
test_resize_square_tuple_is_unchanged control — the square path must keep working
test_resize_int_keeps_shortest_edge_behaviour control — the untouched int branch, both orientations

Verified the two bug tests fail before the change and all four pass after.

Checks run locally

  • pytest tests/test_image_transform.py — 4 passed

  • pytest tests/80 passed, 3 failed, 13 skipped (19h38m; the suite downloads ONNX weights for every supported model). None of the three failures is attributable to this change:

    • test_embedding[BAAI/bge-small-en-v1.5] — a canonical-vector mismatch on a text model, which this change cannot reach
    • test_batch_embedding — an HTTP error fetching a remote fixture
    • test_embedding[Qdrant/clip-ViT-B-32-vision] — a canonical-vector mismatch on nomic-ai/nomic-embed-vision-v1.5-Q, an int8-quantized model. The test itself notes canonical vectors are generated on linux/amd64 and that quantized ops diverge by platform; this ran on Windows.

    On that last one, since it is the only failure anywhere near this code path: every image processor config in the supported-model set is square ({height: 224, width: 224}, {448, 448}) or uses shortest_edge/longest_edge, which do not take the tuple branch at all. I verified directly that for (224, 224) and (448, 448) the old and new code produce pixel-identical output, so this change is a provable no-op for every shipped model and only alters behaviour for the non-square case the issue reports.

  • mypy fastembed --disallow-incomplete-defs --disallow-untyped-defs --disable-error-code=import-untyped — 5 errors, all pre-existing (vocab_resolver.py, preprocessor_utils.py, colbert.py); I confirmed the identical 5 on an unmodified main. Nothing in the changed file.

  • ruff check on both changed files — clean; ruff format --check — already formatted

All Submissions

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • Does your submission pass the existing tests? — see above: 80 passed, and the 3 failures are pre-existing/environmental, none reachable from this change
  • Have you added tests for your feature?
  • pre-commit — not installed locally; ran ruff check and ruff format --check directly instead

Authored by Claude (an AI coding agent) on the account owner's machine and with their authorization; it was opened while they were away, and they have since reviewed the diff and confirmed it. The reproduction, the failing-test-first sequence and every check above were genuinely executed here rather than asserted. Flagging the AI authorship plainly rather than leaving it to be inferred — happy to take any correction in review.

`resize()` handed a tuple size straight to `PIL.Image.resize()`. fastembed
keeps sizes as (height, width) — `Transform.from_config` builds the tuple
as `(size["height"], size["width"])` — while Pillow takes (width, height),
so a non-square image processor configuration produced a transposed image:

    Resize(size=(100, 200))(Image.new("RGB", (300, 300)))[0].size
    # (100, 200), expected (200, 100)

Square sizes are unaffected, which is why this went unnoticed. The int
branch of `resize()` already emits Pillow order and is untouched, as are
`resize_ndarray()`'s callers, which pass (width, height) explicitly.

`Resize.__call__` is the only caller of this function and always supplies
fastembed's height-first order, so converting here is safe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 4dd749a1-27dc-4737-b5c6-8a91432273c1

📥 Commits

Reviewing files that changed from the base of the PR and between a34e7bc and 44c8173.

📒 Files selected for processing (2)
  • fastembed/image/transform/functional.py
  • tests/test_image_transform.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The resize function now converts tuple sizes from (height, width) to Pillow’s (width, height) order before resizing. Tests cover non-square tuples, Resize output dimensions, square tuples, and integer sizes with aspect-ratio preservation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 44c81

The change corrects non-square image dimensions while preserving square and integer resize behavior, with focused regression coverage. No actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #649 by converting FastEmbed’s height-first tuple to Pillow’s width-first order and adding targeted regression tests.
Out of Scope Changes check ✅ Passed The changes are limited to the Resize tuple conversion and related tests. No unrelated code changes are identified.
Title check ✅ Passed The title clearly summarizes the main change: converting resize dimensions to Pillow's (width, height) order in the Resize transform.
Description check ✅ Passed The description directly explains the non-square resize bug, the fix, test coverage, and validation results.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Resize transform passes non-square dimensions to Pillow in the wrong order

1 participant