diff --git a/build/index.php b/build/index.php
index 625e052..eff4778 100644
--- a/build/index.php
+++ b/build/index.php
@@ -355,6 +355,8 @@ textarea ~ input[type=submit] { margin: 0.5rem 0.8rem; padding: 0.5rem; font-wei
 
 .cursor-query { cursor: help; }
 
+summary { cursor: pointer; }
+
 .larger { color: rgb(9, 180, 0); }
 .smaller, .deletion { color: rgb(207, 28, 17); }
 .nochange { color: rgb(132, 123, 199); font-style: italic; }
@@ -1798,7 +1800,7 @@ function render_recent_change($rchange)
 			if(!empty($rchange->newpage))
 				$resultClasses[] = "newpage";
 			
-			$result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml <span class='$size_display_class' title='$size_title_display'>($size_display)</span>";
+			$result .= "<a href='?page=$rchange->page'>$pageDisplayHtml</a> $editorDisplayHtml $timeDisplayHtml <span class='$size_display_class' title='$size_title_display'>($size_display)</span>";
 			break;
 		
 		case "deletion":
@@ -1808,7 +1810,7 @@ function render_recent_change($rchange)
 		
 		case "upload":
 			$resultClasses[] = "upload";
-			$result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml (" . human_filesize($rchange->filesize) . ")";
+			$result .= "<a href='?page=$rchange->page'>$pageDisplayHtml</a> $editorDisplayHtml $timeDisplayHtml (" . human_filesize($rchange->filesize) . ")";
 			break;
 	}
 	
@@ -2626,63 +2628,25 @@ register_module([
 			if(isset($_GET["type"]) and in_array($_GET["type"], [ "image/png", "image/jpeg", "image/webp" ]))
 				$output_mime = $_GET["type"];
 			
-			$preview_image = false;
+			$preview_image = new Imagick();
 			switch(substr($mime_type, 0, strpos($mime_type, "/")))
 			{
 				case "image":
-					// Read in the image
-					$image = false;
-					switch($mime_type)
-					{
-						case "image/jpeg":
-							$image = imagecreatefromjpeg($filepath);
-							break;
-						case "image/gif":
-							$image = imagecreatefromgif($filepath);
-							break;
-						case "image/png":
-							$image = imagecreatefrompng($filepath);
-							break;
-						case "image/webp":
-							$image = imagecreatefromwebp($filepath);
-							break;
-						default:
-							http_response_code(415);
-							$image = errorimage("Unsupported image type.");
-							break;
-					}
-					
-					// Get the size of the image for later
-					$raw_width = imagesx($image);
-					$raw_height = imagesy($image);
-					
-					// Resize the image
-					$preview_image = resize_image($image, $target_size);
-					// Delete the temporary image.
-					imagedestroy($image);
+					$preview_image->readImage($filepath);
 					break;
 				
 				default:
 					http_response_code(501);
 					$preview_image = errorimage("Unrecognised file type '$mime_type'.");
 			}
+			// Scale the image down to the target size
+			$preview_image->resizeImage($target_size, $target_size, imagick::FILTER_LANCZOS, 1, true);
 			
 			// Send the completed preview image to the user
 			header("content-type: $output_mime");
-			switch($output_mime)
-			{
-				case "image/jpeg":
-					imagejpeg($preview_image);
-					break;
-				case "image/png":
-					imagepng($preview_image);
-					break;
-				default:
-				case "image/webp":
-					imagewebp($preview_image);
-					break;
-			}
-			imagedestroy($preview_image);
+			$outputFormat = substr($mime_type, strpos($mime_type, "/") + 1);
+			$preview_image->setImageFormat($outputFormat);
+			echo($preview_image->getImageBlob());
 		});
 		
 		page_renderer::register_part_preprocessor(function(&$parts) {
@@ -2775,26 +2739,6 @@ function errorimage($text)
 	return $image;
 }
 
-function resize_image($image, $size)
-{
-	$cur_width = imagesx($image);
-	$cur_height = imagesy($image);
-	
-	if($cur_width < $size and $cur_height < $size)
-		return $image;
-	
-	$width_ratio = $size / $cur_width;
-	$height_ratio = $size / $cur_height;
-	$ratio = min($width_ratio, $height_ratio);
-	
-	$new_height = floor($cur_height * $ratio);
-	$new_width = floor($cur_width * $ratio);
-	
-	header("x-resize-to: $new_width x $new_height\n");
-	
-	return imagescale($image, $new_width, $new_height);
-}
-
 
 
 
diff --git a/module_index.json b/module_index.json
index 3a5c587..0567c36 100644
--- a/module_index.json
+++ b/module_index.json
@@ -41,7 +41,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds recent changes. Access through the 'recent-changes' action.",
         "id": "feature-recent-changes",
-        "lastupdate": 1459952614,
+        "lastupdate": 1459954970,
         "optional": false
     },
     {
@@ -68,7 +68,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds the ability to upload files to Pepperminty Wiki. Uploaded files act as pages and have the special 'File:' prefix.",
         "id": "feature-upload",
-        "lastupdate": 1459695742,
+        "lastupdate": 1459955981,
         "optional": false
     },
     {
diff --git a/modules/feature-recent-changes.php b/modules/feature-recent-changes.php
index c743fc6..12fffce 100644
--- a/modules/feature-recent-changes.php
+++ b/modules/feature-recent-changes.php
@@ -202,7 +202,7 @@ function render_recent_change($rchange)
 			if(!empty($rchange->newpage))
 				$resultClasses[] = "newpage";
 			
-			$result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml <span class='$size_display_class' title='$size_title_display'>($size_display)</span>";
+			$result .= "<a href='?page=$rchange->page'>$pageDisplayHtml</a> $editorDisplayHtml $timeDisplayHtml <span class='$size_display_class' title='$size_title_display'>($size_display)</span>";
 			break;
 		
 		case "deletion":
@@ -212,7 +212,7 @@ function render_recent_change($rchange)
 		
 		case "upload":
 			$resultClasses[] = "upload";
-			$result .= "$pageDisplayHtml $editorDisplayHtml $timeDisplayHtml (" . human_filesize($rchange->filesize) . ")";
+			$result .= "<a href='?page=$rchange->page'>$pageDisplayHtml</a> $editorDisplayHtml $timeDisplayHtml (" . human_filesize($rchange->filesize) . ")";
 			break;
 	}
 	
diff --git a/modules/feature-upload.php b/modules/feature-upload.php
index c607b12..b129775 100644
--- a/modules/feature-upload.php
+++ b/modules/feature-upload.php
@@ -215,63 +215,25 @@ register_module([
 			if(isset($_GET["type"]) and in_array($_GET["type"], [ "image/png", "image/jpeg", "image/webp" ]))
 				$output_mime = $_GET["type"];
 			
-			$preview_image = false;
+			$preview_image = new Imagick();
 			switch(substr($mime_type, 0, strpos($mime_type, "/")))
 			{
 				case "image":
-					// Read in the image
-					$image = false;
-					switch($mime_type)
-					{
-						case "image/jpeg":
-							$image = imagecreatefromjpeg($filepath);
-							break;
-						case "image/gif":
-							$image = imagecreatefromgif($filepath);
-							break;
-						case "image/png":
-							$image = imagecreatefrompng($filepath);
-							break;
-						case "image/webp":
-							$image = imagecreatefromwebp($filepath);
-							break;
-						default:
-							http_response_code(415);
-							$image = errorimage("Unsupported image type.");
-							break;
-					}
-					
-					// Get the size of the image for later
-					$raw_width = imagesx($image);
-					$raw_height = imagesy($image);
-					
-					// Resize the image
-					$preview_image = resize_image($image, $target_size);
-					// Delete the temporary image.
-					imagedestroy($image);
+					$preview_image->readImage($filepath);
 					break;
 				
 				default:
 					http_response_code(501);
 					$preview_image = errorimage("Unrecognised file type '$mime_type'.");
 			}
+			// Scale the image down to the target size
+			$preview_image->resizeImage($target_size, $target_size, imagick::FILTER_LANCZOS, 1, true);
 			
 			// Send the completed preview image to the user
 			header("content-type: $output_mime");
-			switch($output_mime)
-			{
-				case "image/jpeg":
-					imagejpeg($preview_image);
-					break;
-				case "image/png":
-					imagepng($preview_image);
-					break;
-				default:
-				case "image/webp":
-					imagewebp($preview_image);
-					break;
-			}
-			imagedestroy($preview_image);
+			$outputFormat = substr($mime_type, strpos($mime_type, "/") + 1);
+			$preview_image->setImageFormat($outputFormat);
+			echo($preview_image->getImageBlob());
 		});
 		
 		page_renderer::register_part_preprocessor(function(&$parts) {
@@ -364,24 +326,4 @@ function errorimage($text)
 	return $image;
 }
 
-function resize_image($image, $size)
-{
-	$cur_width = imagesx($image);
-	$cur_height = imagesy($image);
-	
-	if($cur_width < $size and $cur_height < $size)
-		return $image;
-	
-	$width_ratio = $size / $cur_width;
-	$height_ratio = $size / $cur_height;
-	$ratio = min($width_ratio, $height_ratio);
-	
-	$new_height = floor($cur_height * $ratio);
-	$new_width = floor($cur_width * $ratio);
-	
-	header("x-resize-to: $new_width x $new_height\n");
-	
-	return imagescale($image, $new_width, $new_height);
-}
-
 ?>
diff --git a/settings.fragment.php b/settings.fragment.php
index d0f4a7c..e670698 100644
--- a/settings.fragment.php
+++ b/settings.fragment.php
@@ -352,6 +352,8 @@ textarea ~ input[type=submit] { margin: 0.5rem 0.8rem; padding: 0.5rem; font-wei
 
 .cursor-query { cursor: help; }
 
+summary { cursor: pointer; }
+
 .larger { color: rgb(9, 180, 0); }
 .smaller, .deletion { color: rgb(207, 28, 17); }
 .nochange { color: rgb(132, 123, 199); font-style: italic; }
