diff options
Diffstat (limited to 'lib/private/Preview/Imaginary.php')
-rw-r--r-- | lib/private/Preview/Imaginary.php | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php index 4da88f1ab26..d421da74ac8 100644 --- a/lib/private/Preview/Imaginary.php +++ b/lib/private/Preview/Imaginary.php @@ -1,34 +1,19 @@ <?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; +use OC\StreamImage; use OCP\Files\File; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IImage; -use OC\StreamImage; +use OCP\Image; use Psr\Log\LoggerInterface; class Imaginary extends ProviderV2 { @@ -56,11 +41,11 @@ class Imaginary extends ProviderV2 { } public static function supportedMimeTypes(): string { - return '/image\/(bmp|x-bitmap|png|jpeg|gif|heic|svg|webp)/'; + 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 { - $maxSizeForImages = $this->config->getSystemValue('preview_max_filesize_image', 50); + $maxSizeForImages = $this->config->getSystemValueInt('preview_max_filesize_image', 50); $size = $file->getSize(); @@ -77,61 +62,123 @@ class Imaginary extends ProviderV2 { // Object store $stream = $file->fopen('r'); + if (!$stream || !is_resource($stream) || feof($stream)) { + return null; + } $httpClient = $this->service->newClient(); + $convert = false; + $autorotate = true; + switch ($file->getMimeType()) { + case 'image/heic': + // Autorotate seems to be broken for Heic so disable for that + $autorotate = false; + $mimeType = 'jpeg'; + break; case 'image/gif': case 'image/png': $mimeType = 'png'; break; + case 'image/svg+xml': + case 'application/pdf': + case 'application/illustrator': + $convert = true; + // Converted files do not need to be autorotated + $autorotate = false; + $mimeType = 'png'; + break; default: $mimeType = 'jpeg'; } - $operations = [ - [ - 'operation' => 'autorotate', - ], - [ - 'operation' => ($crop ? 'smartcrop' : 'fit'), + $preview_format = $this->config->getSystemValueString('preview_format', 'jpeg'); + + switch ($preview_format) { // Change the format to the correct one + case 'webp': + $mimeType = 'webp'; + break; + default: + } + + $operations = []; + + if ($convert) { + $operations[] = [ + 'operation' => 'convert', 'params' => [ - 'width' => $maxX, - 'height' => $maxY, - 'stripmeta' => 'true', 'type' => $mimeType, - 'norotation' => 'true', ] + ]; + } elseif ($autorotate) { + $operations[] = [ + 'operation' => 'autorotate', + ]; + } + + switch ($mimeType) { + case 'jpeg': + $quality = $this->config->getAppValue('preview', 'jpeg_quality', '80'); + break; + case 'webp': + $quality = $this->config->getAppValue('preview', 'webp_quality', '80'); + break; + default: + $quality = $this->config->getAppValue('preview', 'jpeg_quality', '80'); + } + + $operations[] = [ + 'operation' => ($crop ? 'smartcrop' : 'fit'), + 'params' => [ + 'width' => $maxX, + 'height' => $maxY, + 'stripmeta' => 'true', + 'type' => $mimeType, + 'norotation' => 'true', + 'quality' => $quality, ] ]; try { + $imaginaryKey = $this->config->getSystemValueString('preview_imaginary_key', ''); $response = $httpClient->post( $imaginaryUrl . '/pipeline', [ - 'query' => ['operations' => json_encode($operations)], + 'query' => ['operations' => json_encode($operations), 'key' => $imaginaryKey], 'stream' => true, 'content-type' => $file->getMimeType(), 'body' => $stream, 'nextcloud' => ['allow_local_address' => true], + 'timeout' => 120, + 'connect_timeout' => 3, ]); - } catch (\Exception $e) { - $this->logger->error('Imaginary preview generation failed: ' . $e->getMessage(), [ + } catch (\Throwable $e) { + $this->logger->info('Imaginary preview generation failed: ' . $e->getMessage(), [ 'exception' => $e, ]); return null; } if ($response->getStatusCode() !== 200) { - $this->logger->error('Imaginary preview generation failed: ' . json_decode($response->getBody())['message']); + $this->logger->info('Imaginary preview generation failed: ' . json_decode($response->getBody())['message']); return null; } - if ($response->getHeader('X-Image-Width') && $response->getHeader('X-Image-Height')) { - $maxX = (int)$response->getHeader('X-Image-Width'); - $maxY = (int)$response->getHeader('X-Image-Height'); + // This is not optimal but previews are distorted if the wrong width and height values are + // used. Both dimension headers are only sent when passing the option "-return-size" to + // Imaginary. + if ($response->getHeader('Image-Width') && $response->getHeader('Image-Height')) { + $image = new StreamImage( + $response->getBody(), + $response->getHeader('Content-Type'), + (int)$response->getHeader('Image-Width'), + (int)$response->getHeader('Image-Height'), + ); + } else { + $image = new Image(); + $image->loadFromFileHandle($response->getBody()); } - $image = new StreamImage($response->getBody(), $response->getHeader('Content-Type'), $maxX, $maxY); return $image->valid() ? $image : null; } |