From a8e304ec8ea6d4f1891efdc61fac64237baf68ad Mon Sep 17 00:00:00 2001 From: Mike Schroder Date: Wed, 26 Oct 2016 07:28:32 +0000 Subject: [PATCH] Media: Add support for rendering PDF thumbnails. When support for PDFs is available, on upload, render 'Thumbnail', 'Medium', 'Large', and 'Full' sizes of the first page, and save them in attachment meta. Use these renders within Add Media, Media Gallery and List views, Attachment Details, Post/Attachment Edit screens, and Attachment pages. Support available by default via Imagick -> ImageMagick -> Ghostscript, but can be provided by any `WP_Image_Editor` that supports PDFs. Props adamsilverstein, azaozz, celloexpressions, desrosj, dglingren, ericlewis, ipstenu, joemcgill, joyously, markoheijnen, melchoyce, mikeschroder, tomauger. Fixes #31050. Built from https://develop.svn.wordpress.org/trunk@38949 git-svn-id: http://core.svn.wordpress.org/trunk@38892 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/image.php | 42 ++++++++++++++- wp-admin/includes/media.php | 12 ++++- wp-includes/class-wp-image-editor-imagick.php | 14 ++++- wp-includes/media-template.php | 6 ++- wp-includes/media.php | 53 ++++++++++++++----- wp-includes/version.php | 2 +- 6 files changed, 111 insertions(+), 18 deletions(-) diff --git a/wp-admin/includes/image.php b/wp-admin/includes/image.php index 84e4c4c070..87b819180b 100644 --- a/wp-admin/includes/image.php +++ b/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/wp-admin/includes/media.php b/wp-admin/includes/media.php index 1ccb9980d2..c79e312444 100644 --- a/wp-admin/includes/media.php +++ b/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/wp-includes/media-template.php b/wp-includes/media-template.php index c6699216e9..95fbb9ab4b 100644 --- a/wp-includes/media-template.php +++ b/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/wp-includes/media.php b/wp-includes/media.php index f6c5f0f294..ad733013af 100644 --- a/wp-includes/media.php +++ b/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/wp-includes/version.php b/wp-includes/version.php index 78645d991b..028ff1e952 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.7-alpha-38948'; +$wp_version = '4.7-alpha-38949'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.