gutenberg icon indicating copy to clipboard operation
gutenberg copied to clipboard

Image block: Consider adding a button to compress the image size.

Open youknowriad opened this issue 2 years ago • 21 comments

Users often have to use online services like https://imagecompressor.com or alternatives to optimize their images. It would be great to explore offering a button (or something like that) right in the image block to compress uploaded images.

We don't need to invent anything, there's a number of libraries that provide compression APIs like https://www.npmjs.com/package/compressorjs

Maybe we could suggest an optimal quality and allow the users to tweak the number to avoid compression quality loss.

youknowriad avatar Oct 05 '23 19:10 youknowriad

More generally, given the capabilities of clients and the distributed processing power they have (vs the hosts) what can we do client-side to make this as performant as possible.

m avatar Oct 05 '23 20:10 m

So, this should be a default compression for all images, or a setting(attribute) in Image block to compress existing files or probably pass a flag to media upload, when we're in a placeholder state?

If we go with block level support, it means we should implement this to many more blocks, and also users would have to adjust the quality setting each time, for every block.

ntsekouras avatar Oct 06 '23 07:10 ntsekouras

@ntsekouras I see it as a setting per image but not really a persistent attribute, you decide to compress the image which would update the image if already uploaded or pick a compression factor before upload.

Developing it as block support is not mandatory IMO

youknowriad avatar Oct 06 '23 07:10 youknowriad

This sounds like a great idea to me, and it would tremendously help image performance to have it tightly integrated into right the UI where the user is uploading the image.

If we want to allow users to tweak the compression level per uploaded image, I would suggest that the value chosen, despite not being persistent on the block, is stored persistently as a user preference (i.e. in WordPress user options) so that the compression level that the user chooses effectively becomes the default/initial state for any subsequent images they upload.

felixarntz avatar Oct 06 '23 15:10 felixarntz

There could be quite a few moving parts to consider here, and I'm not sure what the scope for the first iteration should look like, so consider this a first draft of a potential design to kick-off discussion:

Compress
  • A "Compress attachments" section is added to the Advanced panel of any block that includes an image, IE; Image, Cover, Site Logo, Media & Text, Group (when a background image is applied), etc.
  • Clicking the "Compress" icon button opens a modal where the user can configure the compression. Additional affordances like a comparison/preview could be added to the modal in the future. I acknowledge that it might be beneficial to make these decisions on the users behalf in which case we can skip the modal entirely to begin with.
  • After clicking "Compress" the file size in the Advanced panel is replaced with a spinner while the compression takes place.

In the future this pattern could theoretically scale-up to entertain multiple files and bulk compression, for example when a Gallery block is selected, or even at the document level:

Multi-compress

Details like copy and icons can be refined once we decide on a general direction.

jameskoster avatar Oct 06 '23 16:10 jameskoster

@jameskoster Designs look good. Do you think this belongs to the "Advanced" section for blocks or should it be more prominent, like a button in the block toolbar or a dedicate section outside "Advanced".?

youknowriad avatar Oct 06 '23 16:10 youknowriad

@tyxla @jsnajdr While a bit out of scope of the current issue, this feels like a great opportunity to explore "JS lazy loading". The compressor library could be an esm module that you load through the import map API. (Obviously not something that needs to be done in the initial implementation)

youknowriad avatar Oct 06 '23 16:10 youknowriad

FWIW I built a plugin that does this kinda stuff already, using all sorts of WASM stuff. Planning on open sourcing it soon. It could easily be merged into Gutenberg.

swissspidy avatar Oct 06 '23 16:10 swissspidy

I think there are some more nuances here.

  1. If we do it in block level(ex Image block) in an already uploaded image, there would be no good way to seamlessly replace the image in all places it's being used(unless I'm missing something in the REST API). What this means is, we have to delete(?) the current image and upload a compressed one. If we delete the image, other blocks that use that image will break. If we replace that image with a new compressed one and keep the old version, we have the risk of multiple compressed images of the same source.
  2. Probably we would need to keep some meta(compression factor) on the image to avoid showing the compress button with an already compressed image with the same factor.

@swissspidy does your plugin handle the above replacement case? I'm curious because you say WASM and I expect some PHP to be there..

ntsekouras avatar Oct 09 '23 07:10 ntsekouras

If we do it in block level(ex Image block) in an already uploaded image, there would be no good way to seamlessly replace the image in all places it's being used(unless I'm missing something in the REST API). What this means is, we have to delete(?) the current image and upload a compressed one. If we delete the image, other blocks that use that image will break. If we replace that image with a new compressed one and keep the old version, we have the risk of multiple compressed images of the same source.

Don't we have a PUT support in the media endpoint? (updating the files but keeping the same names, urls, ids)

youknowriad avatar Oct 09 '23 09:10 youknowriad

Don't we have a PUT support in the media endpoint? (updating the files but keeping the same names, urls, ids)

No and in general I think WP REST API only uses POST for updates(doesn't really matter in our case though). I looked a bit at the core attachment controller now and it doesn't seem to handle such a case internally.

ntsekouras avatar Oct 09 '23 09:10 ntsekouras

We do have a "put" (update media) endpoint https://developer.wordpress.org/rest-api/reference/media/#update-a-media-item It's not clear from the docs whether it allows updating the file itself or just the other properties, if it's not possible, It would be a good addition IMO.

youknowriad avatar Oct 09 '23 09:10 youknowriad

@ntsekouras Yes there‘s also a lot of PHP of course.

You don‘t want to override or delete the original image to prevent data loss and in case the user wants to revert the changes. So you need to upload a new one, mark it as compressed/optimized, and add a way to connect/link it with the original. My solution does all that. Let me prepare a demo for you all this week.

swissspidy avatar Oct 09 '23 09:10 swissspidy

We don't need to invent anything, there's a number of libraries that provide compression APIs like npmjs.com/package/compressorjs

Also worth looking at https://github.com/kleisauke/wasm-vips (maybe that is what @swissspidy's plugin already leverages?)

adamsilverstein avatar Oct 09 '23 15:10 adamsilverstein

It's worth also making sure we say how big the image is, and then we can show the before and after in size and quality.

m avatar Oct 10 '23 01:10 m

So I wasn't planning on making this public until it was more published, but feel free to check out my media experiments repository here: https://github.com/swissspidy/media-experiments

The readme contains more information about the things I've built already and what I've planned on adding, like bulk optimization. I should be able to get to that soon though.

In the meantime, feel free to reach out to me on Slack if you have any questions.

Here are some demo videos:

Demos

Optimize (compress) an existing image/video

https://github.com/swissspidy/media-experiments/assets/841956/af783b3d-e7f4-425f-8de7-23a63dc2b9f9

Preferences to select preferred image format etc.

Media preferences modal in the block editor

Automatic Poster Generation

https://github.com/swissspidy/media-experiments/assets/841956/ba082f49-145e-441e-89c5-a63acdd039bd

Preview image generation for PDFs

https://github.com/swissspidy/media-experiments/assets/841956/f26b4f7d-f60b-4177-b8d0-b79d12c8863b

Converting GIFs to Videos

https://github.com/swissspidy/media-experiments/assets/841956/df3343e5-6e49-44da-bb45-9f6f43f92665

Mute videos by removing audio channel completely

https://github.com/swissspidy/media-experiments/assets/841956/2a9b566f-58ec-4256-b820-c7443fc53301

Record yourself via webcam & upload the video

https://github.com/swissspidy/media-experiments/assets/841956/dd4ad5ed-8374-48f2-8223-9ed856b590b4

Improved media placeholders

Block sidebar controls showing BlurHash and dominant color of a video

swissspidy avatar Oct 11 '23 18:10 swissspidy

@ntsekouras @swissspidy This is really cool, how do you think we can move forward now? Can we transform this to a Gutenberg PR or something?

youknowriad avatar Oct 12 '23 14:10 youknowriad

Probably best to start by discussing this more in the #core-editor chat, as there is a lot to unpack and many things to be considered. My plugin barely scratches the surface of what can be done and goes way beyond what has been originally proposed in this issue here.

In my experience (I have been working with this kind of stuff for multiple years now), something like compressorjs (which just uses canvas.toBlob() is not nearly enough to accomodate all requirements and browser inconsistencies (e.g. Safari doesn't support quality or image/webp).

I would love if my plugin ends up in Gutenberg eventually, but it's not quite there yet. I suggest checking it out a bit more closely and giving it a try yourself.

swissspidy avatar Oct 12 '23 15:10 swissspidy

@swissspidy your plugin seems to do lots of cool stuff 🚀 . Do you think it would be possible to extract something minimal to include in GB and iterate? For example just the image compression without file type conversion etc..

ntsekouras avatar Oct 12 '23 16:10 ntsekouras

Do you think this belongs to the "Advanced" section for blocks or should it be more prominent, like a button in the block toolbar or a dedicate section outside "Advanced".?

I suggest the Advanced panel because it's the only one that exists for all blocks that might use this affordance. This makes the placement consistent across.

I'd welcome more thoughts, but if the plan is to have a global default 'quality' setting for all uploaded media, then I don't know that this needs to be more prominent. To me it feels like something you'd generally set-and-forget, and the tool in the Advanced panel caters to the edge cases.

It might be useful to have a filterable threshold value, and alert the user somehow (potentially something like https://github.com/WordPress/gutenberg/issues/41747) if an image breaches it, similar to the color contrast warnings.

Including a preview with size details in the modal (as per @swissspidy's plugin) would be neat. Especially if it can update dynamically as you adjust the quality value.

jameskoster avatar Oct 16 '23 11:10 jameskoster

This looks like it has design and that just having the design feedback label would be a more appropriate state, so for now let's just have that here. We can always apply that label back. The key is to get some feedback and not feel it's waiting to have a design made.

karmatosed avatar May 31 '25 09:05 karmatosed