feat(sharp): EXIF auto-orient, .extend(), .trim(), .composite()#5455
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (10)
✅ Files skipped from review due to trivial changes (5)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughVersion bumped to ChangesSharp: EXIF auto-orient, extend, trim, composite
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Comment |
Pure-Rust sharp parity additions (no libvips):
- EXIF auto-orient: read Orientation (1-8) at load via kamadak-exif, store on
the handle. .autoOrient() applies the rotate/flip and clears it; .rotate()
with no angle (NaN arg) also auto-orients. Loaders unified so file & Buffer
inputs share the EXIF path (from_file/from_buffer delegate to
open_image_path/decode_image_bytes).
- .extend({top,bottom,left,right,background}) pads with a {r,g,b,alpha} colour
(default opaque black).
- .trim() auto-crops a uniform border (top-left pixel, tolerance 10).
- .composite([{input,top,left}]) overlays layers (path/Buffer) with alpha
blend, walking the JS array of layer objects at the ext boundary.
All wired end-to-end (media.rs rows, stdlib_ffi decls, entries.rs manifest,
fluent-chain allowlist) + docs regen (2810->2814).
Validated: orientation-6 jpeg -> 4x6 via autoOrient & rotate(); no-EXIF png
unchanged; extend 8x8 -> 14x12; trim round-trip (white-border extend then trim
-> 8x8); composite -> valid png; full autoOrient->resize->extend->jpeg->toBuffer
chain. perry-ext-sharp 9/9 unit tests.
cad035b to
c1bd787
Compare
- .avif(quality): AVIF output via image's `avif` feature (pure-Rust ravif/rav1e).
Encode-only — AVIF decode needs C dav1d, kept out for the static-binary model.
- encode_to_vec helper honours quality for JPEG (JpegEncoder::new_with_quality)
and AVIF (AvifEncoder::new_with_speed_quality); fixes the pre-existing gap where
.jpeg(q) quality was ignored by the default write_to path. toFile encodes by the
output path extension (so .toFile('x.avif') works) and honours quality.
Wired end-to-end (media.rs row, stdlib_ffi decl, entries.rs manifest, fluent
allowlist) + docs regen. Validated: .avif().toBuffer() -> AVIF ftyp/avif box;
.toFile('x.avif') -> valid AVIF (ISO Media); jpeg quality affects size; 9/9 tests.
Stacked on the EXIF/extend/trim/composite branch (#5455).
…5456) - .avif(quality): AVIF output via image's `avif` feature (pure-Rust ravif/rav1e). Encode-only — AVIF decode needs C dav1d, kept out for the static-binary model. - encode_to_vec helper honours quality for JPEG (JpegEncoder::new_with_quality) and AVIF (AvifEncoder::new_with_speed_quality); fixes the pre-existing gap where .jpeg(q) quality was ignored by the default write_to path. toFile encodes by the output path extension (so .toFile('x.avif') works) and honours quality. Wired end-to-end (media.rs row, stdlib_ffi decl, entries.rs manifest, fluent allowlist) + docs regen. Validated: .avif().toBuffer() -> AVIF ftyp/avif box; .toFile('x.avif') -> valid AVIF (ISO Media); jpeg quality affects size; 9/9 tests. Stacked on the EXIF/extend/trim/composite branch (#5455). Co-authored-by: Ralph Küpper <ralph2@skelpo.com>
PR 1 of 2 in the next sharp batch — pure-Rust (no libvips), keeping Perry's static-binary model. Builds on #5444/#5445/#5448. (PR 2 will add AVIF encode + SVG rasterization, which pull heavier deps.)
EXIF auto-orient
The orientation tag (1–8) is read at load (
kamadak-exif) and stored on the handle..autoOrient()applies the rotate/flip so pixels are upright, then clears the tag..rotate()with no angle also auto-orients (classic sharp behavior; a missing arg arrives as NaN).A 6×4 JPEG tagged orientation-6 → upright 4×6; images without EXIF are unchanged.
.extend({ top, bottom, left, right, background })Pads the image with a background colour (
{ r, g, b, alpha }, r/g/b 0–255, alpha 0–1; default opaque black)..trim()Auto-crops a uniform border, detected from the top-left pixel with sharp's default colour tolerance (10).
.composite([{ input, top, left }, …])Overlays layers (each
inputa path or Buffer) onto the base with alpha blending, walking the JS array of layer objects at the ext-crate boundary (js_array_length/js_array_get+ per-element field reads).Wiring & cleanup
All four wired end-to-end (dispatch rows in
native_table/media.rs, FFI decls, manifest entries, fluent-chain allowlist). Loaders unified so file and Buffer inputs share the EXIF-reading path —js_sharp_from_file/from_buffernow delegate toopen_image_path/decode_image_bytes.Validation
.autoOrient()and.rotate()both turn the orientation-6 JPEG into 4×6; no-EXIF PNG stays 8×8..extend()grows 8×8 → 14×12..trim()round-trip: extend a white border then trim back to exactly 8×8 (proves both extend's background fill and trim's border detection/crop)..composite()overlay → valid PNG; fullautoOrient→resize→extend→jpeg→toBufferchain works.perry-ext-sharpunit suite 9/9 (incl. new orientation-transform tests); API docs regenerated (2810→2814 entries).Not in this PR
imagecrate has no animated-WebP encoder; true animation is a much larger lift than AVIF/SVG, so it's deliberately out (would need a different codec path).perry-stdlib/src/sharp.rs— on inspection it's still compiled into the defaultfullfeature set (only stripped at link time by the well-known flip), so removing it is a feature-graph change that deserves its own link-validated PR rather than riding along here.Summary by CodeRabbit
.autoOrient()), automatically reading and applying orientation metadata..extend()using RGBA background color..trim()to crop uniform borders..composite()with alpha-blended overlays (supports inputs from paths or buffers)..rotate()now auto-applies EXIF orientation when called without a valid angle (matching sharp behavior).autoOrient,extend,trim, andcomposite.