2021-12-14 18:32:47 +00:00
< ? php
declare ( strict_types = 1 );
2019-06-12 22:54:06 +00:00
2023-01-10 22:44:09 +00:00
namespace Shimmie2 ;
2019-10-10 15:32:01 +00:00
require_once " config.php " ;
2022-10-27 16:21:46 +00:00
/*
* This is used by the image transcoding code when there is an error while transcoding
*/
2019-06-14 12:47:50 +00:00
class ImageTranscodeException extends SCoreException
{
}
2019-06-12 22:54:06 +00:00
class TranscodeImage extends Extension
{
2020-02-04 00:46:36 +00:00
/** @var TranscodeImageTheme */
2023-06-27 14:56:49 +00:00
protected Themelet $theme ;
2020-02-04 00:46:36 +00:00
2021-12-14 18:32:47 +00:00
public const ACTION_BULK_TRANSCODE = " bulk_transcode " ;
2019-06-27 17:26:09 +00:00
2021-12-14 18:32:47 +00:00
public const INPUT_MIMES = [
2020-06-14 16:05:55 +00:00
" BMP " => MimeType :: BMP ,
" GIF " => MimeType :: GIF ,
" ICO " => MimeType :: ICO ,
" JPG " => MimeType :: JPEG ,
" PNG " => MimeType :: PNG ,
2020-10-26 12:25:47 +00:00
" PPM " => MimeType :: PPM ,
2020-06-14 16:05:55 +00:00
" PSD " => MimeType :: PSD ,
" TIFF " => MimeType :: TIFF ,
2021-01-16 20:18:11 +00:00
" WEBP " => MimeType :: WEBP ,
" TGA " => MimeType :: TGA
2019-06-12 22:54:06 +00:00
];
2021-12-14 18:32:47 +00:00
public const OUTPUT_MIMES = [
2019-06-12 22:54:06 +00:00
" " => " " ,
2020-06-14 16:05:55 +00:00
" JPEG (lossy) " => MimeType :: JPEG ,
" PNG (lossless) " => MimeType :: PNG ,
" WEBP (lossy) " => MimeType :: WEBP ,
" WEBP (lossless) " => MimeType :: WEBP_LOSSLESS ,
2019-06-12 22:54:06 +00:00
];
/**
2019-06-13 16:45:34 +00:00
* Needs to be after upload , but before the processing extensions
2019-06-12 22:54:06 +00:00
*/
public function get_priority () : int
{
return 45 ;
}
2024-01-15 11:52:35 +00:00
public function onInitExt ( InitExtEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
global $config ;
2019-06-18 18:45:59 +00:00
$config -> set_default_bool ( TranscodeConfig :: ENABLED , true );
2020-06-17 00:06:15 +00:00
$config -> set_default_bool ( TranscodeConfig :: GET_ENABLED , false );
2019-06-18 18:45:59 +00:00
$config -> set_default_bool ( TranscodeConfig :: UPLOAD , false );
2019-06-24 15:05:16 +00:00
$config -> set_default_string ( TranscodeConfig :: ENGINE , MediaEngine :: GD );
2019-06-18 18:45:59 +00:00
$config -> set_default_int ( TranscodeConfig :: QUALITY , 80 );
2020-06-14 16:36:52 +00:00
$config -> set_default_string ( TranscodeConfig :: ALPHA_COLOR , Media :: DEFAULT_ALPHA_CONVERSION_COLOR );
2019-06-12 22:54:06 +00:00
2020-06-14 16:05:55 +00:00
foreach ( array_values ( self :: INPUT_MIMES ) as $mime ) {
$config -> set_default_string ( self :: get_mapping_name ( $mime ), " " );
2019-06-12 22:54:06 +00:00
}
}
2020-06-14 16:05:55 +00:00
private static function get_mapping_name ( string $mime ) : string
{
$mime = str_replace ( " . " , " _ " , $mime );
$mime = str_replace ( " / " , " _ " , $mime );
return TranscodeConfig :: UPLOAD_PREFIX . $mime ;
}
2023-08-17 17:12:36 +00:00
private static function get_mapping ( string $mime ) : ? string
2020-06-14 16:05:55 +00:00
{
global $config ;
return $config -> get_string ( self :: get_mapping_name ( $mime ));
}
2023-08-17 17:12:36 +00:00
private static function set_mapping ( string $from_mime , ? string $to_mime ) : void
2020-06-14 16:05:55 +00:00
{
global $config ;
$config -> set_string ( self :: get_mapping_name ( $from_mime ), $to_mime );
}
2024-01-20 14:10:59 +00:00
/**
* @ return string []
*/
2020-06-14 16:05:55 +00:00
public static function get_enabled_mimes () : array
{
$output = [];
foreach ( array_values ( self :: INPUT_MIMES ) as $mime ) {
$value = self :: get_mapping ( $mime );
if ( ! empty ( $value )) {
$output [] = $mime ;
}
}
return $output ;
}
2024-01-15 11:52:35 +00:00
public function onDatabaseUpgrade ( DatabaseUpgradeEvent $event ) : void
2020-06-14 16:05:55 +00:00
{
if ( $this -> get_version ( TranscodeConfig :: VERSION ) < 1 ) {
2023-11-11 21:49:12 +00:00
$old_extensions = [];
2020-06-14 16:05:55 +00:00
foreach ( array_values ( self :: INPUT_MIMES ) as $mime ) {
$old_extensions = array_merge ( $old_extensions , FileExtension :: get_all_for_mime ( $mime ));
}
foreach ( $old_extensions as $old_extension ) {
$oldValue = $this -> get_mapping ( $old_extension );
if ( ! empty ( $oldValue )) {
$from_mime = MimeType :: get_for_extension ( $old_extension );
if ( empty ( $from_mime )) {
continue ;
}
$to_mime = MimeType :: get_for_extension ( $oldValue );
if ( empty ( $to_mime )) {
continue ;
}
$this -> set_mapping ( $from_mime , $to_mime );
$this -> set_mapping ( $old_extension , null );
}
}
$this -> set_version ( TranscodeConfig :: VERSION , 1 );
}
}
2024-01-15 11:52:35 +00:00
public function onImageAdminBlockBuilding ( ImageAdminBlockBuildingEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
global $user , $config ;
2021-04-25 10:50:27 +00:00
if ( $user -> can ( Permissions :: EDIT_FILES ) && $event -> context != " report " ) {
2019-06-18 18:45:59 +00:00
$engine = $config -> get_string ( TranscodeConfig :: ENGINE );
2020-06-14 16:05:55 +00:00
if ( $this -> can_convert_mime ( $engine , $event -> image -> get_mime ())) {
$options = $this -> get_supported_output_mimes ( $engine , $event -> image -> get_mime ());
2019-06-12 22:54:06 +00:00
$event -> add_part ( $this -> theme -> get_transcode_html ( $event -> image , $options ));
}
}
}
2019-08-07 19:53:59 +00:00
2024-01-15 11:52:35 +00:00
public function onSetupBuilding ( SetupBuildingEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
global $config ;
2019-06-18 18:45:59 +00:00
$engine = $config -> get_string ( TranscodeConfig :: ENGINE );
2019-06-12 22:54:06 +00:00
2020-10-26 15:13:28 +00:00
$sb = $event -> panel -> create_new_block ( " Image Transcode " );
2019-06-27 04:00:49 +00:00
$sb -> start_table ();
2020-06-14 16:36:52 +00:00
$sb -> add_bool_option ( TranscodeConfig :: ENABLED , " Allow transcoding images " , true );
2020-06-17 00:06:15 +00:00
$sb -> add_bool_option ( TranscodeConfig :: GET_ENABLED , " Enable GET args " , true );
2020-06-14 16:36:52 +00:00
$sb -> add_bool_option ( TranscodeConfig :: UPLOAD , " Transcode on upload " , true );
$sb -> add_choice_option ( TranscodeConfig :: ENGINE , MediaEngine :: IMAGE_ENGINES , " Engine " , true );
2023-11-11 21:49:12 +00:00
foreach ( self :: INPUT_MIMES as $display => $mime ) {
2020-06-14 16:05:55 +00:00
if ( MediaEngine :: is_input_supported ( $engine , $mime )) {
$outputs = $this -> get_supported_output_mimes ( $engine , $mime );
$sb -> add_choice_option ( self :: get_mapping_name ( $mime ), $outputs , " $display " , true );
2019-06-14 12:47:50 +00:00
}
2019-06-12 22:54:06 +00:00
}
2020-06-11 21:58:19 +00:00
$sb -> add_int_option ( TranscodeConfig :: QUALITY , " Lossy Format Quality " , true );
2020-06-14 16:36:52 +00:00
$sb -> add_color_option ( TranscodeConfig :: ALPHA_COLOR , " Alpha Conversion Color " , true );
2019-06-27 04:00:49 +00:00
$sb -> end_table ();
2019-06-12 22:54:06 +00:00
}
2024-01-15 11:52:35 +00:00
public function onDataUpload ( DataUploadEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
2019-10-02 10:23:57 +00:00
global $config ;
2019-06-12 22:54:06 +00:00
2023-03-22 20:08:23 +00:00
// this onDataUpload happens earlier (or could happen earlier) than handle_pixel.onDataUpload
// it mutates the image such that the incorrect mime type is not checked (checking against
// the post-transcode mime type instead). This is to give user feedback on what the mime type
// was before potential transcoding (the original) at the time of upload, and that it failed if not allowed.
// does it break bulk image importing? ZIP? SVG? there are a few flows that are untested!
if ( $config -> get_bool ( UploadConfig :: MIME_CHECK_ENABLED ) == true ) {
$allowed_mimes = $config -> get_array ( UploadConfig :: ALLOWED_MIME_STRINGS );
if ( ! MimeType :: matches_array ( $event -> mime , $allowed_mimes )) {
throw new UploadException ( " MIME type not supported: " . $event -> mime );
}
}
2019-06-18 18:45:59 +00:00
if ( $config -> get_bool ( TranscodeConfig :: UPLOAD ) == true ) {
2023-11-11 21:49:12 +00:00
if ( $event -> mime === MimeType :: GIF && MimeType :: is_animated_gif ( $event -> tmpname )) {
2019-06-12 22:54:06 +00:00
return ;
}
2023-02-22 23:37:37 +00:00
if ( in_array ( $event -> mime , array_values ( self :: INPUT_MIMES ))) {
$target_mime = self :: get_mapping ( $event -> mime );
2020-06-14 16:05:55 +00:00
if ( empty ( $target_mime )) {
2019-06-12 22:54:06 +00:00
return ;
}
try {
2023-02-22 23:37:37 +00:00
$new_image = $this -> transcode_image ( $event -> tmpname , $event -> mime , $target_mime );
$event -> set_tmpname ( $new_image , $target_mime );
2023-01-11 11:15:26 +00:00
} catch ( \Exception $e ) {
2019-06-14 12:47:50 +00:00
log_error ( " transcode " , " Error while performing upload transcode: " . $e -> getMessage ());
// We don't want to interfere with the upload process,
2019-06-12 22:54:06 +00:00
// so if something goes wrong the untranscoded image jsut continues
}
}
2019-06-14 12:47:50 +00:00
}
2019-06-12 22:54:06 +00:00
}
2024-01-15 11:52:35 +00:00
public function onPageRequest ( PageRequestEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
global $page , $user ;
2024-02-11 11:34:09 +00:00
if ( $event -> page_matches ( " transcode/ { image_id} " , method : " POST " , permission : Permissions :: EDIT_FILES )) {
$image_id = $event -> get_iarg ( 'image_id' );
2024-02-20 00:22:25 +00:00
$image_obj = Image :: by_id_ex ( $image_id );
try {
$this -> transcode_and_replace_image ( $image_obj , $event -> req_POST ( 'transcode_mime' ));
$page -> set_mode ( PageMode :: REDIRECT );
$page -> set_redirect ( make_link ( " post/view/ " . $image_id ));
} catch ( ImageTranscodeException $e ) {
$this -> theme -> display_transcode_error ( $page , " Error Transcoding " , $e -> getMessage ());
2019-06-14 12:47:50 +00:00
}
}
2019-06-12 22:54:06 +00:00
}
2024-01-15 11:52:35 +00:00
public function onImageDownloading ( ImageDownloadingEvent $event ) : void
2020-06-17 00:06:15 +00:00
{
global $config , $user ;
if ( $config -> get_bool ( TranscodeConfig :: GET_ENABLED ) &&
2024-02-09 16:36:57 +00:00
isset ( $event -> params [ 'transcode' ]) &&
2020-06-17 00:06:15 +00:00
$user -> can ( Permissions :: EDIT_FILES ) &&
$this -> can_convert_mime ( $config -> get_string ( TranscodeConfig :: ENGINE ), $event -> image -> get_mime ())) {
2024-02-09 16:36:57 +00:00
$target_mime = $event -> params [ 'transcode' ];
2020-06-17 00:06:15 +00:00
if ( ! MimeType :: is_mime ( $target_mime )) {
$target_mime = MimeType :: get_for_extension ( $target_mime );
}
if ( empty ( $target_mime )) {
2024-02-09 16:36:57 +00:00
throw new ImageTranscodeException ( " Unable to determine output MIME for " . $event -> params [ 'transcode' ]);
2020-06-17 00:06:15 +00:00
}
MediaEngine :: is_output_supported ( $config -> get_string ( TranscodeConfig :: ENGINE ), $target_mime );
$source_mime = $event -> image -> get_mime ();
2023-11-11 21:49:12 +00:00
if ( $source_mime != $target_mime ) {
2020-06-17 00:06:15 +00:00
$tmp_filename = $this -> transcode_image ( $event -> path , $source_mime , $target_mime );
2023-11-11 21:49:12 +00:00
if ( $event -> file_modified === true && $event -> path != $event -> image -> get_image_filename ()) {
2020-06-17 00:06:15 +00:00
// This means that we're dealing with a temp file that will need cleaned up
unlink ( $event -> path );
}
$event -> path = $tmp_filename ;
$event -> mime = $target_mime ;
$event -> file_modified = true ;
}
}
}
2019-08-07 19:53:59 +00:00
2024-01-15 11:52:35 +00:00
public function onBulkActionBlockBuilding ( BulkActionBlockBuildingEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
global $user , $config ;
2019-09-29 18:00:51 +00:00
if ( $user -> can ( Permissions :: EDIT_FILES )) {
2024-05-04 14:43:29 +00:00
$engine = $config -> get_string ( TranscodeConfig :: ENGINE );
2020-08-28 14:11:14 +00:00
$event -> add_action ( self :: ACTION_BULK_TRANSCODE , " Transcode Image " , null , " " , $this -> theme -> get_transcode_picker_html ( $this -> get_supported_output_mimes ( $engine )));
2019-06-12 22:54:06 +00:00
}
}
2024-01-15 11:52:35 +00:00
public function onBulkAction ( BulkActionEvent $event ) : void
2019-06-12 22:54:06 +00:00
{
2019-12-15 19:47:18 +00:00
global $user , $database , $page ;
2019-06-12 22:54:06 +00:00
2019-06-14 12:47:50 +00:00
switch ( $event -> action ) {
2019-06-18 18:45:59 +00:00
case self :: ACTION_BULK_TRANSCODE :
2024-02-10 00:05:33 +00:00
if ( ! isset ( $event -> params [ 'transcode_mime' ])) {
2019-06-12 22:54:06 +00:00
return ;
}
2019-09-29 18:00:51 +00:00
if ( $user -> can ( Permissions :: EDIT_FILES )) {
2024-02-10 00:05:33 +00:00
$mime = $event -> params [ 'transcode_mime' ];
2019-06-12 22:54:06 +00:00
$total = 0 ;
2020-02-24 14:49:40 +00:00
$size_difference = 0 ;
2019-07-05 15:24:46 +00:00
foreach ( $event -> items as $image ) {
2019-06-12 22:54:06 +00:00
try {
2024-01-09 21:59:24 +00:00
$before_size = $image -> filesize ;
$database -> with_savepoint ( function () use ( $image , $mime ) {
$this -> transcode_and_replace_image ( $image , $mime );
});
2019-06-18 18:45:59 +00:00
// If a subsequent transcode fails, the database needs to have everything about the previous
// transcodes recorded already, otherwise the image entries will be stuck pointing to
// missing image files
2019-06-12 22:54:06 +00:00
$total ++ ;
2024-01-09 02:33:14 +00:00
$size_difference += ( $before_size - $image -> filesize );
2023-01-11 11:15:26 +00:00
} catch ( \Exception $e ) {
2020-06-14 16:05:55 +00:00
log_error ( " transcode " , " Error while bulk transcode on item { $image -> id } to $mime : " . $e -> getMessage ());
2019-06-12 22:54:06 +00:00
}
}
2023-11-11 21:49:12 +00:00
if ( $size_difference > 0 ) {
2020-02-24 15:30:23 +00:00
$page -> flash ( " Transcoded $total items, reduced size by " . human_filesize ( $size_difference ));
2023-11-11 21:49:12 +00:00
} elseif ( $size_difference < 0 ) {
$page -> flash ( " Transcoded $total items, increased size by " . human_filesize ( - 1 * $size_difference ));
2020-02-24 14:49:40 +00:00
} else {
$page -> flash ( " Transcoded $total items, no size difference " );
}
2019-06-12 22:54:06 +00:00
}
break ;
}
}
2024-01-20 14:10:59 +00:00
private function can_convert_mime ( string $engine , string $mime ) : bool
2019-06-12 22:54:06 +00:00
{
2020-06-14 16:05:55 +00:00
return MediaEngine :: is_input_supported ( $engine , $mime );
2019-06-12 22:54:06 +00:00
}
2024-01-20 14:10:59 +00:00
/**
* @ return array < string , string >
*/
private function get_supported_output_mimes ( string $engine , ? string $omit_mime = null ) : array
2019-06-12 22:54:06 +00:00
{
$output = [];
2019-06-25 20:17:13 +00:00
2023-11-11 21:49:12 +00:00
foreach ( self :: OUTPUT_MIMES as $key => $value ) {
if ( $value == " " ) {
2019-06-12 22:54:06 +00:00
$output [ $key ] = $value ;
continue ;
}
2020-06-14 16:05:55 +00:00
if ( MediaEngine :: is_output_supported ( $engine , $value )
2023-11-11 21:49:12 +00:00
&& ( empty ( $omit_mime ) || $omit_mime != $value )) {
2019-06-12 22:54:06 +00:00
$output [ $key ] = $value ;
2019-06-14 12:47:50 +00:00
}
2019-06-12 22:54:06 +00:00
}
return $output ;
}
2019-08-07 19:53:59 +00:00
2019-06-18 18:45:59 +00:00
2019-06-12 22:54:06 +00:00
2024-01-09 02:33:14 +00:00
private function transcode_and_replace_image ( Image $image , string $target_mime ) : void
2019-06-12 22:54:06 +00:00
{
2024-01-09 02:33:14 +00:00
$original_file = warehouse_path ( Image :: IMAGE_DIR , $image -> hash );
$tmp_filename = $this -> transcode_image ( $original_file , $image -> get_mime (), $target_mime );
send_event ( new ImageReplaceEvent ( $image , $tmp_filename ));
2019-06-14 12:47:50 +00:00
}
2019-06-12 22:54:06 +00:00
2023-08-17 17:12:36 +00:00
private function transcode_image ( string $source_name , string $source_mime , string $target_mime ) : string
2019-06-12 22:54:06 +00:00
{
global $config ;
2023-11-11 21:49:12 +00:00
if ( $source_mime == $target_mime ) {
2020-06-14 16:05:55 +00:00
throw new ImageTranscodeException ( " Source and target MIMEs are the same: " . $source_mime );
2019-06-12 22:54:06 +00:00
}
2020-06-14 16:36:52 +00:00
$engine = $config -> get_string ( TranscodeConfig :: ENGINE );
2019-06-12 22:54:06 +00:00
2020-06-14 16:05:55 +00:00
if ( ! $this -> can_convert_mime ( $engine , $source_mime )) {
throw new ImageTranscodeException ( " Engine $engine does not support input MIME $source_mime " );
2019-06-12 22:54:06 +00:00
}
2020-06-14 16:05:55 +00:00
if ( ! MediaEngine :: is_output_supported ( $engine , $target_mime )) {
throw new ImageTranscodeException ( " Engine $engine does not support output MIME $target_mime " );
2019-06-12 22:54:06 +00:00
}
2019-06-14 12:47:50 +00:00
switch ( $engine ) {
2019-06-12 22:54:06 +00:00
case " gd " :
2020-06-14 16:05:55 +00:00
return $this -> transcode_image_gd ( $source_name , $source_mime , $target_mime );
2019-06-12 22:54:06 +00:00
case " convert " :
2020-06-14 16:05:55 +00:00
return $this -> transcode_image_convert ( $source_name , $source_mime , $target_mime );
2019-10-02 10:23:57 +00:00
default :
throw new ImageTranscodeException ( " No engine specified " );
2019-06-12 22:54:06 +00:00
}
}
2023-08-17 17:12:36 +00:00
private function transcode_image_gd ( string $source_name , string $source_mime , string $target_mime ) : string
2019-06-12 22:54:06 +00:00
{
global $config ;
2019-08-07 19:53:59 +00:00
2020-08-28 14:11:14 +00:00
$q = $config -> get_int ( TranscodeConfig :: QUALITY );
2019-06-12 22:54:06 +00:00
2024-01-20 20:48:47 +00:00
$tmp_name = shm_tempnam ( " transcode " );
2019-06-12 22:54:06 +00:00
2024-02-20 00:22:25 +00:00
$image = false_throws ( imagecreatefromstring ( \Safe\file_get_contents ( $source_name )));
2019-06-12 22:54:06 +00:00
try {
$result = false ;
2020-06-14 16:05:55 +00:00
switch ( $target_mime ) {
case MimeType :: WEBP :
2019-06-12 22:54:06 +00:00
$result = imagewebp ( $image , $tmp_name , $q );
break ;
2020-06-14 16:05:55 +00:00
case MimeType :: PNG :
2019-06-12 22:54:06 +00:00
$result = imagepng ( $image , $tmp_name , 9 );
break ;
2020-06-14 16:05:55 +00:00
case MimeType :: JPEG :
2019-06-12 22:54:06 +00:00
// In case of alpha channels
$width = imagesx ( $image );
$height = imagesy ( $image );
$new_image = imagecreatetruecolor ( $width , $height );
2023-11-11 21:49:12 +00:00
if ( $new_image === false ) {
2019-06-12 22:54:06 +00:00
throw new ImageTranscodeException ( " Could not create image with dimensions $width x $height " );
}
2019-06-14 12:47:50 +00:00
try {
2020-06-14 16:36:52 +00:00
$background_color = Media :: hex_color_allocate ( $new_image , $config -> get_string ( TranscodeConfig :: ALPHA_COLOR ));
2023-11-11 21:49:12 +00:00
if ( imagefilledrectangle ( $new_image , 0 , 0 , $width , $height , $background_color ) === false ) {
2019-06-12 22:54:06 +00:00
throw new ImageTranscodeException ( " Could not fill background color " );
}
2023-11-11 21:49:12 +00:00
if ( imagecopy ( $new_image , $image , 0 , 0 , 0 , 0 , $width , $height ) === false ) {
2019-06-12 22:54:06 +00:00
throw new ImageTranscodeException ( " Could not copy source image to new image " );
}
$result = imagejpeg ( $new_image , $tmp_name , $q );
} finally {
imagedestroy ( $new_image );
}
break ;
}
} finally {
imagedestroy ( $image );
}
2023-11-11 21:49:12 +00:00
if ( $result === false ) {
2020-06-14 16:05:55 +00:00
throw new ImageTranscodeException ( " Error while transcoding " . $source_name . " to " . $target_mime );
2019-11-04 01:04:08 +00:00
}
return $tmp_name ;
2019-06-12 22:54:06 +00:00
}
2023-08-17 17:12:36 +00:00
private function transcode_image_convert ( string $source_name , string $source_mime , string $target_mime ) : string
2019-06-12 22:54:06 +00:00
{
global $config ;
2019-08-07 19:53:59 +00:00
2020-08-28 14:11:14 +00:00
$q = $config -> get_int ( TranscodeConfig :: QUALITY );
2019-06-24 15:05:16 +00:00
$convert = $config -> get_string ( MediaConfig :: CONVERT_PATH );
2019-06-12 22:54:06 +00:00
2020-08-28 14:11:14 +00:00
if ( empty ( $convert )) {
2019-06-12 22:54:06 +00:00
throw new ImageTranscodeException ( " ImageMagick path not configured " );
}
2020-06-14 16:05:55 +00:00
$ext = Media :: determine_ext ( $target_mime );
2019-06-12 22:54:06 +00:00
2020-06-14 16:36:52 +00:00
$args = " -background " ;
2020-06-14 16:05:55 +00:00
if ( Media :: supports_alpha ( $target_mime )) {
$args .= " none " ;
} else {
2020-06-14 16:36:52 +00:00
$args .= " \" " . $config -> get_string ( TranscodeConfig :: ALPHA_COLOR ) . " \" " ;
2020-06-14 16:05:55 +00:00
}
2020-06-14 16:36:52 +00:00
$args .= " -flatten " ;
2020-06-14 16:05:55 +00:00
switch ( $target_mime ) {
case MimeType :: PNG :
$args .= ' -define png:compression-level=9' ;
2019-06-12 22:54:06 +00:00
break ;
2020-06-14 16:05:55 +00:00
case MimeType :: WEBP_LOSSLESS :
$args .= ' -define webp:lossless=true -quality 100 ' ;
2019-06-12 22:54:06 +00:00
break ;
default :
2020-06-14 16:05:55 +00:00
$args .= ' -quality ' . $q ;
2019-06-12 22:54:06 +00:00
break ;
}
2020-06-16 23:18:56 +00:00
2024-01-20 20:48:47 +00:00
$tmp_name = shm_tempnam ( " transcode " );
2019-06-12 22:54:06 +00:00
2020-06-14 16:05:55 +00:00
$source_type = FileExtension :: get_for_mime ( $source_mime );
$format = '"%s" %s:"%s" %s %s:"%s" 2>&1' ;
$cmd = sprintf ( $format , $convert , $source_type , $source_name , $args , $ext , $tmp_name );
2019-06-14 17:59:12 +00:00
2019-06-12 22:54:06 +00:00
$cmd = str_replace ( " \" convert \" " , " convert " , $cmd ); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27
exec ( $cmd , $output , $ret );
log_debug ( 'transcode' , " Transcoding with command ` $cmd `, returns $ret " );
2023-11-11 21:49:12 +00:00
if ( $ret !== 0 ) {
2019-06-14 17:59:12 +00:00
throw new ImageTranscodeException ( " Transcoding failed with command " . $cmd . " , returning " . implode ( " \r \n " , $output ));
2019-06-12 22:54:06 +00:00
}
return $tmp_name ;
}
}