diff --git src/wp-admin/includes/image.php src/wp-admin/includes/image.php
index 84e4c4c..87b8191 100644
--- src/wp-admin/includes/image.php
+++ 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 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..fb56eb1 100644
--- src/wp-includes/class-wp-image-editor-imagick.php
+++ src/wp-includes/class-wp-image-editor-imagick.php
@@ -73,6 +73,7 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor {
 			'rotateimage',
 			'flipimage',
 			'flopimage',
+			'readimage',
 		);
 
 		// Now, test for deep requirements within Imagick.
@@ -144,7 +145,18 @@ 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 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 src/wp-includes/media-template.php src/wp-includes/media-template.php
index c669921..95fbb9a 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.medium ) { #>
+							<img src="{{ data.sizes.medium.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 f6c5f0f..ad73301 100644
--- src/wp-includes/media.php
+++ 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 tests/phpunit/tests/image/functions.php tests/phpunit/tests/image/functions.php
index 6335df0..aa2940d 100644
--- tests/phpunit/tests/image/functions.php
+++ tests/phpunit/tests/image/functions.php
@@ -351,4 +351,53 @@ 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() {
+		$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 );
+	}
 }
