diff options
author | Georg Ehrke <georg@ownCloud.com> | 2013-04-25 11:18:45 +0200 |
---|---|---|
committer | Georg Ehrke <georg@ownCloud.com> | 2013-04-25 11:41:54 +0200 |
commit | 9ef449842a369c2517f5c34932b502b754393ce0 (patch) | |
tree | bf56e29de38c0a7592d6edd351458ff7d3022c69 /lib/preview.php | |
parent | ec3e97f28f96d06434eb1a9f480f5fe1b3e489f8 (diff) | |
download | nextcloud-server-9ef449842a369c2517f5c34932b502b754393ce0.tar.gz nextcloud-server-9ef449842a369c2517f5c34932b502b754393ce0.zip |
save current work state of Preview Lib
Diffstat (limited to 'lib/preview.php')
-rwxr-xr-x | lib/preview.php | 378 |
1 files changed, 229 insertions, 149 deletions
diff --git a/lib/preview.php b/lib/preview.php index d49e9d3bde3..c7047633212 100755 --- a/lib/preview.php +++ b/lib/preview.php @@ -1,28 +1,139 @@ <?php /** - * Copyright (c) 2012 Frank Karlitschek frank@owncloud.org + * 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. */ - /* -TODO: - - delete thumbnails if files change. - - make it work with external filesystem files. - - movies support - - pdf support - - mp3/id3 support - - more file types + * Thumbnails: + * structure of filename: + * /data/user/thumbnails/pathhash/x-y.png + * + */ -*/ +class OC_Preview { + //the thumbnail folder + const THUMBNAILS_FOLDER = 'thumbnails'; + const MAX_SCALE_FACTOR = 2; + //fileview object + static private $fileview = null; + //preview providers + static private $providers = array(); + static private $registeredProviders = array(); -class OC_Preview { + /** + * @brief check if thumbnail or bigger version of thumbnail of file is cached + * @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 + * @return mixed (bool / string) + * false if thumbnail does not exist + * path to thumbnail if thumbnail exists + */ + private static function isCached($file, $maxX, $maxY, $scalingup){ + $fileinfo = self::$fileview->getFileInfo($file); + $fileid = self::$fileinfo['fileid']; + + //echo self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid; + if(!self::$fileview->is_dir(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid)){ + return false; + } + + //does a preview with the wanted height and width already exist? + if(self::$fileview->file_exists(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid . PATH_SEPARATOR . $x . '-' . $y . '.png')){ + return self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid . PATH_SEPARATOR . $x . '-' . $y . '.png'; + } + + $wantedaspectratio = $maxX / $maxY; + + //array for usable cached thumbnails + $possiblethumbnails = array(); + + $allthumbnails = self::$fileview->getDirectoryContent(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid); + foreach($allthumbnails as $thumbnail){ + $size = explode('-', $thumbnail['name']); + $x = $size[0]; + $y = $size[1]; + + $aspectratio = $x / $y; + if($aspectratio != $wantedaspectratio){ + continue; + } + + if($x < $maxX || $y < $maxY){ + if($scalingup){ + $scalefactor = $maxX / $x; + if($scalefactor > self::MAX_SCALE_FACTOR){ + 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; + } + } + } - // the thumbnail cache folder - const THUMBNAILS_FOLDER = 'thumbnails'; + /** + * @brief delete a preview with a specfic height and width + * @param $file path to the file + * @param $x width of preview + * @param $y height of preview + * @return image + */ + public static function deletePreview($file, $x, $y){ + self::init(); + + $fileinfo = self::$fileview->getFileInfo($file); + $fileid = self::$fileinfo['fileid']; + + return self::$fileview->unlink(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid . PATH_SEPARATOR . $x . '-' . $y . '.png'); + } + + /** + * @brief deletes all previews of a file + * @param $file path of file + * @return bool + */ + public static function deleteAllPrevies($file){ + self::init(); + + $fileinfo = self::$fileview->getFileInfo($file); + $fileid = self::$fileinfo['fileid']; + + return self::$fielview->rmdir(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid); + } /** * @brief return a preview of a file @@ -32,146 +143,115 @@ class OC_Preview { * @param $scaleup Scale smaller images up to the thumbnail size or not. Might look ugly * @return image */ - static public function show($file,$maxX,$maxY,$scalingup) { - // get the mimetype of the file - $mimetype=explode('/',OC_FileSystem::getMimeType($file)); - // it´s an image - if($mimetype[0]=='image'){ - OCP\Response::enableCaching(3600 * 24); // 24 hour - $image=OC_PreviewImage::getThumbnail($file,$maxX,$maxY,$scalingup); - $image->show(); - - // it´s a video - }elseif($mimetype[0]=='video'){ - OCP\Response::enableCaching(3600 * 24); // 24 hour - OC_PreviewMovie::getThumbnail($file,$maxX,$maxY,$scalingup); - - // it´s something else. Let´s create a dummy preview - }else{ - header('Content-type: image/png'); - OC_PreviewUnknown::getThumbnail($maxX,$maxY); + public static function getPreview($file, $maxX, $maxY, $scalingup){ + self::init(); + + $cached = self::isCached($file, $maxX, $maxY); + if($cached){ + $image = new \OC_Image($cached); + if($image->width() != $maxX && $image->height != $maxY){ + $image->preciseResize($maxX, $maxY); + } + return $image; } + + $mimetype = self::$fileview->getMimeType($file); + + $preview; + + foreach(self::$providers as $supportedmimetype => $provider){ + if(!preg_match($supportedmimetype, $mimetype)){ + continue; + } + + $preview = $provider->getThumbnail($file, $maxX, $maxY, $scalingup); + + if(!$preview){ + continue; + } + + if(!($preview instanceof \OC_Image)){ + $preview = @new \OC_Image($preview); + } + + //cache thumbnail + $preview->save(self::$filesview->getAbsolutePath(self::THUMBNAILS_FOLDER . PATH_SEPARATOR . $fileid . PATH_SEPARATOR . $x . '-' . $y . '.png')); + + break; + } + + return $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 showPreview($file, $maxX, $maxY, $scalingup = true, $fontsize = 12){ + OCP\Response::enableCaching(3600 * 24); // 24 hour + $preview = self::getPreview($file, $maxX, $maxY, $scalingup, $fontsize); + $preview->show(); + } + + /** + * @brief check whether or not providers and views are initialized and initialize if not + * @return void + */ + private static function init(){ + if(empty(self::$providers)){ + self::initProviders(); + } + if(is_null(self::$thumbnailsview) || is_null(self::$userlandview)){ + self::initViews(); + } + } -} - - - -class OC_PreviewImage { - - public static function getThumbnail($path,$maxX,$maxY,$scalingup) { - - $thumbnails_view = new \OC_FilesystemView('/'.\OCP\User::getUser() .'/'.OC_Preview::THUMBNAILS_FOLDER); - - // is a preview already in the cache? - if ($thumbnails_view->file_exists($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup)) { - return new \OC_Image($thumbnails_view->getLocalFile($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup)); - } - - // does the sourcefile exist? - if (!\OC_Filesystem::file_exists($path)) { - \OC_Log::write('Preview', 'File '.$path.' don\'t exists', \OC_Log::WARN); - return false; - } - - // open the source image - $image = new \OC_Image(); - $image->loadFromFile(\OC_Filesystem::getLocalFile($path)); - if (!$image->valid()) return false; - - // fix the orientation - $image->fixOrientation(); - - // calculate the right preview size - $Xsize=$image->width(); - $Ysize=$image->height(); - if (($Xsize/$Ysize)>($maxX/$maxY)) { - $factor=$maxX/$Xsize; - } else { - $factor=$maxY/$Ysize; - } - - // only scale up if requested - if($scalingup==false) { - if($factor>1) $factor=1; - } - $newXsize=$Xsize*$factor; - $newYsize=$Ysize*$factor; - - // resize - $ret = $image->preciseResize($newXsize, $newYsize); - if (!$ret) { - \OC_Log::write('Preview', 'Couldn\'t resize image', \OC_Log::ERROR); - unset($image); - return false; - } - - // store in cache - $l = $thumbnails_view->getLocalFile($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup); - $image->save($l); - - return $image; - - - } - - - -} - - -class OC_PreviewMovie { - - public static function isAvailable() { - $check=shell_exec('ffmpeg'); - if($check==NULL) return(false); else return(true); - } - - public static function getThumbnail($path,$maxX,$maxY,$scalingup) { - $thumbnails_view = new \OC_FilesystemView('/'.\OCP\User::getUser() .'/'.OC_Preview::THUMBNAILS_FOLDER); - - // is a preview already in the cache? - if ($thumbnails_view->file_exists($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup)) { - return new \OC_Image($thumbnails_view->getLocalFile($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup)); - } - - // does the sourcefile exist? - if (!\OC_Filesystem::file_exists($path)) { - \OC_Log::write('Preview', 'File '.$path.' don\'t exists', \OC_Log::WARN); - return false; - } - - // call ffmpeg to do the screenshot - shell_exec('ffmpeg -y -i {'.escapeshellarg($path).'} -f mjpeg -vframes 1 -ss 1 -s {'.escapeshellarg($maxX).'}x{'.escapeshellarg($maxY).'} {.'.$thumbnails_view->getLocalFile($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup).'}'); - - // output the generated Preview - $thumbnails_view->getLocalFile($path.'-'.$maxX.'-'.$maxY.'-'.$scalingup); - unset($thumbnails_view); - } - - -} - + /** + * @brief register a new preview provider to be used + * @param string $provider class name of a OC_Preview_Provider + * @return void + */ + public static function registerProvider($class, $options=array()){ + self::$registeredProviders[]=array('class'=>$class, 'options'=>$options); + } -class OC_PreviewUnknown { - public static function getThumbnail($maxX,$maxY) { + /** + * @brief create instances of all the registered preview providers + * @return void + */ + private static function initProviders(){ + if(count(self::$providers)>0) { + return; + } + + foreach(self::$registeredProviders as $provider) { + $class=$provider['class']; + $options=$provider['options']; - // check if GD is installed - if(!extension_loaded('gd') || !function_exists('gd_info')) { - OC_Log::write('preview', __METHOD__.'(): GD module not installed', OC_Log::ERROR); - return false; + $object = new $class($options); + + self::$providers[$object->getMimeType()] = $object; } - - // create a white image - $image = imagecreatetruecolor($maxX, $maxY); - $color = imagecolorallocate($image, 255, 255, 255); - imagefill($image, 0, 0, $color); - - // output the image - imagepng($image); - imagedestroy($image); - } - -} - + + $keys = array_map('strlen', array_keys(self::$providers)); + array_multisort($keys, SORT_DESC, self::$providers); + } + + /** + * @brief initialize a new \OC\Files\View object + * @return void + */ + private static function initViews(){ + if(is_null(self::$fileview)){ + self::$fileview = new OC\Files\View(); + } + } + + public static function previewRouter($params){ + var_dump($params); + } +}
\ No newline at end of file |