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 editing: batch editing in cropper component #23284

Merged
merged 9 commits into from
Jun 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 99 additions & 96 deletions lib/class-wp-rest-image-editor-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
* @subpackage REST_API
*/

/**
* Image editor
*/
include_once __DIR__ . '/image-editor/class-image-editor.php';

/**
* Controller which provides REST API endpoints for image editing.
*
Expand All @@ -30,7 +25,6 @@ class WP_REST_Image_Editor_Controller extends WP_REST_Controller {
public function __construct() {
$this->namespace = '__experimental';
$this->rest_base = '/richimage/(?P<media_id>[\d]+)';
$this->editor = new Image_Editor();
}

/**
Expand All @@ -42,75 +36,35 @@ public function __construct() {
public function register_routes() {
register_rest_route(
$this->namespace,
$this->rest_base . '/rotate',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'rotate_image' ),
'permission_callback' => array( $this, 'permission_callback' ),
'args' => array(
'angle' => array(
'description' => __( 'Rotation angle', 'gutenberg' ),
'type' => 'integer',
'required' => true,
),
),
),
)
);

register_rest_route(
$this->namespace,
$this->rest_base . '/flip',
$this->rest_base . '/apply',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'flip_image' ),
'callback' => array( $this, 'apply_edits' ),
'permission_callback' => array( $this, 'permission_callback' ),
'args' => array(
'direction' => array(
'description' => __( 'Flip direction', 'gutenberg' ),
'type' => 'string',
'enum' => array( 'vertical', 'horizontal' ),
'required' => true,
'x' => array(
'type' => 'float',
'minimum' => 0,
'required' => true,
),
),
),
)
);

register_rest_route(
$this->namespace,
$this->rest_base . '/crop',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'crop_image' ),
'permission_callback' => array( $this, 'permission_callback' ),
'args' => array(
'crop_x' => array(
'description' => __( 'Crop offset percentage from left', 'gutenberg' ),
'type' => 'number',
'minimum' => 0,
'required' => true,
'y' => array(
'type' => 'float',
'minimum' => 0,
'required' => true,
),
'crop_y' => array(
'description' => __( 'Crop offset percentage from top', 'gutenberg' ),
'type' => 'number',
'minimum' => 0,
'required' => true,
'width' => array(
'type' => 'float',
'minimum' => 1,
'required' => true,
),
'crop_width' => array(
'description' => __( 'Crop width percentage', 'gutenberg' ),
'type' => 'number',
'minimum' => 1,
'required' => true,
'height' => array(
'type' => 'float',
'minimum' => 1,
'required' => true,
),
'crop_height' => array(
'description' => __( 'Crop height percentage', 'gutenberg' ),
'type' => 'number',
'minimum' => 1,
'required' => true,
'rotation' => array(
'type' => 'integer',
),
),
),
Expand All @@ -136,47 +90,96 @@ public function permission_callback( $request ) {
}

/**
* Rotates an image.
* Applies all edits in one go.
*
* @since 7.x ?
* @access public
*
* @param WP_REST_Request $request Full details about the request.
* @return array|WP_Error If successful image JSON for the modified image, otherwise a WP_Error.
*/
public function rotate_image( $request ) {
$modifier = new Image_Editor_Rotate( $request['angle'] );
public function apply_edits( $request ) {
require_once ABSPATH . 'wp-admin/includes/image.php';

return $this->editor->modify_image( $request['media_id'], $modifier );
}
$params = $request->get_params();

/**
* Flips/mirrors an image.
*
* @since 7.x ?
* @access public
*
* @param WP_REST_Request $request Full details about the request.
* @return array|WP_Error If successful image JSON for the modified image, otherwise a WP_Error.
*/
public function flip_image( $request ) {
$modifier = new Image_Editor_Flip( $request['direction'] );
$media_id = $params['media_id'];

return $this->editor->modify_image( $request['media_id'], $modifier );
}
// Get image information.
$attachment_info = wp_get_attachment_metadata( $media_id );
$media_url = wp_get_attachment_image_url( $media_id, 'original' );

/**
* Crops an image.
*
* @since 7.x ?
* @access public
*
* @param WP_REST_Request $request Full details about the request.
* @return array|WP_Error If successful image JSON for the modified image, otherwise a WP_Error.
*/
public function crop_image( $request ) {
$modifier = new Image_Editor_Crop( $request['crop_x'], $request['crop_y'], $request['crop_width'], $request['crop_height'] );
if ( ! $attachment_info || ! $media_url ) {
return new WP_Error( 'unknown', 'Unable to get meta information for file' );
}

$meta = array( 'original_name' => basename( $media_url ) );

if ( isset( $attachment_info['richimage'] ) ) {
$meta = array_merge( $meta, $attachment_info['richimage'] );
}

// Try and load the image itself.
$image_path = get_attached_file( $media_id );
if ( empty( $image_path ) ) {
return new WP_Error( 'fileunknown', 'Unable to find original media file' );
}

$image_editor = wp_get_image_editor( $image_path );
if ( ! $image_editor->load() ) {
return new WP_Error( 'fileload', 'Unable to load original media file' );
}

return $this->editor->modify_image( $request['media_id'], $modifier );
$size = $image_editor->get_size();

// Finally apply the modifications.
$crop_x = round( ( $size['width'] * floatval( $params['x'] ) ) / 100.0 );
$crop_y = round( ( $size['height'] * floatval( $params['y'] ) ) / 100.0 );
$width = round( ( $size['width'] * floatval( $params['width'] ) ) / 100.0 );
$height = round( ( $size['height'] * floatval( $params['height'] ) ) / 100.0 );
$image_editor->crop( $crop_x, $crop_y, $width, $height );

if ( isset( $params['rotation'] ) ) {
$image_editor->rotate( 0 - $params['rotation'] );
}

// TODO: Generate filename based on edits.
$target_file = 'edited-' . $meta['original_name'];

$filename = rtrim( dirname( $image_path ), '/' ) . '/' . $target_file;

// Save to disk.
$saved = $image_editor->save( $filename );

if ( is_wp_error( $saved ) ) {
return $saved;
}

// Update attachment details.
$attachment_post = array(
'guid' => $saved['path'],
'post_mime_type' => $saved['mime-type'],
'post_title' => pathinfo( $target_file, PATHINFO_FILENAME ),
'post_content' => '',
'post_status' => 'inherit',
);

// Add this as an attachment.
$attachment_id = wp_insert_attachment( $attachment_post, $saved['path'], 0 );
if ( 0 === $attachment_id ) {
return new WP_Error( 'attachment', 'Unable to add image as attachment' );
}

// Generate thumbnails.
$metadata = wp_generate_attachment_metadata( $attachment_id, $saved['path'] );

$metadata['richimage'] = $meta;

wp_update_attachment_metadata( $attachment_id, $metadata );

return array(
'media_id' => $attachment_id,
'url' => wp_get_attachment_image_url( $attachment_id, 'original' ),
);
}
}
126 changes: 0 additions & 126 deletions lib/image-editor/class-image-editor-crop.php

This file was deleted.

Loading