Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
youknowriad opened this issue Oct 5, 2023 · 20 comments
Open

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

youknowriad opened this issue Oct 5, 2023 · 20 comments
Labels
[Block] Image Affects the Image Block Needs Design Feedback Needs general design feedback. Needs Design Needs design efforts. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts

Comments

@youknowriad
Copy link
Contributor

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 youknowriad added Needs Design Needs design efforts. Needs Dev Ready for, and needs developer efforts [Block] Image Affects the Image Block labels Oct 5, 2023
@m
Copy link

m commented Oct 5, 2023

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.

@youknowriad youknowriad changed the title Image block: Consider add a button to compress the image size. Image block: Consider adding a button to compress the image size. Oct 5, 2023
@annezazu annezazu added the [Type] Performance Related to performance efforts label Oct 5, 2023
@ntsekouras
Copy link
Contributor

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.

@youknowriad
Copy link
Contributor Author

@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

@felixarntz
Copy link
Member

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.

@jameskoster
Copy link
Contributor

jameskoster commented Oct 6, 2023

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 jameskoster added the Needs Design Feedback Needs general design feedback. label Oct 6, 2023
@youknowriad
Copy link
Contributor Author

@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
Copy link
Contributor Author

@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)

@swissspidy
Copy link
Member

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.

@ntsekouras
Copy link
Contributor

ntsekouras commented Oct 9, 2023

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..

@youknowriad
Copy link
Contributor Author

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)

@ntsekouras
Copy link
Contributor

ntsekouras commented Oct 9, 2023

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.

@youknowriad
Copy link
Contributor Author

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.

@swissspidy
Copy link
Member

@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.

@adamsilverstein
Copy link
Member

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?)

@m
Copy link

m commented Oct 10, 2023

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.

@swissspidy
Copy link
Member

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

optimize-existing-media.mov

Preferences to select preferred image format etc.

Media preferences modal in the block editor

Automatic Poster Generation

Screen.Recording.2023-10-11.at.20.28.09.mov

Preview image generation for PDFs

Screen.Recording.2023-10-11.at.20.26.38.mov

Converting GIFs to Videos

Screen.Recording.2023-10-11.at.20.31.20.mov

Mute videos by removing audio channel completely

Screen.Recording.2023-10-11.at.20.32.24.mov

Record yourself via webcam & upload the video

Screen.Recording.2023-10-11.at.20.37.07.mov

Improved media placeholders

Block sidebar controls showing BlurHash and dominant color of a video

@youknowriad
Copy link
Contributor Author

@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?

@swissspidy
Copy link
Member

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.

@ntsekouras
Copy link
Contributor

@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..

@jameskoster
Copy link
Contributor

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 #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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Image Affects the Image Block Needs Design Feedback Needs general design feedback. Needs Design Needs design efforts. Needs Dev Ready for, and needs developer efforts [Type] Enhancement A suggestion for improvement. [Type] Performance Related to performance efforts
Projects
None yet
Development

No branches or pull requests

9 participants