Codebase audit improvements + programmatic before/after previews for all operations#6
Merged
Merged
Conversation
- Port rgb_to_hsv/hsv_to_rgb to pure NumPy (bit-identical to the matplotlib implementation) in layeris.color.hsv; matplotlib was a ~40MB install pulled in for those two functions only - Harden LayerImage.from_url: request timeout + raise_for_status so HTTP errors fail clearly instead of as image-decoding errors - Apply EXIF orientation on load so photos open upright - Validate constructor input (float dtype, HxWx3|4 shape), blend opacity range, curve channels/control points, and resize dimensions with actionable error messages - Support #rgb shorthand hex colours and reject malformed hex strings - Use Image.Resampling.LANCZOS (Pillow>=9.1) instead of deprecated alias - Add __repr__, simplify channel_adjust via ND np.interp - Add [dev] extra (README referenced it but it did not exist), refresh stale requirements.txt (pinned 2019 versions), bump version to 0.4.0 - Extend test suite from 141 to 187 tests covering all of the above Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHVMC2EHFz4h5oiFTuD2Hs
- scripts/generate_previews.py renders a side-by-side before/after JPEG for every operation (9 adjustments, 14 blend modes, chaining) using layeris itself; one operations table drives the images, the docs/index.html static gallery (GitHub Pages ready via /docs), and the README markdown (--markdown) - Previews use the original demo photo and the old README's blend colours; darken-group modes apply to a grayscale base as in the original samples; output is deterministic - GitHub Actions workflow runs the test matrix (3.10-3.13) plus a preview-generation smoke test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHVMC2EHFz4h5oiFTuD2Hs
The operation gallery section is emitted by scripts/generate_previews.py --markdown, so snippets, descriptions and images stay in sync with the generator. Also documents the [dev] extra, the lighter dependency footprint, and how to publish the docs gallery with GitHub Pages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KHVMC2EHFz4h5oiFTuD2Hs
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.
Summary
This PR delivers a codebase audit with fixes, and restores the old README's before/after sample images — now generated programmatically for every operation.
Audit improvements
layeris.color.hsvnow provides pure-NumPyrgb_to_hsv/hsv_to_rgbthat are bit-identical to matplotlib's implementations (verified on random and adversarial inputs). Runtime deps are now just NumPy, Pillow, Requests.from_urlhardening: request timeout +raise_for_status(), so a 404 raises a clearHTTPErrorinstead of a cryptic image-decoding failure.opacitymust be in [0, 1];curvevalidates channel letters and control-point count;resizerejects non-positive sizes; malformed hex colours raiseValueError(and#rgbshorthand is now supported).[dev]extra that the README referenced but didn't exist; refreshedrequirements.txt(was pinned to 2019 versions inconsistent withpyproject.toml); replaced the deprecatedImage.LANCZOSalias; version bumped to 0.4.0.Programmatic before/after previews
scripts/generate_previews.pyregenerates the whole gallery deterministically withpython scripts/generate_previews.py. A single operations table drives:docs/previews/*.jpg— 24 side-by-side before/after composites (left = input, right = result), one per operation: 9 adjustments, all 14 blend modes, and a chained pipeline;docs/index.html— a static gallery page, ready for GitHub Pages (enable Settings → Pages → Deploy from a branch →/docs);--markdown), so snippets, descriptions, and images can't drift apart.Test plan
pytest— 187 passed (run with matplotlib uninstalled to prove the dependency is gone)matplotlib.colorson random arrays, primaries, grays, and boundary valuespython scripts/generate_previews.pyrun twice — byte-identical output (deterministic)docs/index.htmlrendered in headless Chromium and visually inspectedpull_requestevents run it immediately)🤖 Generated with Claude Code
https://claude.ai/code/session_01KHVMC2EHFz4h5oiFTuD2Hs
Generated by Claude Code