Repository navigation
Client-side media: process image edits (crop, rotate, flip) with wasm-vips instead of the server /edit endpoint #82358
Description
What problem does this address?
Image edits made in the editor (crop, rotate, flip) are still processed on the server. Both the block editor's image editor and the new media editor modal build a modifiers array and POST it to the media/<id>/edit REST endpoint, where PHP applies the edits with GD or ImageMagick:
- https://github.com/WordPress/gutenberg/blob/03bab588063/packages/block-editor/src/components/image-editor/use-save-image.js#L89-L96
- https://github.com/WordPress/gutenberg/blob/03bab588063/packages/media-editor/src/components/media-editor-modal/build-modifiers.ts#L78-L82
- https://github.com/WordPress/gutenberg/blob/03bab588063/packages/core-data/src/private-actions.js#L91-L98
Meanwhile, uploads already go through client-side media processing (wasm-vips), which handles the same operations and preserves things the server pipeline drops. That mismatch causes real bugs: cropping or flipping an HDR JPEG strips its gain map and the result is SDR, see #82295. As noted in that thread, GD and ImageMagick are gaining gain map support but it is behind build-time flags and will take a long time to reach most hosts. libvips ships with WordPress today via client-side media, so moving the edit step to the client is the practical path.
What is your proposed solution?
Move crop / rotate / flip processing to the client when client-side media processing is available, and upload the result through the existing upload pipeline instead of calling the /edit endpoint.
Rough sketch:
- When the user saves an edit, fetch the original (full size) file for the attachment rather than the size shown in the editor.
- Apply the modifiers with wasm-vips. The
@wordpress/vipspackage already has the building blocks:cropwith gain map handling (https://github.com/WordPress/gutenberg/blob/03bab588063/packages/vips/src/index.ts#L369-L400), androtateImagecovers rotation and horizontal / vertical flips (https://github.com/WordPress/gutenberg/blob/03bab588063/packages/vips/src/index.ts#L803). - Hand the resulting file to the upload-media store so sub-sizes are generated client-side and uploaded the same way a fresh upload is, then swap the block's
id/urlto the new attachment. - Fall back to the current
/editrequest when client-side processing is unavailable or fails for the file type.
Design Decisions:
- When creating the cropped images match how the Gutenberg image editor creates them, creating a new media item
- Always use/fetch the original image to apply crops.
- A single helper that turns modifiers into vips operations
- Undo behaves as currently - it points the block back at the old id / url
- E2E tests confirm the cropping tool (+rotate/flop) work exactly as expected and that gain maps are preserved
cc: @andrewserong @ramonjd @swissspidy @gregbenz
AI Use
Description by myself and Claude Code, from the discussion on #82295 and a read through the current edit and vips code paths.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fields🏗️ In Progress
Activity
swissspidy commentedon Sep 2, 2026
This makes a lot of sense!
andrewserong commentedon Sep 2, 2026
+1 thanks for capturing this and digging in! It'll also be a good thing to pursue for the future extensibility of the media editor, too, so touching on some of the ideas raised in #79175. TL;DR: to support things like color filters, AI tools and whatnot that will output an image client-side and require uploading to the server, instead of using the
/editendpoint.Also, I've already commented on the PRs but just crossing linking another PR that relates to tracking the original crop, as we look at ensuring the REST API supports both the client-side approach, and future "restore to original" / browsing behaviour for crops of a particular attachment: