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

Add Rich image editing capabilities to Gutenberg #21024

Merged
merged 53 commits into from Jun 2, 2020

Conversation

ajlende
Copy link
Contributor

@ajlende ajlende commented Mar 19, 2020

Description

Copied from #20637
Fixes #13748
Props to @johngodley and @jasmussen for the heavy lifting.

  • Adds new image-editor API endpoints in lib/
  • Adds new "block" that extends image capabilities in the image block

How has this been tested?

  • Add image
  • Click on image and try different editing tools

Screenshots

New toolbar items

image

Zoom crop mode

image

Types of changes

New features: Adds crop, flip, rotate capabilities to images.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@mtias mtias added [Block] Image Affects the Image Block [Feature] Media Anything that impacts the experience of managing media labels Mar 19, 2020
@ajlende ajlende force-pushed the try/13748-rich-image branch 3 times, most recently from 7895448 to c440834 Compare March 20, 2020 19:11
@ellatrix
Copy link
Member

ellatrix commented Jun 3, 2020

As the feature was also flagged as experimental

I see the feature added by default in the Gutenberg plugin, or am I missing something?

If it helps, I expect more review to happen in the much smaller and easier to digest PRs that will be coming in the next couple weeks for the issues opened and linked to this PR.

That's good if the general direction is agreed upon. The problem is that there's no easy, small PR to go from editing on the server to editing in the browser. The PR will need to replace it almost entirely.

This is already being tracked in #22566 and #22579. The first previews the change by editing the image in JS, and the second makes a single request to the server once all image edits are complete.

I'm not talking about previews in the browser, but rather editing it in JS and sending the edited image to the server on save or autosave or some other trigger. There's no for the server to edit the images.

I any case, thanks for working on this!

const { url } = attributes;
const isEditing = ! isCrop && isSelected && url;

if ( ! isSelected ) {
Copy link
Member

Choose a reason for hiding this comment

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

This is causing the block to rerender when it is selected, which is not a great user experience esp. with an image that needs to load.

<Fragment>
{ noticeUI }

<div className={ classes }>
Copy link
Member

Choose a reason for hiding this comment

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

Why the div wrapper? I don't see why image editing tools should affect the structure of a block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The in-progress spinner needs a container to be centered properly on top of the image

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's rethink the spinner so we don't have to have the div. Can be a fading in and out image which I believe we use to indicate transience elsewhere. Happy to work with you on this 👍

@ajlende
Copy link
Contributor Author

ajlende commented Jun 3, 2020

I see the feature added by default in the Gutenberg plugin, or am I missing something?

Experimental, as in Gutenberg phase 2 (#21024 (comment)) as to not ship with core. @talldan also mentioned adding it to the experiments page, which I can go ahead and switch to instead since this is a bigger feature.

EDIT: PR #22870 is now open

I'm not talking about previews in the browser, but rather editing it in JS and sending the edited image to the server on save or autosave or some other trigger.

Which benefits do you think we'll get from editing in the browser instead? Using WP_Image_Editor still seems more straightforward to me. Either way you're going to need to download the saved image since images are saved on the server. In #22579 (batched edits) I was hoping to only do the edit once, ideally on save if I can hook into that event. And I think the CSS animations for previewing from #22566 would be easier and just as smooth as doing them on a canvas.

'permission_callback' => array( $this, 'permission_callback' ),
'args' => array(
'direction' => array(
'type' => 'enum',
Copy link
Member

Choose a reason for hiding this comment

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

enum isn't a type, it should instead be string.

'permission_callback' => array( $this, 'permission_callback' ),
'args' => array(
'cropX' => array(
'type' => 'float',
Copy link
Member

Choose a reason for hiding this comment

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

float is not a json schema type, it should be number.

* @param integer $height Height in pixels for the crop.
*/
public function __construct( $crop_x, $crop_y, $width, $height ) {
$this->crop_x = floatval( $crop_x );
Copy link
Member

Choose a reason for hiding this comment

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

Why are we using floatval is the types are documented as integer? Which is correct?

* @return array Updated metadata.
*/
public function apply_to_meta( $meta ) {
$meta['cropX'] = $this->crop_x;
Copy link
Member

Choose a reason for hiding this comment

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

Are these based off an existing pattern that means these need to be camelCase? Core uses snake_case in PHP land.

@TimothyBJacobs
Copy link
Member

Instead of using WP_REST_Request::get_params() and operating off of that, the code should just use $request['parameter'] directly.

The REST API also uses snake_case not camelCase for parameter names. Those should be updated.

The REST API meets every Thursday at 18:00 UTC in slack at #core-restapi. If you aren't seeing feedback from the REST API team, drop a link to the PR during our open floor.

@gziolo
Copy link
Member

gziolo commented Jun 4, 2020

One note, this PR doesn't add a new block but some of the functionality added here makes the impression that a new experimental block is being registered. Given that this functionality is added using a filter, it should be moved to a different package, @wordpress/editor might be a good fit if this is planned to work on all edit pages. @wordpress/block-library should contain only folders with core blocks.

@mtias
Copy link
Member

mtias commented Jun 4, 2020

If we can address the outstanding issues promptly, I don't think we need to add it to experiments. The discussion on how much to do on the client vs server is a bit nuanced. It makes sense to me to do all manipulation client side and then commit the updates as a new image on "save". Stacking new images on the server every time would be taxing on storage space and memory usage for shared hosts.

@TimothyBJacobs
Copy link
Member

Related ticket: https://core.trac.wordpress.org/ticket/49096

@ellatrix
Copy link
Member

ellatrix commented Jun 4, 2020

Ok, even if you could do previewing in JS or even CSS, why do a round trip with an image to the server at all then, if it can be done on the client side? That's double work. Even more than double because the image is being transferred over the network for each edit. And regardless of that, the preview might not be exactly the same. The algorithm on the server might be different. Things like filters suddenly become more difficult to do, while if we just have to handle the client, it’s fairly easy.

@ajlende
Copy link
Contributor Author

ajlende commented Jun 4, 2020

Doing the edits on the server was under the assumption that #22579 would be implemented so the request only happens once on save, so you wouldn't be downloading an image per edit. You'd POST the instructions for the edits and only download the final image.

When editing in JS, since you send the image to the server, aren't you going to want to replace the image in the editor with the URL of the saved image to make sure the save worked properly for the preview? That was my assumption, and that way you're both uploading and downloading the image.

The algorithms for crop, rotate, and flip are very straightforward, so I don't think there would be much of a chance for the algorithms to be different for them.

I was thinking that filters would continue to be done in CSS like they are in Automattic/block-experiments, but I forgot that CSS filters aren't supported in IE11. It could still be done with SVG filters which are supported across browsers—I started a demo for a duotone filter a while ago in Automattic/block-experiments#88.

Still, it might be nice to save the filtered image as well. In that case filters would have more opportunity for differences since you'd have to replicate the SVG filter on the server.

@ellatrix
Copy link
Member

ellatrix commented Jun 4, 2020

I think filters are not done in CSS for the same reasons rotate and flip are not done in CSS on the front end? The image itself should be adjusted because the content might not include the CSS or might be distributed by email, RSS, social networks, etc. Additionally, if you download the image from the website, you'll get the original image. Generally people are not expecting anyone to have access to the original images.

With the client already doing the edits, I don't see why we should add the complexity of doing the same thing on the server, if we can just upload the image on save/publish.

I could also imagine Gutenberg being used with another API of a CMS that doesn't support image editing. Editing in JS means using the common API of creating/uploading an image, while editing on the server means additional endpoints are required.

@azaozz
Copy link
Contributor

azaozz commented Jun 5, 2020

With the client already doing the edits, I don't see why we should add the complexity of doing the same thing on the server, if we can just upload the image on save/publish.

It would be ideal if that works :) Editing images in the browser (also before uploading them) is the best option. Been looking at that for quite some time, but seems "we're not there yet", the browsers still aren't particularly good image editors.

Known problems with HTML canvas based editors (afaik):

  • Insufficient memory/resources on phones and possibly old/slow computers when attempting to edit larger images (the default base size in WP currently is 2560px). See https://github.com/fengyuanchen/cropperjs#known-issues.
  • Not able to edit/preserve EXIF data.
  • Image quality and/or compression may not be as good as server based editors like ImageMagick.

Would be great if some js based image editors can be evaluated again, there seem to be few that are more popular.

@jasmussen
Copy link
Contributor

I think it might be worth separating the conversation on filters. These were experimental, and might not even be a fit for the core project, regardless of previous implementation. If they are (even just making a photo black and white and adjusting contrast would be delightful), it feels a separate conversation. One which I look forward to having, by the way :)

@ellatrix
Copy link
Member

ellatrix commented Jun 5, 2020

Regarding EXIF data on JPG images, the edited image would have access to the original image data on the server, so we could adjust the function to get the EXIF data to get it from the original, if so desired. Not sure if that would be considered an ugly fix. Alternatively we can try to preserve it in JS, I would need to research it.

Regarding the quality, are there any articles about this? I don't really see a problem at first sight.

Yes, that's really annoying for phones and old/slow computers... what is the limit on a server?

@RickorDD
Copy link
Contributor

RickorDD commented Jun 6, 2020

When i add the Imageblock the Fontbar hidden the Text.

Imagestest

Remove this Bar to the Top?

@oandregal oandregal added [Type] Feature New feature to highlight in changelogs. and removed [Type] Enhancement A suggestion for improvement. labels Jun 8, 2020
@jasmussen
Copy link
Contributor

When i add the Imageblock the Fontbar hidden the Text.

This is a bug with re-rendering, that will be fixed. The caption field should not even be visible in the setup state. Thanks for the report, @RickorDD

@joppuyo
Copy link

joppuyo commented Jun 9, 2020

About editing images in JavaScript:

There are tons of features that depend on native WordPress image editor that are completely sidestepped by implementing image editing in JavaScript using canvas, the first thing that comes to mind is jpeg_quality filter that allows users and plugins to alter the JPEG quality.

WordPress also allows hooking into the image processing so plugins like image optimizers can process the images. It's also possible to completely replace the WP_Image_Editor with another class to customize the image processing, for example using an image processing library like vips instead of GD or ImageMagick.

If a canvas is used for image editing instead of predictable quality and scaling settings, the results will vary depending on which browser or OS was used when editing the image. Replacing native server-side WordPress functionality with JavaScript may seem trivial at first but it has a lot of consequences that need to be taken into account.

@TimothyBJacobs
Copy link
Member

Is there a PR somewhere for addressing the REST API related issues? As well as an overall tracking ticket for image editing?

The REST API team is concerned about the amount of server side REST API code that is needed with this current approach so late in the cycle if we want the feature to land in 5.5. There is already a large amount of complex REST API integrations that are slated for 5.5.

The only way I can see this landing in 5.5 is by doing editing in JS and adding support for https://core.trac.wordpress.org/ticket/49096.

@ajlende ajlende mentioned this pull request Jun 9, 2020
6 tasks
@ajlende
Copy link
Contributor Author

ajlende commented Jun 9, 2020

@TimothyBJacobs I didn't get to your edits because I was going to do a batch editing endpoint instead of all the individual ones in #22959. It's taken longer than expected, so I opened up #23037 for those edits now.

@ellatrix ellatrix mentioned this pull request Jun 16, 2020
12 tasks
@koraysels
Copy link

can we add more aspect ratios to the crop feature? and how do we go about doing this?

@paaljoachim
Copy link
Contributor

I am adding in this associated issue
Hover color over image block
#33939

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 Core REST API Task Task for Core REST API efforts [Feature] Media Anything that impacts the experience of managing media REST API Interaction Related to REST API [Type] Feature New feature to highlight in changelogs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow cropping of images from inside the content editor