WP_Image_Editor_Imagick::thumbnail_image │ protected │ WP 4.5.0
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.
Метод класса: WP_Image_Editor_Imagick{}
Хуки из метода
Возвращает
null|WP_Error.
Использование
// protected - в коде основоного (родительского) или дочернего класса $result = $this->thumbnail_image( $dst_w, $dst_h, $filter_name, $strip_meta );
- $dst_w(int) (обязательный)
- The destination width.
- $dst_h(int) (обязательный)
- The destination height.
- $filter_name(строка)
- The Imagick filter to use when resizing.
По умолчанию: 'FILTER_TRIANGLE' - $strip_meta(true|false)
- Strip all profiles, excluding color profiles, from the image.
По умолчанию: true
Список изменений
| С версии 4.5.0 | Введена. |
Код WP_Image_Editor_Imagick::thumbnail_image() WP Image Editor Imagick::thumbnail image WP 6.9
protected function thumbnail_image( $dst_w, $dst_h, $filter_name = 'FILTER_TRIANGLE', $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 the allowed list and the related
* Imagick constant is defined or fall back to the default filter.
*/
if ( in_array( $filter_name, $allowed_filters, true ) && defined( 'Imagick::' . $filter_name ) ) {
$filter = constant( 'Imagick::' . $filter_name );
} else {
$filter = defined( 'Imagick::FILTER_TRIANGLE' ) ? Imagick::FILTER_TRIANGLE : 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 {
/**
* Special handling for certain types of PNG images:
* 1. For PNG images, we need to specify compression settings and remove unneeded chunks.
* 2. For indexed PNG images, the number of colors must not exceed 256.
* 3. For indexed PNG images with an alpha channel, the tRNS chunk must be preserved.
* 4. For indexed PNG images with true alpha transparency (an alpha channel > 1 bit), we need to avoid saving
* the image using ImageMagick's 'png8' format, because that supports only binary (1 bit) transparency.
*
* For #4 we want to check whether the image has a 1-bit alpha channel before resizing, because resizing
* may cause the number of alpha values to multiply due to antialiasing. If the original image had only a
* 1-bit alpha channel, then a 1-bit alpha channel should be good enough for the resized images.
*
* Perform all the necessary checks before resizing the image and store the results in variables for later use.
*/
$is_png = false;
$is_indexed_png = false;
$is_indexed_png_with_alpha_channel = false;
$is_indexed_png_with_true_alpha_transparency = false;
if ( 'image/png' === $this->mime_type ) {
$is_png = true;
if (
is_callable( array( $this->image, 'getImageProperty' ) )
&& '3' === $this->image->getImageProperty( 'png:IHDR.color-type-orig' )
) {
$is_indexed_png = true;
if (
is_callable( array( $this->image, 'getImageAlphaChannel' ) )
&& $this->image->getImageAlphaChannel()
) {
$is_indexed_png_with_alpha_channel = true;
if (
is_callable( array( $this->image, 'getImageChannelDepth' ) )
&& defined( 'Imagick::CHANNEL_ALPHA' )
&& 1 < $this->image->getImageChannelDepth( Imagick::CHANNEL_ALPHA )
) {
$is_indexed_png_with_true_alpha_transparency = true;
}
}
}
}
/*
* 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 ) {
if ( is_callable( array( $this->image, 'unsharpMaskImage' ) ) ) {
$this->image->unsharpMaskImage( 0.25, 0.25, 8, 0.065 );
}
$this->image->setOption( 'jpeg:fancy-upsampling', 'off' );
}
if ( $is_png ) {
$this->image->setOption( 'png:compression-filter', '5' );
$this->image->setOption( 'png:compression-level', '9' );
$this->image->setOption( 'png:compression-strategy', '1' );
// Indexed PNG files get some additional handling.
// See #63448 for details.
if ( $is_indexed_png ) {
// Check for an alpha channel.
if ( $is_indexed_png_with_alpha_channel ) {
$this->image->setOption( 'png:include-chunk', 'tRNS' );
} else {
$this->image->setOption( 'png:exclude-chunk', 'all' );
}
$this->image->quantizeImage( 256, $this->image->getColorspace(), 0, false, false );
/*
* If the colorspace is 'gray', use the png8 format to ensure it stays indexed.
* ImageMagick tends to save grayscale images as grayscale PNGs rather than indexed PNGs,
* even though grayscale PNGs usually have considerably larger file sizes.
* But we can force ImageMagick to save the image as an indexed PNG instead,
* by telling it to use png8 format.
*
* Note that we need to first call quantizeImage() before checking getImageColorspace(),
* because only after calling quantizeImage() will the colorspace be COLORSPACE_GRAY for grayscale images
* (and we have not found any other way to identify grayscale images).
*
* We need to avoid forcing indexed format for images with true alpha transparency,
* because ImageMagick does not support saving an image with true alpha transparency as an indexed PNG.
*/
if ( Imagick::COLORSPACE_GRAY === $this->image->getImageColorspace() && ! $is_indexed_png_with_true_alpha_transparency ) {
// Set the image format to Indexed PNG.
$this->image->setOption( 'png:format', 'png8' );
}
} else {
$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.
if ( is_callable( array( $this->image, 'getImageDepth' ) ) && is_callable( array( $this->image, 'setImageDepth' ) ) ) {
/**
* Filters the maximum bit depth of resized images.
*
* This filter only applies when resizing using the Imagick editor since GD
* does not support getting or setting bit depth.
*
* Use this to adjust the maximum bit depth of resized images.
*
* @since 6.8.0
*
* @param int $max_depth The maximum bit depth. Default is the input depth.
* @param int $image_depth The bit depth of the original image.
*/
$max_depth = apply_filters( 'image_max_bit_depth', $this->image->getImageDepth(), $this->image->getImageDepth() );
$this->image->setImageDepth( $max_depth );
}
} catch ( Exception $e ) {
return new WP_Error( 'image_resize_error', $e->getMessage() );
}
}