Created
December 9, 2012 00:24
-
-
Save staylor/4242708 to your computer and use it in GitHub Desktop.
I am using a script called "test.php" in the root of WordPress with a folder for images called "test-images/*". The original image is called "scott.jpg" - change that value with your image to play along
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
error_reporting(-1); | |
require( 'wp-load.php' ); | |
require_once( ABSPATH . WPINC . '/class-wp-image-editor.php' ); | |
require_once( ABSPATH . WPINC . '/class-wp-image-editor-imagick.php' ); | |
/** | |
* Tosses Imagick methods up the chain to WP_Image_Editor_Imagick::image. | |
* WP_Image_Editor_Imagick::image is protected, so you can't act on | |
* it directly in an instance / there is no getter. Decorator pattern was an | |
* odd choice here IMO. Probably because its functionality is purposely limited | |
* to the immediate needs of core. Eh. | |
* | |
* Activates the Builder pattern on Imagick methods. | |
* | |
* Output the edited image: | |
* get_cropped()->adaptiveBlurImage(5, 3)->stream(); | |
* Save the edited image: | |
* get_cropped()->adaptiveBlurImage(5, 3)->write( 'blur', false ); | |
* Save the edited image and then display it in an <img> tag: | |
* get_cropped()->adaptiveBlurImage(5, 3)->write( 'blur' ); | |
*/ | |
class WP_Imagick_Access extends WP_Image_Editor_Imagick { | |
function __call( $name, $arguments ) { | |
call_user_func_array( array( $this->image, $name ), $arguments ); | |
return $this; | |
} | |
static function __callStatic( $name, $arguments ) { | |
call_user_func_array( array( $this->image, $name ), $arguments ); | |
return $this; | |
} | |
/** | |
* This works better when using Imagick method to overload | |
* | |
* @param string $mime_type | |
*/ | |
function stream( $mime_type = 'image/jpeg' ) { | |
header( "Content-Type: $mime_type" ); | |
echo $this->image; | |
} | |
/** | |
* Save an image and output an <img> tag | |
* | |
* @param string $name | |
* @param boolean $display | |
* @return \WP_Imagick_Access | |
*/ | |
function write( $name, $display = true ) { | |
//if ( ! file_exists( "test-images/$name.jpg" ) ) | |
$this->save( "test-images/$name.jpg" ); | |
if ( $display ) | |
echo '<img src="', home_url( "test-images/$name.jpg" ), '" />'; | |
return $this; | |
} | |
} | |
function add_wp_imagick_access( $editors ) { | |
array_unshift( $editors, 'WP_Imagick_Access' ); | |
return $editors; | |
} | |
add_filter( 'wp_image_editors', 'add_wp_imagick_access' ); | |
/** | |
* Change size to create new image | |
* | |
* @return WP_Image_Editor_Imagick | |
*/ | |
function get_cropped() { | |
$size = 250; | |
if ( ! file_exists( 'test-images/cropped-' . $size . '.jpg' ) ) { | |
$image = wp_get_image_editor( 'scott.jpg' ); | |
$image->resize( $size, $size, true ); | |
$image->write( 'test-images/cropped-' . $size . '.jpg', false ); | |
} | |
return wp_get_image_editor( 'test-images/cropped-' . $size . '.jpg' ); | |
} | |
/** | |
* Imagick CHANNEL constants | |
*/ | |
$channel = array(); | |
foreach ( array( 'DEFAULT', 'RED', 'GRAY', 'CYAN', 'GREEN', 'MAGENTA', 'BLUE', 'YELLOW', 'ALPHA', 'OPACITY', 'MATTE', 'BLACK', 'INDEX', 'ALL', 'UNDEFINED' ) as $chan ) { | |
$channel["imagick::CHANNEL_{$chan}"] = constant( "imagick::CHANNEL_{$chan}" ); | |
} | |
/** | |
* Imagick NOISE constants | |
*/ | |
$noise = array(); | |
foreach ( array( 'UNIFORM', 'GAUSSIAN', 'MULTIPLICATIVEGAUSSIAN', 'IMPULSE', 'LAPLACIAN', 'POISSON', 'RANDOM' ) as $nois ) { | |
$noise["imagick::NOISE_{$nois}"] = constant( "imagick::NOISE_{$nois}" ); | |
} | |
/** | |
* Min / Max floats for generic parameters - still tweaking ideal values for these | |
*/ | |
$radius = array( 0.5, 50 ); | |
$sigma = array( 0.5, 20 ); | |
$angle = array( 0.0, 360.0 ); | |
$opacity = array( 0.0, 1.0 ); | |
$percentage = array( 0.0, 100.0 ); | |
/** | |
* Since we operate by convention: | |
* slug => array( method, array( param1 => array( min, max ), ... ) ) | |
* | |
* TODO: some of the 0.0 values are wrong, still learning what each method does | |
* | |
*/ | |
$map = array( | |
'adaptive-blur' => array( 'adaptiveBlurImage', array( 'radius' => $radius, 'sigma' => $sigma, 'channel' => $channel ) ), | |
'adaptive-threshold' => array( 'adaptiveThresholdImage', array( 'width' => 0.0, 'height' => 0.0, 'offset' => 0.0 ) ), | |
'adaptive-sharpen' => array( 'adaptiveSharpenImage', array( 'radius' => $radius, 'sigma' => $sigma, 'channel' => $channel ) ), | |
'noise' => array( 'addNoiseImage', array( 'noise_type' => $noise, 'channel' => $channel ) ), | |
'blur' => array( 'blurImage', array( 'radius' => $radius, 'sigma' => $sigma, 'channel' => $channel ) ), | |
'charcoal' => array( 'charcoalImage', array( 'radius' => $radius, 'sigma' => $sigma ) ), | |
'edge' => array( 'edgeImage', array( 'radius' => $radius ) ), | |
'emboss' => array( 'embossImage', array( 'radius' => $radius, 'sigma' => $sigma ) ), | |
'median' => array( 'medianFilterImage', array( 'radius' => $radius ) ), | |
'modulate' => array( 'modulateImage', array( 'brightness' => $percentage , 'saturation' => $percentage, 'hue' => $percentage ) ), | |
'motion' => array( 'motionBlurImage', array( 'radius' => $radius, 'sigma' => $sigma, 'angle' => $angle, 'channel' => $channel ) ), | |
'normalize' => array( 'normalizeImage', array( 'channel' => $channel ) ), | |
'oilpaint' => array( 'oilPaintImage', array( 'radius' => $radius ) ), | |
'radial-blur' => array( 'radialBlurImage', array( 'angle' => $angle, 'channel' => $channel ) ), | |
'random-threshold' => array( 'randomThresholdImage', array( 'low' => 0.0, 'high' => 0.0, 'channel' => $channel ) ), | |
'reduce-noise' => array( 'reduceNoiseImage', array( 'radius' => $radius ) ), | |
'resample' => array( 'resampleImage', array( 'x_resolution' => 0.0, 'y_resolution' => 0.0, 'filter' => 0.0 , 'blur' => 0.0 ) ), | |
'sepia' => array( 'sepiaToneImage', array( 'threshold' => $percentage ) ), | |
'shade' => array( 'shadeImage', array( 'gray' => $percentage, 'azimuth' => $percentage, 'elevation' => $percentage ) ), | |
'sharpen' => array( 'sharpenImage', array( 'opacity' => $opacity, 'sigma' => $sigma, 'x' => 0.0, 'y' => 0.0 ) ), | |
'sketch' => array( 'sketchImage', array( 'radius' => $radius, 'sigma' => $sigma, 'angle' => $angle ) ), | |
'solarize' => array( 'solarizeImage', array( 'threshold' => 0.0 ) ), | |
'spread' => array( 'spreadImage', array( 'radius' => $radius ) ), | |
'swirl' => array( 'swirlImage', array( 'degrees' => $angle ) ), | |
'tint' => array( 'tintImage', array( 'tint' => $percentage, 'opacity' => $opacity ) ), | |
'unsharp' => array( 'unsharpMaskImage', array( 'radius' => $radius, 'sigma' => $sigma, 'amount' => 0.0, 'threshold' => 0.0, 'channel' => $channel ) ), | |
'vignette' => array( 'vignetteImage', array( 'black' => $percentage, 'white' => $percentage, 'x' => 0.0, 'y' => 0.0 ) ), | |
'wave' => array( 'waveImage', array( 'amplitude' => $percentage, 'length' => 0.0 ) ), | |
); | |
/** | |
* Handle a request to resample the cropped image | |
* | |
*/ | |
if ( isset( $_GET['slug'] ) ) { | |
list( $method, $params ) = $map[$_GET['slug']]; | |
$args = array(); | |
foreach ( $params as $arg => $default ) { | |
if ( isset( $_GET[$arg] ) ) { | |
$passed = $_GET[$arg]; | |
if ( is_array( $default ) && empty( $passed ) ) | |
$passed = reset( $default ); | |
if ( is_int( $passed ) || in_array( $arg, array( 'channel', 'noise_type' ) ) ) | |
$cast = intval( $passed ); | |
else | |
$cast = floatval( $passed ); | |
$args[$arg] = $cast; | |
} else { | |
if ( is_array( $default ) ) | |
$args[$arg] = reset( $default ); | |
else | |
$args[$arg] = $default; | |
} | |
} | |
$obj = get_cropped(); | |
/** | |
* Depending on how cray you get, you might run into a memory alloc fatal | |
* if out of sync params are passed (working on it!) | |
*/ | |
try { | |
call_user_func_array( array( $obj, $method ), $args ); | |
} catch (Exception $e) { | |
$obj = get_cropped(); | |
} | |
$obj->stream(); | |
exit(); | |
} | |
/** end resampling */ | |
/** | |
* UI for ImageMagick methods | |
* | |
*/ | |
wp_register_style( 'jquery-ui', '/test-images/jquery-ui-1.9.2.custom.min.css' ); | |
wp_print_styles( array( 'jquery-ui' ) ); | |
wp_print_scripts( array( 'jquery-ui-slider' ) ); | |
/** | |
* Inline Styles | |
* | |
*/ | |
?> | |
<style> | |
* {margin: 0; padding: 0} | |
body {font-family: helvetica; padding: 20px; font-size: 12px} | |
h3 {margin: 10px 0; font-family: monospace; font-weight: normal} | |
#images {overflow: hidden} | |
.image {float: left; margin: 0 10px 10px 0; width: 250px; height: 470px; margin-bottom: 20px} | |
.image-frame {display: block; width: 250px; height: 250px; overflow: hidden; background: #eee} | |
img {display: block} | |
.slider, select {display: block; margin: 10px; width: 85%} | |
.reset-me {color: red; cursor: pointer; text-decoration: underline} | |
.ui-slider .ui-slider-handle {widht: 0.9em; height: 0.9em} | |
.ui-slider-horizontal {height: 0.6em} | |
</style> | |
<script type="text/javascript"> | |
/** | |
* UI event handlers | |
* | |
*/ | |
(function ($) { | |
var locked = false; | |
window.resample = function (event) { | |
if (locked) | |
return; | |
var elem = $(event.target), wrap, query, sliders = $('.slider'); | |
sliders.slider({disabled: true}); | |
wrap = elem.closest('.image'); | |
query = {slug: wrap.prop('id')}; | |
wrap.find('.slider').map(function (index, slider) { | |
slider = $(slider); | |
slider.prev('label').find('span').text(slider.slider('value')); | |
query[slider.data('name')] = slider.slider('value'); | |
}); | |
wrap.find('select').map(function (index, widg) { | |
widg = $(widg); | |
query[widg.prop('name')] = widg.val(); | |
}); | |
/** | |
* Sigma can't be greater than radius, also blows up when 0 | |
*/ | |
if (query.sigma && query.radius && query.sigma > query.radius) { | |
query.sigma = query.radius; | |
wrap.find('.slider[data-name="sigma"]').slider('value', query.radius); | |
} | |
/** | |
* Replace the image with the URL for the altered one | |
*/ | |
wrap.find('img').replaceWith($('<img/>').attr({src: '/test.php?' + $.param(query)})); | |
sliders.slider({disabled: false}); | |
}; | |
/** | |
* Reload cropped image and reset sliders | |
*/ | |
window.reset_me = function (e) { | |
locked = true; | |
var wrap = $(e.target).closest('.image'); | |
wrap.find('.slider').slider('value', 0); | |
wrap.find('select').val(''); | |
wrap.find('img').replaceWith($('<img/>').attr({src: '/test-images/cropped-250.jpg'})); | |
locked = false; | |
}; | |
}(jQuery)); | |
</script> | |
<div id="images"> | |
<?php | |
foreach ( $map as $slug => $data ): | |
list( $method, $params ) = $data; | |
?> | |
<div class="image" id="<?php echo $slug ?>"> | |
<div class="image-frame"> | |
<img src="http://wordpress-core/test-images/cropped-250.jpg"/> | |
</div> | |
<h3>Imagick::<?php echo $method ?></h3> | |
<?php | |
/** | |
* Values are not dynamic | |
*/ | |
foreach ( $params as $key => $default ): | |
if ( in_array( $key, array( 'channel', 'noise_type' ) ) ): ?> | |
<label><?php echo ucwords( str_replace( '_', ' ', $key ) ) ?></label> | |
<select name="<?php echo $key ?>"> | |
<?php | |
foreach ( $default as $const => $value ): ?> | |
<option value="<?php echo $value ?>"><?php echo $const ?></option> | |
<?php | |
endforeach; | |
?> | |
</select> | |
<?php | |
/** | |
* Output minimum for jQuery UI slider | |
*/ | |
else: | |
?> | |
<label><?php echo ucwords( $key ) ?> <span></span></label> | |
<div class="slider <?php echo $key ?>" data-name="<?php echo $key ?>"></div> | |
<?php | |
endif; | |
endforeach ?> | |
<a class="reset-me">Reset</a> | |
<script type="text/javascript"> | |
jQuery(function ($) { | |
<?php | |
/** | |
* For now, output JS inline for each item | |
* Convert max / min to padded int - will be coverted to float later | |
* | |
*/ | |
foreach ( $params as $key => $default ): | |
if ( in_array( $key, array( 'channel', 'noise_type' ) ) ) | |
continue; | |
if ( is_array( $default ) ): | |
$start = reset( $default ); | |
$end = end( $default ); | |
?> | |
var elem = $('#<?php echo $slug, ' .', $key ?>'), params = { | |
animate: true, | |
min: <?php echo $start ?>, | |
max: <?php echo $end ?>, | |
stop : resample, | |
step : 1 | |
}; | |
elem.slider(params); | |
<?php | |
else: | |
/** | |
* These are the 0.0 values, these may sorta work for some params | |
* but need appropriate default ranges later | |
*/ | |
?> | |
var elem = $('#<?php echo $slug, ' .', $key ?>'), params = { | |
animate: true, | |
min : <?php echo $default ?>, | |
max : 800, | |
stop : resample, | |
step : 1 | |
}; | |
elem.slider(params); | |
<?php | |
endif; | |
endforeach ?> | |
}); | |
</script> | |
</div> | |
<?php endforeach ?> | |
</div> | |
<script type="text/javascript"> | |
/** | |
* Generical handlers | |
*/ | |
jQuery(function ($) { | |
$('select').change(resample); | |
$('.reset-me').click(reset_me); | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment