[wp-trac] [WordPress Trac] #40415: Imagick resize filter hook
WordPress Trac
noreply at wordpress.org
Thu Dec 7 12:19:22 UTC 2017
#40415: Imagick resize filter hook
-------------------------+------------------------------
Reporter: virgodesign | Owner:
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Media | Version: 4.7.3
Severity: normal | Resolution:
Keywords: | Focuses:
-------------------------+------------------------------
Comment (by dpacmittal):
+1 for this. Triangle is a really bad default filter. WP should provide a
filter hook, or better default.
In the meanwhile I'm using this workaround:
in your functions.php:
{{{#!php
<?php
require_once('class-imagick-modded.php');
if(class_exists('WP_Image_Editor_Imagick_Modded')){
// Force imagick modded
add_filter('wp_image_editors', function($implementations){
return ['WP_Image_Editor_Imagick_Modded'];
})
}
}}}
class-imagick-modded.php:
{{{#!php
<?php
<?php
/**
* WordPress Imagick Image Editor
*
* @package WordPress
* @subpackage Image_Editor
*/
/**
* WordPress Image Editor Class for Image Manipulation through Imagick PHP
Module
*
* @since 3.5.0
*
* @see WP_Image_Editor
*/
if(!class_exists('WP_Image_Editor_Imagick'))
return;
class WP_Image_Editor_Imagick_Modded extends WP_Image_Editor_Imagick {
/**
* Efficiently resize the current image
*
* This is a WordPress specific implementation of
Imagick::thumbnailImage(),
* which resizes an image to given dimensions and removes any
associated profiles.
*
* @since 4.5.0
*
* @param int $dst_w The destination width.
* @param int $dst_h The destination height.
* @param string $filter_name Optional. The Imagick filter to use when
resizing. Default 'FILTER_TRIANGLE'.
* @param bool $strip_meta Optional. Strip all profiles, excluding
color profiles, from the image. Default true.
* @return bool|WP_Error
*/
protected function thumbnail_image( $dst_w, $dst_h, $filter_name =
'FILTER_HAMMING', $strip_meta = true ) {
$allowed_filters = array(
'FILTER_POINT',
'FILTER_BOX',
'FILTER_TRIANGLE',
'FILTER_HERMITE',
'FILTER_HANNING',
'FILTER_HAMMING',
'FILTER_BLACKMAN',
'FILTER_GAUSSIAN',
'FILTER_QUADRATIC',
'FILTER_CUBIC',
'FILTER_CATROM',
'FILTER_MITCHELL',
'FILTER_LANCZOS',
'FILTER_BESSEL',
'FILTER_SINC',
);
/**
* Set the filter value if '$filter_name' name is in our whitelist
and the related
* Imagick constant is defined or fall back to our default filter.
*/
if ( in_array( $filter_name, $allowed_filters ) && defined(
'Imagick::' . $filter_name ) ) {
$filter = constant( 'Imagick::' . $filter_name );
} else {
$filter = defined( 'Imagick::FILTER_HAMMING' ) ?
Imagick::FILTER_HAMMING : false;
}
/**
* Filters whether to strip metadata from images when they're
resized.
*
* This filter only applies when resizing using the Imagick editor
since GD
* always strips profiles by default.
*
* @since 4.5.0
*
* @param bool $strip_meta Whether to strip image metadata during
resizing. Default true.
*/
if ( apply_filters( 'image_strip_meta', $strip_meta ) ) {
$this->strip_meta(); // Fail silently if not supported.
}
try {
/*
* To be more efficient, resample large images to 5x the
destination size before resizing
* whenever the output size is less that 1/3 of the original
image size (1/3^2 ~= .111),
* unless we would be resampling to a scale smaller than
128x128.
*/
if ( is_callable( array( $this->image, 'sampleImage' ) ) ) {
$resize_ratio = ( $dst_w / $this->size['width'] ) * (
$dst_h / $this->size['height'] );
$sample_factor = 5;
if ( $resize_ratio < .111 && ( $dst_w * $sample_factor >
128 && $dst_h * $sample_factor > 128 ) ) {
$this->image->sampleImage( $dst_w * $sample_factor,
$dst_h * $sample_factor );
}
}
/*
* Use resizeImage() when it's available and a valid filter
value is set.
* Otherwise, fall back to the scaleImage() method for
resizing, which
* results in better image quality over resizeImage() with
default filter
* settings and retains backward compatibility with pre 4.5
functionality.
*/
if ( is_callable( array( $this->image, 'resizeImage' ) ) &&
$filter ) {
$this->image->setOption( 'filter:support', '2.0' );
$this->image->resizeImage( $dst_w, $dst_h, $filter, 1 );
} else {
$this->image->scaleImage( $dst_w, $dst_h );
}
// Set appropriate quality settings after resizing.
if ( 'image/jpeg' == $this->mime_type ) {
$this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065
);
}
$this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
}
if ( 'image/png' === $this->mime_type ) {
$this->image->setOption( 'png:compression-filter', '5' );
$this->image->setOption( 'png:compression-level', '9' );
$this->image->setOption( 'png:compression-strategy', '1'
);
$this->image->setOption( 'png:exclude-chunk', 'all' );
}
/*
* If alpha channel is not defined, set it opaque.
*
* Note that Imagick::getImageAlphaChannel() is only available
if Imagick
* has been compiled against ImageMagick version 6.4.0 or
newer.
*/
if ( is_callable( array( $this->image, 'getImageAlphaChannel'
) )
&& is_callable( array( $this->image,
'setImageAlphaChannel' ) )
&& defined( 'Imagick::ALPHACHANNEL_UNDEFINED' )
&& defined( 'Imagick::ALPHACHANNEL_OPAQUE' )
) {
if ( $this->image->getImageAlphaChannel() ===
Imagick::ALPHACHANNEL_UNDEFINED ) {
$this->image->setImageAlphaChannel(
Imagick::ALPHACHANNEL_OPAQUE );
}
}
// Limit the bit depth of resized images to 8 bits per
channel.
if ( is_callable( array( $this->image, 'getImageDepth' ) ) &&
is_callable( array( $this->image, 'setImageDepth' ) ) ) {
if ( 8 < $this->image->getImageDepth() ) {
$this->image->setImageDepth( 8 );
}
}
if ( is_callable( array( $this->image, 'setInterlaceScheme' )
) && defined( 'Imagick::INTERLACE_NO' ) ) {
$this->image->setInterlaceScheme( Imagick::INTERLACE_NO );
}
} catch ( Exception $e ) {
return new WP_Error( 'image_resize_error', $e->getMessage() );
}
}
}
}}}
--
Ticket URL: <https://core.trac.wordpress.org/ticket/40415#comment:1>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list