Skip to content

Commit 082f6e6

Browse files
Media: improve Imagick handling of colors and alpha channel for PNG image uploads.
Fix an issue where index color (8 bit) PNG uploads were output as true color (24 bit) PNGs, significantly increasing their size. When using Imagick, PNG output images will now match the colors of the uploaded image. Also, correct handling of PNG alpha channel information so it is preserved in output images. Props adamsilverstein, pbearne, nosilver4u, peterdavehello, joemcgill, azaozz, codex-m, kirasong, justlevine, jokanane, sallyruchman, wpfed, tgsrvrs, antpb, tb1909. Fixes #36477. git-svn-id: https://develop.svn.wordpress.org/trunk@59589 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 2bab211 commit 082f6e6

File tree

7 files changed

+85
-1
lines changed

7 files changed

+85
-1
lines changed

src/wp-includes/class-wp-image-editor-imagick.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,38 @@ protected function thumbnail_image( $dst_w, $dst_h, $filter_name = 'FILTER_TRIAN
484484
$this->image->setOption( 'png:compression-filter', '5' );
485485
$this->image->setOption( 'png:compression-level', '9' );
486486
$this->image->setOption( 'png:compression-strategy', '1' );
487-
$this->image->setOption( 'png:exclude-chunk', 'all' );
487+
// Check to see if a PNG is indexed, and find the pixel depth.
488+
if ( is_callable( array( $this->image, 'getImageDepth' ) ) ) {
489+
$indexed_pixel_depth = $this->image->getImageDepth();
490+
491+
// Indexed PNG files get some additional handling.
492+
if ( 0 < $indexed_pixel_depth && 8 >= $indexed_pixel_depth ) {
493+
// Check for an alpha channel.
494+
if (
495+
is_callable( array( $this->image, 'getImageAlphaChannel' ) )
496+
&& $this->image->getImageAlphaChannel()
497+
) {
498+
$this->image->setOption( 'png:include-chunk', 'tRNS' );
499+
} else {
500+
$this->image->setOption( 'png:exclude-chunk', 'all' );
501+
}
502+
503+
// Reduce colors in the images to maximum needed, using the global colorspace.
504+
$max_colors = pow( 2, $indexed_pixel_depth );
505+
if ( is_callable( array( $this->image, 'getImageColors' ) ) ) {
506+
$current_colors = $this->image->getImageColors();
507+
$max_colors = min( $max_colors, $current_colors );
508+
}
509+
$this->image->quantizeImage( $max_colors, $this->image->getColorspace(), 0, false, false );
510+
511+
/**
512+
* If the colorspace is 'gray', use the png8 format to ensure it stays indexed.
513+
*/
514+
if ( Imagick::COLORSPACE_GRAY === $this->image->getImageColorspace() ) {
515+
$this->image->setOption( 'png:format', 'png8' );
516+
}
517+
}
518+
}
488519
}
489520

490521
/*
24.3 KB
Loading
24.4 KB
Loading
103 KB
Loading
196 KB
Loading
44.2 KB
Loading

tests/phpunit/tests/image/editorImagick.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,4 +758,57 @@ public function test_image_max_bit_depth() {
758758
public function __return_eight() {
759759
return 8;
760760
}
761+
762+
/**
763+
* Test that resizes are smaller for 16 bit PNG images.
764+
*
765+
* @ticket 36477
766+
*
767+
* @dataProvider data_resizes_are_small_for_16bit_images
768+
*/
769+
public function test_resizes_are_small_for_16bit_images( $file ) {
770+
771+
$temp_file = DIR_TESTDATA . '/images/test-temp.png';
772+
773+
$imagick_image_editor = new WP_Image_Editor_Imagick( $file );
774+
$imagick_image_editor->load();
775+
$size = $imagick_image_editor->get_size();
776+
777+
$org_filesize = filesize( $file );
778+
779+
$imagick_image_editor->resize( $size['width'] * .5, $size['height'] * .5 );
780+
781+
$saved = $imagick_image_editor->save( $temp_file );
782+
783+
$new_filesize = filesize( $temp_file );
784+
785+
unlink( $temp_file );
786+
787+
$this->assertLessThan( $org_filesize, $new_filesize, 'The resized image file size is not smaller than the original file size.' );
788+
}
789+
790+
/**
791+
* data_test_resizes_are_small_for_16bit
792+
*
793+
* @return array[]
794+
*/
795+
public static function data_resizes_are_small_for_16bit_images() {
796+
return array(
797+
'cloudflare-status' => array(
798+
DIR_TESTDATA . '/images/png-tests/cloudflare-status.png',
799+
),
800+
'deskcat8' => array(
801+
DIR_TESTDATA . '/images/png-tests/deskcat8.png',
802+
),
803+
'17-c3-duplicate-entries' => array(
804+
DIR_TESTDATA . '/images/png-tests/Palette_icon-or8.png',
805+
),
806+
'rabbit-time-paletted' => array(
807+
DIR_TESTDATA . '/images/png-tests/rabbit-time-paletted-or8.png',
808+
),
809+
'test8' => array(
810+
DIR_TESTDATA . '/images/png-tests/test8.png',
811+
),
812+
);
813+
}
761814
}

0 commit comments

Comments
 (0)