Skip to content

Fix image quality degradation caused by quantizeImage on resized PNG assets (Trac #63448) #8810

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

Closed
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
59 changes: 29 additions & 30 deletions src/wp-includes/class-wp-image-editor-imagick.php
Original file line number Diff line number Diff line change
Expand Up @@ -484,38 +484,37 @@ protected function thumbnail_image( $dst_w, $dst_h, $filter_name = 'FILTER_TRIAN
$this->image->setOption( 'png:compression-filter', '5' );
$this->image->setOption( 'png:compression-level', '9' );
$this->image->setOption( 'png:compression-strategy', '1' );
// Check to see if a PNG is indexed, and find the pixel depth.
if ( is_callable( array( $this->image, 'getImageDepth' ) ) ) {
$indexed_pixel_depth = $this->image->getImageDepth();

// Indexed PNG files get some additional handling.
if ( 0 < $indexed_pixel_depth && 8 >= $indexed_pixel_depth ) {
// Check for an alpha channel.
if (
is_callable( array( $this->image, 'getImageAlphaChannel' ) )
&& $this->image->getImageAlphaChannel()
) {
$this->image->setOption( 'png:include-chunk', 'tRNS' );
} else {
$this->image->setOption( 'png:exclude-chunk', 'all' );
}

// Reduce colors in the images to maximum needed, using the global colorspace.
$max_colors = pow( 2, $indexed_pixel_depth );
if ( is_callable( array( $this->image, 'getImageColors' ) ) ) {
$current_colors = $this->image->getImageColors();
$max_colors = min( $max_colors, $current_colors );
}
$this->image->quantizeImage( $max_colors, $this->image->getColorspace(), 0, false, false );

/**
* If the colorspace is 'gray', use the png8 format to ensure it stays indexed.
*/
if ( Imagick::COLORSPACE_GRAY === $this->image->getImageColorspace() ) {
$this->image->setOption( 'png:format', 'png8' );
}

// Handle alpha chunk inclusion or exclusion.
if (
is_callable( array( $this->image, 'getImageAlphaChannel' ) ) &&
$this->image->getImageAlphaChannel()
) {
$this->image->setOption( 'png:include-chunk', 'tRNS' );
} else {
$this->image->setOption( 'png:exclude-chunk', 'all' );
}

// Only apply quantization to actual indexed PNGs.
if (
is_callable( array( $this->image, 'getImageColors' ) ) &&
is_callable( array( $this->image, 'getImageDepth' ) ) &&
is_callable( array( $this->image, 'getImageProperty' ) )
) {
$current_colors = $this->image->getImageColors();
$bit_depth = $this->image->getImageDepth();
$max_colors = pow( 2, $bit_depth );
$color_type = $this->image->getImageProperty( 'png:IHDR.color-type-orig' );

if ( $current_colors <= $max_colors && '3' === $color_type ) {
$this->image->quantizeImage( $current_colors, $this->image->getColorspace(), 0, false, false );
}
}

// If grayscale, ensure format is png8 to retain index palette.
if ( Imagick::COLORSPACE_GRAY === $this->image->getImageColorspace() ) {
$this->image->setOption( 'png:format', 'png8' );
}
}

/*
Expand Down
Loading