diff --git src/wp-admin/includes/image.php src/wp-admin/includes/image.php
index 84e4c4c..4c33dd5 100644
--- src/wp-admin/includes/image.php
+++ src/wp-admin/includes/image.php
@@ -76,7 +76,18 @@ 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 );
+
+	/**
+	 * Filter attachment mime-types that support thumbnail fallback.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param array $mime_types An array of mime-types.
+	 */
+	$attachment_fallback_mimetypes = apply_filters( 'attachment_fallback_mimetypes', array( 'application/pdf' ) );
+
+	if ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) {
 		$imagesize = getimagesize( $file );
 		$metadata['width'] = $imagesize[0];
 		$metadata['height'] = $imagesize[1];
@@ -201,6 +212,27 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) {
 			}
 		}
 	}
+	// Check to see if we support a fallback thumbnail for this mime-type.
+	else if ( in_array( $mime_type, $attachment_fallback_mimetypes ) ) {
+		$editor = wp_get_image_editor( $file );
+		$sizes = array(
+			'thumbnail' => array(
+				'width'  => get_option( "thumbnail_size_w" ),
+				'height' => get_option( "thumbnail_size_h" ),
+				'crop'   => get_option( "thumbnail_crop" )
+			)
+		);
+
+		if ( ! is_wp_error( $editor ) ) { // No support for this type of file
+			$uploaded = $editor->save( $file . '.jpg' );
+			unset( $uploaded['path'] );
+
+			if ( ! is_wp_error( $uploaded ) ) {
+				$metadata['sizes'] = $editor->multi_resize( $sizes );
+				$metadata['sizes']['full'] = $uploaded;
+			}
+		}
+	}
 
 	// Remove the blob of binary data from the array.
 	if ( $metadata ) {
diff --git src/wp-admin/includes/media.php src/wp-admin/includes/media.php
index 1ccb998..c79e312 100644
--- src/wp-admin/includes/media.php
+++ 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] ) ):
+
+		?>
+		<div class="wp_attachment_image wp-clearfix" id="media-head-<?php echo $attachment_id; ?>">
+			<p id="thumbnail-head-<?php echo $attachment_id; ?>">
+				<img class="thumbnail" src="<?php echo set_url_scheme( $thumb_url[0] ); ?>" style="max-width:100%" alt="" />
+			</p>
+		</div>
+		<?php
+
+	else:
 
 		/**
 		 * Fires when an attachment type can't be rendered in the edit form.
diff --git src/wp-includes/class-wp-image-editor-imagick.php src/wp-includes/class-wp-image-editor-imagick.php
index 82b872d..211c600 100644
--- src/wp-includes/class-wp-image-editor-imagick.php
+++ src/wp-includes/class-wp-image-editor-imagick.php
@@ -144,7 +144,20 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 		wp_raise_memory_limit( 'image' );
 
 		try {
-			$this->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 resolution.
+			if ( 'pdf' == $file_parts['extension'] ) {
+				$this->image->setResolution( 200, 200 );
+			}
+
+			// TODO: This is the first readImage use, and we need to be sure it's available.
+			// 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 src/wp-includes/media-template.php src/wp-includes/media-template.php
index c669921..3608a0c 100644
--- src/wp-includes/media-template.php
+++ src/wp-includes/media-template.php
@@ -290,9 +290,9 @@ function wp_print_media_templates() {
 			<div class="thumbnail thumbnail-{{ data.type }}">
 				<# if ( data.uploading ) { #>
 					<div class="media-progress-bar"><div></div></div>
-				<# } else if ( 'image' === data.type && data.sizes && data.sizes.large ) { #>
+				<# } else if ( data.sizes && data.sizes.large ) { #>
 					<img class="details-image" src="{{ data.sizes.large.url }}" draggable="false" alt="" />
-				<# } else if ( 'image' === data.type && data.sizes && data.sizes.full ) { #>
+				<# } else if ( data.sizes && data.sizes.full ) { #>
 					<img class="details-image" src="{{ data.sizes.full.url }}" draggable="false" alt="" />
 				<# } else if ( -1 === jQuery.inArray( data.type, [ 'audio', 'video' ] ) ) { #>
 					<img class="details-image icon" src="{{ data.icon }}" draggable="false" alt="" />
@@ -454,6 +454,8 @@ function wp_print_media_templates() {
 					<div class="centered">
 						<# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
 							<img src="{{ data.image.src }}" class="thumbnail" draggable="false" alt="" />
+						<# } else if ( data.sizes && data.sizes.full ) { #>
+							<img src="{{ data.sizes.full.url }}" class="thumbnail" draggable="false" alt="" />
 						<# } else { #>
 							<img src="{{ data.icon }}" class="icon" draggable="false" alt="" />
 						<# } #>
diff --git src/wp-includes/media.php src/wp-includes/media.php
index 7a316d1..e1e4840 100644
--- src/wp-includes/media.php
+++ src/wp-includes/media.php
@@ -183,25 +183,25 @@ function image_hwstring( $width, $height ) {
  *                     the image is an intermediate size. False on failure.
  */
 function image_downsize( $id, $size = 'medium' ) {
+	$is_image = wp_attachment_is_image( $id );
 
-	if ( !wp_attachment_is_image($id) )
-		return false;
-
-	/**
-	 * Filters whether to preempt the output of image_downsize().
-	 *
-	 * Passing a truthy value to the filter will effectively short-circuit
-	 * down-sizing the image, returning that value as output instead.
-	 *
-	 * @since 2.5.0
-	 *
-	 * @param bool         $downsize Whether to short-circuit the image downsize. Default false.
-	 * @param int          $id       Attachment ID for image.
-	 * @param array|string $size     Size of image. Image size or array of width and height values (in that order).
-	 *                               Default 'medium'.
-	 */
-	if ( $out = apply_filters( 'image_downsize', false, $id, $size ) ) {
-		return $out;
+	if ( $is_image ) {
+		/**
+		 * Filters whether to preempt the output of image_downsize().
+		 *
+		 * Passing a truthy value to the filter will effectively short-circuit
+		 * down-sizing the image, returning that value as output instead.
+		 *
+		 * @since 2.5.0
+		 *
+		 * @param bool         $downsize Whether to short-circuit the image downsize. Default false.
+		 * @param int          $id       Attachment ID for image.
+		 * @param array|string $size     Size of image. Image size or array of width and height values (in that order).
+		 *                               Default 'medium'.
+		 */
+		if ( $out = apply_filters( 'image_downsize', false, $id, $size ) ) {
+			return $out;
+		}
 	}
 
 	$img_url = wp_get_attachment_url($id);
@@ -210,6 +210,18 @@ 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.
+	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);
@@ -226,6 +238,7 @@ function image_downsize( $id, $size = 'medium' ) {
 			$is_intermediate = true;
 		}
 	}
+
 	if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
 		// any other type: use the real image
 		$width = $meta['width'];
@@ -685,6 +698,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 +756,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'] );
@@ -3127,7 +3145,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 */
@@ -3175,16 +3193,30 @@ 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';
+			array_merge( $response, $sizes['full'] );
 		}
+		else if ( $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 ) );
+	}
 
-		$response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] );
-	} elseif ( $meta && 'video' === $type ) {
+	if ( $meta && 'video' === $type ) {
 		if ( isset( $meta['width'] ) )
 			$response['width'] = (int) $meta['width'];
 		if ( isset( $meta['height'] ) )
