diff --git a/lib/class-wp-rest-image-editor-controller.php b/lib/class-wp-rest-image-editor-controller.php index 66c8531e02d7ed..f5034363fef58c 100644 --- a/lib/class-wp-rest-image-editor-controller.php +++ b/lib/class-wp-rest-image-editor-controller.php @@ -43,33 +43,97 @@ public function register_routes() { 'callback' => array( $this, 'apply_edits' ), 'permission_callback' => array( $this, 'permission_callback' ), 'args' => array( - 'rotation' => array( - 'type' => 'integer', - ), - // Src is required to check for correct $image_meta. - 'src' => array( + 'src' => array( 'type' => 'string', 'required' => true, ), + 'modifiers' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'object', + 'oneOf' => array( + // Rotate. Angle is in degrees. + array( + 'properties' => array( + 'type' => array( + 'type' => 'string', + 'const' => 'rotate', + ), + 'angle' => array( + 'type' => 'number', + ), + ), + 'required' => array( + 'type', + 'angle', + ), + ), + + // Crop. Values are in percentages. + array( + 'properties' => array( + 'type' => array( + 'type' => 'string', + 'const' => 'crop', + ), + 'left' => array( + 'type' => 'number', + 'minimum' => 0, + 'maximum' => 100, + ), + 'top' => array( + 'type' => 'number', + 'minimum' => 0, + 'maximum' => 100, + ), + 'width' => array( + 'type' => 'number', + 'minimum' => 1, + 'maximum' => 100, + ), + 'height' => array( + 'type' => 'number', + 'minimum' => 1, + 'maximum' => 100, + ), + ), + 'required' => array( + 'type', + 'left', + 'top', + 'width', + 'height', + ), + ), + ), + ), + ), + + // Deprecated. Use `modifiers` instead. + 'rotation' => array( + 'type' => 'integer', + ), + + // Deprecated. Use `modifiers` instead. // Crop values are in percents. - 'x' => array( + 'x' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), - 'y' => array( + 'y' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), - 'width' => array( + 'width' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), - 'height' => array( + 'height' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 100, @@ -192,20 +256,9 @@ public function apply_edits( $request ) { ); } - // Check if we need to do anything. - $rotate = 0; - $crop = false; - - if ( ! empty( $request['rotation'] ) ) { - // Rotation direction: clockwise vs. counter clockwise. - $rotate = 0 - (int) $request['rotation']; - } - - if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) { - $crop = true; - } + $modifiers = $request['modifiers']; - if ( ! $rotate && ! $crop ) { + if ( 0 === count( $modifiers ) ) { $error = __( 'The image was not edited. Edit the image before applying the changes.', 'gutenberg' ); return new WP_Error( 'rest_image_not_edited', $error, array( 'status' => 400 ) ); } @@ -226,28 +279,34 @@ public function apply_edits( $request ) { return new WP_Error( 'rest_unknown_image_file_type', $error, array( 'status' => 500 ) ); } - if ( 0 !== $rotate ) { - $result = $image_editor->rotate( $rotate ); + foreach ( $modifiers as $modifier ) { + if ( 'rotate' === $modifier['type'] ) { + $rotate = 0 - $modifier['angle']; - if ( is_wp_error( $result ) ) { - $error = __( 'Unable to rotate this image.', 'gutenberg' ); - return new WP_Error( 'rest_image_rotation_failed', $error, array( 'status' => 500 ) ); - } - } + if ( 0 !== $rotate ) { + $result = $image_editor->rotate( $rotate ); - if ( $crop ) { - $size = $image_editor->get_size(); + if ( is_wp_error( $result ) ) { + $error = __( 'Unable to rotate this image.', 'gutenberg' ); + return new WP_Error( 'rest_image_rotation_failed', $error, array( 'status' => 500 ) ); + } + } + } elseif ( 'crop' === $modifier['type'] ) { + $size = $image_editor->get_size(); - $crop_x = round( ( $size['width'] * floatval( $request['x'] ) ) / 100.0 ); - $crop_y = round( ( $size['height'] * floatval( $request['y'] ) ) / 100.0 ); - $width = round( ( $size['width'] * floatval( $request['width'] ) ) / 100.0 ); - $height = round( ( $size['height'] * floatval( $request['height'] ) ) / 100.0 ); + $crop_x = round( ( $size['width'] * floatval( $modifier['left'] ) ) / 100.0 ); + $crop_y = round( ( $size['height'] * floatval( $modifier['top'] ) ) / 100.0 ); + $width = round( ( $size['width'] * floatval( $modifier['width'] ) ) / 100.0 ); + $height = round( ( $size['height'] * floatval( $modifier['height'] ) ) / 100.0 ); - $result = $image_editor->crop( $crop_x, $crop_y, $width, $height ); + if ( $size['width'] !== $width && $size['height'] !== $height ) { + $result = $image_editor->crop( $crop_x, $crop_y, $width, $height ); - if ( is_wp_error( $result ) ) { - $error = __( 'Unable to crop this image.', 'gutenberg' ); - return new WP_Error( 'rest_image_crop_failed', $error, array( 'status' => 500 ) ); + if ( is_wp_error( $result ) ) { + $error = __( 'Unable to crop this image.', 'gutenberg' ); + return new WP_Error( 'rest_image_crop_failed', $error, array( 'status' => 500 ) ); + } + } } } diff --git a/packages/block-library/src/image/image-editor.js b/packages/block-library/src/image/image-editor.js index a3401132390fb3..f856bef0d39f3a 100644 --- a/packages/block-library/src/image/image-editor.js +++ b/packages/block-library/src/image/image-editor.js @@ -187,16 +187,27 @@ export default function ImageEditor( { function apply() { setIsProgress( true ); - let attrs = {}; + const attrs = { + modifiers: [], + }; // The crop script may return some very small, sub-pixel values when the image was not cropped. // Crop only when the new size has changed by more than 0.1%. if ( crop.width < 99.9 || crop.height < 99.9 ) { - attrs = crop; + attrs.modifiers.push( { + type: 'crop', + left: crop.x, + top: crop.y, + width: crop.width, + height: crop.height, + } ); } if ( rotation > 0 ) { - attrs.rotation = rotation; + attrs.modifiers.push( { + type: 'rotate', + angle: rotation, + } ); } attrs.src = url;