?iť?
Current Path : /home/scgforma/www/cloud/apps/gallery/lib/Service/ |
Current File : /home/scgforma/www/cloud/apps/gallery/lib/Service/PreviewService.php |
<?php /** * Nextcloud - Gallery * * This file is licensed under the Affero General Public License version 3 or * later. See the COPYING file. * * @author Olivier Paroz <galleryapps@oparoz.com> * * @copyright Olivier Paroz 2017 */ namespace OCA\Gallery\Service; use OCP\Files\File; use OCP\Image; use OCP\IPreview; use OCP\ILogger; use OCA\Gallery\Environment\Environment; /** * Generates previews * * @package OCA\Gallery\Service */ class PreviewService extends Service { use Base64Encode; /** @var IPreview */ private $previewManager; /** * Constructor * * @param string $appName * @param Environment $environment * @param IPreview $previewManager * @param ILogger $logger */ public function __construct( $appName, Environment $environment, IPreview $previewManager, ILogger $logger ) { parent::__construct($appName, $environment, $logger); $this->previewManager = $previewManager; } /** * Decides if we should download the file instead of generating a preview * * @param File $file * @param bool $animatedPreview * * @return bool */ public function isPreviewRequired($file, $animatedPreview) { $mime = $file->getMimeType(); if ($mime === 'image/svg+xml') { return $this->isSvgPreviewRequired(); } if ($mime === 'image/gif') { return $this->isGifPreviewRequired($file, $animatedPreview); } return true; } /** * Returns an array containing everything needed by the client to be able to display a preview * * * fileid: the file's ID * * mimetype: the file's media type * * preview: the preview's content * * Example logger * $this->logger->debug( * "[PreviewService] Path : {path} / mime: {mimetype} / fileid: {fileid}", * [ * 'path' => $preview['data']['path'], * 'mimetype' => $preview['data']['mimetype'], * 'fileid' => $preview['fileid'] * ] * ); * * @todo Get the max size from the settings * * @param File $file * @param int $maxX asked width for the preview * @param int $maxY asked height for the preview * @param bool $keepAspect * @param bool $base64Encode * * @return string|\OC_Image|string|false preview data * @throws InternalServerErrorServiceException */ public function createPreview( $file, $maxX = 0, $maxY = 0, $keepAspect = true, $base64Encode = false ) { try { $preview = $this->previewManager->getPreview($file, $maxX, $maxY, !$keepAspect); $img = new Image($preview->getContent()); $mimeType = $img->mimeType(); if ($img && $base64Encode) { $img = $this->encode($img); } return [ 'preview' => $img, 'mimetype' => $mimeType ]; } catch (\Exception $exception) { throw new InternalServerErrorServiceException('Preview generation has failed'); } } /** * Returns true if the passed mime type is supported * * In case of a failure, we just return that the media type is not supported * * @param string $mimeType * * @return boolean */ private function isMimeSupported($mimeType = '*') { try { return $this->previewManager->isMimeSupported($mimeType); } catch (\Exception $exception) { unset($exception); return false; } } /** * Decides if we should download the SVG or generate a preview * * SVGs are downloaded if the SVG converter is disabled * Files of any media type are downloaded if requested by the client * * @return bool */ private function isSvgPreviewRequired() { return $this->isMimeSupported('image/svg+xml'); } /** * Decides if we should download the GIF or generate a preview * * GIFs are downloaded if they're animated and we want to show * animations * * @param File $file * @param bool $animatedPreview * * @return bool */ private function isGifPreviewRequired($file, $animatedPreview) { $gifSupport = $this->isMimeSupported('image/gif'); $animatedGif = $this->isGifAnimated($file); return $gifSupport && !($animatedGif && $animatedPreview); } /** * Tests if a GIF is animated * * An animated gif contains multiple "frames", with each frame having a * header made up of: * * a static 4-byte sequence (\x00\x21\xF9\x04) * * 4 variable bytes * * a static 2-byte sequence (\x00\x2C) (Photoshop uses \x00\x21) * * We read through the file until we reach the end of the file, or we've * found at least 2 frame headers * * @link http://php.net/manual/en/function.imagecreatefromgif.php#104473 * * @param File $file * * @return bool */ private function isGifAnimated($file) { $count = 0; $fileHandle = $this->isFileReadable($file); if ($fileHandle) { while (!feof($fileHandle) && $count < 2) { $chunk = fread($fileHandle, 1024 * 100); //read 100kb at a time $count += preg_match_all( '#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches ); } fclose($fileHandle); } return $count > 1; } /** * Determines if we can read the content of the file and returns a file pointer resource * * We can't use something like $node->isReadable() as it's too unreliable * Some storage classes just check for the presence of the file * * @param File $file * * @return resource * @throws InternalServerErrorServiceException */ private function isFileReadable($file) { try { $fileHandle = $file->fopen('rb'); if (!$fileHandle) { throw new \Exception(); } } catch (\Exception $exception) { throw new InternalServerErrorServiceException( 'Something went wrong when trying to read' . $file->getPath() ); } return $fileHandle; } }