Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
First version of the WP_Image_Editor
  • Loading branch information
markoheijnen committed Aug 22, 2012
1 parent d7f7240 commit f96f9db
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 125 deletions.
8 changes: 6 additions & 2 deletions wp-admin/includes/image.php
Expand Up @@ -144,12 +144,16 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) {

$sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes );

$editor = new WP_Image_Editor( $file );

foreach ($sizes as $size => $size_data ) {
$resized = image_make_intermediate_size( $file, $size_data['width'], $size_data['height'], $size_data['crop'] );
if ( $resized )
$resized = $editor->resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
if ( ! is_wp_error( $resized ) && $resized )
$metadata['sizes'][$size] = $resized;
}

unset( $editor );

// fetch additional metadata from exif/iptc
$image_meta = wp_read_image_metadata( $file );
if ( $image_meta )
Expand Down
45 changes: 45 additions & 0 deletions wp-includes/class-wp-image-editor.php
@@ -0,0 +1,45 @@
<?php

class WP_Image_Editor {

final public static function get_instance( $path ) {
$implementation = apply_filters( 'image_editor_class', self::choose_implementation(), $path );

if ( $implementation )
return new $implementation( $path );

return false;
}

/**
* Tests which editors are capable of supporting the request.
*
* @since 3.5.0
* @access private
*
* @return string|bool Class name for the first editor that claims to support the request. False if no editor claims to support the request.
*/
private static function choose_implementation() {
static $implementation;

if ( null === $implementation ) {
$request_order = apply_filters( 'wp_editors', array( 'imagick', 'gd' ) );

// Loop over each editor on each request looking for one which will serve this request's needs
foreach ( $request_order as $editor ) {
$class = 'WP_Image_Editor_' . $editor;

// Check to see if this editor is a possibility, calls the editor statically
if ( ! call_user_func( array( $class, 'test' ) ) )
continue;

if( ! apply_filters( 'wp_editor_use_' . $editor, true ) )
continue;

$implementation = $class;
}
}

return $implementation;
}
}
51 changes: 51 additions & 0 deletions wp-includes/deprecated.php
Expand Up @@ -3203,4 +3203,55 @@ function sticky_class( $post_id = null ) {
*/
function _get_post_ancestors( &$post ) {
_deprecated_function( __FUNCTION__, '3.5' );
}


/**
* Load an image from a string, if PHP supports it.
*
* @since 2.1.0
* @deprecated 3.5.0
* @deprecated wp_get_image_for_editing()
*
* @param string $file Filename of the image to load.
* @return resource The resulting image resource on success, Error string on failure.
*/
function wp_load_image( $file ) {
_deprecated_function( __FUNCTION__, '3.5', 'wp_get_image_for_editing()' );

if ( is_numeric( $file ) )
$file = get_attached_file( $file );

$editor = new WP_Image_Editor_GD;
$editor->load( $file );
}

/**
* Scale down an image to fit a particular size and save a new copy of the image.
*
* The PNG transparency will be preserved using the function, as well as the
* image type. If the file going in is PNG, then the resized image is going to
* be PNG. The only supported image types are PNG, GIF, and JPEG.
*
* Some functionality requires API to exist, so some PHP version may lose out
* support. This is not the fault of WordPress (where functionality is
* downgraded, not actual defects), but of your PHP version.
*
* @since 2.5.0
* @deprecated 3.5.0
* @deprecated wp_get_image_for_editing()
*
* @param string $file Image file path.
* @param int $max_w Maximum width to resize to.
* @param int $max_h Maximum height to resize to.
* @param bool $crop Optional. Whether to crop image or resize.
* @param string $suffix Optional. File suffix.
* @param string $dest_path Optional. New image file path.
* @param int $jpeg_quality Optional, default is 90. Image quality percentage.
* @return mixed WP_Error on failure. String with new destination path.
*/
function image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) {
_deprecated_function( __FUNCTION__, '3.5', 'wp_get_image_for_editing()' );

$editor = new WP_Image_Editor_GD;+ $editor->resize( $file, $max_w, $max_h, $crop, $suffix, $dest_path, $jpeg_quality )

This comment has been minimized.

Copy link
@scribu

scribu Aug 22, 2012

Copy/pasta?

This comment has been minimized.

Copy link
@markoheijnen

markoheijnen Aug 22, 2012

Author Owner

Argh and yes

}
15 changes: 15 additions & 0 deletions wp-includes/editors/class-wp-image-editor-base.php
@@ -0,0 +1,15 @@
<?php

class WP_Image_Editor_Base {
protected $file = false;
protected $size = false;
protected $orig_type = false;

function __construct( $filename ) {
$this->file = $filename;
}

public static function test() {
return false;
}
}
108 changes: 108 additions & 0 deletions wp-includes/editors/class-wp-image-editor-gd.php
@@ -0,0 +1,108 @@
<?php

class WP_Image_Editor_GD extends WP_Image_Editor_Base {
private $image = false;

function __destruct() {
if ( $this->image ) {
// we don't need the original in memory anymore
imagedestroy( $this->image );
}
}

public static function test() {
if ( ! extension_loaded('gd') || ! function_exists('gd_info') )
return false;

return true;
}

private function load() {
if( $this->image )
return true;

if ( ! file_exists( $this->file ) )
return sprintf( __('File &#8220;%s&#8221; doesn&#8217;t exist?'), $this->file );

if ( ! function_exists('imagecreatefromstring') )
return __('The GD image library is not installed.');

// Set artificially high because GD uses uncompressed images in memory
@ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
$this->image = imagecreatefromstring( file_get_contents( $this->file ) );

if ( ! is_resource( $this->image ) )
return sprintf( __('File &#8220;%s&#8221; is not an image.'), $this->file );

$size = @getimagesize( $this->file );
if ( ! $size )
return new WP_Error( 'invalid_image', __('Could not read image size'), $this->file );

$this->size = array( 'width' => $size[0], 'height' => $size[1] );
$this->orig_type = $size[1];

return true;
}

public function resize( $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) {
if ( ! $this->load() )
return;

$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
if ( ! $dims )
return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') );
list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;

$newimage = wp_imagecreatetruecolor( $dst_w, $dst_h );

imagecopyresampled( $newimage, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );

// convert from full colors to index colors, like original PNG.
if ( IMAGETYPE_PNG == $this->orig_type && function_exists('imageistruecolor') && !imageistruecolor( $this->image ) )
imagetruecolortopalette( $newimage, false, imagecolorstotal( $this->image ) );

// $suffix will be appended to the destination filename, just before the extension
if ( ! $suffix )
$suffix = "{$dst_w}x{$dst_h}";

$info = pathinfo( $this->file );
$dir = $info['dirname'];
$ext = $info['extension'];
$name = wp_basename( $this->file, ".$ext" );

if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
$dir = $_dest_path;
$destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";

if ( IMAGETYPE_GIF == $this->orig_type ) {
if ( ! imagegif( $newimage, $destfilename ) )
return new WP_Error( 'resize_path_invalid', __( 'Resize path invalid' ) );
}
elseif ( IMAGETYPE_PNG == $this->orig_type ) {
if ( !imagepng( $newimage, $destfilename ) )
return new WP_Error( 'resize_path_invalid', __( 'Resize path invalid' ) );
}
else {
// all other formats are converted to jpg
if ( 'jpg' != $ext && 'jpeg' != $ext )
$destfilename = "{$dir}/{$name}-{$suffix}.jpg";

if ( ! imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality, 'image_resize' ) ) )
return new WP_Error( 'resize_path_invalid', __( 'Resize path invalid' ) );
}

imagedestroy( $newimage );

// Set correct file permissions
$stat = stat( dirname( $destfilename ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
@ chmod( $destfilename, $perms );

return array(
'path' => $destfilename,
'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $destfilename ) ),
'width' => $dst_w,
'height' => $dst_h
);
}
}
93 changes: 93 additions & 0 deletions wp-includes/editors/class-wp-image-editor-imagick.php
@@ -0,0 +1,93 @@
<?php

class WP_Image_Editor_Imagick extends WP_Image_Editor_Base {
private $image = false;

public static function test() {
if ( ! extension_loaded('imagick') )
return false;

return true;
}

private function load() {
if ( ! file_exists( $this->file ) )
return sprintf( __('File &#8220;%s&#8221; doesn&#8217;t exist?'), $this->file );

try {
$this->image = new Imagick( $this->file );
}
catch ( Exception $e ) {
return sprintf(__('File &#8220;%s&#8221; is not an image.'), $this->file);
}

if( ! $this->image->valid() ) {
return sprintf(__('File &#8220;%s&#8221; is not an image.'), $this->file);
}

$this->size = $this->image->getImageGeometry();
$this->orig_type = $this->image->getImageFormat();
if ( ! $this->size )
return new WP_Error( 'invalid_image', __('Could not read image size'), $this->file );

return true;
}

public function resize( $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) {
// Yes, this is forcing a load every time at the moment.
// However, for multi-resize to work, it needs to do so, unless it's going to resize based on a modified image.
if ( ! $this->load() )
return false;

if ( ! is_object( $this->image ) )
return new WP_Error( 'error_loading_image', $this->image, $this->file );

$dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
if ( ! $dims )
return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') );
list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;

if( 'JPEG' == $this->orig_type ) {
$this->image->setImageCompression( imagick::COMPRESSION_JPEG );
$this->image->setImageCompressionQuality( $jpeg_quality );
}

if ( $crop ) {
$this->image->cropImage( $src_w, $src_h, $src_x, $src_y );
}

//$this->image->thumbnailImage( $dst_w, $dst_h );
$this->image->scaleImage( $dst_w, $dst_h, true );

// $suffix will be appended to the destination filename, just before the extension
if ( ! $suffix )
$suffix = "{$dst_w}x{$dst_h}";

$info = pathinfo( $this->file );
$dir = $info['dirname'];
$ext = $info['extension'];
$name = wp_basename( $this->file, ".$ext" );

if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
$dir = $_dest_path;
$destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";

if( apply_filters( 'wp_editors_stripimage', true ) ) {
$this->image->stripImage();
}

$this->image->writeImage( $destfilename );

// Set correct file permissions
$stat = stat( dirname( $destfilename ) );
$perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
@ chmod( $destfilename, $perms );

return array(
'path' => $destfilename,
'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $destfilename ) ),
'width' => $dst_w,
'height' => $dst_h
);
}
}

0 comments on commit f96f9db

Please sign in to comment.