2020-11-16 16:16:34 -05:00
< ? 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 />
*
*/
namespace OC\Preview ;
use OCP\Files\File ;
use OCP\Http\Client\IClientService ;
use OCP\IConfig ;
use OCP\IImage ;
2022-11-11 08:21:05 -05:00
use OCP\Image ;
2020-11-16 16:16:34 -05:00
use OC\StreamImage ;
use Psr\Log\LoggerInterface ;
class Imaginary extends ProviderV2 {
/** @var IConfig */
private $config ;
/** @var IClientService */
private $service ;
/** @var LoggerInterface */
private $logger ;
public function __construct ( array $config ) {
parent :: __construct ( $config );
$this -> config = \OC :: $server -> get ( IConfig :: class );
$this -> service = \OC :: $server -> get ( IClientService :: class );
$this -> logger = \OC :: $server -> get ( LoggerInterface :: class );
}
/**
* { @ inheritDoc }
*/
public function getMimeType () : string {
return self :: supportedMimeTypes ();
}
public static function supportedMimeTypes () : string {
2023-02-05 10:44:27 -05:00
return '/(image\/(bmp|x-bitmap|png|jpeg|gif|heic|heif|svg\+xml|tiff|webp)|application\/(pdf|illustrator))/' ;
2020-11-16 16:16:34 -05:00
}
public function getCroppedThumbnail ( File $file , int $maxX , int $maxY , bool $crop ) : ? IImage {
2023-04-05 06:50:08 -04:00
$maxSizeForImages = $this -> config -> getSystemValueInt ( 'preview_max_filesize_image' , 50 );
2020-11-16 16:16:34 -05:00
$size = $file -> getSize ();
if ( $maxSizeForImages !== - 1 && $size > ( $maxSizeForImages * 1024 * 1024 )) {
return null ;
}
$imaginaryUrl = $this -> config -> getSystemValueString ( 'preview_imaginary_url' , 'invalid' );
if ( $imaginaryUrl === 'invalid' ) {
$this -> logger -> error ( 'Imaginary preview provider is enabled, but no url is configured. Please provide the url of your imaginary server to the \'preview_imaginary_url\' config variable.' );
return null ;
}
$imaginaryUrl = rtrim ( $imaginaryUrl , '/' );
// Object store
$stream = $file -> fopen ( 'r' );
$httpClient = $this -> service -> newClient ();
2023-02-05 10:44:27 -05:00
$convert = false ;
2023-03-08 11:45:12 -05:00
$autorotate = true ;
2023-02-05 10:44:27 -05:00
2020-11-16 16:16:34 -05:00
switch ( $file -> getMimeType ()) {
2023-03-08 11:45:12 -05:00
case 'image/heic' :
// Autorotate seems to be broken for Heic so disable for that
$autorotate = false ;
$mimeType = 'jpeg' ;
break ;
2020-11-16 16:16:34 -05:00
case 'image/gif' :
case 'image/png' :
$mimeType = 'png' ;
break ;
2023-02-05 10:44:27 -05:00
case 'image/svg+xml' :
case 'application/pdf' :
case 'application/illustrator' :
$convert = true ;
2023-03-08 11:45:12 -05:00
// Converted files do not need to be autorotated
$autorotate = false ;
$mimeType = 'png' ;
2023-02-05 10:44:27 -05:00
break ;
2020-11-16 16:16:34 -05:00
default :
$mimeType = 'jpeg' ;
}
2023-04-05 06:50:08 -04:00
2023-03-08 11:45:12 -05:00
$operations = [];
2020-11-16 16:16:34 -05:00
2023-02-05 10:44:27 -05:00
if ( $convert ) {
2023-03-08 11:45:12 -05:00
$operations [] = [
'operation' => 'convert' ,
'params' => [
'type' => $mimeType ,
2022-04-04 10:38:38 -04:00
]
2023-02-05 10:44:27 -05:00
];
2023-03-08 11:45:12 -05:00
} elseif ( $autorotate ) {
$operations [] = [
'operation' => 'autorotate' ,
2023-02-05 10:44:27 -05:00
];
}
2020-11-16 16:16:34 -05:00
2023-03-08 11:45:12 -05:00
$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 ,
]
];
2020-11-16 16:16:34 -05:00
try {
2023-05-22 12:10:49 -04:00
$imaginaryKey = $this -> config -> getSystemValueString ( 'preview_imaginary_key' , '' );
2020-11-16 16:16:34 -05:00
$response = $httpClient -> post (
2022-04-04 10:38:38 -04:00
$imaginaryUrl . '/pipeline' , [
2023-05-22 12:10:49 -04:00
'query' => [ 'operations' => json_encode ( $operations ), 'key' => $imaginaryKey ],
2020-11-16 16:16:34 -05:00
'stream' => true ,
'content-type' => $file -> getMimeType (),
'body' => $stream ,
'nextcloud' => [ 'allow_local_address' => true ],
2023-03-09 07:15:35 -05:00
'timeout' => 120 ,
'connect_timeout' => 3 ,
2020-11-16 16:16:34 -05:00
]);
} catch ( \Exception $e ) {
$this -> logger -> error ( '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' ]);
return null ;
}
2022-11-11 08:21:05 -05:00
// 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 ());
2020-11-16 16:16:34 -05:00
}
return $image -> valid () ? $image : null ;
}
/**
* { @ inheritDoc }
*/
public function getThumbnail ( File $file , int $maxX , int $maxY ) : ? IImage {
return $this -> getCroppedThumbnail ( $file , $maxX , $maxY , false );
}
}