diff options
author | kondou <kondou@ts.unde.re> | 2013-08-31 23:48:23 +0200 |
---|---|---|
committer | kondou <kondou@ts.unde.re> | 2013-08-31 23:48:23 +0200 |
commit | 235638e5abd35f2f19944bbe0b5a838b83465252 (patch) | |
tree | 27b531a7f9a2de054e707d4415ce7de2a2c51556 /lib | |
parent | 0869f9b655ddd0b285629256521d7eafde2f5d8a (diff) | |
parent | 92e90c8eb995c886b3e9cd77c14e3f0b25b95cd7 (diff) | |
download | nextcloud-server-235638e5abd35f2f19944bbe0b5a838b83465252.tar.gz nextcloud-server-235638e5abd35f2f19944bbe0b5a838b83465252.zip |
Merge branch 'master' into fix_4258
Conflicts:
lib/image.php
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base.php | 9 | ||||
-rw-r--r-- | lib/helper.php | 48 | ||||
-rw-r--r-- | lib/image.php | 5 | ||||
-rwxr-xr-x | lib/preview.php | 627 | ||||
-rw-r--r-- | lib/preview/image.php | 36 | ||||
-rw-r--r-- | lib/preview/movies.php | 47 | ||||
-rw-r--r-- | lib/preview/mp3.php | 48 | ||||
-rw-r--r-- | lib/preview/office-cl.php | 134 | ||||
-rw-r--r-- | lib/preview/office-fallback.php | 142 | ||||
-rw-r--r-- | lib/preview/office.php | 22 | ||||
-rw-r--r-- | lib/preview/pdf.php | 40 | ||||
-rw-r--r-- | lib/preview/provider.php | 19 | ||||
-rw-r--r-- | lib/preview/svg.php | 46 | ||||
-rw-r--r-- | lib/preview/txt.php | 73 | ||||
-rw-r--r-- | lib/preview/unknown.php | 27 | ||||
-rw-r--r-- | lib/public/preview.php | 34 | ||||
-rw-r--r-- | lib/public/template.php | 19 | ||||
-rw-r--r-- | lib/template/functions.php | 16 | ||||
-rwxr-xr-x | lib/util.php | 2 |
19 files changed, 1392 insertions, 2 deletions
diff --git a/lib/base.php b/lib/base.php index ef95909a311..b5c12a683ff 100644 --- a/lib/base.php +++ b/lib/base.php @@ -492,6 +492,7 @@ class OC { self::registerCacheHooks(); self::registerFilesystemHooks(); + self::registerPreviewHooks(); self::registerShareHooks(); self::registerLogRotate(); @@ -580,6 +581,14 @@ class OC { } /** + * register hooks for previews + */ + public static function registerPreviewHooks() { + OC_Hook::connect('OC_Filesystem', 'post_write', 'OC\Preview', 'post_write'); + OC_Hook::connect('OC_Filesystem', 'delete', 'OC\Preview', 'post_delete'); + } + + /** * register hooks for sharing */ public static function registerShareHooks() { diff --git a/lib/helper.php b/lib/helper.php index cfb29028ee3..5fb8fed3459 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -185,7 +185,38 @@ class OC_Helper { * Returns the path to the image of this file type. */ public static function mimetypeIcon($mimetype) { - $alias = array('application/xml' => 'code/xml'); + $alias = array( + 'application/xml' => 'code/xml', + 'application/msword' => 'x-office/document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'x-office/document', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'x-office/document', + 'application/vnd.ms-word.document.macroEnabled.12' => 'x-office/document', + 'application/vnd.ms-word.template.macroEnabled.12' => 'x-office/document', + 'application/vnd.oasis.opendocument.text' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-template' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-web' => 'x-office/document', + 'application/vnd.oasis.opendocument.text-master' => 'x-office/document', + 'application/vnd.ms-powerpoint' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.template.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation', + 'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation', + 'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation', + 'application/vnd.ms-excel' => 'x-office/spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.sheet.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.template.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.addin.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet', + ); + if (isset($alias[$mimetype])) { $mimetype = $alias[$mimetype]; } @@ -220,6 +251,21 @@ class OC_Helper { } /** + * @brief get path to preview of file + * @param string $path path + * @return string the url + * + * Returns the path to the preview of the file. + */ + public static function previewIcon($path) { + return self::linkToRoute( 'core_ajax_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path) )); + } + + public static function publicPreviewIcon( $path, $token ) { + return self::linkToRoute( 'core_ajax_public_preview', array('x' => 36, 'y' => 36, 'file' => urlencode($path), 't' => $token)); + } + + /** * @brief Make a human file size * @param int $bytes file size in bytes * @return string a human readable file size diff --git a/lib/image.php b/lib/image.php index fcb13a1fa14..badc30ab9a0 100644 --- a/lib/image.php +++ b/lib/image.php @@ -522,6 +522,11 @@ class OC_Image { if (\OC_Util::fileInfoLoaded()) { $this->mimeType = $this->fileInfo->buffer($str); } + if(is_resource($this->resource)) { + imagealphablending($this->resource, false); + imagesavealpha($this->resource, true); + } + if(!$this->resource) { OC_Log::write('core', 'OC_Image->loadFromData, couldn\'t load', OC_Log::DEBUG); return false; diff --git a/lib/preview.php b/lib/preview.php new file mode 100755 index 00000000000..b40ba191fba --- /dev/null +++ b/lib/preview.php @@ -0,0 +1,627 @@ +<?php +/** + * 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. + * + * Thumbnails: + * structure of filename: + * /data/user/thumbnails/pathhash/x-y.png + * + */ +namespace OC; + +require_once 'preview/image.php'; +require_once 'preview/movies.php'; +require_once 'preview/mp3.php'; +require_once 'preview/pdf.php'; +require_once 'preview/svg.php'; +require_once 'preview/txt.php'; +require_once 'preview/unknown.php'; +require_once 'preview/office.php'; + +class Preview { + //the thumbnail folder + const THUMBNAILS_FOLDER = 'thumbnails'; + + //config + private $maxScaleFactor; + private $configMaxX; + private $configMaxY; + + //fileview object + private $fileView = null; + private $userView = null; + + //vars + private $file; + private $maxX; + private $maxY; + private $scalingup; + + //preview images object + private $preview; + + //preview providers + static private $providers = array(); + static private $registeredProviders = array(); + + /** + * @brief check if thumbnail or bigger version of thumbnail of file is cached + * @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 + * @param bool $scalingUp Disable/Enable upscaling of previews + * @return mixed (bool / string) + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ + public function __construct($user='', $root='/', $file='', $maxX=1, $maxY=1, $scalingUp=true) { + //set config + $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); + + //save parameters + $this->setFile($file); + $this->setMaxX($maxX); + $this->setMaxY($maxY); + $this->setScalingUp($scalingUp); + + //init fileviews + if($user === ''){ + $user = \OC_User::getUser(); + } + $this->fileView = new \OC\Files\View('/' . $user . '/' . $root); + $this->userView = new \OC\Files\View('/' . $user); + + $this->preview = null; + + //check if there are preview backends + if(empty(self::$providers)) { + self::initProviders(); + } + + if(empty(self::$providers)) { + \OC_Log::write('core', 'No preview providers exist', \OC_Log::ERROR); + throw new \Exception('No preview providers'); + } + } + + /** + * @brief returns the path of the file you want a thumbnail from + * @return string + */ + public function getFile() { + return $this->file; + } + + /** + * @brief returns the max width of the preview + * @return integer + */ + public function getMaxX() { + return $this->maxX; + } + + /** + * @brief returns the max height of the preview + * @return integer + */ + public function getMaxY() { + return $this->maxY; + } + + /** + * @brief returns whether or not scalingup is enabled + * @return bool + */ + public function getScalingUp() { + return $this->scalingup; + } + + /** + * @brief returns the name of the thumbnailfolder + * @return string + */ + public function getThumbnailsFolder() { + return self::THUMBNAILS_FOLDER; + } + + /** + * @brief returns the max scale factor + * @return integer + */ + public function getMaxScaleFactor() { + return $this->maxScaleFactor; + } + + /** + * @brief returns the max width set in ownCloud's config + * @return integer + */ + public function getConfigMaxX() { + return $this->configMaxX; + } + + /** + * @brief returns the max height set in ownCloud's config + * @return integer + */ + public function getConfigMaxY() { + return $this->configMaxY; + } + + /** + * @brief set the path of the file you want a thumbnail from + * @param string $file + * @return $this + */ + public function setFile($file) { + $this->file = $file; + return $this; + } + + /** + * @brief set the the max width of the preview + * @param int $maxX + * @return $this + */ + public function setMaxX($maxX=1) { + if($maxX <= 0) { + throw new \Exception('Cannot set width of 0 or smaller!'); + } + $configMaxX = $this->getConfigMaxX(); + if(!is_null($configMaxX)) { + if($maxX > $configMaxX) { + \OC_Log::write('core', 'maxX reduced from ' . $maxX . ' to ' . $configMaxX, \OC_Log::DEBUG); + $maxX = $configMaxX; + } + } + $this->maxX = $maxX; + return $this; + } + + /** + * @brief set the the max height of the preview + * @param int $maxY + * @return $this + */ + public function setMaxY($maxY=1) { + if($maxY <= 0) { + throw new \Exception('Cannot set height of 0 or smaller!'); + } + $configMaxY = $this->getConfigMaxY(); + if(!is_null($configMaxY)) { + if($maxY > $configMaxY) { + \OC_Log::write('core', 'maxX reduced from ' . $maxY . ' to ' . $configMaxY, \OC_Log::DEBUG); + $maxY = $configMaxY; + } + } + $this->maxY = $maxY; + return $this; + } + + /** + * @brief set whether or not scalingup is enabled + * @param bool $scalingUp + * @return $this + */ + public function setScalingup($scalingUp) { + if($this->getMaxScaleFactor() === 1) { + $scalingUp = false; + } + $this->scalingup = $scalingUp; + return $this; + } + + /** + * @brief check if all parameters are valid + * @return bool + */ + public function isFileValid() { + $file = $this->getFile(); + if($file === '') { + \OC_Log::write('core', 'No filename passed', \OC_Log::DEBUG); + return false; + } + + if(!$this->fileView->file_exists($file)) { + \OC_Log::write('core', 'File:"' . $file . '" not found', \OC_Log::DEBUG); + return false; + } + + return true; + } + + /** + * @brief deletes previews of a file with specific x and y + * @return bool + */ + public function deletePreview() { + $file = $this->getFile(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/' . $this->getMaxX() . '-' . $this->getMaxY() . '.png'; + $this->userView->unlink($previewPath); + return !$this->userView->file_exists($previewPath); + } + + /** + * @brief deletes all previews of a file + * @return bool + */ + public function deleteAllPreviews() { + $file = $this->getFile(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + $this->userView->deleteAll($previewPath); + $this->userView->rmdir($previewPath); + return !$this->userView->is_dir($previewPath); + } + + /** + * @brief check if thumbnail or bigger version of thumbnail of file is cached + * @return mixed (bool / string) + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ + private function isCached() { + $file = $this->getFile(); + $maxX = $this->getMaxX(); + $maxY = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + $maxScaleFactor = $this->getMaxScaleFactor(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + if(is_null($fileId)) { + return false; + } + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + if(!$this->userView->is_dir($previewPath)) { + return false; + } + + //does a preview with the wanted height and width already exist? + if($this->userView->file_exists($previewPath . $maxX . '-' . $maxY . '.png')) { + return $previewPath . $maxX . '-' . $maxY . '.png'; + } + + $wantedAspectRatio = (float) ($maxX / $maxY); + + //array for usable cached thumbnails + $possibleThumbnails = array(); + + $allThumbnails = $this->userView->getDirectoryContent($previewPath); + foreach($allThumbnails as $thumbnail) { + $name = rtrim($thumbnail['name'], '.png'); + $size = explode('-', $name); + $x = (int) $size[0]; + $y = (int) $size[1]; + + $aspectRatio = (float) ($x / $y); + if($aspectRatio !== $wantedAspectRatio) { + continue; + } + + if($x < $maxX || $y < $maxY) { + if($scalingUp) { + $scalefactor = $maxX / $x; + if($scalefactor > $maxScaleFactor) { + continue; + } + }else{ + continue; + } + } + $possibleThumbnails[$x] = $thumbnail['path']; + } + + if(count($possibleThumbnails) === 0) { + return false; + } + + if(count($possibleThumbnails) === 1) { + return current($possibleThumbnails); + } + + ksort($possibleThumbnails); + + if(key(reset($possibleThumbnails)) > $maxX) { + return current(reset($possibleThumbnails)); + } + + if(key(end($possibleThumbnails)) < $maxX) { + return current(end($possibleThumbnails)); + } + + foreach($possibleThumbnails as $width => $path) { + if($width < $maxX) { + continue; + }else{ + return $path; + } + } + } + + /** + * @brief return a preview of a file + * @return \OC_Image + */ + public function getPreview() { + if(!is_null($this->preview) && $this->preview->valid()){ + return $this->preview; + } + + $this->preview = null; + $file = $this->getFile(); + $maxX = $this->getMaxX(); + $maxY = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + + $fileInfo = $this->fileView->getFileInfo($file); + $fileId = $fileInfo['fileid']; + + $cached = $this->isCached(); + + if($cached) { + $image = new \OC_Image($this->userView->file_get_contents($cached, 'r')); + $this->preview = $image->valid() ? $image : null; + $this->resizeAndCrop(); + } + + if(is_null($this->preview)) { + $mimetype = $this->fileView->getMimeType($file); + $preview = null; + + foreach(self::$providers as $supportedMimetype => $provider) { + if(!preg_match($supportedMimetype, $mimetype)) { + continue; + } + + \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)) { + continue; + } + + $this->preview = $preview; + $this->resizeAndCrop(); + + $previewPath = $this->getThumbnailsFolder() . '/' . $fileId . '/'; + $cachePath = $previewPath . $maxX . '-' . $maxY . '.png'; + + if($this->userView->is_dir($this->getThumbnailsFolder() . '/') === false) { + $this->userView->mkdir($this->getThumbnailsFolder() . '/'); + } + + if($this->userView->is_dir($previewPath) === false) { + $this->userView->mkdir($previewPath); + } + + $this->userView->file_put_contents($cachePath, $preview->data()); + + break; + } + } + + if(is_null($this->preview)) { + $this->preview = new \OC_Image(); + } + + return $this->preview; + } + + /** + * @brief show preview + * @return void + */ + public function showPreview() { + \OCP\Response::enableCaching(3600 * 24); // 24 hours + if(is_null($this->preview)) { + $this->getPreview(); + } + $this->preview->show(); + return; + } + + /** + * @brief show preview + * @return void + */ + public function show() { + $this->showPreview(); + return; + } + + /** + * @brief resize, crop and fix orientation + * @return void + */ + private function resizeAndCrop() { + $image = $this->preview; + $x = $this->getMaxX(); + $y = $this->getMaxY(); + $scalingUp = $this->getScalingUp(); + $maxscalefactor = $this->getMaxScaleFactor(); + + if(!($image instanceof \OC_Image)) { + \OC_Log::write('core', '$this->preview is not an instance of OC_Image', \OC_Log::DEBUG); + return; + } + + $image->fixOrientation(); + + $realx = (int) $image->width(); + $realy = (int) $image->height(); + + if($x === $realx && $y === $realy) { + $this->preview = $image; + return; + } + + $factorX = $x / $realx; + $factorY = $y / $realy; + + if($factorX >= $factorY) { + $factor = $factorX; + }else{ + $factor = $factorY; + } + + if($scalingUp === false) { + if($factor > 1) { + $factor = 1; + } + } + + if(!is_null($maxscalefactor)) { + if($factor > $maxscalefactor) { + \OC_Log::write('core', 'scalefactor reduced from ' . $factor . ' to ' . $maxscalefactor, \OC_Log::DEBUG); + $factor = $maxscalefactor; + } + } + + $newXsize = (int) ($realx * $factor); + $newYsize = (int) ($realy * $factor); + + $image->preciseResize($newXsize, $newYsize); + + if($newXsize === $x && $newYsize === $y) { + $this->preview = $image; + return; + } + + if($newXsize >= $x && $newYsize >= $y) { + $cropX = floor(abs($x - $newXsize) * 0.5); + //don't crop previews on the Y axis, this sucks if it's a document. + //$cropY = floor(abs($y - $newYsize) * 0.5); + $cropY = 0; + + $image->crop($cropX, $cropY, $x, $y); + + $this->preview = $image; + return; + } + + if($newXsize < $x || $newYsize < $y) { + if($newXsize > $x) { + $cropX = floor(($newXsize - $x) * 0.5); + $image->crop($cropX, 0, $x, $newYsize); + } + + if($newYsize > $y) { + $cropY = floor(($newYsize - $y) * 0.5); + $image->crop(0, $cropY, $newXsize, $y); + } + + $newXsize = (int) $image->width(); + $newYsize = (int) $image->height(); + + //create transparent background layer + $backgroundlayer = imagecreatetruecolor($x, $y); + $white = imagecolorallocate($backgroundlayer, 255, 255, 255); + imagefill($backgroundlayer, 0, 0, $white); + + $image = $image->resource(); + + $mergeX = floor(abs($x - $newXsize) * 0.5); + $mergeY = floor(abs($y - $newYsize) * 0.5); + + imagecopy($backgroundlayer, $image, $mergeX, $mergeY, 0, 0, $newXsize, $newYsize); + + //$black = imagecolorallocate(0,0,0); + //imagecolortransparent($transparentlayer, $black); + + $image = new \OC_Image($backgroundlayer); + + $this->preview = $image; + return; + } + } + + /** + * @brief register a new preview provider to be used + * @param string $provider class name of a Preview_Provider + * @param array $options + * @return void + */ + public static function registerProvider($class, $options=array()) { + self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); + } + + /** + * @brief create instances of all the registered preview providers + * @return void + */ + private static function initProviders() { + if(!\OC_Config::getValue('enable_previews', true)) { + $provider = new Preview\Unknown(array()); + self::$providers = array($provider->getMimeType() => $provider); + return; + } + + if(count(self::$providers)>0) { + return; + } + + foreach(self::$registeredProviders as $provider) { + $class=$provider['class']; + $options=$provider['options']; + + $object = new $class($options); + + self::$providers[$object->getMimeType()] = $object; + } + + $keys = array_map('strlen', array_keys(self::$providers)); + array_multisort($keys, SORT_DESC, self::$providers); + } + + public static function post_write($args) { + self::post_delete($args); + } + + public static function post_delete($args) { + $path = $args['path']; + if(substr($path, 0, 1) === '/') { + $path = substr($path, 1); + } + $preview = new Preview(\OC_User::getUser(), 'files/', $path); + $preview->deleteAllPreviews(); + } + + 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(); + } + + //remove last element because it has the mimetype * + $providers = array_slice(self::$providers, 0, -1); + foreach($providers as $supportedMimetype => $provider) { + if(preg_match($supportedMimetype, $mimetype)) { + return true; + } + } + return false; + } +}
\ No newline at end of file diff --git a/lib/preview/image.php b/lib/preview/image.php new file mode 100644 index 00000000000..9aec967282d --- /dev/null +++ b/lib/preview/image.php @@ -0,0 +1,36 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +class Image extends Provider { + + public function getMimeType() { + return '/image\/.*/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + //get fileinfo + $fileInfo = $fileview->getFileInfo($path); + if(!$fileInfo) { + return false; + } + + //check if file is encrypted + if($fileInfo['encrypted'] === true) { + $image = new \OC_Image(stream_get_contents($fileview->fopen($path, 'r'))); + }else{ + $image = new \OC_Image(); + $image->loadFromFile($fileview->getLocalFile($path)); + } + + return $image->valid() ? $image : false; + } +} + +\OC\Preview::registerProvider('OC\Preview\Image');
\ No newline at end of file diff --git a/lib/preview/movies.php b/lib/preview/movies.php new file mode 100644 index 00000000000..e2a1b8edddc --- /dev/null +++ b/lib/preview/movies.php @@ -0,0 +1,47 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +$isShellExecEnabled = !in_array('shell_exec', explode(', ', ini_get('disable_functions'))); +$whichFFMPEG = shell_exec('which ffmpeg'); +$isFFMPEGAvailable = !empty($whichFFMPEG); + +if($isShellExecEnabled && $isFFMPEGAvailable) { + + class Movie extends Provider { + + public function getMimeType() { + return '/video\/.*/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $absPath = \OC_Helper::tmpFile(); + $tmpPath = \OC_Helper::tmpFile(); + + $handle = $fileview->fopen($path, 'rb'); + + $firstmb = stream_get_contents($handle, 1048576); //1024 * 1024 = 1048576 + file_put_contents($absPath, $firstmb); + + //$cmd = 'ffmpeg -y -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 -ss 1 -s ' . escapeshellarg($maxX) . 'x' . escapeshellarg($maxY) . ' ' . $tmpPath; + $cmd = 'ffmpeg -an -y -i ' . escapeshellarg($absPath) . ' -f mjpeg -vframes 1 -ss 1 ' . escapeshellarg($tmpPath); + + shell_exec($cmd); + + $image = new \OC_Image($tmpPath); + + unlink($absPath); + unlink($tmpPath); + + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\Movie'); +}
\ No newline at end of file diff --git a/lib/preview/mp3.php b/lib/preview/mp3.php new file mode 100644 index 00000000000..1eed566315c --- /dev/null +++ b/lib/preview/mp3.php @@ -0,0 +1,48 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +class MP3 extends Provider { + + public function getMimeType() { + return '/audio\/mpeg/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + require_once('getid3/getid3.php'); + + $getID3 = new \getID3(); + + $tmpPath = $fileview->toTmpFile($path); + + $tags = $getID3->analyze($tmpPath); + \getid3_lib::CopyTagsToComments($tags); + if(isset($tags['id3v2']['APIC'][0]['data'])) { + $picture = @$tags['id3v2']['APIC'][0]['data']; + unlink($tmpPath); + $image = new \OC_Image($picture); + return $image->valid() ? $image : $this->getNoCoverThumbnail(); + } + + return $this->getNoCoverThumbnail(); + } + + private function getNoCoverThumbnail() { + $icon = \OC::$SERVERROOT . '/core/img/filetypes/audio.png'; + + if(!file_exists($icon)) { + return false; + } + + $image = new \OC_Image($icon); + return $image->valid() ? $image : false; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MP3');
\ No newline at end of file diff --git a/lib/preview/office-cl.php b/lib/preview/office-cl.php new file mode 100644 index 00000000000..112909d6523 --- /dev/null +++ b/lib/preview/office-cl.php @@ -0,0 +1,134 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +//we need imagick to convert +class Office extends Provider { + + private $cmd; + + public function getMimeType() { + return null; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $this->initCmd(); + if(is_null($this->cmd)) { + return false; + } + + $absPath = $fileview->toTmpFile($path); + + $tmpDir = get_temp_dir(); + + $defaultParameters = ' --headless --nologo --nofirststartwizard --invisible --norestore -convert-to pdf -outdir '; + $clParameters = \OCP\Config::getSystemValue('preview_office_cl_parameters', $defaultParameters); + + $exec = $this->cmd . $clParameters . escapeshellarg($tmpDir) . ' ' . escapeshellarg($absPath); + $export = 'export HOME=/' . $tmpDir; + + shell_exec($export . "\n" . $exec); + + //create imagick object from pdf + try{ + $pdf = new \imagick($absPath . '.pdf' . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + unlink($absPath); + unlink($absPath . '.pdf'); + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + $image = new \OC_Image($pdf); + + unlink($absPath); + unlink($absPath . '.pdf'); + + return $image->valid() ? $image : false; + } + + private function initCmd() { + $cmd = ''; + + if(is_string(\OC_Config::getValue('preview_libreoffice_path', null))) { + $cmd = \OC_Config::getValue('preview_libreoffice_path', null); + } + + $whichLibreOffice = shell_exec('which libreoffice'); + if($cmd === '' && !empty($whichLibreOffice)) { + $cmd = 'libreoffice'; + } + + $whichOpenOffice = shell_exec('which openoffice'); + if($cmd === '' && !empty($whichOpenOffice)) { + $cmd = 'openoffice'; + } + + if($cmd === '') { + $cmd = null; + } + + $this->cmd = $cmd; + } +} + +//.doc, .dot +class MSOfficeDoc extends Office { + + public function getMimeType() { + return '/application\/msword/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOfficeDoc'); + +//.docm, .dotm, .xls(m), .xlt(m), .xla(m), .ppt(m), .pot(m), .pps(m), .ppa(m) +class MSOffice2003 extends Office { + + public function getMimeType() { + return '/application\/vnd.ms-.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOffice2003'); + +//.docx, .dotx, .xlsx, .xltx, .pptx, .potx, .ppsx +class MSOffice2007 extends Office { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\MSOffice2007'); + +//.odt, .ott, .oth, .odm, .odg, .otg, .odp, .otp, .ods, .ots, .odc, .odf, .odb, .odi, .oxt +class OpenDocument extends Office { + + public function getMimeType() { + return '/application\/vnd.oasis.opendocument.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\OpenDocument'); + +//.sxw, .stw, .sxc, .stc, .sxd, .std, .sxi, .sti, .sxg, .sxm +class StarOffice extends Office { + + public function getMimeType() { + return '/application\/vnd.sun.xml.*/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\StarOffice');
\ No newline at end of file diff --git a/lib/preview/office-fallback.php b/lib/preview/office-fallback.php new file mode 100644 index 00000000000..e69ab0ab8cb --- /dev/null +++ b/lib/preview/office-fallback.php @@ -0,0 +1,142 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +/* //There is no (good) php-only solution for converting 2003 word documents to pdfs / pngs ... +class DOC extends Provider { + + public function getMimeType() { + return '/application\/msword/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + require_once(''); + } + +} + +\OC\Preview::registerProvider('OC\Preview\DOC'); +*/ + +class DOCX extends Provider { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.wordprocessingml.document/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + require_once('phpdocx/classes/TransformDoc.inc'); + + $tmpDoc = $fileview->toTmpFile($path); + + $transformdoc = new \TransformDoc(); + $transformdoc->setStrFile($tmpDoc); + $transformdoc->generatePDF($tmpDoc); + + $pdf = new \imagick($tmpDoc . '[0]'); + $pdf->setImageFormat('jpg'); + + unlink($tmpDoc); + + $image = new \OC_Image($pdf); + + return $image->valid() ? $image : false; + } + +} + +\OC\Preview::registerProvider('OC\Preview\DOCX'); + +class MSOfficeExcel extends Provider { + + public function getMimeType() { + return null; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + require_once('PHPExcel/Classes/PHPExcel.php'); + require_once('PHPExcel/Classes/PHPExcel/IOFactory.php'); + + $absPath = $fileview->toTmpFile($path); + $tmpPath = \OC_Helper::tmpFile(); + + $rendererName = \PHPExcel_Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = \OC::$THIRDPARTYROOT . '/3rdparty/dompdf'; + + \PHPExcel_Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + + $phpexcel = new \PHPExcel($absPath); + $excel = \PHPExcel_IOFactory::createWriter($phpexcel, 'PDF'); + $excel->save($tmpPath); + + $pdf = new \imagick($tmpPath . '[0]'); + $pdf->setImageFormat('jpg'); + + unlink($absPath); + unlink($tmpPath); + + $image = new \OC_Image($pdf); + + return $image->valid() ? $image : false; + } + +} + +class XLS extends MSOfficeExcel { + + public function getMimeType() { + return '/application\/vnd.ms-excel/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\XLS'); + +class XLSX extends MSOfficeExcel { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\XLSX'); + +/* //There is no (good) php-only solution for converting powerpoint documents to pdfs / pngs ... +class MSOfficePowerPoint extends Provider { + + public function getMimeType() { + return null; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + return false; + } + +} + +class PPT extends MSOfficePowerPoint { + + public function getMimeType() { + return '/application\/vnd.ms-powerpoint/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PPT'); + +class PPTX extends MSOfficePowerPoint { + + public function getMimeType() { + return '/application\/vnd.openxmlformats-officedocument.presentationml.presentation/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PPTX'); +*/
\ No newline at end of file diff --git a/lib/preview/office.php b/lib/preview/office.php new file mode 100644 index 00000000000..5287bbd6ac1 --- /dev/null +++ b/lib/preview/office.php @@ -0,0 +1,22 @@ +<?php +/** + * 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. + */ +//both, libreoffice backend and php fallback, need imagick +if (extension_loaded('imagick')) { + $isShellExecEnabled = !in_array('shell_exec', explode(', ', ini_get('disable_functions'))); + $whichLibreOffice = shell_exec('which libreoffice'); + $isLibreOfficeAvailable = !empty($whichLibreOffice); + $whichOpenOffice = shell_exec('which libreoffice'); + $isOpenOfficeAvailable = !empty($whichOpenOffice); + //let's see if there is libreoffice or openoffice on this machine + if($isShellExecEnabled && ($isLibreOfficeAvailable || $isOpenOfficeAvailable || is_string(\OC_Config::getValue('preview_libreoffice_path', null)))) { + require_once('office-cl.php'); + }else{ + //in case there isn't, use our fallback + require_once('office-fallback.php'); + } +}
\ No newline at end of file diff --git a/lib/preview/pdf.php b/lib/preview/pdf.php new file mode 100644 index 00000000000..cc974b68818 --- /dev/null +++ b/lib/preview/pdf.php @@ -0,0 +1,40 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +if (extension_loaded('imagick')) { + + class PDF extends Provider { + + public function getMimeType() { + return '/application\/pdf/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $tmpPath = $fileview->toTmpFile($path); + + //create imagick object from pdf + try{ + $pdf = new \imagick($tmpPath . '[0]'); + $pdf->setImageFormat('jpg'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + unlink($tmpPath); + + //new image object + $image = new \OC_Image($pdf); + //check if image object is valid + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\PDF'); +} diff --git a/lib/preview/provider.php b/lib/preview/provider.php new file mode 100644 index 00000000000..e4a730bafc8 --- /dev/null +++ b/lib/preview/provider.php @@ -0,0 +1,19 @@ +<?php +namespace OC\Preview; + +abstract class Provider { + private $options; + + public function __construct($options) { + $this->options=$options; + } + + abstract public function getMimeType(); + + /** + * search for $query + * @param string $query + * @return + */ + abstract public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview); +} diff --git a/lib/preview/svg.php b/lib/preview/svg.php new file mode 100644 index 00000000000..b49e51720fa --- /dev/null +++ b/lib/preview/svg.php @@ -0,0 +1,46 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +if (extension_loaded('imagick')) { + + class SVG extends Provider { + + public function getMimeType() { + return '/image\/svg\+xml/'; + } + + public function getThumbnail($path,$maxX,$maxY,$scalingup,$fileview) { + try{ + $svg = new \Imagick(); + $svg->setBackgroundColor(new \ImagickPixel('transparent')); + + $content = stream_get_contents($fileview->fopen($path, 'r')); + if(substr($content, 0, 5) !== '<?xml') { + $content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $content; + } + + $svg->readImageBlob($content); + $svg->setImageFormat('png32'); + } catch (\Exception $e) { + \OC_Log::write('core', $e->getmessage(), \OC_Log::ERROR); + return false; + } + + + //new image object + $image = new \OC_Image(); + $image->loadFromData($svg); + //check if image object is valid + return $image->valid() ? $image : false; + } + } + + \OC\Preview::registerProvider('OC\Preview\SVG'); + +}
\ No newline at end of file diff --git a/lib/preview/txt.php b/lib/preview/txt.php new file mode 100644 index 00000000000..a487330691e --- /dev/null +++ b/lib/preview/txt.php @@ -0,0 +1,73 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +class TXT extends Provider { + + public function getMimeType() { + return '/text\/.*/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $content = $fileview->fopen($path, 'r'); + $content = stream_get_contents($content); + + //don't create previews of empty text files + if(trim($content) === '') { + return false; + } + + $lines = preg_split("/\r\n|\n|\r/", $content); + + $fontSize = 5; //5px + $lineSize = ceil($fontSize * 1.25); + + $image = imagecreate($maxX, $maxY); + imagecolorallocate($image, 255, 255, 255); + $textColor = imagecolorallocate($image, 0, 0, 0); + + foreach($lines as $index => $line) { + $index = $index + 1; + + $x = (int) 1; + $y = (int) ($index * $lineSize) - $fontSize; + + imagestring($image, 1, $x, $y, $line, $textColor); + + if(($index * $lineSize) >= $maxY) { + break; + } + } + + $image = new \OC_Image($image); + + return $image->valid() ? $image : false; + } +} + +\OC\Preview::registerProvider('OC\Preview\TXT'); + +class PHP extends TXT { + + public function getMimeType() { + return '/application\/x-php/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\PHP'); + +class JavaScript extends TXT { + + public function getMimeType() { + return '/application\/javascript/'; + } + +} + +\OC\Preview::registerProvider('OC\Preview\JavaScript');
\ No newline at end of file diff --git a/lib/preview/unknown.php b/lib/preview/unknown.php new file mode 100644 index 00000000000..9e6cd68d401 --- /dev/null +++ b/lib/preview/unknown.php @@ -0,0 +1,27 @@ +<?php +/** + * 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. + */ +namespace OC\Preview; + +class Unknown extends Provider { + + public function getMimeType() { + return '/.*/'; + } + + public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) { + $mimetype = $fileview->getMimeType($path); + + $path = \OC_Helper::mimetypeIcon($mimetype); + $path = \OC::$SERVERROOT . substr($path, strlen(\OC::$WEBROOT)); + + return new \OC_Image($path); + } +} + +\OC\Preview::registerProvider('OC\Preview\Unknown');
\ No newline at end of file diff --git a/lib/public/preview.php b/lib/public/preview.php new file mode 100644 index 00000000000..e488eade4da --- /dev/null +++ b/lib/public/preview.php @@ -0,0 +1,34 @@ +<?php +/** + * 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. + */ +namespace OCP; + +/** + * This class provides functions to render and show thumbnails and previews of files + */ +class Preview { + + /** + * @brief return a preview of a file + * @param $file The path to the file where you want a thumbnail from + * @param $maxX The maximum X size of the thumbnail. It can be smaller depending on the shape of the image + * @param $maxY The maximum Y size of the thumbnail. It can be smaller depending on the shape of the image + * @param $scaleup Scale smaller images up to the thumbnail size or not. Might look ugly + * @return image + */ + public static function show($file,$maxX=100,$maxY=75,$scaleup=false) { + return(\OC_Preview::show($file,$maxX,$maxY,$scaleup)); + } + + + + public static function isMimeSupported($mimetype='*') { + return \OC\Preview::isMimeSupported($mimetype); + } + +} diff --git a/lib/public/template.php b/lib/public/template.php index ab1089c332d..3b1a4ed4906 100644 --- a/lib/public/template.php +++ b/lib/public/template.php @@ -54,6 +54,25 @@ function mimetype_icon( $mimetype ) { return(\mimetype_icon( $mimetype )); } +/** + * @brief make preview_icon available as a simple function + * Returns the path to the preview of the image. + * @param $path path of file + * @returns link to the preview + */ +function preview_icon( $path ) { + return(\preview_icon( $path )); +} + +/** + * @brief make publicpreview_icon available as a simple function + * Returns the path to the preview of the image. + * @param $path path of file + * @returns link to the preview + */ +function publicPreview_icon ( $path, $token ) { + return(\publicPreview_icon( $path, $token )); +} /** * @brief make OC_Helper::humanFileSize available as a simple function diff --git a/lib/template/functions.php b/lib/template/functions.php index 717e197c1cb..501f8081bff 100644 --- a/lib/template/functions.php +++ b/lib/template/functions.php @@ -59,6 +59,22 @@ function mimetype_icon( $mimetype ) { } /** + * @brief make preview_icon available as a simple function + * Returns the path to the preview of the image. + * @param $path path of file + * @returns link to the preview + * + * For further information have a look at OC_Helper::previewIcon + */ +function preview_icon( $path ) { + return OC_Helper::previewIcon( $path ); +} + +function publicPreview_icon ( $path, $token ) { + return OC_Helper::publicPreviewIcon( $path, $token ); +} + +/** * @brief make OC_Helper::humanFileSize available as a simple function * @param int $bytes size in bytes * @return string size as string diff --git a/lib/util.php b/lib/util.php index e03667b0794..6195178701b 100755 --- a/lib/util.php +++ b/lib/util.php @@ -98,7 +98,7 @@ class OC_Util { public static function getVersion() { // hint: We only can count up. Reset minor/patchlevel when // updating major/minor version number. - return array(5, 80, 05); + return array(5, 80, 07); } /** |