Skip to content
Snippets Groups Projects
Unverified Commit 958c1289 authored by Roeland Jago Douma's avatar Roeland Jago Douma
Browse files

New preview generator

parent b129adfb
No related branches found
No related tags found
No related merge requests found
......@@ -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();
}
<?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);
......@@ -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')
......
......@@ -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);
......
<?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;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment