Skip to content

One fast resampling path, shared 8-bit alpha helpers - #72

Merged
matmen merged 1 commit into
masterfrom
cleanup
Oct 16, 2026
Merged

matmen merged 1 commit into
masterfrom
cleanup

Conversation

@matmen

@matmen matmen commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

This PR cleans up the fast resampling from #71 and the 8-bit alpha code it duplicated from blur().

Changes

  • One fast path: resampleOpaqueFast and resampleTransparentFast are merged into resampleFast.
    • The red+blue and green+alpha lanes work for opaque pixels as well. Alpha stays exactly 255, because the weights sum to 256.
    • The function is split into verticalFast and horizontalFast.
    • Opacity is still detected without an extra scan: first the first and last rows are checked, then the vertical pass ANDs the pixels together. If it finds transparency in the middle of the image, the vertical pass runs again on premultiplied pixels.
  • Shared helpers in src/util/alpha.ts:
    • isOpaque, premultiply8, unpremultiply8, and a single littleEndian flag.
    • Used by both resample and blur.
    • unpremultiply8 uses a 64K lookup table that rounds like the clamped arrays, so blur() gives the same results as before.
  • blur()'s 8-bit path now explicitly requires little endian, because the helpers work on 32-bit words. On big-endian machines it falls back to the float path.

Verified

  • blur() is bit-identical to master on 1313 corpus images, 5 sigmas each, with and without alpha.
  • Resizing matches master except where unpremultiplying lands exactly on .5. That affects 0.003–0.007% of the values, by 1, and only in the unreleased fast path for transparent images.
  • tests/resize.js adds an image whose only transparent pixel is in the middle, which exercises the rerun path.

Speed (resize() of a 1920×1080 photo, master → this PR)

opaque alpha 200
halving 12.8 → 12.6 ms 24.0 → 24.2 ms
doubling 63.2 → 63.9 ms 117 → 103 ms

🤖 Generated with Claude Code

https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ

- resampleOpaqueFast and resampleTransparentFast become one resampleFast
  (red+blue and green+alpha lanes work for opaque pixels too), split into
  a vertical and a horizontal pass. Transparency in the middle of an image
  is found by the vertical pass, which then reruns premultiplied.
- src/util/alpha.ts: isOpaque, premultiply8 and unpremultiply8 (lookup
  table, rounding like the clamped arrays), used by resample and blur;
  one littleEndian flag.
- Blur results are unchanged (corpus). Fast resizing of transparent images
  differs by 1 only where unpremultiplying hits exactly .5 (0.003-0.007% of
  the values). Doubling a photo with alpha: 117 -> 103 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ
@matmen
matmen merged commit ecb3317 into master Oct 16, 2026
13 checks passed
@matmen
matmen deleted the cleanup branch October 16, 2026 17:48
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.

1 participant