diff --git a/core/ajax/preview.php b/core/ajax/preview.php
index 6cfba6aef30320dc89eaf47fbf978385d0c19fab..aac623b5ce6e2dcda748bf81c780e5629c56ef98 100644
--- a/core/ajax/preview.php
+++ b/core/ajax/preview.php
@@ -49,19 +49,27 @@ if ($maxX === 0 || $maxY === 0) {
 	exit;
 }
 
-$info = \OC\Files\Filesystem::getFileInfo($file);
+$folder = \OC::$server->getUserFolder();
 
-if (!$info instanceof OCP\Files\FileInfo || !$always && !\OC::$server->getPreviewManager()->isAvailable($info)) {
+try {
+	$file = $folder->get($file);
+} catch (\OCP\Files\NotFoundException $e) {
+	return \OC_Response::setStatus(404);
+}
+
+if (!$file instanceof OCP\Files\File || !$always && !\OC::$server->getPreviewManager()->isAvailable($file)) {
 	\OC_Response::setStatus(404);
 } else if (!$info->isReadable()) {
 	\OC_Response::setStatus(403);
 } else {
-	$preview = new \OC\Preview(\OC_User::getUser(), 'files');
-	$preview->setFile($file, $info);
-	$preview->setMaxX($maxX);
-	$preview->setMaxY($maxY);
-	$preview->setScalingUp($scalingUp);
-	$preview->setMode($mode);
-	$preview->setKeepAspect($keepAspect);
-	$preview->showPreview();
+	$preview = new \OC\Preview2(
+		\OC::$server->getRootFolder(),
+		\OC::$server->getConfig(),
+		\OC::$server->getPreviewManager(),
+		$file
+	);
+	$image = $preview->getPreview($maxX, $maxY, !$keepAspect, $mode);
+
+	header('Content-Type: ' . $image->getMimeType());
+	echo $image->getContent();
 }
diff --git a/core/ajax/preview2.php b/core/ajax/preview2.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2bbf64c6d20430d862e87d3017bb49dc6c63a01
--- /dev/null
+++ b/core/ajax/preview2.php
@@ -0,0 +1,36 @@
+<?php
+
+\OC_Util::checkLoggedIn();
+\OC::$server->getSession()->close();
+
+$file = array_key_exists('file', $_GET) ? (string)$_GET['file'] : '';
+$maxX = array_key_exists('x', $_GET) ? (int)$_GET['x'] : '32';
+$maxY = array_key_exists('y', $_GET) ? (int)$_GET['y'] : '32';
+$keepAspect = array_key_exists('a', $_GET) ? true : false;
+$always = array_key_exists('forceIcon', $_GET) ? (bool)$_GET['forceIcon'] : true;
+$mode = array_key_exists('mode', $_GET) ? $_GET['mode'] : 'fill';
+
+if ($file === '') {
+	//400 Bad Request
+	\OC_Response::setStatus(400);
+	\OCP\Util::writeLog('core-preview', 'No file parameter was passed', \OCP\Util::DEBUG);
+	exit;
+}
+
+if ($maxX === 0 || $maxY === 0) {
+	//400 Bad Request
+	\OC_Response::setStatus(400);
+	\OCP\Util::writeLog('core-preview', 'x and/or y set to 0', \OCP\Util::DEBUG);
+	exit;
+}
+
+$userFolder = \OC::$server->getUserFolder();
+$file = $userFolder->get($file);
+
+$p = new \OC\Preview2(\OC::$server->getRootFolder(),
+	\OC::$server->getConfig(),
+	\OC::$server->getPreviewManager(),
+	$file);
+
+$p->getPreview($maxX, $maxY, !$keepAspect, $mode);
+
diff --git a/core/routes.php b/core/routes.php
index 7978001af7d85ddd9d4569a4fe2c41fc5414a1ad..4b73a86042a6c79178a21157cb7ba2f68a050bed 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -70,6 +70,8 @@ $this->create('search_ajax_search', '/core/search')
 // Routing
 $this->create('core_ajax_preview', '/core/preview')
 	->actionInclude('core/ajax/preview.php');
+$this->create('core_ajax_preview2', '/core/preview2')
+	->actionInclude('core/ajax/preview2.php');
 $this->create('core_ajax_preview', '/core/preview.png')
 	->actionInclude('core/ajax/preview.php');
 $this->create('core_ajax_update', '/core/ajax/update.php')
diff --git a/lib/private/Preview.php b/lib/private/Preview.php
index ccaec738caf7c9b4529844c9ca658792a9faae9c..caa1e89baccee4247b39ed7cef77dadd10fc94d2 100644
--- a/lib/private/Preview.php
+++ b/lib/private/Preview.php
@@ -125,7 +125,7 @@ class Preview {
 		$sysConfig = \OC::$server->getConfig();
 		$this->configMaxWidth = $sysConfig->getSystemValue('preview_max_x', 2048);
 		$this->configMaxHeight = $sysConfig->getSystemValue('preview_max_y', 2048);
-		$this->maxScaleFactor = $sysConfig->getSystemValue('preview_max_scale_factor', 2);
+		$this->maxScaleFactor = $sysConfig->getSystemValue('preview_max_scale_factor', 1);
 
 		//save parameters
 		$this->setFile($file);
diff --git a/lib/private/Preview2.php b/lib/private/Preview2.php
new file mode 100644
index 0000000000000000000000000000000000000000..11e699a2e72e14f9aa89d43025c3d7f2d4025dac
--- /dev/null
+++ b/lib/private/Preview2.php
@@ -0,0 +1,366 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC;
+
+use OC\Files\View;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IConfig;
+use OCP\IImage;
+use OCP\Image;
+use OCP\IPreview;
+use OCP\Preview\IProvider;
+
+class Preview2 {
+	//the thumbnail folder
+	const THUMBNAILS_FOLDER = 'thumbnails';
+
+	const MODE_FILL = 'fill';
+	const MODE_COVER = 'cover';
+
+	/** @var IRootFolder*/
+	private $rootFolder;
+	/** @var File */
+	private $file;
+	/** @var IPreview */
+	private $previewManager;
+	/** @var IConfig */
+	private $config;
+
+	public function __construct(
+		IRootFolder $rootFolder,
+		IConfig $config,
+		IPreview $previewManager,
+		File $file
+	) {
+		$this->rootFolder = $rootFolder;
+		$this->config = $config;
+		$this->file = $file;
+		$this->previewManager = $previewManager;
+	}
+
+	/**
+	 * Returns a preview of a file
+	 *
+	 * The cache is searched first and if nothing usable was found then a preview is
+	 * generated by one of the providers
+	 *
+	 * @param int $width
+	 * @param int $height
+	 * @param bool $crop
+	 * @param string $mode
+	 * @return File
+	 * @throws NotFoundException
+	 */
+	public function getPreview($width = -1, $height = -1, $crop = false, $mode = Preview2::MODE_FILL) {
+		if (!$this->previewManager->isMimeSupported($this->file->getMimeType())) {
+			throw new NotFoundException();
+		}
+
+		/*
+		 * Get the preview folder
+		 * TODO: Separate preview creation from storing previews
+		 */
+		$previewFolder = $this->getPreviewFolder();
+
+		// Get the max preview and infer the max preview sizes from that
+		$maxPreview = $this->getMaxPreview($previewFolder);
+		list($maxWidth, $maxHeight) = $this->getPreviewSize($maxPreview);
+
+		// Calculate the preview size
+		list($width, $height) = $this->calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight);
+
+		// Try to get a cached preview. Else generate (and store) one
+		try {
+			$file = $this->getCachedPreview($previewFolder, $width, $height, $crop);
+		} catch (NotFoundException $e) {
+			$file = $this->generatePreview($previewFolder, $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight);
+		}
+
+		return $file;
+	}
+
+	/**
+	 * @param Folder $previewFolder
+	 * @return File
+	 * @throws NotFoundException
+	 */
+	private function getMaxPreview(Folder $previewFolder) {
+		$nodes = $previewFolder->getDirectoryListing();
+
+		/** @var File $node */
+		foreach ($nodes as $node) {
+			if (strpos($node->getName(), 'max')) {
+				return $node;
+			}
+		}
+
+		$previewProviders = $this->previewManager->getProviders();
+		foreach ($previewProviders as $supportedMimeType => $providers) {
+			if (!preg_match($supportedMimeType, $this->file->getMimeType())) {
+				continue;
+			}
+
+			foreach ($providers as $provider) {
+				$provider = $provider();
+				if (!($provider instanceof IProvider)) {
+					continue;
+				}
+
+				list($view, $path) = $this->getViewAndPath($this->file);
+
+				$maxWidth = (int)$this->config->getSystemValue('preview_max_x', 2048);
+				$maxHeight = (int)$this->config->getSystemValue('preview_max_y', 2048);
+
+				$preview = $provider->getThumbnail($path, $maxWidth, $maxHeight, false, $view);
+
+				if (!($preview instanceof IImage)) {
+					continue;
+				}
+
+				$path = strval($preview->width()) . '-' . strval($preview->height()) . '-max.png';
+				$file = $previewFolder->newFile($path);
+				$file->putContent($preview->data());
+
+				return $file;
+			}
+		}
+
+		throw new NotFoundException();
+	}
+
+	/**
+	 * @param File $file
+	 * @return int[]
+	 */
+	private function getPreviewSize(File $file) {
+		$size = explode('-', $file->getName());
+		return [(int)$size[0], (int)$size[1]];
+	}
+
+	/**
+	 * @param int $width
+	 * @param int $height
+	 * @param bool $crop
+	 * @return string
+	 */
+	private function generatePath($width, $height, $crop) {
+		$path = strval($width) . '-' . strval($height);
+		if ($crop) {
+			$path .= '-crop';
+		}
+		$path .= '.png';
+		return $path;
+	}
+
+	/**
+	 * @param File $file
+	 * @return array
+	 * This is required to create the old view and path
+	 */
+	private function getViewAndPath(File $file) {
+		$owner = $file->getOwner()->getUID();
+
+		$userFolder = $this->rootFolder->getUserFolder($owner)->getParent();
+		$nodes = $userFolder->getById($file->getId());
+
+		$file = $nodes[0];
+
+		$view = new View($userFolder->getPath());
+		$path = $userFolder->getRelativePath($file->getPath());
+
+		return [$view, $path];
+	}
+
+	/**
+	 * @param int $width
+	 * @param int $height
+	 * @param bool $crop
+	 * @param string $mode
+	 * @param int $maxWidth
+	 * @param int $maxHeight
+	 * @return int[]
+	 */
+	private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight) {
+
+		/*
+		 * If we are not cropping we have to make sure the requested image
+		 * respects the aspect ratio of the original.
+		 */
+		if (!$crop) {
+			$ratio = $maxHeight / $maxWidth;
+
+			if ($width === -1) {
+				$width = $height / $ratio;
+			}
+			if ($height === -1) {
+				$height = $width * $ratio;
+			}
+
+			$ratioH = $height / $maxHeight;
+			$ratioW = $width / $maxWidth;
+
+			/*
+			 * Fill means that the $height and $width are the max
+			 * Cover means min.
+			 */
+			if ($mode === self::MODE_FILL) {
+				if ($ratioH > $ratioW) {
+					$height = $width * $ratio;
+				} else {
+					$width = $height / $ratio;
+				}
+			} else if ($mode === self::MODE_COVER) {
+				if ($ratioH > $ratioW) {
+					$width = $height / $ratio;
+				} else {
+					$height = $width * $ratio;
+				}
+			}
+		}
+
+		if ($height !== $maxHeight && $width !== $maxWidth) {
+			/*
+			 * Scale to the nearest power of two
+			 */
+			$pow2height = pow(2, ceil(log($height) / log(2)));
+			$pow2width = pow(2, ceil(log($width) / log(2)));
+
+			$ratioH = $height / $pow2height;
+			$ratioW = $width / $pow2width;
+
+			if ($ratioH < $ratioW) {
+				$width = $pow2width;
+				$height = $height / $ratioW;
+			} else {
+				$height = $pow2height;
+				$width = $width / $ratioH;
+			}
+		}
+
+		/*
+ 		 * Make sure the requested height and width fall within the max
+ 		 * of the preview.
+ 		 */
+		if ($height > $maxHeight) {
+			$ratio = $height / $maxHeight;
+			$height = $maxHeight;
+			$width = $width / $ratio;
+		}
+		if ($width > $maxWidth) {
+			$ratio = $width / $maxWidth;
+			$width = $maxWidth;
+			$height = $height / $ratio;
+		}
+
+		return [(int)round($width), (int)round($height)];
+	}
+
+	/**
+	 * @param Folder $previewFolder
+	 * @param File $maxPreview
+	 * @param int $width
+	 * @param int $height
+	 * @param bool $crop
+	 * @param int $maxWidth,
+	 * @param int $maxHeight
+	 * @return File
+	 * @throws NotFoundException
+	 */
+	private function generatePreview(Folder $previewFolder, File $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight) {
+		$preview = new Image($maxPreview->getContent());
+
+		if ($crop) {
+			if ($height !== $preview->height() && $width !== $preview->width()) {
+				//Resize
+				$widthR = $preview->width() / $width;
+				$heightR = $preview->height() / $height;
+
+				if ($widthR > $heightR) {
+					$scaleH = $height;
+					$scaleW = $maxWidth / $heightR;
+				} else {
+					$scaleH = $maxHeight / $widthR;
+					$scaleW = $width;
+				}
+				$preview->preciseResize(round($scaleW), round($scaleH));
+			}
+			$cropX = floor(abs($width - $preview->width()) * 0.5);
+			$cropY = 0;
+			$preview->crop($cropX, $cropY, $width, $height);
+		} else {
+			$preview->resize(max($width, $height));
+		}
+
+		$path = $this->generatePath($width, $height, $crop);
+		$file = $previewFolder->newFile($path);
+		$file->putContent($preview->data());
+
+		return $file;
+	}
+
+	/**
+	 * @param Folder $previewFolder
+	 * @param int $width
+	 * @param int $height
+	 * @param bool $crop
+	 * @return File
+	 *
+	 * @throws NotFoundException
+	 */
+	private function getCachedPreview(Folder $previewFolder, $width, $height, $crop) {
+		$path = $this->generatePath($width, $height, $crop);
+
+		return $previewFolder->get($path);
+	}
+
+	/**
+	 * Get the specific preview folder for this file
+	 *
+	 * @return Folder
+	 */
+	private function getPreviewFolder() {
+		$user = $this->file->getOwner();
+		$user = $user->getUID();
+
+		$previewRoot = $this->rootFolder->getUserFolder($user);
+		$previewRoot = $previewRoot->getParent();
+
+		try {
+			/** @var Folder $previewRoot */
+			$previewRoot = $previewRoot->get(self::THUMBNAILS_FOLDER);
+		} catch (NotFoundException $e) {
+			$previewRoot = $previewRoot->newFolder(self::THUMBNAILS_FOLDER);
+		}
+
+		try {
+			$previewFolder = $previewRoot->get($this->file->getId());
+		} catch (NotFoundException $e) {
+			$previewFolder = $previewRoot->newFolder($this->file->getId());
+		}
+
+		return $previewFolder;
+	}
+}