diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php index 756fcce894..f29373f253 100644 --- a/src/wp-includes/class-wp-image-editor-imagick.php +++ b/src/wp-includes/class-wp-image-editor-imagick.php @@ -168,6 +168,10 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { $this->image->setIteratorIndex( 0 ); } + if ( 'pdf' === $file_extension ) { + $this->remove_pdf_alpha_channel(); + } + $this->mime_type = $this->get_mime_type( $this->image->getImageFormat() ); } catch ( Exception $e ) { return new WP_Error( 'invalid_image', $e->getMessage(), $this->file ); @@ -751,6 +755,24 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { return $saved; } + /** + * Removes PDF alpha after it's been read. + * + * @since 6.4.0 + */ + protected function remove_pdf_alpha_channel() { + $version = Imagick::getVersion(); + // Remove alpha channel if possible to avoid black backgrounds for Ghostscript >= 9.14. RemoveAlphaChannel added in ImageMagick 6.7.5. + if ( $version['versionNumber'] >= 0x675 ) { + try { + // Imagick::ALPHACHANNEL_REMOVE mapped to RemoveAlphaChannel in PHP imagick 3.2.0b2. + $this->image->setImageAlphaChannel( defined( 'Imagick::ALPHACHANNEL_REMOVE' ) ? Imagick::ALPHACHANNEL_REMOVE : 12 ); + } catch ( Exception $e ) { + return new WP_Error( 'pdf_alpha_process_failed', $e->getMessage() ); + } + } + } + /** * @since 3.5.0 * @since 6.0.0 The `$filesize` value was added to the returned array. diff --git a/tests/phpunit/data/images/test-alpha.pdf b/tests/phpunit/data/images/test-alpha.pdf new file mode 100644 index 0000000000..1cbd4686e7 Binary files /dev/null and b/tests/phpunit/data/images/test-alpha.pdf differ diff --git a/tests/phpunit/tests/image/editorImagick.php b/tests/phpunit/tests/image/editorImagick.php index a8db8a3210..1209203904 100644 --- a/tests/phpunit/tests/image/editorImagick.php +++ b/tests/phpunit/tests/image/editorImagick.php @@ -641,4 +641,54 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { $this->assertNotWPError( $saved ); } + + /** + * Tests that the alpha channel of PDFs is removed from PDF previews. + * + * Only affects systems with Ghostscript version >= 9.14. + * + * @ticket 39216 + * + * @covers WP_Image_Editor_Imagick::remove_pdf_alpha_channel + */ + public function test_remove_pdf_alpha_channel_should_remove_the_alpha_channel_in_preview() { + if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) { + $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); + } + + $test_file = DIR_TESTDATA . '/images/test-alpha.pdf'; + $attachment_id = $this->factory->attachment->create_upload_object( $test_file ); + $this->assertNotEmpty( $attachment_id, 'The attachment was not created before testing.' ); + + $attached_file = get_attached_file( $attachment_id ); + $this->assertNotEmpty( $attached_file, 'The attached file was not returned.' ); + + $rgb = array( + 'r' => true, + 'g' => true, + 'b' => true, + ); + + // White. + $expected = array( + 'r' => 1, + 'g' => 1, + 'b' => 1, + ); + + $check = image_get_intermediate_size( $attachment_id, 'full' ); + $this->assertIsArray( $check, 'The intermediate size could not be retrieved.' ); + $this->assertArrayHasKey( 'file', $check, 'The intermediate size file was not found.' ); + + $check_file = path_join( dirname( $attached_file ), $check['file'] ); + $imagick = new Imagick( $check_file ); + $output = array_map( + static function( $value ) { + return (int) round( $value ); + }, + array_intersect_key( $imagick->getImagePixelColor( 100, 100 )->getColor( true /* normalized */ ), $rgb ) + ); + $imagick->destroy(); + $this->assertSame( $expected, $output, 'The image color of the generated thumb does not match expected opaque background.' ); // Allow for floating point equivalence. + } }