diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php index 84e4c4c070..87b819180b 100644 --- a/src/wp-admin/includes/image.php +++ b/src/wp-admin/includes/image.php @@ -76,7 +76,9 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) { $metadata = array(); $support = false; - if ( preg_match('!^image/!', get_post_mime_type( $attachment )) && file_is_displayable_image($file) ) { + $mime_type = get_post_mime_type( $attachment ); + + if ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) { $imagesize = getimagesize( $file ); $metadata['width'] = $imagesize[0]; $metadata['height'] = $imagesize[1]; @@ -201,6 +203,44 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) { } } } + // Try to create image thumbnails for PDFs + else if ( 'application/pdf' === $mime_type ) { + $editor = wp_get_image_editor( $file ); + + $fallback_sizes = array( + 'thumbnail', + 'medium', + 'large', + ); + + $sizes = array(); + + foreach ( $fallback_sizes as $s ) { + $sizes[$s]['width'] = get_option( "{$s}_size_w" ); + $sizes[$s]['height'] = get_option( "{$s}_size_h" ); + + // Force thumbnails to be soft crops. + if ( ! 'thumbnail' === $s ) { + $sizes[$s]['crop'] = get_option( "{$s}_crop" ); + } + } + + if ( ! is_wp_error( $editor ) ) { // No support for this type of file + $uploaded = $editor->save( $file, 'image/jpeg' ); + unset( $editor ); + + // Resize based on the full size image, rather than the source. + if ( ! is_wp_error( $uploaded ) ) { + $editor = wp_get_image_editor( $uploaded['path'] ); + unset( $uploaded['path'] ); + + if ( ! is_wp_error( $editor ) ) { + $metadata['sizes'] = $editor->multi_resize( $sizes ); + $metadata['sizes']['full'] = $uploaded; + } + } + } + } // Remove the blob of binary data from the array. if ( $metadata ) { diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 1ccb9980d2..c79e312444 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -2766,7 +2766,17 @@ function edit_form_image_editor( $post ) { echo wp_video_shortcode( $attr ); - else : + elseif ( isset( $thumb_url[0] ) ): + + ?> +
+

+ +

+
+ image = new Imagick( $this->file ); + $this->image = new Imagick(); + $file_parts = pathinfo( $this->file ); + + // By default, PDFs are rendered in a very low resolution. + // We want the thumbnail to be readable, so increase the rendering dpi. + if ( 'pdf' == strtolower( $file_parts['extension'] ) ) { + $this->image->setResolution( 128, 128 ); + } + + // Reading image after Imagick instantiation because `setResolution` + // only applies correctly before the image is read. + $this->image->readImage( $this->file ); if ( ! $this->image->valid() ) return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file); diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index c6699216e9..95fbb9ab4b 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -290,9 +290,9 @@ function wp_print_media_templates() {
<# if ( data.uploading ) { #>
- <# } else if ( 'image' === data.type && data.sizes && data.sizes.large ) { #> + <# } else if ( data.sizes && data.sizes.large ) { #> - <# } else if ( 'image' === data.type && data.sizes && data.sizes.full ) { #> + <# } else if ( data.sizes && data.sizes.full ) { #> <# } else if ( -1 === jQuery.inArray( data.type, [ 'audio', 'video' ] ) ) { #> @@ -454,6 +454,8 @@ function wp_print_media_templates() {
<# if ( data.image && data.image.src && data.image.src !== data.icon ) { #> + <# } else if ( data.sizes && data.sizes.medium ) { #> + <# } else { #> <# } #> diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index f6c5f0f294..ad733013af 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -183,9 +183,7 @@ function image_hwstring( $width, $height ) { * the image is an intermediate size. False on failure. */ function image_downsize( $id, $size = 'medium' ) { - - if ( !wp_attachment_is_image($id) ) - return false; + $is_image = wp_attachment_is_image( $id ); /** * Filters whether to preempt the output of image_downsize(). @@ -210,6 +208,19 @@ function image_downsize( $id, $size = 'medium' ) { $is_intermediate = false; $img_url_basename = wp_basename($img_url); + // If the file isn't an image, attempt to replace its URL with a rendered image from its meta. + // Otherwise, a non-image type could be returned. + if ( ! $is_image ) { + if ( ! empty( $meta['sizes'] ) ) { + $img_url = str_replace( $img_url_basename, $meta['sizes']['full']['file'], $img_url ); + $img_url_basename = $meta['sizes']['full']['file']; + $width = $meta['sizes']['full']['width']; + $height = $meta['sizes']['full']['height']; + } else { + return false; + } + } + // try for a new style intermediate size if ( $intermediate = image_get_intermediate_size($id, $size) ) { $img_url = str_replace($img_url_basename, $intermediate['file'], $img_url); @@ -685,6 +696,11 @@ function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) { if ( is_array( $size ) ) { $candidates = array(); + if ( ! isset( $imagedata['file'] ) && isset( $imagedata['sizes']['full'] ) ) { + $imagedata['height'] = $imagedata['sizes']['full']['height']; + $imagedata['width'] = $imagedata['sizes']['full']['width']; + } + foreach ( $imagedata['sizes'] as $_size => $data ) { // If there's an exact match to an existing image size, short circuit. if ( $data['width'] == $size[0] && $data['height'] == $size[1] ) { @@ -738,7 +754,7 @@ function image_get_intermediate_size( $post_id, $size = 'thumbnail' ) { } // include the full filesystem path of the intermediate file - if ( empty($data['path']) && !empty($data['file']) ) { + if ( empty( $data['path'] ) && ! empty( $data['file'] ) && ! empty( $imagedata['file'] ) ) { $file_url = wp_get_attachment_url($post_id); $data['path'] = path_join( dirname($imagedata['file']), $data['file'] ); $data['url'] = path_join( dirname($file_url), $data['file'] ); @@ -3123,7 +3139,7 @@ function wp_prepare_attachment_for_js( $attachment ) { if ( current_user_can( 'delete_post', $attachment->ID ) ) $response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID ); - if ( $meta && 'image' === $type ) { + if ( $meta && ! empty( $meta['sizes'] ) ) { $sizes = array(); /** This filter is documented in wp-admin/includes/media.php */ @@ -3171,16 +3187,29 @@ function wp_prepare_attachment_for_js( $attachment ) { } } - $sizes['full'] = array( 'url' => $attachment_url ); + if ( 'image' === $type ) { + $sizes['full'] = array( 'url' => $attachment_url ); - if ( isset( $meta['height'], $meta['width'] ) ) { - $sizes['full']['height'] = $meta['height']; - $sizes['full']['width'] = $meta['width']; - $sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape'; + if ( isset( $meta['height'], $meta['width'] ) ) { + $sizes['full']['height'] = $meta['height']; + $sizes['full']['width'] = $meta['width']; + $sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape'; + } + + $response = array_merge( $response, $sizes['full'] ); + } elseif ( $meta['sizes']['full']['file'] ) { + $sizes['full'] = array( + 'url' => $base_url . $meta['sizes']['full']['file'], + 'height' => $meta['sizes']['full']['height'], + 'width' => $meta['sizes']['full']['width'], + 'orientation' => $meta['sizes']['full']['height'] > $meta['sizes']['full']['width'] ? 'portrait' : 'landscape' + ); } - $response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] ); - } elseif ( $meta && 'video' === $type ) { + $response = array_merge( $response, array( 'sizes' => $sizes ) ); + } + + if ( $meta && 'video' === $type ) { if ( isset( $meta['width'] ) ) $response['width'] = (int) $meta['width']; if ( isset( $meta['height'] ) ) diff --git a/tests/phpunit/data/images/wordpress-gsoc-flyer.pdf b/tests/phpunit/data/images/wordpress-gsoc-flyer.pdf new file mode 100644 index 0000000000..d7e1799575 Binary files /dev/null and b/tests/phpunit/data/images/wordpress-gsoc-flyer.pdf differ diff --git a/tests/phpunit/tests/image/functions.php b/tests/phpunit/tests/image/functions.php index 6335df02af..f058560cdf 100644 --- a/tests/phpunit/tests/image/functions.php +++ b/tests/phpunit/tests/image/functions.php @@ -351,4 +351,57 @@ class Tests_Image_Functions extends WP_UnitTestCase { remove_filter( 'wp_image_editors', array( $this, 'mock_image_editor' ) ); WP_Image_Editor_Mock::$save_return = array(); } + + /** + * @ticket 31050 + */ + public function test_wp_generate_attachment_metadata_pdf() { + if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) { + $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); + } + + $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; + $test_file = '/tmp/wordpress-gsoc-flyer.pdf'; + copy( $orig_file, $test_file ); + + $attachment_id = $this->factory->attachment->create_object( $test_file, 0, array( + 'post_mime_type' => 'application/pdf', + ) ); + + $this->assertNotEmpty( $attachment_id ); + + $expected = array( + 'sizes' => array( + 'thumbnail' => array( + 'file' => "wordpress-gsoc-flyer-116x150.jpg", + 'width' => 116, + 'height' => 150, + 'mime-type' => "image/jpeg", + ), + 'medium' => array( + 'file' => "wordpress-gsoc-flyer-232x300.jpg", + 'width' => 232, + 'height' => 300, + 'mime-type' => "image/jpeg", + ), + 'large' => array( + 'file' => "wordpress-gsoc-flyer-791x1024.jpg", + 'width' => 791, + 'height' => 1024, + 'mime-type' => "image/jpeg", + ), + 'full' => array( + 'file' => "wordpress-gsoc-flyer.jpg", + 'width' => 1088, + 'height' => 1408, + 'mime-type' => "image/jpeg", + ), + ), + ); + + $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); + $this->assertSame( $expected, $metadata ); + + unlink( $test_file ); + } }