Skip to content

Close the roadmap's remaining known gaps - #73

Open
Joker666 wants to merge 1 commit into
fix/width-height-resizefrom
feat/metadata-and-smart-gravity
Open

Close the roadmap's remaining known gaps#73
Joker666 wants to merge 1 commit into
fix/width-height-resizefrom
feat/metadata-and-smart-gravity

Conversation

@Joker666

@Joker666 Joker666 commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Stack (merge bottom-up)

  1. Restructure processing and service, and close the geometry compatibility gaps #66 Restructure processing and service, and close the geometry compatibility gaps
  2. Process animated sources frame by frame #67 Process animated sources frame by frame
  3. Add the imgproxy delivery layer #68 Add the imgproxy delivery layer
  4. Build the image on Debian trixie for libvips 8.16 #69 Build the image on Debian trixie for libvips 8.16
  5. Correct quality precedence and cache-hit header consistency #70 Correct quality precedence and cache-hit header consistency
  6. Bring the remaining docs up to date #71 Bring the remaining docs up to date
  7. Let width and height fill in a resize the type created #72 Let width and height fill in a resize the type created
  8. Close the roadmap's remaining known gaps #73 Close the roadmap's remaining known gaps
  9. Implement the Pro options that were only ever cheap #74 Implement the Pro options that were only ever cheap
  10. Run the pipeline in imgproxy's stage order #75 Run the pipeline in imgproxy's stage order

Each PR targets the one before it, so its diff shows only its own change. Together they make up the 0.18.0 release.

Stacked on #72. Three entries were left in the roadmap's own "Known gaps" list, one of them flagged there as cheap.

keep_copyright beyond JPEG

libvips' keep flags have no copyright granularity, so retaining the field across a metadata strip means writing it back afterwards. That existed for JPEG only. PNG now gets an eXIf chunk and WebP an EXIF chunk — which also means synthesising the VP8X extended header a simple WebP lacks and the container spec requires before it carries metadata at all.

Both writers replace an existing block rather than appending one. The first attempt appended, and the copyright came back unreadable: a reader takes the first block it finds, and libvips had already written one.

The PNG chunk needs a CRC-32; it is computed bitwise (a copyright string is a few dozen bytes, so a table would cost more than it saves) and checked in a test against the published IEND constant.

Smart gravity

gravity:sm hands the window choice to libvips' smartcrop, which scores the image for the region a viewer's eye would settle on — the one thing a geometric anchor cannot do, and the answer when no fixed anchor is right for every image in a catalogue. It applies to crop and to the implicit crop a fill performs. imgproxy gates this behind its Pro tier.

The roadmap called it the one Pro entry that would be cheap. It was, so leaving it undone was not defensible.

webp_options preset

An unrecognised name was accepted and then dropped on the way to the encoder, so a typo silently produced a different image. It is refused now, like every other bad argument. The suffix builder still matches against the known set rather than interpolating on trust — a preset carrying ],lossless would otherwise close the bracket and set an option the request never asked for.

Notes for review

The smart-gravity tests needed an image with exactly one thing worth looking at; a uniform image gives an attention map indistinguishable from noise. They assert the smart crop is measurably darker than the centre crop, i.e. that it actually found the subject.

Validation

cargo fmt -- --check
cargo clippy --all-targets -- -D warnings
cargo test --all -- --test-threads=1

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eecf92ff79

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/processing/metadata.rs Outdated
let mut header = Vec::with_capacity(body.len() + 18);
header.extend_from_slice(b"VP8X");
header.extend_from_slice(&10u32.to_le_bytes());
header.push(0b0000_1000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve alpha in synthesized VP8X headers

When keep_copyright is used with a transparent lossless WebP whose original container contains only a VP8L chunk, this synthesized VP8X header advertises EXIF but not the alpha feature encoded in the VP8L header. The resulting container has inconsistent feature flags, so strict WebP readers may reject it or treat transparent pixels as opaque. Derive and set the VP8X alpha bit when the VP8L bitstream reports transparency.

Useful? React with 👍 / 👎.

Comment on lines +193 to +196
} else if is_png(&encoded) {
attach_to_png(&encoded, &tiff)
} else if is_webp(&encoded) {
attach_to_webp(&encoded, &tiff)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for attached metadata when enforcing max_bytes

For the newly supported PNG and WebP paths, max_bytes is enforced by the encoder before this post-processing step adds the EXIF chunk. If the bare encode fits the limit but the tagged result does not, the request returns an oversized response even though lowering the encoding quality could have met the limit. Include the attachment overhead in the size loop or re-check the final bytes after attaching.

Useful? React with 👍 / 👎.

@Joker666

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d90d9448df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"soea" => Some(Self::SouthEast),
"sowe" => Some(Self::SouthWest),
"fp" => Some(Self::FocusPoint),
"sm" => Some(Self::Smart),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject smart gravity for canvas extension

When a URL uses extend:true:sm or extend_aspect_ratio:true:sm, the shared gravity parser now accepts it, but both extension paths pass the value to calc_position, where Smart falls through to the center-anchor branch instead of invoking smartcrop. The request therefore succeeds while silently behaving as ce; restrict sm to crop/fill contexts, as is already done for watermark positioning, or define explicit extension semantics.

Useful? React with 👍 / 👎.

@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from d90d944 to e6bad1d Compare August 17, 2026 05:05
@Joker666

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e6bad1d513

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread doc/5_processing_options.md Outdated

- **`strip_metadata`** drops the descriptive tags (EXIF, XMP, IPTC) and leaves the colour profile alone. **`strip_color_profile`** does the reverse. Set both to drop everything.
- **`keep_copyright`** carries the EXIF `Copyright` and `Artist` tags across a `strip_metadata`. libvips has no copyright granularity in its `keep` flags — they are `none|exif|xmp|iptc|icc|other|gainmap|all` — so imgforge reads the two fields from the source and splices a minimal EXIF segment back into the encoded result. That mechanism is JPEG-only; other output formats strip as normal, and the option is a no-op for them.
- **`keep_copyright`** carries the EXIF `Copyright` and `Artist` tags across a `strip_metadata`. libvips has no copyright granularity in its `keep` flags — they are `none|exif|xmp|iptc|icc|other|gainmap|all` — so imgforge reads the two fields from the source and writes a minimal EXIF block back into the encoded result: an APP1 segment for JPEG, an `eXIf` chunk for PNG, and an `EXIF` chunk for WebP, synthesising the extended header WebP needs to carry one. Formats that cannot hold EXIF at all strip as normal, and the option is a no-op for them.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the quick reference for non-JPEG copyright retention

This expanded PNG/WebP support is contradicted by the quick-reference row at line 46, which still states that keep_copyright is JPEG-only. Users relying on the table will incorrectly conclude that the option is a no-op for PNG and WebP, so update that row to match the behavior documented here.

Useful? React with 👍 / 👎.

@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from e6bad1d to 78372c4 Compare August 21, 2026 03:53
@Joker666

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 78372c4be1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 78372c4 to 242c4a0 Compare August 21, 2026 06:26
@Joker666

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 242c4a07f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md Outdated
Comment on lines +69 to +70
`keep_copyright` (`kcr`) carries the EXIF copyright across a metadata strip, for every container that can hold
EXIF: an APP1 segment for JPEG, an `eXIf` chunk for PNG, and an `EXIF` chunk for WebP, synthesising the extended

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Narrow the all-container copyright claim

For strip_metadata:true plus keep_copyright:true with TIFF, AVIF, or HEIF output, these supported containers can carry EXIF, but attach_copyright only handles JPEG, PNG, and WebP and returns the stripped encoding unchanged for every other format. Consequently the new claim that copyright is retained for “every container that can hold EXIF” is false; either add preservation for the remaining EXIF-capable outputs or explicitly limit the claim to the three implemented formats.

Useful? React with 👍 / 👎.

@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 242c4a0 to c2bd8eb Compare August 21, 2026 19:03
@Joker666

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2bd8eb712

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +679 to +680
#[test]
fn test_smart_gravity_finds_the_subject_a_centre_crop_would_miss() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add end-to-end processing integration coverage

These new tests exercise processing helpers directly, but the diff adds no coverage under tests/ for the handler-level behavior introduced here, including smart-gravity URL handling and the PNG/WebP copyright response bytes. That leaves routing, option propagation, HTTP error mapping, and final encoded responses unchecked despite the repository explicitly requiring the extended integration suite to be expanded whenever processing changes.

AGENTS.md reference: AGENTS.md:L21-L21

Useful? React with 👍 / 👎.

@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from c2bd8eb to 79a4df5 Compare August 21, 2026 21:13
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 79a4df5 to 05ef538 Compare August 21, 2026 21:44
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 05ef538 to 11d5dd8 Compare August 21, 2026 23:44
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 11d5dd8 to dcf1a96 Compare August 21, 2026 23:53
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch 2 times, most recently from 22d8559 to c3e549e Compare August 22, 2026 00:19
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from c3e549e to 78b4b0f Compare August 22, 2026 00:26
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from 78b4b0f to a108bcd Compare August 22, 2026 00:36
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from a108bcd to 27376c0 Compare August 22, 2026 00:43
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch 2 times, most recently from cdce7c5 to f9d0905 Compare August 22, 2026 01:01
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from f9d0905 to d97273a Compare August 22, 2026 01:12
Three entries were left in the roadmap's own "Known gaps" list, one of
them flagged there as cheap. They are gone.

keep_copyright now works for every container that can carry EXIF, not
just JPEG: an eXIf chunk for PNG and an EXIF chunk for WebP, which also
means synthesising the VP8X extended header a simple WebP lacks and
libwebp requires before it will carry metadata at all. Both writers
replace an existing block rather than appending one — a reader takes the
first it finds, and the first attempt left the copyright stranded behind
whatever the encoder had already written.

gravity:sm hands the window choice to libvips' smartcrop, for crop and
for the implicit crop a fill performs. The roadmap called this the one
Pro option that would be cheap; it was, so leaving it undone was not
defensible.

An unrecognised webp_options preset is now refused instead of accepted
and then dropped on the way to the encoder, where a typo silently
produced a different image than the URL asked for.
@Joker666
Joker666 force-pushed the feat/metadata-and-smart-gravity branch from d97273a to 45c512a Compare August 22, 2026 01:23
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