Parent: #129. First issue in the F14.1 foundation batch.
Scope
Add the image-decoding and area-sampling boundary that turns a local source image into a small deterministic grid before palette reduction.
Implementation
- Add a focused module under
src/services/paint-by-number/.
- Accept
ImageData plus a target long-side size; keep file decoding in a thin browser adapter.
- Preserve source aspect ratio and produce integer width/height of at least 1.
- Average every source region that contributes to a destination cell.
- Preserve hard transparency: cells below the documented alpha threshold become transparent.
- Keep the sampling result independent from palette selection.
Acceptance
- Landscape, portrait, square, one-pixel, and partially transparent inputs produce expected dimensions and pixels.
- The same input always produces byte-identical output.
- Tests exercise non-integer downscale factors.
- No palette, project, persistence, or UI code is introduced.
Verification
- Targeted Vitest coverage
npm run lint
git diff --check
Parent: #129. First issue in the F14.1 foundation batch.
Scope
Add the image-decoding and area-sampling boundary that turns a local source image into a small deterministic grid before palette reduction.
Implementation
src/services/paint-by-number/.ImageDataplus a target long-side size; keep file decoding in a thin browser adapter.Acceptance
Verification
npm run lintgit diff --check