server/lib/private/preview.php

862 lines
20 KiB
PHP
Raw Normal View History

<?php
/**
2013-04-25 09:18:45 +00:00
* Copyright (c) 2013 Frank Karlitschek frank@owncloud.org
* Copyright (c) 2013 Georg Ehrke georg@ownCloud.com
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
2013-05-09 21:59:16 +00:00
*
2013-04-25 09:18:45 +00:00
* Thumbnails:
* structure of filename:
* /data/user/thumbnails/pathhash/x-y.png
*
2013-04-25 09:18:45 +00:00
*/
2013-05-29 10:33:24 +00:00
namespace OC;
2014-04-04 09:37:47 +00:00
use OC\Preview\Provider;
use OCP\Files\NotFoundException;
2014-04-04 09:37:47 +00:00
2013-08-19 10:16:55 +00:00
require_once 'preview/image.php';
require_once 'preview/movies.php';
require_once 'preview/mp3.php';
require_once 'preview/svg.php';
require_once 'preview/txt.php';
require_once 'preview/office.php';
require_once 'preview/bitmap.php';
2013-05-29 10:33:24 +00:00
class Preview {
2013-07-10 15:57:04 +00:00
//the thumbnail folder
2013-04-25 09:18:45 +00:00
const THUMBNAILS_FOLDER = 'thumbnails';
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
//config
2013-07-11 17:03:21 +00:00
private $maxScaleFactor;
private $configMaxX;
private $configMaxY;
2013-04-25 09:18:45 +00:00
//fileview object
2013-08-19 10:16:55 +00:00
private $fileView = null;
private $userView = null;
2013-05-09 21:59:16 +00:00
//vars
private $file;
private $maxX;
private $maxY;
2014-04-04 14:21:50 +00:00
private $scalingUp;
private $mimeType;
private $keepAspect = false;
2013-05-17 17:08:16 +00:00
//filemapper used for deleting previews
// index is path, value is fileinfo
static public $deleteFileMapper = array();
2013-09-04 21:45:11 +00:00
/**
2014-04-04 09:37:47 +00:00
* preview images object
*
2013-09-04 21:45:11 +00:00
* @var \OC_Image
*/
2013-05-09 21:59:16 +00:00
private $preview;
//preview providers
static private $providers = array();
static private $registeredProviders = array();
static private $enabledProviders = array();
2014-02-27 12:15:18 +00:00
/**
* @var \OCP\Files\FileInfo
*/
protected $info;
2013-04-25 09:18:45 +00:00
/**
* check if thumbnail or bigger version of thumbnail of file is cached
2013-07-11 17:21:37 +00:00
* @param string $user userid - if no user is given, OC_User::getUser will be used
* @param string $root path of root
* @param string $file The path to the file where you want a thumbnail from
* @param int $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image
* @param int $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image
2013-07-30 10:29:12 +00:00
* @param bool $scalingUp Disable/Enable upscaling of previews
2014-04-21 13:44:54 +00:00
* @throws \Exception
* @return mixed (bool / string)
2014-02-27 12:15:18 +00:00
* false if thumbnail does not exist
* path to thumbnail if thumbnail exists
*/
public function __construct($user = '', $root = '/', $file = '', $maxX = 1, $maxY = 1, $scalingUp = true) {
//init fileviews
2014-02-27 12:15:18 +00:00
if ($user === '') {
$user = \OC_User::getUser();
}
$this->fileView = new \OC\Files\View('/' . $user . '/' . $root);
$this->userView = new \OC\Files\View('/' . $user);
2013-05-09 21:59:16 +00:00
//set config
2013-07-11 17:03:21 +00:00
$this->configMaxX = \OC_Config::getValue('preview_max_x', null);
$this->configMaxY = \OC_Config::getValue('preview_max_y', null);
$this->maxScaleFactor = \OC_Config::getValue('preview_max_scale_factor', 2);
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
//save parameters
2013-07-10 15:57:04 +00:00
$this->setFile($file);
$this->setMaxX($maxX);
$this->setMaxY($maxY);
2013-07-30 10:29:12 +00:00
$this->setScalingUp($scalingUp);
2013-05-09 21:59:16 +00:00
2013-07-10 15:57:04 +00:00
$this->preview = null;
2013-05-09 21:59:16 +00:00
2013-07-10 15:57:04 +00:00
//check if there are preview backends
2014-02-27 12:15:18 +00:00
if (empty(self::$providers)) {
self::initProviders();
2013-07-10 15:57:04 +00:00
}
2013-06-13 07:52:39 +00:00
2014-02-27 12:15:18 +00:00
if (empty(self::$providers)) {
2013-07-10 15:57:04 +00:00
\OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR);
throw new \Exception('No preview providers');
2013-05-09 21:59:16 +00:00
}
}
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
/**
* returns the path of the file you want a thumbnail from
2013-05-09 21:59:16 +00:00
* @return string
2014-02-27 12:15:18 +00:00
*/
public function getFile() {
2013-05-09 21:59:16 +00:00
return $this->file;
}
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
/**
* returns the max width of the preview
2013-05-09 21:59:16 +00:00
* @return integer
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getMaxX() {
2013-05-09 21:59:16 +00:00
return $this->maxX;
}
/**
* returns the max height of the preview
2013-05-09 21:59:16 +00:00
* @return integer
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getMaxY() {
2013-05-09 21:59:16 +00:00
return $this->maxY;
}
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
/**
* returns whether or not scalingup is enabled
2013-05-09 21:59:16 +00:00
* @return bool
2014-02-27 12:15:18 +00:00
*/
2013-07-30 10:29:12 +00:00
public function getScalingUp() {
2014-04-04 14:21:50 +00:00
return $this->scalingUp;
2013-05-09 21:59:16 +00:00
}
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
/**
* returns the name of the thumbnailfolder
2013-05-09 21:59:16 +00:00
* @return string
2014-02-27 12:15:18 +00:00
*/
2013-07-10 15:57:04 +00:00
public function getThumbnailsFolder() {
2013-05-09 21:59:16 +00:00
return self::THUMBNAILS_FOLDER;
}
/**
* returns the max scale factor
* @return string
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getMaxScaleFactor() {
2013-07-11 17:03:21 +00:00
return $this->maxScaleFactor;
2013-05-09 21:59:16 +00:00
}
/**
* returns the max width set in ownCloud's config
* @return string
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getConfigMaxX() {
2013-07-11 17:03:21 +00:00
return $this->configMaxX;
2013-05-09 21:59:16 +00:00
}
/**
* returns the max height set in ownCloud's config
* @return string
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getConfigMaxY() {
2013-07-11 17:03:21 +00:00
return $this->configMaxY;
2013-05-09 21:59:16 +00:00
}
2013-05-17 17:08:16 +00:00
2014-04-21 13:44:54 +00:00
/**
* @return false|Files\FileInfo|\OCP\Files\FileInfo
*/
2014-02-27 12:15:18 +00:00
protected function getFileInfo() {
$absPath = $this->fileView->getAbsolutePath($this->file);
$absPath = Files\Filesystem::normalizePath($absPath);
if(array_key_exists($absPath, self::$deleteFileMapper)) {
$this->info = self::$deleteFileMapper[$absPath];
} else if (!$this->info) {
2014-02-27 12:15:18 +00:00
$this->info = $this->fileView->getFileInfo($this->file);
}
return $this->info;
}
2013-07-10 15:57:04 +00:00
/**
* set the path of the file you want a thumbnail from
2013-07-11 17:21:37 +00:00
* @param string $file
2014-05-13 10:22:18 +00:00
* @return \OC\Preview $this
2014-02-27 12:15:18 +00:00
*/
2013-07-10 15:57:04 +00:00
public function setFile($file) {
$this->file = $file;
2014-02-27 12:15:18 +00:00
$this->info = null;
if ($file !== '') {
$this->getFileInfo();
if($this->info !== null && $this->info !== false) {
2014-04-04 14:21:50 +00:00
$this->mimeType = $this->info->getMimetype();
}
}
2013-07-10 15:57:04 +00:00
return $this;
}
2013-11-28 18:05:43 +00:00
/**
* set mime type explicitly
2014-04-04 14:21:50 +00:00
* @param string $mimeType
2013-11-28 18:05:43 +00:00
*/
2014-04-04 14:21:50 +00:00
public function setMimetype($mimeType) {
$this->mimeType = $mimeType;
}
2013-07-10 15:57:04 +00:00
/**
* set the the max width of the preview
2013-07-11 17:21:37 +00:00
* @param int $maxX
2014-04-21 13:44:54 +00:00
* @throws \Exception
* @return \OC\Preview $this
2014-02-27 12:15:18 +00:00
*/
public function setMaxX($maxX = 1) {
if ($maxX <= 0) {
2013-07-30 10:29:12 +00:00
throw new \Exception('Cannot set width of 0 or smaller!');
2013-07-10 15:57:04 +00:00
}
$configMaxX = $this->getConfigMaxX();
2014-02-27 12:15:18 +00:00
if (!is_null($configMaxX)) {
if ($maxX > $configMaxX) {
2013-07-10 15:57:04 +00:00
\OC_Log::write('core', 'maxX reduced from ' . $maxX . ' to ' . $configMaxX, \OC_Log::DEBUG);
$maxX = $configMaxX;
}
}
$this->maxX = $maxX;
return $this;
}
/**
* set the the max height of the preview
2013-07-11 17:21:37 +00:00
* @param int $maxY
2014-04-21 13:44:54 +00:00
* @throws \Exception
* @return \OC\Preview $this
2014-02-27 12:15:18 +00:00
*/
public function setMaxY($maxY = 1) {
if ($maxY <= 0) {
2013-07-30 10:29:12 +00:00
throw new \Exception('Cannot set height of 0 or smaller!');
2013-07-10 15:57:04 +00:00
}
$configMaxY = $this->getConfigMaxY();
2014-02-27 12:15:18 +00:00
if (!is_null($configMaxY)) {
if ($maxY > $configMaxY) {
2013-07-10 15:57:04 +00:00
\OC_Log::write('core', 'maxX reduced from ' . $maxY . ' to ' . $configMaxY, \OC_Log::DEBUG);
$maxY = $configMaxY;
}
}
$this->maxY = $maxY;
return $this;
}
/**
* set whether or not scalingup is enabled
2013-07-30 10:29:12 +00:00
* @param bool $scalingUp
* @return \OC\Preview $this
2014-02-27 12:15:18 +00:00
*/
2013-07-30 10:29:12 +00:00
public function setScalingup($scalingUp) {
2014-02-27 12:15:18 +00:00
if ($this->getMaxScaleFactor() === 1) {
2013-07-30 10:29:12 +00:00
$scalingUp = false;
2013-07-10 15:57:04 +00:00
}
2014-04-04 14:21:50 +00:00
$this->scalingUp = $scalingUp;
2013-07-10 15:57:04 +00:00
return $this;
}
public function setKeepAspect($keepAspect) {
$this->keepAspect = $keepAspect;
return $this;
}
2013-07-10 15:57:04 +00:00
/**
* check if all parameters are valid
2013-07-11 17:21:37 +00:00
* @return bool
2014-02-27 12:15:18 +00:00
*/
2013-07-10 15:57:04 +00:00
public function isFileValid() {
$file = $this->getFile();
2014-02-27 12:15:18 +00:00
if ($file === '') {
2013-08-19 10:16:55 +00:00
\OC_Log::write('core', 'No filename passed', \OC_Log::DEBUG);
2013-07-10 15:57:04 +00:00
return false;
}
2014-02-27 12:15:18 +00:00
if (!$this->fileView->file_exists($file)) {
2013-08-19 10:16:55 +00:00
\OC_Log::write('core', 'File:"' . $file . '" not found', \OC_Log::DEBUG);
2013-07-10 15:57:04 +00:00
return false;
}
return true;
}
2013-05-09 21:59:16 +00:00
/**
* deletes previews of a file with specific x and y
2013-05-09 21:59:16 +00:00
* @return bool
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function deletePreview() {
2013-07-10 15:57:04 +00:00
$file = $this->getFile();
2014-02-27 12:15:18 +00:00
$fileInfo = $this->getFileInfo($file);
if($fileInfo !== null && $fileInfo !== false) {
$fileId = $fileInfo->getId();
$previewPath = $this->buildCachePath($fileId);
return $this->userView->unlink($previewPath);
}
return false;
2013-05-09 21:59:16 +00:00
}
/**
* deletes all previews of a file
2013-05-09 21:59:16 +00:00
* @return bool
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function deleteAllPreviews() {
2013-07-10 15:57:04 +00:00
$file = $this->getFile();
2013-05-09 21:59:16 +00:00
2014-02-27 12:15:18 +00:00
$fileInfo = $this->getFileInfo($file);
if($fileInfo !== null && $fileInfo !== false) {
$fileId = $fileInfo->getId();
2014-08-26 14:43:08 +00:00
$previewPath = $this->getPreviewPath($fileId);
$this->userView->deleteAll($previewPath);
return $this->userView->rmdir($previewPath);
}
return false;
2013-05-09 21:59:16 +00:00
}
/**
* check if thumbnail or bigger version of thumbnail of file is cached
2014-04-02 16:32:32 +00:00
* @param int $fileId fileId of the original image
2014-04-02 15:59:39 +00:00
* @return string|false path to thumbnail if it exists or false
2014-02-27 12:15:18 +00:00
*/
2014-04-04 14:21:50 +00:00
public function isCached($fileId) {
2014-02-27 12:15:18 +00:00
if (is_null($fileId)) {
return false;
}
2013-05-09 21:59:16 +00:00
$preview = $this->buildCachePath($fileId);
2013-05-09 21:59:16 +00:00
2013-04-25 09:18:45 +00:00
//does a preview with the wanted height and width already exist?
if ($this->userView->file_exists($preview)) {
return $preview;
2013-04-25 09:18:45 +00:00
}
2013-05-09 21:59:16 +00:00
2014-04-02 16:32:32 +00:00
return $this->isCachedBigger($fileId);
2014-04-02 15:59:39 +00:00
}
/**
* check if a bigger version of thumbnail of file is cached
2014-04-02 16:32:32 +00:00
* @param int $fileId fileId of the original image
2014-04-02 15:59:39 +00:00
* @return string|false path to bigger thumbnail if it exists or false
*/
2014-04-02 16:32:32 +00:00
private function isCachedBigger($fileId) {
2013-05-09 21:59:16 +00:00
2014-02-27 12:15:18 +00:00
if (is_null($fileId)) {
return false;
}
// in order to not loose quality we better generate aspect preserving previews from the original file
if ($this->keepAspect) {
return false;
}
2014-04-02 15:59:39 +00:00
$maxX = $this->getMaxX();
2014-04-02 16:32:32 +00:00
//array for usable cached thumbnails
$possibleThumbnails = $this->getPossibleThumbnails($fileId);
foreach ($possibleThumbnails as $width => $path) {
if ($width < $maxX) {
continue;
} else {
return $path;
}
2013-05-09 21:59:16 +00:00
}
2014-04-02 16:32:32 +00:00
return false;
}
2014-04-04 09:37:47 +00:00
2014-04-02 16:32:32 +00:00
/**
* get possible bigger thumbnails of the given image
2014-04-02 16:32:32 +00:00
* @param int $fileId fileId of the original image
2014-05-11 17:13:51 +00:00
* @return array an array of paths to bigger thumbnails
2014-04-02 16:32:32 +00:00
*/
private function getPossibleThumbnails($fileId) {
2014-04-02 15:59:39 +00:00
if (is_null($fileId)) {
2014-04-02 16:32:32 +00:00
return array();
2013-04-25 09:18:45 +00:00
}
2013-05-09 21:59:16 +00:00
2014-08-26 14:43:08 +00:00
$previewPath = $this->getPreviewPath($fileId);
2014-04-02 16:32:32 +00:00
$wantedAspectRatio = (float) ($this->getMaxX() / $this->getMaxY());
2013-05-09 21:59:16 +00:00
2013-04-25 09:18:45 +00:00
//array for usable cached thumbnails
2013-07-30 10:29:12 +00:00
$possibleThumbnails = array();
2013-05-09 21:59:16 +00:00
2013-08-19 10:16:55 +00:00
$allThumbnails = $this->userView->getDirectoryContent($previewPath);
2014-02-27 12:15:18 +00:00
foreach ($allThumbnails as $thumbnail) {
$name = rtrim($thumbnail['name'], '.png');
2014-04-02 16:32:32 +00:00
list($x, $y, $aspectRatio) = $this->getDimensionsFromFilename($name);
2013-05-09 21:59:16 +00:00
if (abs($aspectRatio - $wantedAspectRatio) >= 0.000001
2014-04-02 16:32:32 +00:00
|| $this->unscalable($x, $y)
) {
2013-04-25 09:18:45 +00:00
continue;
}
2013-07-30 10:29:12 +00:00
$possibleThumbnails[$x] = $thumbnail['path'];
2013-04-25 09:18:45 +00:00
}
2013-05-09 21:59:16 +00:00
2013-07-30 10:29:12 +00:00
ksort($possibleThumbnails);
2013-05-09 21:59:16 +00:00
2014-04-02 16:32:32 +00:00
return $possibleThumbnails;
}
2013-05-09 21:59:16 +00:00
2014-04-21 13:44:54 +00:00
/**
* @param string $name
* @return array
*/
2014-04-02 16:32:32 +00:00
private function getDimensionsFromFilename($name) {
$size = explode('-', $name);
$x = (int) $size[0];
$y = (int) $size[1];
$aspectRatio = (float) ($x / $y);
2014-04-04 14:21:50 +00:00
return array($x, $y, $aspectRatio);
2014-04-02 16:32:32 +00:00
}
2013-05-09 21:59:16 +00:00
2014-04-21 13:44:54 +00:00
/**
* @param int $x
* @param int $y
* @return bool
*/
2014-04-02 16:32:32 +00:00
private function unscalable($x, $y) {
2014-04-02 16:32:32 +00:00
$maxX = $this->getMaxX();
$maxY = $this->getMaxY();
$scalingUp = $this->getScalingUp();
$maxScaleFactor = $this->getMaxScaleFactor();
2014-04-02 16:32:32 +00:00
if ($x < $maxX || $y < $maxY) {
if ($scalingUp) {
$scalefactor = $maxX / $x;
if ($scalefactor > $maxScaleFactor) {
return true;
}
2014-02-27 12:15:18 +00:00
} else {
2014-04-02 16:32:32 +00:00
return true;
2013-04-25 09:18:45 +00:00
}
}
2014-04-02 15:34:48 +00:00
return false;
2013-04-25 09:18:45 +00:00
}
2013-04-25 09:18:45 +00:00
/**
* return a preview of a file
2013-07-30 10:29:12 +00:00
* @return \OC_Image
2014-02-27 12:15:18 +00:00
*/
2013-05-29 11:03:33 +00:00
public function getPreview() {
2014-02-27 12:15:18 +00:00
if (!is_null($this->preview) && $this->preview->valid()) {
2013-07-10 15:57:04 +00:00
return $this->preview;
}
$this->preview = null;
$file = $this->getFile();
$maxX = $this->getMaxX();
$maxY = $this->getMaxY();
2013-07-30 10:29:12 +00:00
$scalingUp = $this->getScalingUp();
2013-04-25 09:18:45 +00:00
2014-02-27 12:15:18 +00:00
$fileInfo = $this->getFileInfo($file);
if($fileInfo === null || $fileInfo === false) {
return new \OC_Image();
}
2014-02-27 12:15:18 +00:00
$fileId = $fileInfo->getId();
2013-05-09 21:59:16 +00:00
2014-04-02 16:32:32 +00:00
$cached = $this->isCached($fileId);
2014-02-27 12:15:18 +00:00
if ($cached) {
$stream = $this->userView->fopen($cached, 'r');
$this->preview = null;
if ($stream) {
$image = new \OC_Image();
$image->loadFromFileHandle($stream);
$this->preview = $image->valid() ? $image : null;
$this->resizeAndCrop();
fclose($stream);
}
2013-07-10 15:57:04 +00:00
}
2013-05-17 17:08:16 +00:00
2014-02-27 12:15:18 +00:00
if (is_null($this->preview)) {
2013-06-26 08:57:37 +00:00
$preview = null;
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
foreach (self::$providers as $supportedMimeType => $provider) {
if (!preg_match($supportedMimeType, $this->mimeType)) {
2013-05-09 21:59:16 +00:00
continue;
}
2013-05-17 17:08:16 +00:00
2013-08-15 11:21:35 +00:00
\OC_Log::write('core', 'Generating preview for "' . $file . '" with "' . get_class($provider) . '"', \OC_Log::DEBUG);
2014-04-04 09:37:47 +00:00
/** @var $provider Provider */
2013-08-19 10:16:55 +00:00
$preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView);
2014-02-27 12:15:18 +00:00
if (!($preview instanceof \OC_Image)) {
2013-05-09 21:59:16 +00:00
continue;
}
2013-05-17 17:08:16 +00:00
2013-07-10 15:57:04 +00:00
$this->preview = $preview;
$this->resizeAndCrop();
2014-08-26 14:43:08 +00:00
$previewPath = $this->getPreviewPath($fileId);
$cachePath = $this->buildCachePath($fileId);
2013-07-10 15:57:04 +00:00
2014-02-27 12:15:18 +00:00
if ($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) {
2013-08-19 10:16:55 +00:00
$this->userView->mkdir($this->getThumbnailsFolder() . '/');
2013-05-09 21:59:16 +00:00
}
2013-05-17 17:08:16 +00:00
2014-02-27 12:15:18 +00:00
if ($this->userView->is_dir($previewPath) === false) {
2013-08-19 10:16:55 +00:00
$this->userView->mkdir($previewPath);
}
2013-07-10 11:38:42 +00:00
2013-08-19 10:16:55 +00:00
$this->userView->file_put_contents($cachePath, $preview->data());
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
break;
}
2013-07-10 15:57:04 +00:00
}
2013-06-26 08:57:37 +00:00
2014-02-27 12:15:18 +00:00
if (is_null($this->preview)) {
2013-07-10 15:57:04 +00:00
$this->preview = new \OC_Image();
2013-05-09 21:59:16 +00:00
}
2013-07-10 15:57:04 +00:00
2013-05-09 21:59:16 +00:00
return $this->preview;
2013-04-25 09:18:45 +00:00
}
/**
* @param null|string $mimeType
* @throws NotFoundException
2014-02-27 12:15:18 +00:00
*/
public function showPreview($mimeType = null) {
// Check if file is valid
if($this->isFileValid() === false) {
throw new NotFoundException('File not found.');
}
2013-07-10 15:57:04 +00:00
\OCP\Response::enableCaching(3600 * 24); // 24 hours
2014-02-27 12:15:18 +00:00
if (is_null($this->preview)) {
2013-07-10 15:57:04 +00:00
$this->getPreview();
2013-05-09 21:59:16 +00:00
}
if ($this->preview instanceof \OC_Image) {
$this->preview->show($mimeType);
}
}
2013-05-09 21:59:16 +00:00
/**
* resize, crop and fix orientation
2013-07-30 10:29:12 +00:00
* @return void
2014-02-27 12:15:18 +00:00
*/
2013-07-10 15:57:04 +00:00
private function resizeAndCrop() {
2013-05-09 21:59:16 +00:00
$image = $this->preview;
2013-07-10 15:57:04 +00:00
$x = $this->getMaxX();
$y = $this->getMaxY();
2013-07-30 10:29:12 +00:00
$scalingUp = $this->getScalingUp();
2014-04-04 14:21:50 +00:00
$maxScaleFactor = $this->getMaxScaleFactor();
2013-05-09 21:59:16 +00:00
2014-02-27 12:15:18 +00:00
if (!($image instanceof \OC_Image)) {
2013-07-10 15:57:04 +00:00
\OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG);
2013-05-09 21:59:16 +00:00
return;
}
2014-04-04 14:21:50 +00:00
$realX = (int)$image->width();
$realY = (int)$image->height();
2013-05-09 21:59:16 +00:00
// compute $maxY and $maxX using the aspect of the generated preview
if ($this->keepAspect) {
$ratio = $realX / $realY;
if($x / $ratio < $y) {
// width restricted
$y = $x / $ratio;
} else {
$x = $y * $ratio;
}
}
2014-04-04 14:21:50 +00:00
if ($x === $realX && $y === $realY) {
2013-07-10 15:57:04 +00:00
$this->preview = $image;
2013-08-19 10:16:55 +00:00
return;
2013-05-09 21:59:16 +00:00
}
2014-04-04 14:21:50 +00:00
$factorX = $x / $realX;
$factorY = $y / $realY;
2013-07-10 15:57:04 +00:00
2014-02-27 12:15:18 +00:00
if ($factorX >= $factorY) {
2013-05-09 21:59:16 +00:00
$factor = $factorX;
2014-02-27 12:15:18 +00:00
} else {
2013-05-09 21:59:16 +00:00
$factor = $factorY;
}
2013-07-10 15:57:04 +00:00
2014-02-27 12:15:18 +00:00
if ($scalingUp === false) {
if ($factor > 1) {
2013-07-10 15:57:04 +00:00
$factor = 1;
}
2013-05-09 21:59:16 +00:00
}
2013-07-10 15:57:04 +00:00
2014-04-04 14:21:50 +00:00
if (!is_null($maxScaleFactor)) {
if ($factor > $maxScaleFactor) {
\OC_Log::write('core', 'scale factor reduced from ' . $factor . ' to ' . $maxScaleFactor, \OC_Log::DEBUG);
$factor = $maxScaleFactor;
2013-04-25 09:18:45 +00:00
}
}
2013-05-09 21:59:16 +00:00
2014-04-04 14:21:50 +00:00
$newXSize = (int)($realX * $factor);
$newYSize = (int)($realY * $factor);
2013-07-10 15:57:04 +00:00
2014-04-04 14:21:50 +00:00
$image->preciseResize($newXSize, $newYSize);
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
if ($newXSize === $x && $newYSize === $y) {
2013-05-09 21:59:16 +00:00
$this->preview = $image;
return;
}
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
if ($newXSize >= $x && $newYSize >= $y) {
$cropX = floor(abs($x - $newXSize) * 0.5);
2013-07-10 15:57:04 +00:00
//don't crop previews on the Y axis, this sucks if it's a document.
2013-06-11 08:45:50 +00:00
//$cropY = floor(abs($y - $newYsize) * 0.5);
$cropY = 0;
2013-05-09 21:59:16 +00:00
$image->crop($cropX, $cropY, $x, $y);
2013-05-09 21:59:16 +00:00
$this->preview = $image;
return;
}
2013-05-17 17:08:16 +00:00
if (($newXSize < $x || $newYSize < $y) && $scalingUp) {
2014-04-04 14:21:50 +00:00
if ($newXSize > $x) {
$cropX = floor(($newXSize - $x) * 0.5);
$image->crop($cropX, 0, $x, $newYSize);
2013-04-25 09:18:45 +00:00
}
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
if ($newYSize > $y) {
$cropY = floor(($newYSize - $y) * 0.5);
$image->crop(0, $cropY, $newXSize, $y);
2013-04-25 09:18:45 +00:00
}
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
$newXSize = (int)$image->width();
$newYSize = (int)$image->height();
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
//create transparent background layer
2014-04-04 14:21:50 +00:00
$backgroundLayer = imagecreatetruecolor($x, $y);
$white = imagecolorallocate($backgroundLayer, 255, 255, 255);
imagefill($backgroundLayer, 0, 0, $white);
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
$image = $image->resource();
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
$mergeX = floor(abs($x - $newXSize) * 0.5);
$mergeY = floor(abs($y - $newYSize) * 0.5);
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
imagecopy($backgroundLayer, $image, $mergeX, $mergeY, 0, 0, $newXSize, $newYSize);
2013-05-17 17:08:16 +00:00
//$black = imagecolorallocate(0,0,0);
//imagecolortransparent($transparentlayer, $black);
2013-05-17 17:08:16 +00:00
2014-04-04 14:21:50 +00:00
$image = new \OC_Image($backgroundLayer);
2013-05-17 17:08:16 +00:00
2013-05-09 21:59:16 +00:00
$this->preview = $image;
return;
2013-04-25 09:18:45 +00:00
}
}
2013-04-25 09:18:45 +00:00
/**
* Register a new preview provider to be used
* @param $class
2013-07-11 17:21:37 +00:00
* @param array $options
2013-04-25 09:18:45 +00:00
*/
2014-02-27 12:15:18 +00:00
public static function registerProvider($class, $options = array()) {
/**
* Only register providers that have been explicitly enabled
*
* The following providers are enabled by default:
* - OC\Preview\Image
* - OC\Preview\MP3
* - OC\Preview\TXT
* - OC\Preview\MarkDown
*
* The following providers are disabled by default due to performance or privacy concerns:
* - OC\Preview\MSOfficeDoc
* - OC\Preview\MSOffice2003
* - OC\Preview\MSOffice2007
* - OC\Preview\OpenDocument
* - OC\Preview\StarOffice
* - OC\Preview\SVG
* - OC\Preview\Movies
* - OC\Preview\PDF
* - OC\Preview\TIFF
* - OC\Preview\Illustrator
* - OC\Preview\Postscript
* - OC\Preview\Photoshop
*/
if(empty(self::$enabledProviders)) {
self::$enabledProviders = \OC::$server->getConfig()->getSystemValue('enabledPreviewProviders', array(
'OC\Preview\Image',
'OC\Preview\MP3',
'OC\Preview\TXT',
'OC\Preview\MarkDown',
));
}
if(in_array($class, self::$enabledProviders)) {
self::$registeredProviders[] = array('class' => $class, 'options' => $options);
}
2013-04-25 09:18:45 +00:00
}
2013-04-25 09:18:45 +00:00
/**
* create instances of all the registered preview providers
2013-04-25 09:18:45 +00:00
* @return void
*/
private static function initProviders() {
if (!\OC::$server->getConfig()->getSystemValue('enable_previews', true)) {
self::$providers = array();
2013-08-23 21:05:44 +00:00
return;
}
2014-02-27 12:15:18 +00:00
if (count(self::$providers) > 0) {
2013-04-25 09:18:45 +00:00
return;
}
2013-05-17 17:08:16 +00:00
2014-02-27 12:15:18 +00:00
foreach (self::$registeredProviders as $provider) {
$class = $provider['class'];
$options = $provider['options'];
2013-05-17 17:08:16 +00:00
2014-04-04 09:37:47 +00:00
/** @var $object Provider */
2013-04-25 09:18:45 +00:00
$object = new $class($options);
self::$providers[$object->getMimeType()] = $object;
}
2013-05-17 17:08:16 +00:00
2013-04-25 09:18:45 +00:00
$keys = array_map('strlen', array_keys(self::$providers));
array_multisort($keys, SORT_DESC, self::$providers);
2013-04-25 09:18:45 +00:00
}
2013-05-17 17:08:16 +00:00
2013-05-29 11:03:33 +00:00
public static function post_write($args) {
self::post_delete($args, 'files/');
}
public static function prepare_delete_files($args) {
self::prepare_delete($args, 'files/');
}
public static function prepare_delete($args, $prefix='') {
$path = $args['path'];
2014-02-27 12:15:18 +00:00
if (substr($path, 0, 1) === '/') {
$path = substr($path, 1);
}
$view = new \OC\Files\View('/' . \OC_User::getUser() . '/' . $prefix);
$info = $view->getFileInfo($path);
\OC\Preview::$deleteFileMapper = array_merge(
\OC\Preview::$deleteFileMapper,
array(
Files\Filesystem::normalizePath($view->getAbsolutePath($path)) => $info,
)
);
}
public static function post_delete_files($args) {
self::post_delete($args, 'files/');
}
public static function post_delete($args, $prefix='') {
$path = Files\Filesystem::normalizePath($args['path']);
$preview = new Preview(\OC_User::getUser(), $prefix, $path);
$preview->deleteAllPreviews();
}
2014-07-30 14:29:18 +00:00
/**
* Check if a preview can be generated for a file
*
* @param \OC\Files\FileInfo $file
* @return bool
*/
public static function isAvailable(\OC\Files\FileInfo $file) {
2014-07-30 14:29:18 +00:00
if (!\OC_Config::getValue('enable_previews', true)) {
return false;
}
//check if there are preview backends
if (empty(self::$providers)) {
self::initProviders();
}
foreach (self::$providers as $supportedMimeType => $provider) {
2014-07-30 14:29:18 +00:00
/**
* @var \OC\Preview\Provider $provider
*/
if (preg_match($supportedMimeType, $file->getMimetype())) {
return $provider->isAvailable($file);
}
}
return false;
}
/**
2014-04-04 14:21:50 +00:00
* @param string $mimeType
2014-04-21 13:44:54 +00:00
* @return bool
*/
2014-04-04 14:21:50 +00:00
public static function isMimeSupported($mimeType) {
2014-02-27 12:15:18 +00:00
if (!\OC_Config::getValue('enable_previews', true)) {
2013-08-23 21:05:44 +00:00
return false;
}
//check if there are preview backends
2014-02-27 12:15:18 +00:00
if (empty(self::$providers)) {
self::initProviders();
}
// FIXME: Ugly hack to prevent SVG of being returned if the SVG
// provider is not enabled.
// This is required because the preview system is designed in a
// bad way and relies on opt-in with asterisks (i.e. image/*)
// which will lead to the fact that a SVG will also match the image
// provider.
if($mimeType === 'image/svg+xml' && !array_key_exists('/image\/svg\+xml/', self::$providers)) {
return false;
}
foreach(self::$providers as $supportedMimetype => $provider) {
if(preg_match($supportedMimetype, $mimeType)) {
return true;
}
}
return false;
}
/**
* @param int $fileId
* @return string
*/
private function buildCachePath($fileId) {
$maxX = $this->getMaxX();
$maxY = $this->getMaxY();
2014-08-26 14:43:08 +00:00
$previewPath = $this->getPreviewPath($fileId);
$preview = $previewPath . strval($maxX) . '-' . strval($maxY);
if ($this->keepAspect) {
2014-08-26 14:43:08 +00:00
$preview .= '-with-aspect';
}
2014-08-26 14:43:08 +00:00
$preview .= '.png';
return $preview;
}
2014-08-26 14:43:08 +00:00
2014-08-27 08:05:02 +00:00
/**
* @param int $fileId
* @return string
*/
2014-08-26 14:43:08 +00:00
private function getPreviewPath($fileId) {
return $this->getThumbnailsFolder() . '/' . $fileId . '/';
}
2013-09-04 21:45:11 +00:00
}