diff options
Diffstat (limited to 'lib/private/Preview')
44 files changed, 569 insertions, 1065 deletions
diff --git a/lib/private/Preview/BMP.php b/lib/private/Preview/BMP.php index c429f31f0e2..f275aecf0cf 100644 --- a/lib/private/Preview/BMP.php +++ b/lib/private/Preview/BMP.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/BackgroundCleanupJob.php b/lib/private/Preview/BackgroundCleanupJob.php index 4376cc06eca..3138abb1bf9 100644 --- a/lib/private/Preview/BackgroundCleanupJob.php +++ b/lib/private/Preview/BackgroundCleanupJob.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -35,31 +18,18 @@ use OCP\Files\NotPermittedException; use OCP\IDBConnection; class BackgroundCleanupJob extends TimedJob { - /** @var IDBConnection */ - private $connection; - /** @var Root */ - private $previewFolder; - - /** @var bool */ - private $isCLI; - - /** @var IMimeTypeLoader */ - private $mimeTypeLoader; - - public function __construct(ITimeFactory $timeFactory, - IDBConnection $connection, - Root $previewFolder, - IMimeTypeLoader $mimeTypeLoader, - bool $isCLI) { + public function __construct( + ITimeFactory $timeFactory, + private IDBConnection $connection, + private Root $previewFolder, + private IMimeTypeLoader $mimeTypeLoader, + private bool $isCLI, + ) { parent::__construct($timeFactory); // Run at most once an hour - $this->setInterval(3600); - - $this->connection = $connection; - $this->previewFolder = $previewFolder; - $this->isCLI = $isCLI; - $this->mimeTypeLoader = $mimeTypeLoader; + $this->setInterval(60 * 60); + $this->setTimeSensitivity(self::TIME_INSENSITIVE); } public function run($argument) { @@ -81,6 +51,11 @@ class BackgroundCleanupJob extends TimedJob { } private function getOldPreviewLocations(): \Iterator { + if ($this->connection->getShardDefinition('filecache')) { + // sharding is new enough that we don't need to support this + return; + } + $qb = $this->connection->getQueryBuilder(); $qb->select('a.name') ->from('filecache', 'a') @@ -88,18 +63,20 @@ class BackgroundCleanupJob extends TimedJob { $qb->expr()->castColumn('a.name', IQueryBuilder::PARAM_INT), 'b.fileid' )) ->where( - $qb->expr()->isNull('b.fileid') - )->andWhere( - $qb->expr()->eq('a.parent', $qb->createNamedParameter($this->previewFolder->getId())) - )->andWhere( - $qb->expr()->like('a.name', $qb->createNamedParameter('__%')) + $qb->expr()->andX( + $qb->expr()->isNull('b.fileid'), + $qb->expr()->eq('a.storage', $qb->createNamedParameter($this->previewFolder->getStorageId())), + $qb->expr()->eq('a.parent', $qb->createNamedParameter($this->previewFolder->getId())), + $qb->expr()->like('a.name', $qb->createNamedParameter('__%')), + $qb->expr()->eq('a.mimetype', $qb->createNamedParameter($this->mimeTypeLoader->getId('httpd/unix-directory'))) + ) ); if (!$this->isCLI) { $qb->setMaxResults(10); } - $cursor = $qb->execute(); + $cursor = $qb->executeQuery(); while ($row = $cursor->fetch()) { yield $row['name']; @@ -113,7 +90,7 @@ class BackgroundCleanupJob extends TimedJob { $qb->select('path', 'mimetype') ->from('filecache') ->where($qb->expr()->eq('fileid', $qb->createNamedParameter($this->previewFolder->getId()))); - $cursor = $qb->execute(); + $cursor = $qb->executeQuery(); $data = $cursor->fetch(); $cursor->closeCursor(); @@ -121,6 +98,15 @@ class BackgroundCleanupJob extends TimedJob { return []; } + if ($this->connection->getShardDefinition('filecache')) { + $chunks = $this->getAllPreviewIds($data['path'], 1000); + foreach ($chunks as $chunk) { + yield from $this->findMissingSources($chunk); + } + + return; + } + /* * This lovely like is the result of the way the new previews are stored * We take the md5 of the name (fileid) and split the first 7 chars. That way @@ -162,7 +148,7 @@ class BackgroundCleanupJob extends TimedJob { $qb->setMaxResults(10); } - $cursor = $qb->execute(); + $cursor = $qb->executeQuery(); while ($row = $cursor->fetch()) { yield $row['name']; @@ -170,4 +156,46 @@ class BackgroundCleanupJob extends TimedJob { $cursor->closeCursor(); } + + private function getAllPreviewIds(string $previewRoot, int $chunkSize): \Iterator { + // See `getNewPreviewLocations` for some more info about the logic here + $like = $this->connection->escapeLikeParameter($previewRoot) . '/_/_/_/_/_/_/_/%'; + + $qb = $this->connection->getQueryBuilder(); + $qb->select('name', 'fileid') + ->from('filecache') + ->where( + $qb->expr()->andX( + $qb->expr()->eq('storage', $qb->createNamedParameter($this->previewFolder->getStorageId())), + $qb->expr()->like('path', $qb->createNamedParameter($like)), + $qb->expr()->eq('mimetype', $qb->createNamedParameter($this->mimeTypeLoader->getId('httpd/unix-directory'))), + $qb->expr()->gt('fileid', $qb->createParameter('min_id')), + ) + ) + ->orderBy('fileid', 'ASC') + ->setMaxResults($chunkSize); + + $minId = 0; + while (true) { + $qb->setParameter('min_id', $minId); + $rows = $qb->executeQuery()->fetchAll(); + if (count($rows) > 0) { + $minId = $rows[count($rows) - 1]['fileid']; + yield array_map(function ($row) { + return (int)$row['name']; + }, $rows); + } else { + break; + } + } + } + + private function findMissingSources(array $ids): array { + $qb = $this->connection->getQueryBuilder(); + $qb->select('fileid') + ->from('filecache') + ->where($qb->expr()->in('fileid', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))); + $found = $qb->executeQuery()->fetchAll(\PDO::FETCH_COLUMN); + return array_diff($ids, $found); + } } diff --git a/lib/private/Preview/Bitmap.php b/lib/private/Preview/Bitmap.php index 84c7b4a8968..a3d5fbfd4ec 100644 --- a/lib/private/Preview/Bitmap.php +++ b/lib/private/Preview/Bitmap.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -38,6 +19,18 @@ use Psr\Log\LoggerInterface; */ abstract class Bitmap extends ProviderV2 { /** + * List of MIME types that this preview provider is allowed to process. + * + * These should correspond to the MIME types *identified* by Imagemagick + * for files to be processed by this provider. These do / will not + * necessarily need to match the MIME types stored in the database + * (which are identified by IMimeTypeDetector). + * + * @return string Regular expression + */ + abstract protected function getAllowedMimeTypes(): string; + + /** * {@inheritDoc} */ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage { @@ -68,7 +61,7 @@ abstract class Bitmap extends ProviderV2 { //new bitmap image object $image = new \OCP\Image(); - $image->loadFromData((string) $bp); + $image->loadFromData((string)$bp); //check if image object is valid return $image->valid() ? $image : null; } @@ -86,10 +79,19 @@ abstract class Bitmap extends ProviderV2 { * @param int $maxY * * @return \Imagick + * + * @throws \Exception */ private function getResizedPreview($tmpPath, $maxX, $maxY) { $bp = new Imagick(); + // Validate mime type + $bp->pingImage($tmpPath . '[0]'); + $mimeType = $bp->getImageMimeType(); + if (!preg_match($this->getAllowedMimeTypes(), $mimeType)) { + throw new \Exception('File mime type does not match the preview provider: ' . $mimeType); + } + // Layer 0 contains either the bitmap or a flat representation of all vector layers $bp->readImage($tmpPath . '[0]'); diff --git a/lib/private/Preview/Bundled.php b/lib/private/Preview/Bundled.php index 2a408b90c4e..6100e8262a4 100644 --- a/lib/private/Preview/Bundled.php +++ b/lib/private/Preview/Bundled.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/EMF.php b/lib/private/Preview/EMF.php index 2b5f40e66af..a3c48e7d8aa 100644 --- a/lib/private/Preview/EMF.php +++ b/lib/private/Preview/EMF.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright 2023 Daniel Kesselberg <mail@danielkesselberg.de> - * - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/Font.php b/lib/private/Preview/Font.php index baf29e1defc..79e537f6ffb 100644 --- a/lib/private/Preview/Font.php +++ b/lib/private/Preview/Font.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -30,4 +15,11 @@ class Font extends Bitmap { public function getMimeType(): string { return '/application\/(?:font-sfnt|x-font$)/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/(application|image)\/(?:font-sfnt|x-font|x-otf|x-ttf|x-pfb$)/'; + } } diff --git a/lib/private/Preview/GIF.php b/lib/private/Preview/GIF.php index 482f014e3dc..941ef68648a 100644 --- a/lib/private/Preview/GIF.php +++ b/lib/private/Preview/GIF.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index ddb68e012b0..4a7341896ef 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -1,31 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Elijah Martin-Merrill <elijah@nyp-itsours.com> - * @author J0WI <J0WI@users.noreply.github.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Scott Dutton <scott@exussum.co.uk> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -35,6 +12,7 @@ use OCP\Files\IAppData; use OCP\Files\InvalidPathException; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\InMemoryFile; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IConfig; @@ -44,34 +22,20 @@ use OCP\IStreamImage; use OCP\Preview\BeforePreviewFetchedEvent; use OCP\Preview\IProviderV2; use OCP\Preview\IVersionedPreviewFile; +use Psr\Log\LoggerInterface; class Generator { public const SEMAPHORE_ID_ALL = 0x0a11; public const SEMAPHORE_ID_NEW = 0x07ea; - /** @var IPreview */ - private $previewManager; - /** @var IConfig */ - private $config; - /** @var IAppData */ - private $appData; - /** @var GeneratorHelper */ - private $helper; - /** @var IEventDispatcher */ - private $eventDispatcher; - public function __construct( - IConfig $config, - IPreview $previewManager, - IAppData $appData, - GeneratorHelper $helper, - IEventDispatcher $eventDispatcher + private IConfig $config, + private IPreview $previewManager, + private IAppData $appData, + private GeneratorHelper $helper, + private IEventDispatcher $eventDispatcher, + private LoggerInterface $logger, ) { - $this->config = $config; - $this->previewManager = $previewManager; - $this->appData = $appData; - $this->helper = $helper; - $this->eventDispatcher = $eventDispatcher; } /** @@ -80,17 +44,19 @@ class Generator { * The cache is searched first and if nothing usable was found then a preview is * generated by one of the providers * - * @param File $file - * @param int $width - * @param int $height - * @param bool $crop - * @param string $mode - * @param string|null $mimeType * @return ISimpleFile * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) */ - public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) { + public function getPreview( + File $file, + int $width = -1, + int $height = -1, + bool $crop = false, + string $mode = IPreview::MODE_FILL, + ?string $mimeType = null, + bool $cacheResult = true, + ): ISimpleFile { $specification = [ 'width' => $width, 'height' => $height, @@ -104,25 +70,33 @@ class Generator { $height, $crop, $mode, + $mimeType, )); + $this->logger->debug('Requesting preview for {path} with width={width}, height={height}, crop={crop}, mode={mode}, mimeType={mimeType}', [ + 'path' => $file->getPath(), + 'width' => $width, + 'height' => $height, + 'crop' => $crop, + 'mode' => $mode, + 'mimeType' => $mimeType, + ]); + + // since we only ask for one preview, and the generate method return the last one it created, it returns the one we want - return $this->generatePreviews($file, [$specification], $mimeType); + return $this->generatePreviews($file, [$specification], $mimeType, $cacheResult); } /** * Generates previews of a file * - * @param File $file - * @param non-empty-array $specifications - * @param string $mimeType - * @return ISimpleFile the last preview that was generated * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) */ - public function generatePreviews(File $file, array $specifications, $mimeType = null) { + public function generatePreviews(File $file, array $specifications, ?string $mimeType = null, bool $cacheResult = true): ISimpleFile { //Make sure that we can read the file if (!$file->isReadable()) { + $this->logger->warning('Cannot read file: {path}, skipping preview generation.', ['path' => $file->getPath()]); throw new NotFoundException('Cannot read file'); } @@ -144,6 +118,7 @@ class Generator { $maxPreviewImage = null; // only load the image when we need it if ($maxPreview->getSize() === 0) { $maxPreview->delete(); + $this->logger->error('Max preview generated for file {path} has size 0, deleting and throwing exception.', ['path' => $file->getPath()]); throw new NotFoundException('Max preview size 0, invalid!'); } @@ -190,12 +165,13 @@ class Generator { $maxPreviewImage = $this->helper->getImage($maxPreview); } - $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion); + $this->logger->debug('Cached preview not found for file {path}, generating a new preview.', ['path' => $file->getPath()]); + $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion, $cacheResult); // New file, augment our array $previewFiles[] = $preview; } } catch (\InvalidArgumentException $e) { - throw new NotFoundException("", 0, $e); + throw new NotFoundException('', 0, $e); } if ($preview->getSize() === 0) { @@ -296,13 +272,13 @@ class Generator { $hardwareConcurrency = self::getHardwareConcurrency(); switch ($type) { - case "preview_concurrency_all": + case 'preview_concurrency_all': $fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency * 2 : 8; $concurrency_all = $this->config->getSystemValueInt($type, $fallback); - $concurrency_new = $this->getNumConcurrentPreviews("preview_concurrency_new"); + $concurrency_new = $this->getNumConcurrentPreviews('preview_concurrency_new'); $cached[$type] = max($concurrency_all, $concurrency_new); break; - case "preview_concurrency_new": + case 'preview_concurrency_new': $fallback = $hardwareConcurrency > 0 ? $hardwareConcurrency : 4; $cached[$type] = $this->config->getSystemValueInt($type, $fallback); break; @@ -358,6 +334,11 @@ class Generator { $previewConcurrency = $this->getNumConcurrentPreviews('preview_concurrency_new'); $sem = self::guardWithSemaphore(self::SEMAPHORE_ID_NEW, $previewConcurrency); try { + $this->logger->debug('Calling preview provider for {mimeType} with width={width}, height={height}', [ + 'mimeType' => $mimeType, + 'width' => $width, + 'height' => $height, + ]); $preview = $this->helper->getThumbnail($provider, $file, $width, $height); } finally { self::unguardWithSemaphore($sem); @@ -369,11 +350,10 @@ class Generator { $path = $this->generatePath($preview->width(), $preview->height(), $crop, $max, $preview->dataMimeType(), $prefix); try { - $file = $previewFolder->newFile($path); if ($preview instanceof IStreamImage) { - $file->putContent($preview->resource()); + return $previewFolder->newFile($path, $preview->resource()); } else { - $file->putContent($preview->data()); + return $previewFolder->newFile($path, $preview->data()); } } catch (NotPermittedException $e) { throw new NotFoundException(); @@ -508,19 +488,20 @@ class Generator { } /** - * @param ISimpleFolder $previewFolder - * @param ISimpleFile $maxPreview - * @param int $width - * @param int $height - * @param bool $crop - * @param int $maxWidth - * @param int $maxHeight - * @param string $prefix - * @return ISimpleFile * @throws NotFoundException * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid) */ - private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) { + private function generatePreview( + ISimpleFolder $previewFolder, + IImage $maxPreview, + int $width, + int $height, + bool $crop, + int $maxWidth, + int $maxHeight, + string $prefix, + bool $cacheResult, + ): ISimpleFile { $preview = $maxPreview; if (!$preview->valid()) { throw new \InvalidArgumentException('Failed to generate preview, failed to load image'); @@ -557,12 +538,14 @@ class Generator { $path = $this->generatePath($width, $height, $crop, false, $preview->dataMimeType(), $prefix); try { - $file = $previewFolder->newFile($path); - $file->putContent($preview->data()); + if ($cacheResult) { + return $previewFolder->newFile($path, $preview->data()); + } else { + return new InMemoryFile($path, $preview->data()); + } } catch (NotPermittedException $e) { throw new NotFoundException(); } - return $file; } @@ -581,6 +564,7 @@ class Generator { $path = $this->generatePath($width, $height, $crop, false, $mimeType, $prefix); foreach ($files as $file) { if ($file->getName() === $path) { + $this->logger->debug('Found cached preview: {path}', ['path' => $path]); return $file; } } diff --git a/lib/private/Preview/GeneratorHelper.php b/lib/private/Preview/GeneratorHelper.php index 64714a9f899..e914dcc2002 100644 --- a/lib/private/Preview/GeneratorHelper.php +++ b/lib/private/Preview/GeneratorHelper.php @@ -1,27 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/HEIC.php b/lib/private/Preview/HEIC.php index 71df98f9ac6..64eb48e58df 100644 --- a/lib/private/Preview/HEIC.php +++ b/lib/private/Preview/HEIC.php @@ -3,35 +3,16 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2018, ownCloud GmbH - * @copyright Copyright (c) 2018, Sebastian Steinmetz (me@sebastiansteinmetz.ch) - * - * @author J0WI <J0WI@users.noreply.github.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Sebastian Steinmetz <462714+steiny2k@users.noreply.github.com> - * @author Sebastian Steinmetz <me@sebastiansteinmetz.ch> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2018 ownCloud GmbH + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; use OCP\Files\File; use OCP\Files\FileInfo; use OCP\IImage; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -44,14 +25,14 @@ class HEIC extends ProviderV2 { * {@inheritDoc} */ public function getMimeType(): string { - return '/image\/hei(f|c)/'; + return '/image\/(x-)?hei(f|c)/'; } /** * {@inheritDoc} */ public function isAvailable(FileInfo $file): bool { - return in_array('HEIC', \Imagick::queryFormats("HEI*")); + return in_array('HEIC', \Imagick::queryFormats('HEI*')); } /** @@ -64,8 +45,8 @@ class HEIC extends ProviderV2 { $tmpPath = $this->getLocalFile($file); if ($tmpPath === false) { - \OC::$server->get(LoggerInterface::class)->error( - 'Failed to get thumbnail for: ' . $file->getPath(), + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), ['app' => 'core'] ); return null; @@ -90,7 +71,7 @@ class HEIC extends ProviderV2 { //new bitmap image object $image = new \OCP\Image(); - $image->loadFromData((string) $bp); + $image->loadFromData((string)$bp); //check if image object is valid return $image->valid() ? $image : null; } @@ -108,10 +89,20 @@ class HEIC extends ProviderV2 { * @param int $maxY * * @return \Imagick + * + * @throws \Exception */ private function getResizedPreview($tmpPath, $maxX, $maxY) { $bp = new \Imagick(); + // Some HEIC files just contain (or at least are identified as) other formats + // like JPEG. We just need to check if the image is safe to process. + $bp->pingImage($tmpPath . '[0]'); + $mimeType = $bp->getImageMimeType(); + if (!preg_match('/^image\/(x-)?(png|jpeg|gif|bmp|tiff|webp|hei(f|c)|avif)$/', $mimeType)) { + throw new \Exception('File mime type does not match the preview provider: ' . $mimeType); + } + // Layer 0 contains either the bitmap or a flat representation of all vector layers $bp->readImage($tmpPath . '[0]'); diff --git a/lib/private/Preview/IMagickSupport.php b/lib/private/Preview/IMagickSupport.php index e22ae93ab94..8225b1e7644 100644 --- a/lib/private/Preview/IMagickSupport.php +++ b/lib/private/Preview/IMagickSupport.php @@ -1,5 +1,9 @@ <?php +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ namespace OC\Preview; use OCP\ICache; diff --git a/lib/private/Preview/Illustrator.php b/lib/private/Preview/Illustrator.php index 3d926c304c5..bff556a3177 100644 --- a/lib/private/Preview/Illustrator.php +++ b/lib/private/Preview/Illustrator.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -31,4 +15,11 @@ class Illustrator extends Bitmap { public function getMimeType(): string { return '/application\/illustrator/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/application\/(illustrator|pdf)/'; + } } diff --git a/lib/private/Preview/Image.php b/lib/private/Preview/Image.php index 95b66a922fd..78a402c636a 100644 --- a/lib/private/Preview/Image.php +++ b/lib/private/Preview/Image.php @@ -1,36 +1,16 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author J0WI <J0WI@users.noreply.github.com> - * @author Joas Schilling <coding@schilljs.com> - * @author josh4trunks <joshruehlig@gmail.com> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; use OCP\Files\File; use OCP\IImage; +use OCP\Server; +use Psr\Log\LoggerInterface; abstract class Image extends ProviderV2 { /** @@ -47,6 +27,13 @@ abstract class Image extends ProviderV2 { $image = new \OCP\Image(); $fileName = $this->getLocalFile($file); + if ($fileName === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), + ['app' => 'core'] + ); + return null; + } $image->loadFromFile($fileName); $image->fixOrientation(); diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php index faf84696e17..d421da74ac8 100644 --- a/lib/private/Preview/Imaginary.php +++ b/lib/private/Preview/Imaginary.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2020, Nextcloud, GmbH. - * - * @author Vincent Petry <vincent@nextcloud.com> - * @author Carl Schwan <carl@carlschwan.eu> - * - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -57,7 +41,7 @@ class Imaginary extends ProviderV2 { } public static function supportedMimeTypes(): string { - return '/(image\/(bmp|x-bitmap|png|jpeg|gif|heic|heif|svg\+xml|tiff|webp)|application\/(pdf|illustrator))/'; + return '/(image\/(bmp|x-bitmap|png|jpeg|gif|heic|heif|svg\+xml|tiff|webp)|application\/illustrator)/'; } public function getCroppedThumbnail(File $file, int $maxX, int $maxY, bool $crop): ?IImage { diff --git a/lib/private/Preview/ImaginaryPDF.php b/lib/private/Preview/ImaginaryPDF.php new file mode 100644 index 00000000000..d26c6d1b7ff --- /dev/null +++ b/lib/private/Preview/ImaginaryPDF.php @@ -0,0 +1,14 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OC\Preview; + +class ImaginaryPDF extends Imaginary { + public static function supportedMimeTypes(): string { + return '/application\/pdf/'; + } +} diff --git a/lib/private/Preview/JPEG.php b/lib/private/Preview/JPEG.php index 14ae95690c0..a1a394f81c9 100644 --- a/lib/private/Preview/JPEG.php +++ b/lib/private/Preview/JPEG.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/Krita.php b/lib/private/Preview/Krita.php index eb25db9928c..e96fac993aa 100644 --- a/lib/private/Preview/Krita.php +++ b/lib/private/Preview/Krita.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2020 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/MP3.php b/lib/private/Preview/MP3.php index 4c5f932f477..add0028738e 100644 --- a/lib/private/Preview/MP3.php +++ b/lib/private/Preview/MP3.php @@ -1,37 +1,18 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Tanghus <thomas@tanghus.net> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; use OCP\Files\File; use OCP\IImage; +use OCP\Server; use Psr\Log\LoggerInterface; use wapmorgan\Mp3Info\Mp3Info; +use function OCP\Log\logger; class MP3 extends ProviderV2 { /** @@ -46,15 +27,22 @@ class MP3 extends ProviderV2 { */ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage { $tmpPath = $this->getLocalFile($file); + if ($tmpPath === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), + ['app' => 'core'] + ); + return null; + } try { $audio = new Mp3Info($tmpPath, true); /** @var string|null|false $picture */ $picture = $audio->getCover(); } catch (\Throwable $e) { - \OC::$server->get(LoggerInterface::class)->info($e->getMessage(), [ - 'exception' => $e, - 'app' => 'core', + logger('core')->info('Error while getting cover from mp3 file: ' . $e->getMessage(), [ + 'fileId' => $file->getId(), + 'filePath' => $file->getPath(), ]); return null; } finally { diff --git a/lib/private/Preview/MSOffice2003.php b/lib/private/Preview/MSOffice2003.php index 34cee499ff8..a52e618d484 100644 --- a/lib/private/Preview/MSOffice2003.php +++ b/lib/private/Preview/MSOffice2003.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/MSOffice2007.php b/lib/private/Preview/MSOffice2007.php index 3d3049e1c12..317f2dcc7f1 100644 --- a/lib/private/Preview/MSOffice2007.php +++ b/lib/private/Preview/MSOffice2007.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/MSOfficeDoc.php b/lib/private/Preview/MSOfficeDoc.php index e04503629e1..2e1044395f1 100644 --- a/lib/private/Preview/MSOfficeDoc.php +++ b/lib/private/Preview/MSOfficeDoc.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/MarkDown.php b/lib/private/Preview/MarkDown.php index d3806ce6c0e..c20433a1ac0 100644 --- a/lib/private/Preview/MarkDown.php +++ b/lib/private/Preview/MarkDown.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -70,7 +52,7 @@ class MarkDown extends TXT { $lines = preg_split("/\r\n|\n|\r/", $content); // Define text size of text file preview - $fontSize = $maxX ? (int) ((1 / ($maxX >= 512 ? 60 : 40) * $maxX)) : 10; + $fontSize = $maxX ? (int)((1 / ($maxX >= 512 ? 60 : 40) * $maxX)) : 10; $image = imagecreate($maxX, $maxY); imagecolorallocate($image, 255, 255, 255); diff --git a/lib/private/Preview/MimeIconProvider.php b/lib/private/Preview/MimeIconProvider.php index 80073c307c9..d1963fe882b 100644 --- a/lib/private/Preview/MimeIconProvider.php +++ b/lib/private/Preview/MimeIconProvider.php @@ -1,23 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * - * @license AGPL-3.0-or-later - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -38,7 +23,7 @@ class MimeIconProvider implements IMimeIconProvider { ) { } - public function getMimeIconUrl(string $mime): null|string { + public function getMimeIconUrl(string $mime): ?string { if (!$mime) { return null; } @@ -47,7 +32,7 @@ class MimeIconProvider implements IMimeIconProvider { $aliases = $this->mimetypeDetector->getAllAliases(); // Remove comments - $aliases = array_filter($aliases, static function ($key) { + $aliases = array_filter($aliases, static function (string $key) { return !($key === '' || $key[0] === '_'); }, ARRAY_FILTER_USE_KEY); @@ -70,8 +55,8 @@ class MimeIconProvider implements IMimeIconProvider { return null; } - - private function searchfileName(string $fileName): null|string { + + private function searchfileName(string $fileName): ?string { // If the file exists in the current enabled legacy // custom theme, let's return it $theme = $this->config->getSystemValue('theme', ''); @@ -81,7 +66,7 @@ class MimeIconProvider implements IMimeIconProvider { return $this->urlGenerator->getAbsoluteURL($path); } } - + // Previously, we used to pass this through Theming // But it was only used to colour icons containing // 0082c9. Since with vue we moved to inline svg icons, diff --git a/lib/private/Preview/Movie.php b/lib/private/Preview/Movie.php index 1943bd97591..47895f999d8 100644 --- a/lib/private/Preview/Movie.php +++ b/lib/private/Preview/Movie.php @@ -1,58 +1,31 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Alexander A. Klimov <grandmaster@al2klimov.de> - * @author Daniel Schneider <daniel@schneidoa.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OC\Preview; use OCP\Files\File; use OCP\Files\FileInfo; +use OCP\IConfig; use OCP\IImage; +use OCP\ITempManager; +use OCP\Server; use Psr\Log\LoggerInterface; class Movie extends ProviderV2 { - /** - * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2 - * @var string - */ - public static $avconvBinary; + private IConfig $config; - /** - * @deprecated 23.0.0 pass option to \OCP\Preview\ProviderV2 - * @var string - */ - public static $ffmpegBinary; + private ?string $binary = null; - /** @var string */ - private $binary; + public function __construct(array $options = []) { + parent::__construct($options); + $this->config = Server::get(IConfig::class); + } - /** - * {@inheritDoc} - */ public function getMimeType(): string { return '/video\/.*/'; } @@ -61,14 +34,9 @@ class Movie extends ProviderV2 { * {@inheritDoc} */ public function isAvailable(FileInfo $file): bool { - // TODO: remove when avconv is dropped if (is_null($this->binary)) { if (isset($this->options['movieBinary'])) { $this->binary = $this->options['movieBinary']; - } elseif (is_string(self::$avconvBinary)) { - $this->binary = self::$avconvBinary; - } elseif (is_string(self::$ffmpegBinary)) { - $this->binary = self::$ffmpegBinary; } } return is_string($this->binary); @@ -86,10 +54,15 @@ class Movie extends ProviderV2 { $result = null; if ($this->useTempFile($file)) { - // try downloading 5 MB first as it's likely that the first frames are present there - // in some cases this doesn't work for example when the moov atom is at the - // end of the file, so if it fails we fall back to getting the full file - $sizeAttempts = [5242880, null]; + // Try downloading 5 MB first, as it's likely that the first frames are present there. + // In some cases this doesn't work, for example when the moov atom is at the + // end of the file, so if it fails we fall back to getting the full file. + // Unless the file is not local (e.g. S3) as we do not want to download the whole (e.g. 37Gb) file + if ($file->getStorage()->isLocal()) { + $sizeAttempts = [5242880, null]; + } else { + $sizeAttempts = [5242880]; + } } else { // size is irrelevant, only attempt once $sizeAttempts = [null]; @@ -97,15 +70,19 @@ class Movie extends ProviderV2 { foreach ($sizeAttempts as $size) { $absPath = $this->getLocalFile($file, $size); + if ($absPath === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), + ['app' => 'core'] + ); + return null; + } - $result = null; - if (is_string($absPath)) { - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5); + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5); + if ($result === null) { + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1); if ($result === null) { - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1); - if ($result === null) { - $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0); - } + $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0); } } @@ -119,8 +96,42 @@ class Movie extends ProviderV2 { return $result; } + private function useHdr(string $absPath): bool { + // load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path + $ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe'); + // run ffprobe on the video file to get value of "color_transfer" + $test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0', + '-show_entries', 'stream=color_transfer', + '-of', 'default=noprint_wrappers=1:nokey=1', + $absPath]; + $test_hdr_proc = proc_open($test_hdr_cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $test_hdr_pipes); + if ($test_hdr_proc === false) { + return false; + } + $test_hdr_stdout = trim(stream_get_contents($test_hdr_pipes[1])); + $test_hdr_stderr = trim(stream_get_contents($test_hdr_pipes[2])); + proc_close($test_hdr_proc); + // search build options for libzimg (provides zscale filter) + $ffmpeg_libzimg_installed = strpos($test_hdr_stderr, '--enable-libzimg'); + // Only values of "smpte2084" and "arib-std-b67" indicate an HDR video. + // Only return true if video is detected as HDR and libzimg is installed. + if (($test_hdr_stdout === 'smpte2084' || $test_hdr_stdout === 'arib-std-b67') && $ffmpeg_libzimg_installed !== false) { + return true; + } else { + return false; + } + } + private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage { - $tmpPath = \OC::$server->getTempManager()->getTemporaryFile(); + $tmpPath = Server::get(ITempManager::class)->getTemporaryFile(); + + if ($tmpPath === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $absPath, + ['app' => 'core'] + ); + return null; + } $binaryType = substr(strrchr($this->binary, '/'), 1); @@ -130,10 +141,21 @@ class Movie extends ProviderV2 { '-an', '-f', 'mjpeg', '-vframes', '1', '-vsync', '1', $tmpPath]; } elseif ($binaryType === 'ffmpeg') { - $cmd = [$this->binary, '-y', '-ss', (string)$second, - '-i', $absPath, - '-f', 'mjpeg', '-vframes', '1', - $tmpPath]; + if ($this->useHdr($absPath)) { + // Force colorspace to '2020_ncl' because some videos are + // tagged incorrectly as 'reserved' resulting in fail if not forced. + $cmd = [$this->binary, '-y', '-ss', (string)$second, + '-i', $absPath, + '-f', 'mjpeg', '-vframes', '1', + '-vf', 'zscale=min=2020_ncl:t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p', + $tmpPath]; + } else { + // always default to generating preview using non-HDR command + $cmd = [$this->binary, '-y', '-ss', (string)$second, + '-i', $absPath, + '-f', 'mjpeg', '-vframes', '1', + $tmpPath]; + } } else { // Not supported unlink($tmpPath); @@ -142,10 +164,10 @@ class Movie extends ProviderV2 { $proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes); $returnCode = -1; - $output = ""; + $output = ''; if (is_resource($proc)) { - $stdout = trim(stream_get_contents($pipes[1])); $stderr = trim(stream_get_contents($pipes[2])); + $stdout = trim(stream_get_contents($pipes[1])); $returnCode = proc_close($proc); $output = $stdout . $stderr; } @@ -162,7 +184,7 @@ class Movie extends ProviderV2 { } if ($second === 0) { - $logger = \OC::$server->get(LoggerInterface::class); + $logger = Server::get(LoggerInterface::class); $logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]); } diff --git a/lib/private/Preview/Office.php b/lib/private/Preview/Office.php index 68499a6fea6..ffba0211de2 100644 --- a/lib/private/Preview/Office.php +++ b/lib/private/Preview/Office.php @@ -1,30 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Tor Lillqvist <tml@collabora.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -33,6 +12,7 @@ use OCP\Files\FileInfo; use OCP\IImage; use OCP\ITempManager; use OCP\Server; +use Psr\Log\LoggerInterface; abstract class Office extends ProviderV2 { /** @@ -54,6 +34,13 @@ abstract class Office extends ProviderV2 { // The file to generate the preview for. $absPath = $this->getLocalFile($file); + if ($absPath === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), + ['app' => 'core'] + ); + return null; + } // The destination for the LibreOffice user profile. // LibreOffice can rune once per user profile and therefore instance id and file id are included. diff --git a/lib/private/Preview/OpenDocument.php b/lib/private/Preview/OpenDocument.php index 5f27e325d31..f590eb6a59c 100644 --- a/lib/private/Preview/OpenDocument.php +++ b/lib/private/Preview/OpenDocument.php @@ -1,26 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Julius Härtl <jus@bitgrid.net> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/PDF.php b/lib/private/Preview/PDF.php index 405fd1545f9..9de14685925 100644 --- a/lib/private/Preview/PDF.php +++ b/lib/private/Preview/PDF.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -31,4 +15,11 @@ class PDF extends Bitmap { public function getMimeType(): string { return '/application\/pdf/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/application\/pdf/'; + } } diff --git a/lib/private/Preview/PNG.php b/lib/private/Preview/PNG.php index 5a3f2136575..49d0cd059ba 100644 --- a/lib/private/Preview/PNG.php +++ b/lib/private/Preview/PNG.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/Photoshop.php b/lib/private/Preview/Photoshop.php index 9d79abf8191..b7209120530 100644 --- a/lib/private/Preview/Photoshop.php +++ b/lib/private/Preview/Photoshop.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -31,4 +15,11 @@ class Photoshop extends Bitmap { public function getMimeType(): string { return '/application\/x-photoshop/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/(application|image)\/(x-photoshop|x-psd)/'; + } } diff --git a/lib/private/Preview/Postscript.php b/lib/private/Preview/Postscript.php index 06ea7fc8037..04c667926aa 100644 --- a/lib/private/Preview/Postscript.php +++ b/lib/private/Preview/Postscript.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -31,4 +15,11 @@ class Postscript extends Bitmap { public function getMimeType(): string { return '/application\/postscript/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/application\/postscript/'; + } } diff --git a/lib/private/Preview/Provider.php b/lib/private/Preview/Provider.php index e87aded4786..26f0ac09f08 100644 --- a/lib/private/Preview/Provider.php +++ b/lib/private/Preview/Provider.php @@ -1,28 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Jörn Friedrich Dreyer <jfd@butonic.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/ProviderV1Adapter.php b/lib/private/Preview/ProviderV1Adapter.php index 5e50db9d8da..ba8826ef765 100644 --- a/lib/private/Preview/ProviderV1Adapter.php +++ b/lib/private/Preview/ProviderV1Adapter.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2019 Robin Appelman <robin@icewind.nl> - * - * @author Julius Härtl <jus@bitgrid.net> - * @author Robin Appelman <robin@icewind.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/ProviderV2.php b/lib/private/Preview/ProviderV2.php index 6d80594d1c8..556d1099d2d 100644 --- a/lib/private/Preview/ProviderV2.php +++ b/lib/private/Preview/ProviderV2.php @@ -3,47 +3,26 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2019 Robin Appelman <robin@icewind.nl> - * - * @author Robin Appelman <robin@icewind.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OC\Preview; use OCP\Files\File; use OCP\Files\FileInfo; use OCP\IImage; +use OCP\ITempManager; use OCP\Preview\IProviderV2; +use OCP\Server; +use Psr\Log\LoggerInterface; abstract class ProviderV2 implements IProviderV2 { - /** @var array */ - protected $options; - - /** @var array */ - protected $tmpFiles = []; + protected array $tmpFiles = []; - /** - * Constructor - * - * @param array $options - */ - public function __construct(array $options = []) { - $this->options = $options; + public function __construct( + protected array $options = [], + ) { } /** @@ -67,7 +46,7 @@ abstract class ProviderV2 implements IProviderV2 { * @param File $file * @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 - * @return null|\OCP\IImage false if no preview was generated + * @return null|\OCP\IImage null if no preview was generated * @since 17.0.0 */ abstract public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage; @@ -80,14 +59,24 @@ abstract class ProviderV2 implements IProviderV2 { * Get a path to either the local file or temporary file * * @param File $file - * @param int $maxSize maximum size for temporary files - * @return string|false + * @param ?int $maxSize maximum size for temporary files */ - protected function getLocalFile(File $file, ?int $maxSize = null) { + protected function getLocalFile(File $file, ?int $maxSize = null): string|false { if ($this->useTempFile($file)) { - $absPath = \OC::$server->getTempManager()->getTemporaryFile(); + $absPath = Server::get(ITempManager::class)->getTemporaryFile(); + + if ($absPath === false) { + Server::get(LoggerInterface::class)->error( + 'Failed to get local file to generate thumbnail for: ' . $file->getPath(), + ['app' => 'core'] + ); + return false; + } $content = $file->fopen('r'); + if ($content === false) { + return false; + } if ($maxSize) { $content = stream_get_contents($content, $maxSize); diff --git a/lib/private/Preview/SGI.php b/lib/private/Preview/SGI.php index 9f392d2252f..78b1ea5828a 100644 --- a/lib/private/Preview/SGI.php +++ b/lib/private/Preview/SGI.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2021 John Molakvoæ <skjnldsv@protonmail.com> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -28,6 +12,13 @@ class SGI extends Bitmap { * {@inheritDoc} */ public function getMimeType(): string { - return '/image\/sgi/'; + return '/image\/(x-)?sgi/'; + } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/image\/(x-)?sgi/'; } } diff --git a/lib/private/Preview/SVG.php b/lib/private/Preview/SVG.php index fd472083533..d9f7701f411 100644 --- a/lib/private/Preview/SVG.php +++ b/lib/private/Preview/SVG.php @@ -1,29 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -44,32 +24,41 @@ class SVG extends ProviderV2 { */ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage { try { - $svg = new \Imagick(); - $svg->setBackgroundColor(new \ImagickPixel('transparent')); - $content = stream_get_contents($file->fopen('r')); if (substr($content, 0, 5) !== '<?xml') { $content = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . $content; } // Do not parse SVG files with references - if (stripos($content, 'xlink:href') !== false) { + if (preg_match('/["\s](xlink:)?href\s*=/i', $content)) { return null; } + $svg = new \Imagick(); + + $svg->pingImageBlob($content); + $mimeType = $svg->getImageMimeType(); + if (!preg_match($this->getMimeType(), $mimeType)) { + throw new \Exception('File mime type does not match the preview provider: ' . $mimeType); + } + + $svg->setBackgroundColor(new \ImagickPixel('transparent')); $svg->readImageBlob($content); $svg->setImageFormat('png32'); } catch (\Exception $e) { - \OC::$server->get(LoggerInterface::class)->error($e->getMessage(), [ - 'exception' => $e, - 'app' => 'core', - ]); + \OC::$server->get(LoggerInterface::class)->error( + 'File: ' . $file->getPath() . ' Imagick says:', + [ + 'exception' => $e, + 'app' => 'core', + ] + ); return null; } //new image object $image = new \OCP\Image(); - $image->loadFromData((string) $svg); + $image->loadFromData((string)$svg); //check if image object is valid if ($image->valid()) { $image->scaleDownToFit($maxX, $maxY); diff --git a/lib/private/Preview/StarOffice.php b/lib/private/Preview/StarOffice.php index 58f210d2ff6..9ea540dc912 100644 --- a/lib/private/Preview/StarOffice.php +++ b/lib/private/Preview/StarOffice.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; diff --git a/lib/private/Preview/Storage/Root.php b/lib/private/Preview/Storage/Root.php index c4191228ec7..41378653962 100644 --- a/lib/private/Preview/Storage/Root.php +++ b/lib/private/Preview/Storage/Root.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Morris Jobke <hey@morrisjobke.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview\Storage; diff --git a/lib/private/Preview/TGA.php b/lib/private/Preview/TGA.php index cb591be2231..675907b4e49 100644 --- a/lib/private/Preview/TGA.php +++ b/lib/private/Preview/TGA.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2021 John Molakvoæ <skjnldsv@protonmail.com> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; @@ -28,6 +12,13 @@ class TGA extends Bitmap { * {@inheritDoc} */ public function getMimeType(): string { - return '/image\/t(ar)?ga/'; + return '/image\/(x-)?t(ar)?ga/'; + } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/image\/(x-)?t(ar)?ga/'; } } diff --git a/lib/private/Preview/TIFF.php b/lib/private/Preview/TIFF.php index 1a5d957d3ee..cd81e611d0b 100644 --- a/lib/private/Preview/TIFF.php +++ b/lib/private/Preview/TIFF.php @@ -1,25 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -31,4 +15,11 @@ class TIFF extends Bitmap { public function getMimeType(): string { return '/image\/tiff/'; } + + /** + * {@inheritDoc} + */ + protected function getAllowedMimeTypes(): string { + return '/image\/tiff/'; + } } diff --git a/lib/private/Preview/TXT.php b/lib/private/Preview/TXT.php index f5a68f92be4..1a1d64f3e08 100644 --- a/lib/private/Preview/TXT.php +++ b/lib/private/Preview/TXT.php @@ -1,31 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Jan-Christoph Borchardt <hey@jancborchardt.net> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Nmz <nemesiz@nmz.lt> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; @@ -72,7 +50,7 @@ class TXT extends ProviderV2 { $lines = preg_split("/\r\n|\n|\r/", $content); // Define text size of text file preview - $fontSize = $maxX ? (int) ((1 / 32) * $maxX) : 5; //5px + $fontSize = $maxX ? (int)((1 / 32) * $maxX) : 5; //5px $lineSize = ceil($fontSize * 1.5); $image = imagecreate($maxX, $maxY); @@ -89,7 +67,7 @@ class TXT extends ProviderV2 { $index = $index + 1; $x = 1; - $y = (int) ($index * $lineSize); + $y = (int)($index * $lineSize); if ($canUseTTF === true) { imagettftext($image, $fontSize, 0, $x, $y, $textColor, $fontFile, $line); diff --git a/lib/private/Preview/Watcher.php b/lib/private/Preview/Watcher.php index ad6fed56020..21f040d8342 100644 --- a/lib/private/Preview/Watcher.php +++ b/lib/private/Preview/Watcher.php @@ -3,28 +3,12 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; +use OCP\Files\FileInfo; use OCP\Files\Folder; use OCP\Files\IAppData; use OCP\Files\Node; @@ -54,7 +38,7 @@ class Watcher { $this->deleteNode($node); } - protected function deleteNode(Node $node) { + protected function deleteNode(FileInfo $node) { // We only handle files if ($node instanceof Folder) { return; diff --git a/lib/private/Preview/WatcherConnector.php b/lib/private/Preview/WatcherConnector.php index b11a6ab86da..c34dd1dde4d 100644 --- a/lib/private/Preview/WatcherConnector.php +++ b/lib/private/Preview/WatcherConnector.php @@ -3,66 +3,39 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; use OC\SystemConfig; +use OCA\Files_Versions\Events\VersionRestoredEvent; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\IRootFolder; use OCP\Files\Node; class WatcherConnector { - /** @var IRootFolder */ - private $root; - - /** @var SystemConfig */ - private $config; - - /** - * WatcherConnector constructor. - * - * @param IRootFolder $root - * @param SystemConfig $config - */ - public function __construct(IRootFolder $root, - SystemConfig $config) { - $this->root = $root; - $this->config = $config; + public function __construct( + private IRootFolder $root, + private SystemConfig $config, + private IEventDispatcher $dispatcher, + ) { } - /** - * @return Watcher - */ private function getWatcher(): Watcher { return \OCP\Server::get(Watcher::class); } - public function connectWatcher() { + public function connectWatcher(): void { // Do not connect if we are not setup yet! if ($this->config->getValue('instanceid', null) !== null) { $this->root->listen('\OC\Files', 'postWrite', function (Node $node) { $this->getWatcher()->postWrite($node); }); - \OC_Hook::connect('\OCP\Versions', 'rollback', $this->getWatcher(), 'versionRollback'); + $this->dispatcher->addListener(VersionRestoredEvent::class, function (VersionRestoredEvent $event) { + $this->getWatcher()->versionRollback(['node' => $event->getVersion()->getSourceFile()]); + }); } } } diff --git a/lib/private/Preview/WebP.php b/lib/private/Preview/WebP.php index c8f8d11c393..25b922e9190 100644 --- a/lib/private/Preview/WebP.php +++ b/lib/private/Preview/WebP.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OC\Preview; diff --git a/lib/private/Preview/XBitmap.php b/lib/private/Preview/XBitmap.php index e0adb48b881..c8337cc252d 100644 --- a/lib/private/Preview/XBitmap.php +++ b/lib/private/Preview/XBitmap.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Olivier Paroz <github@oparoz.com> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OC\Preview; |