Conversation
…s correctly Three defects in the resize path, all reachable from the public API. crop() copies within the caller's own buffer. The comment describes it as a speed and memory optimisation, but `inputPixels` is a Uint32Array view onto the caller's ImageData, so copyWithin writes straight through it - any resize with `fitMethod: 'contain'` destroys the image it was given. The function then slices a copy out anyway, so the aliasing bought nothing. Reproducible on a 4x4 gradient: the caller's first four pixels come back holding the cropped region. Contain fit computes its offsets from the original dimensions but crops `input`, which the hqx branch may already have upscaled by 2-4x, so contain + hqx crops the wrong region. Offsets now come from the image actually being cropped, and are clamped so rounding cannot exceed it. `new Uint8Array(data.data.buffer)` ignores byteOffset and byteLength in three places. An ImageData whose `data` is a view into a larger allocation - tiling, a pooled buffer, anything sliced from a bigger read - silently resizes the wrong bytes. Uint32Array views additionally require 4-byte alignment, so an unaligned source is copied rather than mis-viewed. Also: the resize module is no longer instantiated for magic-kernel-only calls, which never touch it. Adds regression tests for the mutation and the offset view. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011nRtc2GmmpARzSXa2y7ABs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three defects in
@jsquash/resize, all reachable from the public API and all live in the published package.crop() writes through to the caller's ImageData
crop()copies within the caller's own buffer. The comment describes it as a speed and memory optimisation, butinputPixelsis aUint32Arrayview onto the caller'sImageData, socopyWithinwrites straight through it. Any resize withfitMethod: 'contain'destroys the image it was given. The function then slices a copy out anyway, so the aliasing bought nothing.Reproducible on a 4×4 gradient — the caller's own pixels afterwards:
contain + hqx crops the wrong region
Contain fit computes its offsets from the original dimensions but crops
input, which the hqx branch may already have upscaled by 2–4×. Offsets now come from the image actually being cropped, and are clamped so rounding cannot exceed its bounds.byteOffset is ignored in three places
new Uint8Array(data.data.buffer)discardsbyteOffset/byteLength. AnImageDatawhosedatais a view into a larger allocation — tiling, a pooled buffer, anything sliced out of a bigger read — silently resizes the wrong bytes.Uint32Arrayviews additionally require 4-byte alignment, so an unaligned source is copied rather than mis-viewed.Also
The resize module is no longer instantiated for magic-kernel-only calls, which never touch it.
Adds regression tests for the mutation and the offset view. Depends on #108 for green CI.