Commit afa88729 authored by Thomas Müller's avatar Thomas Müller
Browse files

Merge pull request #14857 from owncloud/preview-provider-registration-in-manager

Preview provider registration in manager
parents a45e45df 8f063538
...@@ -170,6 +170,7 @@ class ShareController extends Controller { ...@@ -170,6 +170,7 @@ class ShareController extends Controller {
$shareTmpl['filename'] = $file; $shareTmpl['filename'] = $file;
$shareTmpl['directory_path'] = $linkItem['file_target']; $shareTmpl['directory_path'] = $linkItem['file_target'];
$shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath); $shareTmpl['mimetype'] = Filesystem::getMimeType($originalSharePath);
$shareTmpl['previewSupported'] = \OC::$server->getPreviewManager()->isMimeSupported($shareTmpl['mimetype']);
$shareTmpl['dirToken'] = $linkItem['token']; $shareTmpl['dirToken'] = $linkItem['token'];
$shareTmpl['sharingToken'] = $token; $shareTmpl['sharingToken'] = $token;
$shareTmpl['server2serversharing'] = Helper::isOutgoingServer2serverShareEnabled(); $shareTmpl['server2serversharing'] = Helper::isOutgoingServer2serverShareEnabled();
......
...@@ -19,11 +19,10 @@ OCP\Util::addScript('files', 'files'); ...@@ -19,11 +19,10 @@ OCP\Util::addScript('files', 'files');
OCP\Util::addScript('files', 'filelist'); OCP\Util::addScript('files', 'filelist');
OCP\Util::addscript('files', 'keyboardshortcuts'); OCP\Util::addscript('files', 'keyboardshortcuts');
$thumbSize=1024; $thumbSize = 1024;
$previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'false';
?> ?>
<?php if ( \OC\Preview::isMimeSupported($_['mimetype'])): /* This enables preview images for links (e.g. on Facebook, Google+, ...)*/?> <?php if ($_['previewSupported']): /* This enables preview images for links (e.g. on Facebook, Google+, ...)*/?>
<link rel="image_src" href="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $thumbSize, 'y' => $thumbSize, 'file' => $_['directory_path'], 't' => $_['dirToken']))); ?>" /> <link rel="image_src" href="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $thumbSize, 'y' => $thumbSize, 'file' => $_['directory_path'], 't' => $_['dirToken']))); ?>" />
<?php endif; ?> <?php endif; ?>
...@@ -38,7 +37,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals ...@@ -38,7 +37,7 @@ $previewSupported = OC\Preview::isMimeSupported($_['mimetype']) ? 'true' : 'fals
<input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken"> <input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken">
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename"> <input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype"> <input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
<input type="hidden" name="previewSupported" value="<?php p($previewSupported); ?>" id="previewSupported"> <input type="hidden" name="previewSupported" value="<?php p($_['previewSupported'] ? 'true' : 'false'); ?>" id="previewSupported">
<input type="hidden" name="mimetypeIcon" value="<?php p(OC_Helper::mimetypeIcon($_['mimetype'])); ?>" id="mimetypeIcon"> <input type="hidden" name="mimetypeIcon" value="<?php p(OC_Helper::mimetypeIcon($_['mimetype'])); ?>" id="mimetypeIcon">
<input type="hidden" name="filesize" value="<?php p($_['nonHumanFileSize']); ?>" id="filesize"> <input type="hidden" name="filesize" value="<?php p($_['nonHumanFileSize']); ?>" id="filesize">
<input type="hidden" name="maxSizeAnimateGif" value="<?php p($_['maxSizeAnimateGif']); ?>" id="maxSizeAnimateGif"> <input type="hidden" name="maxSizeAnimateGif" value="<?php p($_['maxSizeAnimateGif']); ?>" id="maxSizeAnimateGif">
......
...@@ -158,6 +158,7 @@ class ShareControllerTest extends \Test\TestCase { ...@@ -158,6 +158,7 @@ class ShareControllerTest extends \Test\TestCase {
'fileSize' => '33 B', 'fileSize' => '33 B',
'nonHumanFileSize' => 33, 'nonHumanFileSize' => 33,
'maxSizeAnimateGif' => 10, 'maxSizeAnimateGif' => 10,
'previewSupported' => true,
); );
$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
......
...@@ -29,13 +29,12 @@ if ($maxX === 0 || $maxY === 0) { ...@@ -29,13 +29,12 @@ if ($maxX === 0 || $maxY === 0) {
exit; exit;
} }
$preview = new \OC\Preview(\OC_User::getUser(), 'files');
$info = \OC\Files\Filesystem::getFileInfo($file); $info = \OC\Files\Filesystem::getFileInfo($file);
if (!$info instanceof OCP\Files\FileInfo || !$always && !$preview->isAvailable($info)) { if (!$info instanceof OCP\Files\FileInfo || !$always && !\OC::$server->getPreviewManager()->isAvailable($info)) {
\OC_Response::setStatus(404); \OC_Response::setStatus(404);
} else { } else {
$preview = new \OC\Preview(\OC_User::getUser(), 'files');
$preview->setFile($file); $preview->setFile($file);
$preview->setMaxX($maxX); $preview->setMaxX($maxX);
$preview->setMaxY($maxY); $preview->setMaxY($maxY);
......
...@@ -95,7 +95,7 @@ class AvatarController extends Controller { ...@@ -95,7 +95,7 @@ class AvatarController extends Controller {
$avatar = $this->avatarManager->getAvatar($userId); $avatar = $this->avatarManager->getAvatar($userId);
$image = $avatar->get($size); $image = $avatar->get($size);
if ($image instanceof \OC_Image) { if ($image instanceof \OCP\IImage) {
$resp = new DataDisplayResponse($image->data(), $resp = new DataDisplayResponse($image->data(),
Http::STATUS_OK, Http::STATUS_OK,
['Content-Type' => $image->mimeType()]); ['Content-Type' => $image->mimeType()]);
......
...@@ -29,7 +29,7 @@ class Avatar implements \OCP\IAvatar { ...@@ -29,7 +29,7 @@ class Avatar implements \OCP\IAvatar {
/** /**
* get the users avatar * get the users avatar
* @param int $size size in px of the avatar, avatars are square, defaults to 64 * @param int $size size in px of the avatar, avatars are square, defaults to 64
* @return boolean|\OC_Image containing the avatar or false if there's no image * @return boolean|\OCP\IImage containing the avatar or false if there's no image
*/ */
public function get ($size = 64) { public function get ($size = 64) {
if ($this->view->file_exists('avatar.jpg')) { if ($this->view->file_exists('avatar.jpg')) {
...@@ -57,14 +57,14 @@ class Avatar implements \OCP\IAvatar { ...@@ -57,14 +57,14 @@ class Avatar implements \OCP\IAvatar {
/** /**
* sets the users avatar * sets the users avatar
* @param \OC_Image|resource|string $data OC_Image, imagedata or path to set a new avatar * @param \OCP\IImage|resource|string $data An image object, imagedata or path to set a new avatar
* @throws \Exception if the provided file is not a jpg or png image * @throws \Exception if the provided file is not a jpg or png image
* @throws \Exception if the provided image is not valid * @throws \Exception if the provided image is not valid
* @throws \OC\NotSquareException if the image is not square * @throws \OC\NotSquareException if the image is not square
* @return void * @return void
*/ */
public function set ($data) { public function set ($data) {
if($data instanceOf OC_Image) { if($data instanceOf \OCP\IImage) {
$img = $data; $img = $data;
$data = $img->data(); $data = $img->data();
} else { } else {
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
/** /**
* Class for basic image manipulation * Class for basic image manipulation
*/ */
class OC_Image { class OC_Image implements \OCP\IImage {
protected $resource = false; // tmp resource. protected $resource = false; // tmp resource.
protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident. protected $imageType = IMAGETYPE_PNG; // Default to png if file type isn't evident.
protected $mimeType = "image/png"; // Default to png protected $mimeType = "image/png"; // Default to png
...@@ -285,7 +285,7 @@ class OC_Image { ...@@ -285,7 +285,7 @@ class OC_Image {
/** /**
* @return null|string Returns the raw image data. * @return null|string Returns the raw image data.
*/ */
function data() { public function data() {
if (!$this->valid()) { if (!$this->valid()) {
return null; return null;
} }
...@@ -949,6 +949,9 @@ class OC_Image { ...@@ -949,6 +949,9 @@ class OC_Image {
return true; return true;
} }
/**
* Destroys the current image and resets the object
*/
public function destroy() { public function destroy() {
if ($this->valid()) { if ($this->valid()) {
imagedestroy($this->resource); imagedestroy($this->resource);
......
...@@ -46,15 +46,10 @@ class Preview { ...@@ -46,15 +46,10 @@ class Preview {
/** /**
* preview images object * preview images object
* *
* @var \OC_Image * @var \OCP\IImage
*/ */
private $preview; private $preview;
//preview providers
static private $providers = array();
static private $registeredProviders = array();
static private $enabledProviders = array();
/** /**
* @var \OCP\Files\FileInfo * @var \OCP\Files\FileInfo
*/ */
...@@ -95,11 +90,7 @@ class Preview { ...@@ -95,11 +90,7 @@ class Preview {
$this->preview = null; $this->preview = null;
//check if there are preview backends //check if there are preview backends
if (empty(self::$providers)) { if (!\OC::$server->getPreviewManager()->hasProviders() && \OC::$server->getConfig()->getSystemValue('enable_previews', true)) {
self::initProviders();
}
if (empty(self::$providers) && \OC::$server->getConfig()->getSystemValue('enable_previews', true)) {
\OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR); \OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR);
throw new \Exception('No preview providers'); throw new \Exception('No preview providers');
} }
...@@ -474,7 +465,7 @@ class Preview { ...@@ -474,7 +465,7 @@ class Preview {
/** /**
* return a preview of a file * return a preview of a file
* @return \OC_Image * @return \OCP\IImage
*/ */
public function getPreview() { public function getPreview() {
if (!is_null($this->preview) && $this->preview->valid()) { if (!is_null($this->preview) && $this->preview->valid()) {
...@@ -510,37 +501,45 @@ class Preview { ...@@ -510,37 +501,45 @@ class Preview {
if (is_null($this->preview)) { if (is_null($this->preview)) {
$preview = null; $preview = null;
foreach (self::$providers as $supportedMimeType => $provider) { $previewProviders = \OC::$server->getPreviewManager()->getProviders();
foreach ($previewProviders as $supportedMimeType => $providers) {
if (!preg_match($supportedMimeType, $this->mimeType)) { if (!preg_match($supportedMimeType, $this->mimeType)) {
continue; continue;
} }
\OC_Log::write('core', 'Generating preview for "' . $file . '" with "' . get_class($provider) . '"', \OC_Log::DEBUG); foreach ($providers as $closure) {
$provider = $closure();
if (!($provider instanceof \OCP\Preview\IProvider)) {
continue;
}
/** @var $provider Provider */ \OC_Log::write('core', 'Generating preview for "' . $file . '" with "' . get_class($provider) . '"', \OC_Log::DEBUG);
$preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView);
if (!($preview instanceof \OC_Image)) { /** @var $provider Provider */
continue; $preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingUp, $this->fileView);
}
$this->preview = $preview; if (!($preview instanceof \OCP\IImage)) {
$this->resizeAndCrop(); continue;
}
$previewPath = $this->getPreviewPath($fileId); $this->preview = $preview;
$cachePath = $this->buildCachePath($fileId); $this->resizeAndCrop();
if ($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { $previewPath = $this->getPreviewPath($fileId);
$this->userView->mkdir($this->getThumbnailsFolder() . '/'); $cachePath = $this->buildCachePath($fileId);
}
if ($this->userView->is_dir($previewPath) === false) { if ($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) {
$this->userView->mkdir($previewPath); $this->userView->mkdir($this->getThumbnailsFolder() . '/');
} }
if ($this->userView->is_dir($previewPath) === false) {
$this->userView->mkdir($previewPath);
}
$this->userView->file_put_contents($cachePath, $preview->data()); $this->userView->file_put_contents($cachePath, $preview->data());
break; break 2;
}
} }
} }
...@@ -565,7 +564,7 @@ class Preview { ...@@ -565,7 +564,7 @@ class Preview {
if (is_null($this->preview)) { if (is_null($this->preview)) {
$this->getPreview(); $this->getPreview();
} }
if ($this->preview instanceof \OC_Image) { if ($this->preview instanceof \OCP\IImage) {
$this->preview->show($mimeType); $this->preview->show($mimeType);
} }
} }
...@@ -581,8 +580,8 @@ class Preview { ...@@ -581,8 +580,8 @@ class Preview {
$scalingUp = $this->getScalingUp(); $scalingUp = $this->getScalingUp();
$maxScaleFactor = $this->getMaxScaleFactor(); $maxScaleFactor = $this->getMaxScaleFactor();
if (!($image instanceof \OC_Image)) { if (!($image instanceof \OCP\IImage)) {
\OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG); \OC_Log::write('core', '$this->preview is not an instance of \OCP\IImage', \OC_Log::DEBUG);
return; return;
} }
...@@ -685,146 +684,6 @@ class Preview { ...@@ -685,146 +684,6 @@ class Preview {
} }
} }
/**
* register a new preview provider to be used
* @param string $class
* @param array $options
*/
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\Movie
* - OC\Preview\PDF
* - OC\Preview\TIFF
* - OC\Preview\Illustrator
* - OC\Preview\Postscript
* - OC\Preview\Photoshop
* - OC\Preview\Font
*/
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);
}
}
/**
* create instances of all the registered preview providers
* @return void
*/
private static function initProviders() {
if (!\OC::$server->getConfig()->getSystemValue('enable_previews', true)) {
self::$providers = array();
return;
}
if (!empty(self::$providers)) {
return;
}
self::registerCoreProviders();
foreach (self::$registeredProviders as $provider) {
$class = $provider['class'];
$options = $provider['options'];
/** @var $object Provider */
$object = new $class($options);
self::$providers[$object->getMimeType()] = $object;
}
$keys = array_map('strlen', array_keys(self::$providers));
array_multisort($keys, SORT_DESC, self::$providers);
}
protected static function registerCoreProviders() {
self::registerProvider('OC\Preview\TXT');
self::registerProvider('OC\Preview\MarkDown');
self::registerProvider('OC\Preview\Image');
self::registerProvider('OC\Preview\MP3');
// SVG, Office and Bitmap require imagick
if (extension_loaded('imagick')) {
$checkImagick = new \Imagick();
$imagickProviders = array(
'SVG' => 'OC\Preview\SVG',
'TIFF' => 'OC\Preview\TIFF',
'PDF' => 'OC\Preview\PDF',
'AI' => 'OC\Preview\Illustrator',
'PSD' => 'OC\Preview\Photoshop',
'EPS' => 'OC\Preview\Postscript',
'TTF' => 'OC\Preview\Font',
);
foreach ($imagickProviders as $queryFormat => $provider) {
if (count($checkImagick->queryFormats($queryFormat)) === 1) {
self::registerProvider($provider);
}
}
if (count($checkImagick->queryFormats('PDF')) === 1) {
// Office previews are currently not supported on Windows
if (!\OC_Util::runningOnWindows() && \OC_Helper::is_function_enabled('shell_exec')) {
$officeFound = is_string(\OC::$server->getConfig()->getSystemValue('preview_libreoffice_path', null));
if (!$officeFound) {
//let's see if there is libreoffice or openoffice on this machine
$whichLibreOffice = shell_exec('command -v libreoffice');
$officeFound = !empty($whichLibreOffice);
if (!$officeFound) {
$whichOpenOffice = shell_exec('command -v openoffice');
$officeFound = !empty($whichOpenOffice);
}
}
if ($officeFound) {
self::registerProvider('OC\Preview\MSOfficeDoc');
self::registerProvider('OC\Preview\MSOffice2003');
self::registerProvider('OC\Preview\MSOffice2007');
self::registerProvider('OC\Preview\OpenDocument');
self::registerProvider('OC\Preview\StarOffice');
}
}
}
}
// Video requires avconv or ffmpeg and is therefor
// currently not supported on Windows.
if (!\OC_Util::runningOnWindows()) {
$avconvBinary = \OC_Helper::findBinaryPath('avconv');
$ffmpegBinary = ($avconvBinary) ? null : \OC_Helper::findBinaryPath('ffmpeg');
if ($avconvBinary || $ffmpegBinary) {
// FIXME // a bit hacky but didn't want to use subclasses
\OC\Preview\Movie::$avconvBinary = $avconvBinary;
\OC\Preview\Movie::$ffmpegBinary = $ffmpegBinary;
self::registerProvider('OC\Preview\Movie');
}
}
}
/** /**
* @param array $args * @param array $args
*/ */
...@@ -914,60 +773,6 @@ class Preview { ...@@ -914,60 +773,6 @@ class Preview {
$preview->deleteAllPreviews(); $preview->deleteAllPreviews();
} }
/**
* 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) {
if (!\OC_Config::getValue('enable_previews', true)) {
return false;
}
$mount = $file->getMountPoint();
if ($mount and !$mount->getOption('previews', true)){
return false;
}
//check if there are preview backends
if (empty(self::$providers)) {
self::initProviders();
}
foreach (self::$providers as $supportedMimeType => $provider) {
/**
* @var \OC\Preview\Provider $provider
*/
if (preg_match($supportedMimeType, $file->getMimetype())) {
return $provider->isAvailable($file);
}
}
return false;
}
/**
* @param string $mimeType
* @return bool
*/
public static function isMimeSupported($mimeType) {
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) {
if(preg_match($supportedMimetype, $mimeType)) {
return true;
}
}
return false;
}
/** /**
* @param int $fileId * @param int $fileId
* @return string * @return string
......
...@@ -61,7 +61,7 @@ class Movie extends Provider { ...@@ -61,7 +61,7 @@ class Movie extends Provider {
* @param int $maxY * @param int $maxY
* @param string $absPath * @param string $absPath
* @param int $second * @param int $second
* @return bool|\OC_Image * @return bool|\OCP\IImage
*/ */
private function generateThumbNail($maxX, $maxY, $absPath, $second) { private function generateThumbNail($maxX, $maxY, $absPath, $second) {
$tmpPath = \OC_Helper::tmpFile(); $tmpPath = \OC_Helper::tmpFile();
......
...@@ -39,8 +39,7 @@ class MP3 extends Provider { ...@@ -39,8 +39,7 @@ class MP3 extends Provider {
/** /**
* Generates a default image when the file has no cover * Generates a default image when the file has no cover
* *
* @return false|\OC_Image False if the default image is missing or invalid, * @return bool|\OCP\IImage false if the default image is missing or invalid
* otherwise the image is returned as \OC_Image
*/ */
private function getNoCoverThumbnail() { private function getNoCoverThumbnail() {
$icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png'; $icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png';
......
<?php <?php
namespace OC\Preview; namespace OC\Preview;
abstract class Provider { use OCP\Preview\IProvider;
abstract class Provider implements IProvider {
private $options; private $options;
public function __construct($options) { /**
* Constructor
*
* @param array $options
*/
public function __construct(array $options = []) {
$this->options = $options; $this->options = $options;
}