Skip to content

Fix drawing on I;16B images - #9982

Merged
radarhere merged 12 commits into
python-pillow:mainfrom
akx:draw16
Oct 13, 2026
Merged

radarhere merged 12 commits into
python-pillow:mainfrom
akx:draw16

Conversation

@akx

@akx akx commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

While reworking #9772, I noticed 16bpp drawing was piggybacking on draw8... and then it kind of turned out that not all 16bpp modes were drawing things correctly.

This PR:

  • moves explicit I;16 draw tests into their own file
  • adds (failing) tests covering more draw functions in all of the I;16 modes
  • steals the Bresenham detriplication from Speed up rectangle, polygon and line drawing #9772
  • implements draw16, the suite of point/hline/line functions for 16-bpp images, with some additional twists and turns of big-endian support (which was also incorrect in another special way).

Along with correctness, this should also yield a bit of performance since draw8 functions don't need to do per-pixel checks for the image mode (and the Bresenham de-triplication commit also adds the option to use hline).

Note

This PR now underpins #9772.

Comment thread src/libImaging/Draw.c Outdated
@akx
akx marked this pull request as ready for review September 10, 2026 13:38
@codspeed

codspeed Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 22.75%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
❌ 3 regressed benchmarks
✅ 636 untouched benchmarks
⏩ 338 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ test_draw_lines[1237x811-LA] 430.6 µs 686.9 µs -37.31%
❌ test_draw_lines[1237x811-RGBA] 431.2 µs 687.5 µs -37.28%
❌ test_draw_lines[1237x811-RGB] 442.6 µs 699.5 µs -36.73%
⚡ test_draw_lines[1237x811-L] 911.4 µs 636.7 µs +43.14%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing akx:draw16 (0f1f3d0) with main (9ddcb85)

Open in CodSpeed

Footnotes

  1. 338 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

Comment thread Tests/test_imagedraw_i16.py

@aclark4life aclark4life left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drawing the same shapes on I;16, I;16L, I;16B and I;16N now gives the same pixel values in every mode (on main I;16B differs in about a third of cases 😮) and output for all other modes is unchanged. LGTM

@aclark4life aclark4life added the Bug Any unexpected behavior, until confirmed feature. label Oct 11, 2026
Comment thread src/libImaging/Draw.c
}
} else {
UINT8 *p = im->image8[y0];
while (x0 <= x1) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, why change from while?

@akx akx Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a loop that increments its iterator variable by constant step, I find it reads clearer than a while where I'd need to find how exactly the iterator gets increased.

@akx

This comment was marked as outdated.

Comment thread src/libImaging/Draw.c Outdated
Comment thread src/libImaging/Draw.c Outdated
@radarhere

Copy link
Copy Markdown
Member

I've created akx#37 with a suggestion - you can replace the GEN_LINE define with a function, to remove all those pesky backslashes.

@radarhere radarhere changed the title Implement correct draw functions for 16-bpp modes Fix drawing on I;16B images Oct 13, 2026
@radarhere
radarhere enabled auto-merge (squash) October 13, 2026 10:47
@radarhere
radarhere merged commit 248b971 into python-pillow:main Oct 13, 2026
32 of 61 checks passed
@akx

akx commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Well, looks like some of the latter changes introduced performance regressions for some modes? I could look into that but I can't open new PRs right now due to the repo limit.

EDIT: Yeah, it was 30657fb preventing compilers from inlining the functions. There's an elegant fix (without all those Pesky Backslashes) now in #9772.

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants