From a41e99d1af182c2e2d3a97b6ad71b9dd7a0d9d00 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Mon, 24 Jun 2019 10:05:16 -0500 Subject: [PATCH] Renamed graphics extension to media extension --- core/imageboard/misc.php | 3 +- core/sys_config.php | 2 +- core/util.php | 2 +- ext/et/main.php | 6 +- ext/et/theme.php | 4 +- ext/graphics/theme.php | 6 - ext/handle_flash/main.php | 2 +- ext/handle_ico/main.php | 4 +- ext/handle_svg/main.php | 4 +- ext/handle_video/main.php | 4 +- ext/image/main.php | 4 +- ext/{graphics => media}/main.php | 265 +++++++++++++++++++++---------- ext/media/theme.php | 6 + ext/resize/main.php | 10 +- ext/rotate/main.php | 2 +- ext/transcode/main.php | 40 ++--- themes/lite/view.theme.php | 2 + 17 files changed, 229 insertions(+), 137 deletions(-) delete mode 100644 ext/graphics/theme.php rename ext/{graphics => media}/main.php (74%) create mode 100644 ext/media/theme.php diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index 2a349c80..5af65d6f 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -95,7 +95,6 @@ function get_extension_from_mime(String $file_path): String throw new UploadException("Could not determine file mime type: ".$file_path); } - /** * Given a full size pair of dimensions, return a pair scaled down to fit * into the configured thumbnail square, with ratio intact. @@ -179,7 +178,7 @@ function create_image_thumb(string $hash, string $type, string $engine = null) { $engine = $config->get_string(ImageConfig::THUMB_ENGINE); } - send_event(new GraphicResizeEvent( + send_event(new MediaResizeEvent( $engine, $inname, $type, diff --git a/core/sys_config.php b/core/sys_config.php index a489a96f..9ce0d8d0 100644 --- a/core/sys_config.php +++ b/core/sys_config.php @@ -40,7 +40,7 @@ _d("SEARCH_ACCEL", false); // boolean use search accelerator _d("WH_SPLITS", 1); // int how many levels of subfolders to put in the warehouse _d("VERSION", '2.7-beta'); // string shimmie version _d("TIMEZONE", null); // string timezone -_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,handle_static,comment,tag_list,index,tag_edit,alias_editor,graphics"); // extensions to always enable +_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,handle_static,comment,tag_list,index,tag_edit,alias_editor,media"); // extensions to always enable _d("EXTRA_EXTS", ""); // string optional extra extensions _d("BASE_URL", null); // string force a specific base URL (default is auto-detect) _d("MIN_PHP_VERSION", '7.1');// string minimum supported PHP version diff --git a/core/util.php b/core/util.php index 24bda493..91e467ff 100644 --- a/core/util.php +++ b/core/util.php @@ -79,7 +79,7 @@ function get_memory_limit(): int // thumbnail generation requires lots of memory $default_limit = 8*1024*1024; // 8 MB of memory is PHP's default. - $shimmie_limit = parse_shorthand_int($config->get_int(GraphicsConfig::MEM_LIMIT)); + $shimmie_limit = parse_shorthand_int($config->get_int(MediaConfig::MEM_LIMIT)); if ($shimmie_limit < 3*1024*1024) { // we aren't going to fit, override diff --git a/ext/et/main.php b/ext/et/main.php index 50a639e1..e3e9b9c7 100644 --- a/ext/et/main.php +++ b/ext/et/main.php @@ -53,9 +53,9 @@ class ET extends Extension to_shorthand_int(disk_total_space("./")); $info['sys_server'] = isset($_SERVER["SERVER_SOFTWARE"]) ? $_SERVER["SERVER_SOFTWARE"] : 'unknown'; - $info[GraphicsConfig::FFMPEG_PATH] = $config->get_string(GraphicsConfig::FFMPEG_PATH); - $info[GraphicsConfig::CONVERT_PATH] = $config->get_string(GraphicsConfig::CONVERT_PATH); - $info[GraphicsConfig::MEM_LIMIT] = $config->get_int(GraphicsConfig::MEM_LIMIT); + $info[MediaConfig::FFMPEG_PATH] = $config->get_string(MediaConfig::FFMPEG_PATH); + $info[MediaConfig::CONVERT_PATH] = $config->get_string(MediaConfig::CONVERT_PATH); + $info[MediaConfig::MEM_LIMIT] = $config->get_int(MediaConfig::MEM_LIMIT); $info[ImageConfig::THUMB_ENGINE] = $config->get_string(ImageConfig::THUMB_ENGINE); $info[ImageConfig::THUMB_QUALITY] = $config->get_int(ImageConfig::THUMB_QUALITY); diff --git a/ext/et/theme.php b/ext/et/theme.php index a0778dff..0582fddf 100644 --- a/ext/et/theme.php +++ b/ext/et/theme.php @@ -35,8 +35,8 @@ Database: {$info['sys_db']} Server: {$info['sys_server']} Disk use: {$info['sys_disk']} -Graphics System: -Memory Limit: {$info[GraphicsConfig::MEM_LIMIT]} +Media System: +Memory Limit: {$info[MediaConfig::MEM_LIMIT]} Thumbnail Generation: Engine: {$info[ImageConfig::THUMB_ENGINE]} diff --git a/ext/graphics/theme.php b/ext/graphics/theme.php deleted file mode 100644 index 6210644e..00000000 --- a/ext/graphics/theme.php +++ /dev/null @@ -1,6 +0,0 @@ -getMessage()); return false; } diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index b73f07de..4df1154b 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -36,9 +36,9 @@ class SVGFileHandler extends DataHandlerExtension protected function create_thumb(string $hash, string $type): bool { try { - create_image_thumb($hash, $type, GraphicsEngine::IMAGICK); + create_image_thumb($hash, $type, MediaEngine::IMAGICK); return true; - } catch (GraphicsException $e) { + } catch (MediaException $e) { log_warning("handle_svg", "Could not generate thumbnail. " . $e->getMessage()); copy("ext/handle_svg/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash)); return false; diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index 15f192cc..666def30 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -53,7 +53,7 @@ class VideoFileHandler extends DataHandlerExtension */ protected function create_thumb(string $hash, string $type): bool { - return Graphics::create_thumbnail_ffmpeg($hash); + return Media::create_thumbnail_ffmpeg($hash); } protected function supported_ext(string $ext): bool @@ -65,7 +65,7 @@ class VideoFileHandler extends DataHandlerExtension { $image = new Image(); - $size = Graphics::video_size($filename); + $size = Media::video_size($filename); $image->width = $size[0]; $image->height = $size[1]; diff --git a/ext/image/main.php b/ext/image/main.php index fbcac36f..c851a90d 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -41,8 +41,8 @@ class ImageIO extends Extension const THUMBNAIL_ENGINES = [ - 'Built-in GD' => GraphicsEngine::GD, - 'ImageMagick' => GraphicsEngine::IMAGICK + 'Built-in GD' => MediaEngine::GD, + 'ImageMagick' => MediaEngine::IMAGICK ]; const THUMBNAIL_TYPES = [ diff --git a/ext/graphics/main.php b/ext/media/main.php similarity index 74% rename from ext/graphics/main.php rename to ext/media/main.php index 98cfd42e..610959a9 100644 --- a/ext/graphics/main.php +++ b/ext/media/main.php @@ -1,65 +1,66 @@ - * Description: Provides common functions and settings used for graphic operations. + * Description: Provides common functions and settings used for media operations. * License: MIT * Version: 1.0 */ /* -* This is used by the graphics code when there is an error +* This is used by the media code when there is an error */ -abstract class GraphicsConfig +abstract class MediaConfig { - const FFMPEG_PATH = "graphics_ffmpeg_path"; - const FFPROBE_PATH = "graphics_ffprobe_path"; - const CONVERT_PATH = "graphics_convert_path"; - const VERSION = "ext_graphics_version"; - const MEM_LIMIT = 'graphics_mem_limit'; + const FFMPEG_PATH = "media_ffmpeg_path"; + const FFPROBE_PATH = "media_ffprobe_path"; + const CONVERT_PATH = "media_convert_path"; + const VERSION = "ext_media_version"; + const MEM_LIMIT = 'media_mem_limit'; } -abstract class GraphicsEngine { +abstract class MediaEngine +{ public const GD = "gd"; public const IMAGICK = "convert"; public const FFMPEG = "ffmpeg"; public const ALL = [ - GraphicsEngine::GD, - GraphicsEngine::FFMPEG, - GraphicsEngine::IMAGICK + MediaEngine::GD, + MediaEngine::FFMPEG, + MediaEngine::IMAGICK ]; public const OUTPUT_SUPPORT = [ - GraphicsEngine::GD => [ + MediaEngine::GD => [ "gif", "jpg", "png", "webp", - Graphics::WEBP_LOSSY, + Media::WEBP_LOSSY, ], - GraphicsEngine::IMAGICK => [ + MediaEngine::IMAGICK => [ "gif", "jpg", "png", "webp", - Graphics::WEBP_LOSSY, - Graphics::WEBP_LOSSLESS, + Media::WEBP_LOSSY, + Media::WEBP_LOSSLESS, ], - GraphicsEngine::FFMPEG => [ + MediaEngine::FFMPEG => [ ] ]; public const INPUT_SUPPORT = [ - GraphicsEngine::GD => [ + MediaEngine::GD => [ "bmp", "gif", "jpg", "png", "webp", ], - GraphicsEngine::IMAGICK => [ + MediaEngine::IMAGICK => [ "bmp", "gif", "jpg", @@ -69,7 +70,7 @@ abstract class GraphicsEngine { "webp", "ico", ], - GraphicsEngine::FFMPEG => [ + MediaEngine::FFMPEG => [ "avi", "mkv", "webm", @@ -80,11 +81,11 @@ abstract class GraphicsEngine { ]; } -class GraphicsException extends SCoreException +class MediaException extends SCoreException { } -class GraphicResizeEvent extends Event +class MediaResizeEvent extends Event { public $engine; public $input_path; @@ -106,7 +107,7 @@ class GraphicResizeEvent extends Event bool $minimize = false, bool $allow_upscale = true) { - assert(in_array($engine, GraphicsEngine::ALL)); + assert(in_array($engine, MediaEngine::ALL)); $this->engine = $engine; $this->input_path = $input_path; $this->input_type = $input_type; @@ -121,14 +122,28 @@ class GraphicResizeEvent extends Event } } -class Graphics extends Extension +class MediaCheckLosslessEvent extends Event +{ + public $file_name; + public $ext; + public $result = false; + + public function __construct(string $file_name, string $ext) + { + $this->file_name = $file_name; + $this->ext = $ext; + } + +} + +class Media extends Extension { const WEBP_LOSSY = "webp-lossy"; const WEBP_LOSSLESS = "webp-lossless"; - const IMAGE_GRAPHICS_ENGINES = [ - "GD" => GraphicsEngine::GD, - "ImageMagick" => GraphicsEngine::IMAGICK, + const IMAGE_MEDIA_ENGINES = [ + "GD" => MediaEngine::GD, + "ImageMagick" => MediaEngine::IMAGICK, ]; const LOSSLESS_FORMATS = [ @@ -148,6 +163,16 @@ class Graphics extends Extension ]; + //RIFF####WEBPVP8?..............ANIM + private const WEBP_ANIMATION_HEADER = + [0x52, 0x49, 0x46, 0x46, null, null, null, null, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0x41, 0x4E, 0x49, 0x4D]; + + //RIFF####WEBPVP8L + private const WEBP_LOSSLESS_HEADER = + [0x52, 0x49, 0x46, 0x46, null, null, null, null, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, 0x4C]; + + static function imagick_available(): bool { return extension_loaded("imagick"); @@ -164,46 +189,46 @@ class Graphics extends Extension public function onInitExt(InitExtEvent $event) { global $config; - $config->set_default_string(GraphicsConfig::FFPROBE_PATH, 'ffprobe'); - $config->set_default_int(GraphicsConfig::MEM_LIMIT, parse_shorthand_int('8MB')); - $config->set_default_string(GraphicsConfig::FFMPEG_PATH, ''); - $config->set_default_string(GraphicsConfig::CONVERT_PATH, 'convert'); + $config->set_default_string(MediaConfig::FFPROBE_PATH, 'ffprobe'); + $config->set_default_int(MediaConfig::MEM_LIMIT, parse_shorthand_int('8MB')); + $config->set_default_string(MediaConfig::FFMPEG_PATH, ''); + $config->set_default_string(MediaConfig::CONVERT_PATH, 'convert'); - if ($config->get_int(GraphicsConfig::VERSION) < 1) { + if ($config->get_int(MediaConfig::VERSION) < 1) { $current_value = $config->get_string("thumb_ffmpeg_path"); if (!empty($current_value)) { - $config->set_string(GraphicsConfig::FFMPEG_PATH, $current_value); + $config->set_string(MediaConfig::FFMPEG_PATH, $current_value); } elseif ($ffmpeg = shell_exec((PHP_OS == 'WINNT' ? 'where' : 'which') . ' ffmpeg')) { //ffmpeg exists in PATH, check if it's executable, and if so, default to it instead of static if (is_executable(strtok($ffmpeg, PHP_EOL))) { - $config->set_default_string(GraphicsConfig::FFMPEG_PATH, 'ffmpeg'); + $config->set_default_string(MediaConfig::FFMPEG_PATH, 'ffmpeg'); } } $current_value = $config->get_string("thumb_convert_path"); if (!empty($current_value)) { - $config->set_string(GraphicsConfig::CONVERT_PATH, $current_value); + $config->set_string(MediaConfig::CONVERT_PATH, $current_value); } elseif ($convert = shell_exec((PHP_OS == 'WINNT' ? 'where' : 'which') . ' convert')) { //ffmpeg exists in PATH, check if it's executable, and if so, default to it instead of static if (is_executable(strtok($convert, PHP_EOL))) { - $config->set_default_string(GraphicsConfig::CONVERT_PATH, 'convert'); + $config->set_default_string(MediaConfig::CONVERT_PATH, 'convert'); } } $current_value = $config->get_int("thumb_mem_limit"); if (!empty($current_value)) { - $config->set_int(GraphicsConfig::MEM_LIMIT, $current_value); + $config->set_int(MediaConfig::MEM_LIMIT, $current_value); } - $config->set_int(GraphicsConfig::VERSION, 1); - log_info("graphics", "extension installed"); + $config->set_int(MediaConfig::VERSION, 1); + log_info("media", "extension installed"); } } public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Graphic Engines"); + $sb = new SetupBlock("Media Engines"); // if (self::imagick_available()) { // try { @@ -214,29 +239,29 @@ class Graphics extends Extension // $sb->add_label("ImageMagick not detected"); // } // } else { - $sb->add_text_option(GraphicsConfig::CONVERT_PATH, "convert command: "); + $sb->add_text_option(MediaConfig::CONVERT_PATH, "convert command: "); // } - $sb->add_text_option(GraphicsConfig::FFMPEG_PATH, "
ffmpeg command: "); + $sb->add_text_option(MediaConfig::FFMPEG_PATH, "
ffmpeg command: "); - $sb->add_shorthand_int_option(GraphicsConfig::MEM_LIMIT, "
Max memory use: "); + $sb->add_shorthand_int_option(MediaConfig::MEM_LIMIT, "
Max memory use: "); $event->panel->add_block($sb); } /** - * @param GraphicResizeEvent $event - * @throws GraphicsException + * @param MediaResizeEvent $event + * @throws MediaException * @throws InsufficientMemoryException */ - public function onGraphicResize(GraphicResizeEvent $event) + public function onMediaResize(MediaResizeEvent $event) { switch ($event->engine) { - case GraphicsEngine::GD: + case MediaEngine::GD: $info = getimagesize($event->input_path); if ($info === false) { - throw new GraphicsException("getimagesize failed for " . $event->input_path); + throw new MediaException("getimagesize failed for " . $event->input_path); } self::image_resize_gd( @@ -251,7 +276,7 @@ class Graphics extends Extension $event->allow_upscale); break; - case GraphicsEngine::IMAGICK: + case MediaEngine::IMAGICK: // if (self::imagick_available()) { // } else { self::image_resize_convert( @@ -268,7 +293,7 @@ class Graphics extends Extension //} break; default: - throw new GraphicsException("Engine not supported for resize: " . $event->engine); + throw new MediaException("Engine not supported for resize: " . $event->engine); } // TODO: Get output optimization tools working better @@ -277,6 +302,22 @@ class Graphics extends Extension // } } + public function onMediaCheckLossless(MediaCheckLosslessEvent $event) + { + switch ($event->ext) { + case "png": + case "psd": + case "bmp": + case "gif": + case "ico": + $event->result = true; + break; + case "webp": + $event->result = Media::is_lossless_webp($event->file_name); + break; + } + } + /** * Check Memory usage limits * @@ -310,15 +351,15 @@ class Graphics extends Extension * * @param $hash * @return bool true if successful, false if not. - * @throws GraphicsException + * @throws MediaException */ public static function create_thumbnail_ffmpeg($hash): bool { global $config; - $ffmpeg = $config->get_string(GraphicsConfig::FFMPEG_PATH); + $ffmpeg = $config->get_string(MediaConfig::FFMPEG_PATH); if ($ffmpeg == null || $ffmpeg == "") { - throw new GraphicsException("ffmpeg command configured"); + throw new MediaException("ffmpeg command configured"); } $inname = warehouse_path(Image::IMAGE_DIR, $hash); @@ -355,10 +396,10 @@ class Graphics extends Extension exec($cmd, $output, $ret); if ((int)$ret == (int)0) { - log_debug('graphics', "Generating thumbnail with command `$cmd`, returns $ret"); + log_debug('Media', "Generating thumbnail with command `$cmd`, returns $ret"); return true; } else { - log_error('graphics', "Generating thumbnail with command `$cmd`, returns $ret"); + log_error('Media', "Generating thumbnail with command `$cmd`, returns $ret"); return false; } } @@ -498,10 +539,10 @@ class Graphics extends Extension { global $config; - $convert = $config->get_string(GraphicsConfig::CONVERT_PATH); + $convert = $config->get_string(MediaConfig::CONVERT_PATH); if (empty($convert)) { - throw new GraphicsException("convert command not configured"); + throw new MediaException("convert command not configured"); } if (empty($output_type)) { @@ -533,9 +574,9 @@ class Graphics extends Extension $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); if ($ret != 0) { - throw new GraphicsException("Resizing image with command `$cmd`, returns $ret, outputting " . implode("\r\n", $output)); + throw new MediaException("Resizing image with command `$cmd`, returns $ret, outputting " . implode("\r\n", $output)); } else { - log_debug('graphics', "Generating thumbnail with command `$cmd`, returns $ret"); + log_debug('Media', "Generating thumbnail with command `$cmd`, returns $ret"); } } @@ -549,7 +590,7 @@ class Graphics extends Extension * @param string $output_filename * @param string|null $output_type If set to null, the output file type will be automatically determined via the $info parameter. Otherwise an exception will be thrown. * @param int $output_quality Defaults to 80. - * @throws GraphicsException + * @throws MediaException * @throws InsufficientMemoryException if the estimated memory usage exceeds the memory limit. */ public static function image_resize_gd( @@ -586,7 +627,7 @@ class Graphics extends Extension $output_type = "bmp"; break; default: - throw new GraphicsException("Failed to save the new image - Unsupported image type."); + throw new MediaException("Failed to save the new image - Unsupported image type."); } } @@ -609,10 +650,10 @@ class Graphics extends Extension $image_resized = imagecreatetruecolor($new_width, $new_height); try { if ($image === false) { - throw new GraphicsException("Could not load image: " . $image_filename); + throw new MediaException("Could not load image: " . $image_filename); } if ($image_resized === false) { - throw new GraphicsException("Could not create output image with dimensions $new_width c $new_height "); + throw new MediaException("Could not create output image with dimensions $new_width c $new_height "); } // Handle transparent images @@ -629,12 +670,12 @@ class Graphics extends Extension // Allocate the same color in the new image resource $transparency = imagecolorallocate($image_resized, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']); if ($transparency === false) { - throw new GraphicsException("Unable to allocate transparent color"); + throw new MediaException("Unable to allocate transparent color"); } // Completely fill the background of the new image with allocated color. if (imagefill($image_resized, 0, 0, $transparency) === false) { - throw new GraphicsException("Unable to fill new image with transparent color"); + throw new MediaException("Unable to fill new image with transparent color"); } // Set the background color for new image to transparent @@ -647,17 +688,17 @@ class Graphics extends Extension // More info here: http://stackoverflow.com/questions/279236/how-do-i-resize-pngs-with-transparency-in-php // if (imagealphablending($image_resized, false) === false) { - throw new GraphicsException("Unable to disable image alpha blending"); + throw new MediaException("Unable to disable image alpha blending"); } if (imagesavealpha($image_resized, true) === false) { - throw new GraphicsException("Unable to enable image save alpha"); + throw new MediaException("Unable to enable image save alpha"); } $transparent_color = imagecolorallocatealpha($image_resized, 255, 255, 255, 127); if ($transparent_color === false) { - throw new GraphicsException("Unable to allocate transparent color"); + throw new MediaException("Unable to allocate transparent color"); } if (imagefilledrectangle($image_resized, 0, 0, $new_width, $new_height, $transparent_color) === false) { - throw new GraphicsException("Unable to fill new image with transparent color"); + throw new MediaException("Unable to fill new image with transparent color"); } break; } @@ -675,7 +716,7 @@ class Graphics extends Extension $width, $height ) === false) { - throw new GraphicsException("Unable to copy resized image data to new image"); + throw new MediaException("Unable to copy resized image data to new image"); } switch ($output_type) { @@ -683,7 +724,7 @@ class Graphics extends Extension $result = imagebmp($image_resized, $output_filename, true); break; case "webp": - case Graphics::WEBP_LOSSY: + case Media::WEBP_LOSSY: $result = imagewebp($image_resized, $output_filename, $output_quality); break; case "jpg": @@ -697,10 +738,10 @@ class Graphics extends Extension $result = imagegif($image_resized, $output_filename); break; default: - throw new GraphicsException("Failed to save the new image - Unsupported image type: $output_type"); + throw new MediaException("Failed to save the new image - Unsupported image type: $output_type"); } if ($result === false) { - throw new GraphicsException("Failed to save the new image, function returned false when saving type: $output_type"); + throw new MediaException("Failed to save the new image, function returned false when saving type: $output_type"); } } finally { @imagedestroy($image); @@ -714,19 +755,69 @@ class Graphics extends Extension * @param String $image_filename The path of the file to check. * @return bool true if the file is an animated gif, false if it is not. */ - public static function is_animated_gif(String $image_filename) + public static function is_animated_gif(String $image_filename): bool { $is_anim_gif = 0; if (($fh = @fopen($image_filename, 'rb'))) { - //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) - while (!feof($fh) && $is_anim_gif < 2) { - $chunk = fread($fh, 1024 * 100); - $is_anim_gif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches); + try { + //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) + while (!feof($fh) && $is_anim_gif < 2) { + $chunk = fread($fh, 1024 * 100); + $is_anim_gif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches); + } + } finally { + @fclose($fh); } } return ($is_anim_gif == 0); } + + + + private static function compare_file_bytes(String $file_name, array $comparison): bool + { + $size= filesize($file_name); + if ($size < count($comparison)) { + // Can't match because it's too small + return false; + } + + if (($fh = @fopen($file_name, 'rb'))) { + try { + $chunk = unpack("C*",fread($fh, count($comparison))); + + for ($i = 0; $i < count($comparison); $i++) { + $byte = $comparison[$i]; + if($byte==null) { + continue; + } else { + $fileByte = $chunk[$i+1]; + if($fileByte!=$byte) { + return false; + } + } + } + return true; + } finally { + @fclose($fh); + } + } else { + throw new MediaException("Unable to open file for byte check: $file_name"); + } + + } + + public static function is_animated_webp(String $image_filename): bool + { + return self::compare_file_bytes($image_filename, self::WEBP_ANIMATION_HEADER); + } + + public static function is_lossless_webp(String $image_filename): bool + { + return self::compare_file_bytes($image_filename, self::WEBP_LOSSLESS_HEADER); + } + public static function supports_alpha(string $format) { return in_array(self::normalize_format($format), self::ALPHA_FORMATS); @@ -735,7 +826,7 @@ class Graphics extends Extension public static function is_input_supported($engine, $format): bool { $format = self::normalize_format($format); - if (!in_array($format, GraphicsEngine::INPUT_SUPPORT[$engine])) { + if (!in_array($format, MediaEngine::INPUT_SUPPORT[$engine])) { return false; } return true; @@ -744,7 +835,7 @@ class Graphics extends Extension public static function is_output_supported($engine, $format): bool { $format = self::normalize_format($format); - if (!in_array($format, GraphicsEngine::OUTPUT_SUPPORT[$engine])) { + if (!in_array($format, MediaEngine::OUTPUT_SUPPORT[$engine])) { return false; } return true; @@ -752,15 +843,15 @@ class Graphics extends Extension /** * Checks if a format (normally a file extension) is a variant name of another format (ie, jpg and jpeg). - * If one is found, then the maine name that the Graphics extension will recognize is returned, + * If one is found, then the maine name that the Media extension will recognize is returned, * otherwise the incoming format is returned. * * @param $format - * @return string|null The format name that the graphics extension will recognize. + * @return string|null The format name that the media extension will recognize. */ static public function normalize_format($format): ?string { - if (array_key_exists($format, Graphics::FORMAT_ALIASES)) { + if (array_key_exists($format, Media::FORMAT_ALIASES)) { return self::FORMAT_ALIASES[$format]; } return $format; @@ -776,7 +867,7 @@ class Graphics extends Extension static public function video_size(string $filename): array { global $config; - $ffmpeg = $config->get_string(GraphicsConfig::FFMPEG_PATH); + $ffmpeg = $config->get_string(MediaConfig::FFMPEG_PATH); $cmd = escapeshellcmd(implode(" ", [ escapeshellarg($ffmpeg), "-y", "-i", escapeshellarg($filename), @@ -795,7 +886,7 @@ class Graphics extends Extension } else { $size = [1, 1]; } - log_debug('graphics', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]"); + log_debug('Media', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]"); return $size; } diff --git a/ext/media/theme.php b/ext/media/theme.php new file mode 100644 index 00000000..e213a0e9 --- /dev/null +++ b/ext/media/theme.php @@ -0,0 +1,6 @@ +set_default_bool(ResizeConfig::ENABLED, true); $config->set_default_bool(ResizeConfig::UPLOAD, false); - $config->set_default_string(ResizeConfig::ENGINE, GraphicsEngine::GD); + $config->set_default_string(ResizeConfig::ENGINE, MediaEngine::GD); $config->set_default_int(ResizeConfig::DEFAULT_WIDTH, 0); $config->set_default_int(ResizeConfig::DEFAULT_HEIGHT, 0); } @@ -174,8 +174,8 @@ class ResizeImage extends Extension { global $config; $engine = $config->get_string(ResizeConfig::ENGINE); - return Graphics::is_input_supported($engine, $format) - && Graphics::is_output_supported($engine, $format); + return Media::is_input_supported($engine, $format) + && Media::is_output_supported($engine, $format); } @@ -205,8 +205,8 @@ class ResizeImage extends Extension throw new ImageResizeException("Unable to save temporary image file."); } - send_event(new GraphicResizeEvent( - GraphicsEngine::GD, + send_event(new MediaResizeEvent( + MediaEngine::GD, $image_filename, $image_obj->ext, $tmp_filename, diff --git a/ext/rotate/main.php b/ext/rotate/main.php index bf539ba8..4936ca59 100644 --- a/ext/rotate/main.php +++ b/ext/rotate/main.php @@ -130,7 +130,7 @@ class RotateImage extends Extension $info = getimagesize($image_filename); - $memory_use = Graphics::calc_memory_use($info); + $memory_use = Media::calc_memory_use($info); $memory_limit = get_memory_limit(); if ($memory_use > $memory_limit) { diff --git a/ext/transcode/main.php b/ext/transcode/main.php index 650af1bb..41dfa07e 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -48,8 +48,8 @@ class TranscodeImage extends Extension "" => "", "JPEG (lossy)" => "jpg", "PNG (lossless)" => "png", - "WEBP (lossy)" => Graphics::WEBP_LOSSY, - "WEBP (lossless)" => Graphics::WEBP_LOSSLESS, + "WEBP (lossy)" => Media::WEBP_LOSSY, + "WEBP (lossless)" => Media::WEBP_LOSSLESS, ]; /** @@ -66,7 +66,7 @@ class TranscodeImage extends Extension global $config; $config->set_default_bool(TranscodeConfig::ENABLED, true); $config->set_default_bool(TranscodeConfig::UPLOAD, false); - $config->set_default_string(TranscodeConfig::ENGINE, GraphicsEngine::GD); + $config->set_default_string(TranscodeConfig::ENGINE, MediaEngine::GD); $config->set_default_int(TranscodeConfig::QUALITY, 80); foreach (array_values(self::INPUT_FORMATS) as $format) { @@ -98,9 +98,9 @@ class TranscodeImage extends Extension $sb->start_table(); $sb->add_bool_option(TranscodeConfig::ENABLED, "Allow transcoding images: ", true); $sb->add_bool_option(TranscodeConfig::UPLOAD, "Transcode on upload: ", true); - $sb->add_choice_option(TranscodeConfig::ENGINE, Graphics::IMAGE_GRAPHICS_ENGINES, "Engine", true); + $sb->add_choice_option(TranscodeConfig::ENGINE, Media::IMAGE__MEDIA_ENGINES, "Engine", true); foreach (self::INPUT_FORMATS as $display=>$format) { - if (in_array($format, GraphicsEngine::INPUT_SUPPORT[$engine])) { + if (in_array($format, MediaEngine::INPUT_SUPPORT[$engine])) { $outputs = $this->get_supported_output_formats($engine, $format); $sb->add_choice_option(TranscodeConfig::UPLOAD_PREFIX.$format, $outputs, "$display", true); } @@ -117,9 +117,9 @@ class TranscodeImage extends Extension if ($config->get_bool(TranscodeConfig::UPLOAD) == true) { $ext = strtolower($event->type); - $ext = Graphics::normalize_format($ext); + $ext = Media::normalize_format($ext); - if ($event->type=="gif"&&Graphics::is_animated_gif($event->tmpname)) { + if ($event->type=="gif"&&Media::is_animated_gif($event->tmpname)) { return; } @@ -130,7 +130,7 @@ class TranscodeImage extends Extension } try { $new_image = $this->transcode_image($event->tmpname, $ext, $target_format); - $event->set_type(Graphics::determine_ext($target_format)); + $event->set_type(Media::determine_ext($target_format)); $event->set_tmpname($new_image); } catch (Exception $e) { log_error("transcode", "Error while performing upload transcode: ".$e->getMessage()); @@ -224,21 +224,21 @@ class TranscodeImage extends Extension private function can_convert_format($engine, $format): bool { - return Graphics::is_input_supported($engine, $format); + return Media::is_input_supported($engine, $format); } private function get_supported_output_formats($engine, ?String $omit_format = null): array { - $omit_format = Graphics::normalize_format($omit_format); + $omit_format = Media::normalize_format($omit_format); $output = []; foreach (self::OUTPUT_FORMATS as $key=>$value) { if ($value=="") { $output[$key] = $value; continue; } - if(Graphics::is_output_supported($engine, $value) - &&(empty($omit_format)||$omit_format!=Graphics::determine_ext($value))) { + if(Media::is_output_supported($engine, $value) + &&(empty($omit_format)||$omit_format!=Media::determine_ext($value))) { $output[$key] = $value; } } @@ -259,7 +259,7 @@ class TranscodeImage extends Extension $new_image->filename = $image_obj->filename; $new_image->width = $image_obj->width; $new_image->height = $image_obj->height; - $new_image->ext = Graphics::determine_ext($target_format); + $new_image->ext = Media::determine_ext($target_format); /* Move the new image into the main storage location */ $target = warehouse_path(Image::IMAGE_DIR, $new_image->hash); @@ -278,7 +278,7 @@ class TranscodeImage extends Extension { global $config; - if ($source_format==Graphics::determine_ext($target_format)) { + if ($source_format==Media::determine_ext($target_format)) { throw new ImageTranscodeException("Source and target formats are the same: ".$source_format); } @@ -289,7 +289,7 @@ class TranscodeImage extends Extension if (!$this->can_convert_format($engine, $source_format)) { throw new ImageTranscodeException("Engine $engine does not support input format $source_format"); } - if (!in_array($target_format, GraphicsEngine::OUTPUT_SUPPORT[$engine])) { + if (!in_array($target_format, MediaEngine::OUTPUT_SUPPORT[$engine])) { throw new ImageTranscodeException("Engine $engine does not support output format $target_format"); } @@ -313,7 +313,7 @@ class TranscodeImage extends Extension try { $result = false; switch ($target_format) { - case "webp-lossy": + case Media::WEBP_LOSSY: $result = imagewebp($image, $tmp_name, $q); break; case "png": @@ -358,20 +358,20 @@ class TranscodeImage extends Extension global $config; $q = $config->get_int("transcode_quality"); - $convert = $config->get_string(GraphicsConfig::CONVERT_PATH); + $convert = $config->get_string(MediaConfig::CONVERT_PATH); if ($convert==null||$convert=="") { throw new ImageTranscodeException("ImageMagick path not configured"); } - $ext = Graphics::determine_ext($target_format); + $ext = Media::determine_ext($target_format); $args = " -flatten "; $bg = "none"; switch ($target_format) { - case Graphics::WEBP_LOSSLESS: + case Media::WEBP_LOSSLESS: $args .= '-define webp:lossless=true'; break; - case Graphics::WEBP_LOSSY: + case Media::WEBP_LOSSY: $args .= ''; break; case "png": diff --git a/themes/lite/view.theme.php b/themes/lite/view.theme.php index b3ae0046..4c1beac9 100644 --- a/themes/lite/view.theme.php +++ b/themes/lite/view.theme.php @@ -18,6 +18,7 @@ class CustomViewImageTheme extends ViewImageTheme $h_owner = html_escape($image->get_owner()->name); $h_ownerlink = "$h_owner"; $h_ip = html_escape($image->owner_ip); + $h_type = html_escape($image->get_mime_type()); $h_date = autodate($image->posted); $h_filesize = to_shorthand_int($image->filesize); @@ -31,6 +32,7 @@ class CustomViewImageTheme extends ViewImageTheme
Posted: $h_date by $h_ownerlink
Size: {$image->width}x{$image->height}
Filesize: $h_filesize +
Type: ".$h_type." "; if (!is_null($image->source)) {