New Graphics extension
Added constants to several extensions
This commit is contained in:
parent
3dce134fe9
commit
3859e27839
24 changed files with 1069 additions and 628 deletions
|
@ -58,7 +58,7 @@ class BaseThemelet
|
|||
$tsize = get_thumbnail_size($image->width, $image->height);
|
||||
} else {
|
||||
//Use max thumbnail size if using thumbless filetype
|
||||
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
|
||||
$tsize = get_thumbnail_size($config->get_int(ImageConfig::THUMB_WIDTH), $config->get_int(ImageConfig::THUMB_WIDTH));
|
||||
}
|
||||
|
||||
$custom_classes = "";
|
||||
|
|
|
@ -463,7 +463,7 @@ class Image
|
|||
*/
|
||||
public function get_image_link(): string
|
||||
{
|
||||
return $this->get_link('image_ilink', '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext');
|
||||
return $this->get_link(ImageConfig::ILINK, '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -480,8 +480,8 @@ class Image
|
|||
public function get_thumb_link(): string
|
||||
{
|
||||
global $config;
|
||||
$ext = $config->get_string("thumb_type");
|
||||
return $this->get_link('image_tlink', '_thumbs/$hash/thumb.'.$ext, 'thumb/$id.'.$ext);
|
||||
$ext = $config->get_string(ImageConfig::THUMB_TYPE);
|
||||
return $this->get_link(ImageConfig::TLINK, '_thumbs/$hash/thumb.'.$ext, 'thumb/$id.'.$ext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,7 +512,7 @@ class Image
|
|||
public function get_tooltip(): string
|
||||
{
|
||||
global $config;
|
||||
$tt = $this->parse_link_template($config->get_string('image_tip'), "no_escape");
|
||||
$tt = $this->parse_link_template($config->get_string(ImageConfig::TIP), "no_escape");
|
||||
|
||||
// Removes the size tag if the file is an mp3
|
||||
if ($this->ext === 'mp3') {
|
||||
|
|
|
@ -125,24 +125,31 @@ function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_sca
|
|||
}
|
||||
|
||||
|
||||
if ($use_dpi_scaling) {
|
||||
$max_size = get_thumbnail_max_size_scaled();
|
||||
$max_width = $max_size[0];
|
||||
$max_height = $max_size[1];
|
||||
if($use_dpi_scaling) {
|
||||
list($max_width, $max_height) = get_thumbnail_max_size_scaled();
|
||||
} else {
|
||||
$max_width = $config->get_int('thumb_width');
|
||||
$max_height = $config->get_int('thumb_height');
|
||||
$max_width = $config->get_int(ImageConfig::THUMB_WIDTH);
|
||||
$max_height = $config->get_int(ImageConfig::THUMB_HEIGHT);
|
||||
}
|
||||
|
||||
$xscale = ($max_height / $orig_height);
|
||||
$yscale = ($max_width / $orig_width);
|
||||
$scale = ($xscale < $yscale) ? $xscale : $yscale;
|
||||
$output = get_scaled_by_aspect_ratio($orig_width, $orig_height, $max_width, $max_height);
|
||||
|
||||
if ($scale > 1 && $config->get_bool('thumb_upscale')) {
|
||||
if ($output[2] > 1 && $config->get_bool('thumb_upscale')) {
|
||||
return [(int)$orig_width, (int)$orig_height];
|
||||
} else {
|
||||
return [(int)($orig_width*$scale), (int)($orig_height*$scale)];
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function get_scaled_by_aspect_ratio(int $original_width, int $original_height, int $max_width, int $max_height) : array
|
||||
{
|
||||
$xscale = ($max_width/ $original_width);
|
||||
$yscale = ($max_height/ $original_height);
|
||||
|
||||
$scale = ($yscale < $xscale) ? $yscale : $xscale ;
|
||||
|
||||
return [(int)($original_width*$scale), (int)($original_height*$scale), $scale];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,355 +161,37 @@ function get_thumbnail_max_size_scaled(): array
|
|||
{
|
||||
global $config;
|
||||
|
||||
$scaling = $config->get_int("thumb_scaling");
|
||||
$max_width = $config->get_int('thumb_width') * ($scaling/100);
|
||||
$max_height = $config->get_int('thumb_height') * ($scaling/100);
|
||||
$scaling = $config->get_int(ImageConfig::THUMB_SCALING);
|
||||
$max_width = $config->get_int(ImageConfig::THUMB_WIDTH) * ($scaling/100);
|
||||
$max_height = $config->get_int(ImageConfig::THUMB_HEIGHT) * ($scaling/100);
|
||||
return [$max_width, $max_height];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a thumbnail file using ImageMagick's convert command.
|
||||
*
|
||||
* @param $hash
|
||||
* @param string $input_type Optional, allows specifying the input format. Usually not necessary.
|
||||
* @return bool true is successful, false if not.
|
||||
*/
|
||||
function create_thumbnail_convert($hash, $input_type = ""): bool
|
||||
{
|
||||
|
||||
function create_image_thumb(string $hash, string $type, string $engine = null) {
|
||||
global $config;
|
||||
|
||||
$inname = warehouse_path(Image::IMAGE_DIR, $hash);
|
||||
$outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
|
||||
$tsize = get_thumbnail_max_size_scaled();
|
||||
|
||||
$q = $config->get_int("thumb_quality");
|
||||
$convert = $config->get_string("thumb_convert_path");
|
||||
|
||||
if ($convert==null||$convert=="") {
|
||||
return false;
|
||||
if(empty($engine)) {
|
||||
$engine = $config->get_string(ImageConfig::THUMB_ENGINE);
|
||||
}
|
||||
|
||||
// ffff imagemagick fails sometimes, not sure why
|
||||
//$format = "'%s' '%s[0]' -format '%%[fx:w] %%[fx:h]' info:";
|
||||
//$cmd = sprintf($format, $convert, $inname);
|
||||
//$size = shell_exec($cmd);
|
||||
//$size = explode(" ", trim($size));
|
||||
list($w, $h) = get_thumbnail_max_size_scaled();
|
||||
|
||||
|
||||
// running the call with cmd.exe requires quoting for our paths
|
||||
$type = $config->get_string('thumb_type');
|
||||
|
||||
$options = "";
|
||||
if (!$config->get_bool('thumb_upscale')) {
|
||||
$options .= "\>";
|
||||
}
|
||||
|
||||
$bg = "black";
|
||||
if ($type=="webp") {
|
||||
$bg = "none";
|
||||
}
|
||||
if (!empty($input_type)) {
|
||||
$input_type = $input_type.":";
|
||||
}
|
||||
$format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s %s"%s[0]" %s:"%s" 2>&1';
|
||||
$cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg, $input_type, $inname, $type, $outname);
|
||||
$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) {
|
||||
log_warning('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret, outputting ".implode("\r\n", $output));
|
||||
} else {
|
||||
log_debug('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
}
|
||||
|
||||
if ($config->get_bool("thumb_optim", false)) {
|
||||
exec("jpegoptim $outname", $output, $ret);
|
||||
}
|
||||
|
||||
return true;
|
||||
send_event(new GraphicResizeEvent(
|
||||
$engine,
|
||||
$inname,
|
||||
$type,
|
||||
$outname,
|
||||
$tsize[0],
|
||||
$tsize[1],
|
||||
false,
|
||||
$config->get_string(ImageConfig::THUMB_TYPE),
|
||||
$config->get_int(ImageConfig::THUMB_QUALITY),
|
||||
true,
|
||||
$config->get_bool('thumb_upscale', false)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a thumbnail using ffmpeg.
|
||||
*
|
||||
* @param $hash
|
||||
* @return bool true if successful, false if not.
|
||||
*/
|
||||
function create_thumbnail_ffmpeg($hash): bool
|
||||
{
|
||||
global $config;
|
||||
|
||||
$ffmpeg = $config->get_string("thumb_ffmpeg_path");
|
||||
if ($ffmpeg==null||$ffmpeg=="") {
|
||||
return false;
|
||||
}
|
||||
|
||||
$inname = warehouse_path(Image::IMAGE_DIR, $hash);
|
||||
$outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
|
||||
|
||||
$orig_size = video_size($inname);
|
||||
$scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1], true);
|
||||
|
||||
$codec = "mjpeg";
|
||||
$quality = $config->get_int("thumb_quality");
|
||||
if ($config->get_string("thumb_type")=="webp") {
|
||||
$codec = "libwebp";
|
||||
} else {
|
||||
// mjpeg quality ranges from 2-31, with 2 being the best quality.
|
||||
$quality = floor(31 - (31 * ($quality/100)));
|
||||
if ($quality<2) {
|
||||
$quality = 2;
|
||||
}
|
||||
}
|
||||
|
||||
$args = [
|
||||
escapeshellarg($ffmpeg),
|
||||
"-y", "-i", escapeshellarg($inname),
|
||||
"-vf", "thumbnail,scale={$scaled_size[0]}:{$scaled_size[1]}",
|
||||
"-f", "image2",
|
||||
"-vframes", "1",
|
||||
"-c:v", $codec,
|
||||
"-q:v", $quality,
|
||||
escapeshellarg($outname),
|
||||
];
|
||||
|
||||
$cmd = escapeshellcmd(implode(" ", $args));
|
||||
|
||||
exec($cmd, $output, $ret);
|
||||
|
||||
if ((int)$ret == (int)0) {
|
||||
log_debug('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
return true;
|
||||
} else {
|
||||
log_error('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the dimensions of a video file using ffmpeg.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array [width, height]
|
||||
*/
|
||||
function video_size(string $filename): array
|
||||
{
|
||||
global $config;
|
||||
$ffmpeg = $config->get_string("thumb_ffmpeg_path");
|
||||
$cmd = escapeshellcmd(implode(" ", [
|
||||
escapeshellarg($ffmpeg),
|
||||
"-y", "-i", escapeshellarg($filename),
|
||||
"-vstats"
|
||||
]));
|
||||
$output = shell_exec($cmd . " 2>&1");
|
||||
// error_log("Getting size with `$cmd`");
|
||||
|
||||
$regex_sizes = "/Video: .* ([0-9]{1,4})x([0-9]{1,4})/";
|
||||
if (preg_match($regex_sizes, $output, $regs)) {
|
||||
if (preg_match("/displaymatrix: rotation of (90|270).00 degrees/", $output)) {
|
||||
$size = [$regs[2], $regs[1]];
|
||||
} else {
|
||||
$size = [$regs[1], $regs[2]];
|
||||
}
|
||||
} else {
|
||||
$size = [1, 1];
|
||||
}
|
||||
log_debug('imageboard/misc', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]");
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Memory usage limits
|
||||
*
|
||||
* Old check: $memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
|
||||
* New check: $memory_use = $width * $height * ($bits_per_channel) * channels * 2.5
|
||||
*
|
||||
* It didn't make sense to compute the memory usage based on the NEW size for the image. ($width*$height*4)
|
||||
* We need to consider the size that we are GOING TO instead.
|
||||
*
|
||||
* The factor of 2.5 is simply a rough guideline.
|
||||
* http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
|
||||
*
|
||||
* @param array $info The output of getimagesize() for the source file in question.
|
||||
* @return int The number of bytes an image resize operation is estimated to use.
|
||||
*/
|
||||
function calc_memory_use(array $info): int
|
||||
{
|
||||
if (isset($info['bits']) && isset($info['channels'])) {
|
||||
$memory_use = ($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels'] * 2.5) / 1024;
|
||||
} else {
|
||||
// If we don't have bits and channel info from the image then assume default values
|
||||
// of 8 bits per color and 4 channels (R,G,B,A) -- ie: regular 24-bit color
|
||||
$memory_use = ($info[0] * $info[1] * 1 * 4 * 2.5) / 1024;
|
||||
}
|
||||
return (int)$memory_use;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a resize operation on an image file using GD.
|
||||
*
|
||||
* @param String $image_filename The source file to be resized.
|
||||
* @param array $info The output of getimagesize() for the source file.
|
||||
* @param int $new_width
|
||||
* @param int $new_height
|
||||
* @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 ImageResizeException
|
||||
* @throws InsufficientMemoryException if the estimated memory usage exceeds the memory limit.
|
||||
*/
|
||||
function image_resize_gd(
|
||||
String $image_filename,
|
||||
array $info,
|
||||
int $new_width,
|
||||
int $new_height,
|
||||
string $output_filename,
|
||||
string $output_type=null,
|
||||
int $output_quality = 80
|
||||
) {
|
||||
$width = $info[0];
|
||||
$height = $info[1];
|
||||
|
||||
if ($output_type==null) {
|
||||
/* If not specified, output to the same format as the original image */
|
||||
switch ($info[2]) {
|
||||
case IMAGETYPE_GIF: $output_type = "gif"; break;
|
||||
case IMAGETYPE_JPEG: $output_type = "jpeg"; break;
|
||||
case IMAGETYPE_PNG: $output_type = "png"; break;
|
||||
case IMAGETYPE_WEBP: $output_type = "webp"; break;
|
||||
case IMAGETYPE_BMP: $output_type = "bmp"; break;
|
||||
default: throw new ImageResizeException("Failed to save the new image - Unsupported image type.");
|
||||
}
|
||||
}
|
||||
|
||||
$memory_use = calc_memory_use($info);
|
||||
$memory_limit = get_memory_limit();
|
||||
if ($memory_use > $memory_limit) {
|
||||
throw new InsufficientMemoryException("The image is too large to resize given the memory limits. ($memory_use > $memory_limit)");
|
||||
}
|
||||
|
||||
$image = imagecreatefromstring(file_get_contents($image_filename));
|
||||
$image_resized = imagecreatetruecolor($new_width, $new_height);
|
||||
try {
|
||||
if ($image===false) {
|
||||
throw new ImageResizeException("Could not load image: ".$image_filename);
|
||||
}
|
||||
if ($image_resized===false) {
|
||||
throw new ImageResizeException("Could not create output image with dimensions $new_width c $new_height ");
|
||||
}
|
||||
|
||||
// Handle transparent images
|
||||
switch ($info[2]) {
|
||||
case IMAGETYPE_GIF:
|
||||
$transparency = imagecolortransparent($image);
|
||||
$palletsize = imagecolorstotal($image);
|
||||
|
||||
// If we have a specific transparent color
|
||||
if ($transparency >= 0 && $transparency < $palletsize) {
|
||||
// Get the original image's transparent color's RGB values
|
||||
$transparent_color = imagecolorsforindex($image, $transparency);
|
||||
|
||||
// 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 ImageResizeException("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 ImageResizeException("Unable to fill new image with transparent color");
|
||||
}
|
||||
|
||||
// Set the background color for new image to transparent
|
||||
imagecolortransparent($image_resized, $transparency);
|
||||
}
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
case IMAGETYPE_WEBP:
|
||||
//
|
||||
// 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 ImageResizeException("Unable to disable image alpha blending");
|
||||
}
|
||||
if (imagesavealpha($image_resized, true)===false) {
|
||||
throw new ImageResizeException("Unable to enable image save alpha");
|
||||
}
|
||||
$transparent_color = imagecolorallocatealpha($image_resized, 255, 255, 255, 127);
|
||||
if ($transparent_color===false) {
|
||||
throw new ImageResizeException("Unable to allocate transparent color");
|
||||
}
|
||||
if (imagefilledrectangle($image_resized, 0, 0, $new_width, $new_height, $transparent_color)===false) {
|
||||
throw new ImageResizeException("Unable to fill new image with transparent color");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Actually resize the image.
|
||||
if (imagecopyresampled(
|
||||
$image_resized,
|
||||
$image,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$new_width,
|
||||
$new_height,
|
||||
$width,
|
||||
$height
|
||||
)===false) {
|
||||
throw new ImageResizeException("Unable to copy resized image data to new image");
|
||||
}
|
||||
|
||||
|
||||
switch ($output_type) {
|
||||
case "bmp":
|
||||
$result = imagebmp($image_resized, $output_filename, true);
|
||||
break;
|
||||
case "webp":
|
||||
$result = imagewebp($image_resized, $output_filename, $output_quality);
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
$result = imagejpeg($image_resized, $output_filename, $output_quality);
|
||||
break;
|
||||
case "png":
|
||||
$result = imagepng($image_resized, $output_filename, 9);
|
||||
break;
|
||||
case "gif":
|
||||
$result = imagegif($image_resized, $output_filename);
|
||||
break;
|
||||
default:
|
||||
throw new ImageResizeException("Failed to save the new image - Unsupported image type: $output_type");
|
||||
}
|
||||
if ($result==false) {
|
||||
throw new ImageResizeException("Failed to save the new image, function returned false when saving type: $output_type");
|
||||
}
|
||||
} finally {
|
||||
imagedestroy($image);
|
||||
imagedestroy($image_resized);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a file is an animated gif.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
function is_animated_gif(String $image_filename)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
return ($is_anim_gif == 0);
|
||||
}
|
||||
|
||||
function image_to_id(Image $image): int
|
||||
{
|
||||
return $image->id;
|
||||
}
|
||||
|
|
|
@ -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"); // 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,graphics"); // 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
|
||||
|
|
|
@ -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("thumb_mem_limit"));
|
||||
$shimmie_limit = parse_shorthand_int($config->get_int(GraphicsConfig::MEM_LIMIT));
|
||||
|
||||
if ($shimmie_limit < 3*1024*1024) {
|
||||
// we aren't going to fit, override
|
||||
|
|
|
@ -52,14 +52,17 @@ class ET extends Extension
|
|||
$info['sys_disk'] = to_shorthand_int(disk_total_space("./") - disk_free_space("./")) . " / " .
|
||||
to_shorthand_int(disk_total_space("./"));
|
||||
$info['sys_server'] = isset($_SERVER["SERVER_SOFTWARE"]) ? $_SERVER["SERVER_SOFTWARE"] : 'unknown';
|
||||
|
||||
$info['thumb_engine'] = $config->get_string("thumb_engine");
|
||||
$info['thumb_quality'] = $config->get_int('thumb_quality');
|
||||
$info['thumb_width'] = $config->get_int('thumb_width');
|
||||
$info['thumb_height'] = $config->get_int('thumb_height');
|
||||
$info['thumb_scaling'] = $config->get_int('thumb_scaling');
|
||||
$info['thumb_type'] = $config->get_string('thumb_type');
|
||||
$info['thumb_mem'] = $config->get_int("thumb_mem_limit");
|
||||
|
||||
$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[ImageConfig::THUMB_ENGINE] = $config->get_string(ImageConfig::THUMB_ENGINE);
|
||||
$info[ImageConfig::THUMB_QUALITY] = $config->get_int(ImageConfig::THUMB_QUALITY);
|
||||
$info[ImageConfig::THUMB_WIDTH] = $config->get_int(ImageConfig::THUMB_WIDTH);
|
||||
$info[ImageConfig::THUMB_HEIGHT] = $config->get_int(ImageConfig::THUMB_HEIGHT);
|
||||
$info[ImageConfig::THUMB_SCALING] = $config->get_int(ImageConfig::THUMB_SCALING);
|
||||
$info[ImageConfig::THUMB_TYPE] = $config->get_string(ImageConfig::THUMB_TYPE);
|
||||
|
||||
$info['stat_images'] = $database->get_one("SELECT COUNT(*) FROM images");
|
||||
$info['stat_comments'] = $database->get_one("SELECT COUNT(*) FROM comments");
|
||||
|
|
|
@ -35,14 +35,16 @@ Database: {$info['sys_db']}
|
|||
Server: {$info['sys_server']}
|
||||
Disk use: {$info['sys_disk']}
|
||||
|
||||
Graphics System:
|
||||
Memory Limit: {$info[GraphicsConfig::MEM_LIMIT]}
|
||||
|
||||
Thumbnail Generation:
|
||||
Engine: {$info['thumb_engine']}
|
||||
Type: {$info['thumb_type']}
|
||||
Memory: {$info['thumb_mem']}
|
||||
Quality: {$info['thumb_quality']}
|
||||
Width: {$info['thumb_width']}
|
||||
Height: {$info['thumb_height']}
|
||||
Scaling: {$info['thumb_scaling']}
|
||||
Engine: {$info[ImageConfig::THUMB_ENGINE]}
|
||||
Type: {$info[ImageConfig::THUMB_TYPE]}
|
||||
Quality: {$info[ImageConfig::THUMB_QUALITY]}
|
||||
Width: {$info[ImageConfig::THUMB_WIDTH]}
|
||||
Height: {$info[ImageConfig::THUMB_HEIGHT]}
|
||||
Scaling: {$info[ImageConfig::THUMB_SCALING]}
|
||||
|
||||
Shimmie stats:
|
||||
Images: {$info['stat_images']}
|
||||
|
|
808
ext/graphics/main.php
Normal file
808
ext/graphics/main.php
Normal file
|
@ -0,0 +1,808 @@
|
|||
<?php
|
||||
/*
|
||||
* Name: Graphics
|
||||
* Author: Matthew Barbour <matthew@darkholme.net>
|
||||
* Description: Provides common functions and settings used for graphic operations.
|
||||
* License: MIT
|
||||
* Version: 1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is used by the graphics code when there is an error
|
||||
*/
|
||||
|
||||
use FFMpeg\FFMpeg;
|
||||
|
||||
abstract class GraphicsConfig
|
||||
{
|
||||
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';
|
||||
|
||||
}
|
||||
|
||||
class GraphicsException extends SCoreException
|
||||
{
|
||||
}
|
||||
|
||||
class GraphicResizeEvent extends Event
|
||||
{
|
||||
public $engine;
|
||||
public $input_path;
|
||||
public $input_type;
|
||||
public $output_path;
|
||||
public $target_format;
|
||||
public $target_width;
|
||||
public $target_height;
|
||||
public $target_quality;
|
||||
public $minimize;
|
||||
public $ignore_aspect_ratio;
|
||||
public $allow_upscale;
|
||||
|
||||
public function __construct(String $engine, string $input_path, string $input_type, string $output_path,
|
||||
int $target_width, int $target_height,
|
||||
bool $ignore_aspect_ratio = false,
|
||||
string $target_format = null,
|
||||
int $target_quality = 80,
|
||||
bool $minimize = false,
|
||||
bool $allow_upscale = true)
|
||||
{
|
||||
assert(in_array($engine, Graphics::GRAPHICS_ENGINES));
|
||||
$this->engine = $engine;
|
||||
$this->input_path = $input_path;
|
||||
$this->input_type = $input_type;
|
||||
$this->output_path = $output_path;
|
||||
$this->target_height = $target_height;
|
||||
$this->target_width = $target_width;
|
||||
$this->target_format = $target_format;
|
||||
$this->target_quality = $target_quality;
|
||||
$this->minimize = $minimize;
|
||||
$this->ignore_aspect_ratio = $ignore_aspect_ratio;
|
||||
$this->allow_upscale = $allow_upscale;
|
||||
}
|
||||
}
|
||||
|
||||
class Graphics extends Extension
|
||||
{
|
||||
const WEBP_LOSSY = "webp-lossy";
|
||||
const WEBP_LOSSLESS = "webp-lossless";
|
||||
|
||||
const FFMPEG_ENGINE = "ffmpeg";
|
||||
const GD_ENGINE = "gd";
|
||||
const IMAGICK_ENGINE = "convert";
|
||||
|
||||
const GRAPHICS_ENGINES = [
|
||||
self::GD_ENGINE,
|
||||
self::FFMPEG_ENGINE,
|
||||
self::IMAGICK_ENGINE
|
||||
];
|
||||
|
||||
const IMAGE_GRAPHICS_ENGINES = [
|
||||
"GD" => self::GD_ENGINE,
|
||||
"ImageMagick" => self::IMAGICK_ENGINE,
|
||||
];
|
||||
|
||||
const ENGINE_INPUT_SUPPORT = [
|
||||
self::GD_ENGINE => [
|
||||
"bmp",
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"webp",
|
||||
],
|
||||
self::IMAGICK_ENGINE => [
|
||||
"bmp",
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"psd",
|
||||
"tiff",
|
||||
"webp",
|
||||
"ico",
|
||||
],
|
||||
self::FFMPEG_ENGINE => [
|
||||
"avi",
|
||||
"mkv",
|
||||
"webm",
|
||||
"mp4",
|
||||
"mov",
|
||||
"flv"
|
||||
]
|
||||
];
|
||||
|
||||
const ENGINE_OUTPUT_SUPPORT = [
|
||||
self::GD_ENGINE => [
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"webp",
|
||||
self::WEBP_LOSSY,
|
||||
],
|
||||
self::IMAGICK_ENGINE => [
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"webp",
|
||||
self::WEBP_LOSSY,
|
||||
self::WEBP_LOSSLESS,
|
||||
],
|
||||
self::FFMPEG_ENGINE => [
|
||||
|
||||
]
|
||||
];
|
||||
|
||||
const LOSSLESS_FORMATS = [
|
||||
self::WEBP_LOSSLESS,
|
||||
"png",
|
||||
];
|
||||
|
||||
const ALPHA_FORMATS = [
|
||||
self::WEBP_LOSSLESS,
|
||||
self::WEBP_LOSSY,
|
||||
"png",
|
||||
];
|
||||
|
||||
const FORMAT_ALIASES = [
|
||||
"tif" => "tiff",
|
||||
"jpeg" => "jpg",
|
||||
];
|
||||
|
||||
|
||||
static function imagick_available(): bool
|
||||
{
|
||||
return extension_loaded("imagick");
|
||||
}
|
||||
|
||||
/**
|
||||
* High priority just so that it can be early in the settings
|
||||
*/
|
||||
public function get_priority(): int
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_string(GraphicsConfig::FFPROBE_PATH, 'ffprobe');
|
||||
|
||||
|
||||
if ($config->get_int(GraphicsConfig::VERSION) < 1) {
|
||||
$current_value = $config->get_string("thumb_ffmpeg_path");
|
||||
if(!empty($current_value)) {
|
||||
$config->set_string(GraphicsConfig::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');
|
||||
}
|
||||
} else {
|
||||
$config->set_default_string(GraphicsConfig::FFMPEG_PATH, '');
|
||||
}
|
||||
|
||||
$current_value = $config->get_string("thumb_convert_path");
|
||||
if(!empty($current_value)) {
|
||||
$config->set_string(GraphicsConfig::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');
|
||||
}
|
||||
} else {
|
||||
$config->set_default_string(GraphicsConfig::CONVERT_PATH, '');
|
||||
}
|
||||
|
||||
$current_value = $config->get_int("thumb_mem_limit");
|
||||
if(!empty($current_value)) {
|
||||
$config->set_int(GraphicsConfig::MEM_LIMIT, $current_value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$config->set_int(GraphicsConfig::VERSION, 1);
|
||||
log_info("graphics", "extension installed");
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
{
|
||||
$sb = new SetupBlock("Graphics");
|
||||
|
||||
// if (self::imagick_available()) {
|
||||
// try {
|
||||
// $image = new Imagick(realpath('tests/favicon.png'));
|
||||
// $image->clear();
|
||||
// $sb->add_label("ImageMagick detected");
|
||||
// } catch (ImagickException $e) {
|
||||
// $sb->add_label("<b style='color:red'>ImageMagick not detected</b>");
|
||||
// }
|
||||
// } else {
|
||||
$sb->add_text_option(GraphicsConfig::CONVERT_PATH, "convert command: ");
|
||||
// }
|
||||
|
||||
$sb->add_text_option(GraphicsConfig::FFMPEG_PATH, "<br/>ffmpeg command: ");
|
||||
|
||||
$sb->add_shorthand_int_option(GraphicsConfig::MEM_LIMIT, "<br />Max memory use: ");
|
||||
|
||||
$event->panel->add_block($sb);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GraphicResizeEvent $event
|
||||
* @throws GraphicsException
|
||||
* @throws InsufficientMemoryException
|
||||
*/
|
||||
public function onGraphicResize(GraphicResizeEvent $event)
|
||||
{
|
||||
switch ($event->engine) {
|
||||
case self::GD_ENGINE:
|
||||
$info = getimagesize($event->input_path);
|
||||
if ($info === false) {
|
||||
throw new GraphicsException("getimagesize failed for " . $event->input_path);
|
||||
}
|
||||
|
||||
self::image_resize_gd(
|
||||
$event->input_path,
|
||||
$info,
|
||||
$event->target_width,
|
||||
$event->target_height,
|
||||
$event->output_path,
|
||||
$event->target_format,
|
||||
$event->ignore_aspect_ratio,
|
||||
$event->target_quality,
|
||||
$event->allow_upscale);
|
||||
|
||||
break;
|
||||
case self::IMAGICK_ENGINE:
|
||||
// if (self::imagick_available()) {
|
||||
// } else {
|
||||
self::image_resize_convert(
|
||||
$event->input_path,
|
||||
$event->input_type,
|
||||
$event->target_width,
|
||||
$event->target_height,
|
||||
$event->output_path,
|
||||
$event->target_format,
|
||||
$event->ignore_aspect_ratio,
|
||||
$event->target_quality,
|
||||
$event->minimize,
|
||||
$event->allow_upscale);
|
||||
//}
|
||||
break;
|
||||
default:
|
||||
throw new GraphicsException("Engine not supported for resize: " . $event->engine);
|
||||
}
|
||||
|
||||
// TODO: Get output optimization tools working better
|
||||
// if ($config->get_bool("thumb_optim", false)) {
|
||||
// exec("jpegoptim $outname", $output, $ret);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Memory usage limits
|
||||
*
|
||||
* Old check: $memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
|
||||
* New check: $memory_use = $width * $height * ($bits_per_channel) * channels * 2.5
|
||||
*
|
||||
* It didn't make sense to compute the memory usage based on the NEW size for the image. ($width*$height*4)
|
||||
* We need to consider the size that we are GOING TO instead.
|
||||
*
|
||||
* The factor of 2.5 is simply a rough guideline.
|
||||
* http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
|
||||
*
|
||||
* @param array $info The output of getimagesize() for the source file in question.
|
||||
* @return int The number of bytes an image resize operation is estimated to use.
|
||||
*/
|
||||
static function calc_memory_use(array $info): int
|
||||
{
|
||||
if (isset($info['bits']) && isset($info['channels'])) {
|
||||
$memory_use = ($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels'] * 2.5) / 1024;
|
||||
} else {
|
||||
// If we don't have bits and channel info from the image then assume default values
|
||||
// of 8 bits per color and 4 channels (R,G,B,A) -- ie: regular 24-bit color
|
||||
$memory_use = ($info[0] * $info[1] * 1 * 4 * 2.5) / 1024;
|
||||
}
|
||||
return (int)$memory_use;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a thumbnail using ffmpeg.
|
||||
*
|
||||
* @param $hash
|
||||
* @return bool true if successful, false if not.
|
||||
* @throws GraphicsException
|
||||
*/
|
||||
static function create_thumbnail_ffmpeg($hash): bool
|
||||
{
|
||||
global $config;
|
||||
|
||||
$ffmpeg = $config->get_string(GraphicsConfig::FFMPEG_PATH);
|
||||
if ($ffmpeg == null || $ffmpeg == "") {
|
||||
throw new GraphicsException("ffmpeg command configured");
|
||||
}
|
||||
|
||||
$inname = warehouse_path(Image::IMAGE_DIR, $hash);
|
||||
$outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
|
||||
|
||||
$orig_size = self::video_size($inname);
|
||||
$scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1], true);
|
||||
|
||||
$codec = "mjpeg";
|
||||
$quality = $config->get_int(ImageConfig::THUMB_QUALITY);
|
||||
if ($config->get_string(ImageConfig::THUMB_TYPE) == "webp") {
|
||||
$codec = "libwebp";
|
||||
} else {
|
||||
// mjpeg quality ranges from 2-31, with 2 being the best quality.
|
||||
$quality = floor(31 - (31 * ($quality / 100)));
|
||||
if ($quality < 2) {
|
||||
$quality = 2;
|
||||
}
|
||||
}
|
||||
|
||||
$args = [
|
||||
escapeshellarg($ffmpeg),
|
||||
"-y", "-i", escapeshellarg($inname),
|
||||
"-vf", "thumbnail,scale={$scaled_size[0]}:{$scaled_size[1]}",
|
||||
"-f", "image2",
|
||||
"-vframes", "1",
|
||||
"-c:v", $codec,
|
||||
"-q:v", $quality,
|
||||
escapeshellarg($outname),
|
||||
];
|
||||
|
||||
$cmd = escapeshellcmd(implode(" ", $args));
|
||||
|
||||
exec($cmd, $output, $ret);
|
||||
|
||||
if ((int)$ret == (int)0) {
|
||||
log_debug('graphics', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
return true;
|
||||
} else {
|
||||
log_error('graphics', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function determine_ext(String $format): String
|
||||
{
|
||||
$format = self::normalize_format($format);
|
||||
switch ($format) {
|
||||
case self::WEBP_LOSSLESS:
|
||||
case self::WEBP_LOSSY:
|
||||
return "webp";
|
||||
default:
|
||||
return $format;
|
||||
}
|
||||
}
|
||||
|
||||
// private static function image_save_imagick(Imagick $image, string $path, string $format, int $output_quality = 80, bool $minimize)
|
||||
// {
|
||||
// switch ($format) {
|
||||
// case "png":
|
||||
// $result = $image->setOption('png:compression-level', 9);
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not set png compression option");
|
||||
// }
|
||||
// break;
|
||||
// case Graphics::WEBP_LOSSLESS:
|
||||
// $result = $image->setOption('webp:lossless', true);
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not set lossless webp option");
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// $result = $image->setImageCompressionQuality($output_quality);
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not set compression quality for $path to $output_quality");
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// if (self::supports_alpha($format)) {
|
||||
// $result = $image->setImageBackgroundColor(new \ImagickPixel('transparent'));
|
||||
// } else {
|
||||
// $result = $image->setImageBackgroundColor(new \ImagickPixel('black'));
|
||||
// }
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not set background color");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if ($minimize) {
|
||||
// $profiles = $image->getImageProfiles("icc", true);
|
||||
// $result = $image->stripImage();
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not strip information from image");
|
||||
// }
|
||||
// if (!empty($profiles)) {
|
||||
// $image->profileImage("icc", $profiles['icc']);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// $ext = self::determine_ext($format);
|
||||
//
|
||||
// $result = $image->writeImage($ext . ":" . $path);
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not write image to $path");
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static function image_resize_imagick(
|
||||
// String $input_path,
|
||||
// String $input_type,
|
||||
// int $new_width,
|
||||
// int $new_height,
|
||||
// string $output_filename,
|
||||
// string $output_type = null,
|
||||
// bool $ignore_aspect_ratio = false,
|
||||
// int $output_quality = 80,
|
||||
// bool $minimize = false,
|
||||
// bool $allow_upscale = true
|
||||
// ): void
|
||||
// {
|
||||
// global $config;
|
||||
//
|
||||
// if (!empty($input_type)) {
|
||||
// $input_type = self::determine_ext($input_type);
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// $image = new Imagick($input_type . ":" . $input_path);
|
||||
// try {
|
||||
// $result = $image->flattenImages();
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not flatten image $input_path");
|
||||
// }
|
||||
//
|
||||
// $height = $image->getImageHeight();
|
||||
// $width = $image->getImageWidth();
|
||||
// if (!$allow_upscale &&
|
||||
// ($new_width > $width || $new_height > $height)) {
|
||||
// $new_height = $height;
|
||||
// $new_width = $width;
|
||||
// }
|
||||
//
|
||||
// $result = $image->resizeImage($new_width, $new_width, Imagick::FILTER_LANCZOS, 0, !$ignore_aspect_ratio);
|
||||
// if ($result !== true) {
|
||||
// throw new GraphicsException("Could not perform image resize on $input_path");
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if (empty($output_type)) {
|
||||
// $output_type = $input_type;
|
||||
// }
|
||||
//
|
||||
// self::image_save_imagick($image, $output_filename, $output_type, $output_quality);
|
||||
//
|
||||
// } finally {
|
||||
// $image->destroy();
|
||||
// }
|
||||
// } catch (ImagickException $e) {
|
||||
// throw new GraphicsException("Error while resizing with Imagick: " . $e->getMessage(), $e->getCode(), $e);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
public static function image_resize_convert(
|
||||
String $input_path,
|
||||
String $input_type,
|
||||
int $new_width,
|
||||
int $new_height,
|
||||
string $output_filename,
|
||||
string $output_type = null,
|
||||
bool $ignore_aspect_ratio = false,
|
||||
int $output_quality = 80,
|
||||
bool $minimize = false,
|
||||
bool $allow_upscale = true
|
||||
): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
$convert = $config->get_string(GraphicsConfig::CONVERT_PATH);
|
||||
|
||||
if ($convert == null || $convert == "") {
|
||||
throw new GraphicsException("convert command not configured");
|
||||
}
|
||||
|
||||
if (empty($output_type)) {
|
||||
$output_type = $input_type;
|
||||
}
|
||||
|
||||
$bg = "black";
|
||||
if (self::supports_alpha($output_type)) {
|
||||
$bg = "none";
|
||||
}
|
||||
if (!empty($input_type)) {
|
||||
$input_type = $input_type . ":";
|
||||
}
|
||||
$args = "";
|
||||
if ($minimize) {
|
||||
$args = " -strip -thumbnail";
|
||||
}
|
||||
|
||||
$resize_args = "";
|
||||
if (!$allow_upscale) {
|
||||
$resize_args .= "\>";
|
||||
}
|
||||
if ($ignore_aspect_ratio) {
|
||||
$resize_args .= "\!";
|
||||
}
|
||||
|
||||
$format = '"%s" -flatten %s %ux%u%s -quality %u -background %s %s"%s[0]" %s:"%s" 2>&1';
|
||||
$cmd = sprintf($format, $convert, $args, $new_width, $new_height, $resize_args, $output_quality, $bg, $input_type, $input_path, $output_type, $output_filename);
|
||||
$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));
|
||||
} else {
|
||||
log_debug('graphics', "Generating thumbnail with command `$cmd`, returns $ret");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a resize operation on an image file using GD.
|
||||
*
|
||||
* @param String $image_filename The source file to be resized.
|
||||
* @param array $info The output of getimagesize() for the source file.
|
||||
* @param int $new_width
|
||||
* @param int $new_height
|
||||
* @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 InsufficientMemoryException if the estimated memory usage exceeds the memory limit.
|
||||
*/
|
||||
public static function image_resize_gd(
|
||||
String $image_filename,
|
||||
array $info,
|
||||
int $new_width,
|
||||
int $new_height,
|
||||
string $output_filename,
|
||||
string $output_type = null,
|
||||
bool $ignore_aspect_ratio = false,
|
||||
int $output_quality = 80,
|
||||
bool $allow_upscale = true
|
||||
)
|
||||
{
|
||||
$width = $info[0];
|
||||
$height = $info[1];
|
||||
|
||||
if ($output_type == null) {
|
||||
/* If not specified, output to the same format as the original image */
|
||||
switch ($info[2]) {
|
||||
case IMAGETYPE_GIF:
|
||||
$output_type = "gif";
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
$output_type = "jpeg";
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$output_type = "png";
|
||||
break;
|
||||
case IMAGETYPE_WEBP:
|
||||
$output_type = "webp";
|
||||
break;
|
||||
case IMAGETYPE_BMP:
|
||||
$output_type = "bmp";
|
||||
break;
|
||||
default:
|
||||
throw new GraphicsException("Failed to save the new image - Unsupported image type.");
|
||||
}
|
||||
}
|
||||
|
||||
$memory_use = self::calc_memory_use($info);
|
||||
$memory_limit = get_memory_limit();
|
||||
if ($memory_use > $memory_limit) {
|
||||
throw new InsufficientMemoryException("The image is too large to resize given the memory limits. ($memory_use > $memory_limit)");
|
||||
}
|
||||
|
||||
if (!$ignore_aspect_ratio) {
|
||||
list($new_width, $new_height) = get_scaled_by_aspect_ratio($width, $height, $new_width, $new_height);
|
||||
}
|
||||
if (!$allow_upscale &&
|
||||
($new_width > $width || $new_height > $height)) {
|
||||
$new_height = $height;
|
||||
$new_width = $width;
|
||||
}
|
||||
|
||||
$image = imagecreatefromstring(file_get_contents($image_filename));
|
||||
$image_resized = imagecreatetruecolor($new_width, $new_height);
|
||||
try {
|
||||
if ($image === false) {
|
||||
throw new GraphicsException("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 ");
|
||||
}
|
||||
|
||||
// Handle transparent images
|
||||
switch ($info[2]) {
|
||||
case IMAGETYPE_GIF:
|
||||
$transparency = imagecolortransparent($image);
|
||||
$pallet_size = imagecolorstotal($image);
|
||||
|
||||
// If we have a specific transparent color
|
||||
if ($transparency >= 0 && $transparency < $pallet_size) {
|
||||
// Get the original image's transparent color's RGB values
|
||||
$transparent_color = imagecolorsforindex($image, $transparency);
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Set the background color for new image to transparent
|
||||
imagecolortransparent($image_resized, $transparency);
|
||||
}
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
case IMAGETYPE_WEBP:
|
||||
//
|
||||
// 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");
|
||||
}
|
||||
if (imagesavealpha($image_resized, true) === false) {
|
||||
throw new GraphicsException("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");
|
||||
}
|
||||
if (imagefilledrectangle($image_resized, 0, 0, $new_width, $new_height, $transparent_color) === false) {
|
||||
throw new GraphicsException("Unable to fill new image with transparent color");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Actually resize the image.
|
||||
if (imagecopyresampled(
|
||||
$image_resized,
|
||||
$image,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$new_width,
|
||||
$new_height,
|
||||
$width,
|
||||
$height
|
||||
) === false) {
|
||||
throw new GraphicsException("Unable to copy resized image data to new image");
|
||||
}
|
||||
|
||||
switch ($output_type) {
|
||||
case "bmp":
|
||||
$result = imagebmp($image_resized, $output_filename, true);
|
||||
break;
|
||||
case "webp":
|
||||
case Graphics::WEBP_LOSSY:
|
||||
$result = imagewebp($image_resized, $output_filename, $output_quality);
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
$result = imagejpeg($image_resized, $output_filename, $output_quality);
|
||||
break;
|
||||
case "png":
|
||||
$result = imagepng($image_resized, $output_filename, 9);
|
||||
break;
|
||||
case "gif":
|
||||
$result = imagegif($image_resized, $output_filename);
|
||||
break;
|
||||
default:
|
||||
throw new GraphicsException("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");
|
||||
}
|
||||
} finally {
|
||||
@imagedestroy($image);
|
||||
@imagedestroy($image_resized);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a file is an animated gif.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
return ($is_anim_gif == 0);
|
||||
}
|
||||
|
||||
public static function supports_alpha(string $format)
|
||||
{
|
||||
return in_array(self::normalize_format($format), self::ALPHA_FORMATS);
|
||||
}
|
||||
|
||||
public static function is_input_supported($engine, $format): bool
|
||||
{
|
||||
$format = self::normalize_format($format);
|
||||
if (!in_array($format, Graphics::ENGINE_INPUT_SUPPORT[$engine])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function is_output_supported($engine, $format): bool
|
||||
{
|
||||
$format = self::normalize_format($format);
|
||||
if (!in_array($format, Graphics::ENGINE_OUTPUT_SUPPORT[$engine])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* otherwise the incoming format is returned.
|
||||
*
|
||||
* @param $format
|
||||
* @return string|null The format name that the graphics extension will recognize.
|
||||
*/
|
||||
static public function normalize_format($format): ?string
|
||||
{
|
||||
if (array_key_exists($format, Graphics::FORMAT_ALIASES)) {
|
||||
return self::FORMAT_ALIASES[$format];
|
||||
}
|
||||
return $format;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the dimensions of a video file using ffmpeg.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array [width, height]
|
||||
*/
|
||||
static public function video_size(string $filename): array
|
||||
{
|
||||
global $config;
|
||||
$ffmpeg = $config->get_string(GraphicsConfig::FFMPEG_PATH);
|
||||
$cmd = escapeshellcmd(implode(" ", [
|
||||
escapeshellarg($ffmpeg),
|
||||
"-y", "-i", escapeshellarg($filename),
|
||||
"-vstats"
|
||||
]));
|
||||
$output = shell_exec($cmd . " 2>&1");
|
||||
// error_log("Getting size with `$cmd`");
|
||||
|
||||
$regex_sizes = "/Video: .* ([0-9]{1,4})x([0-9]{1,4})/";
|
||||
if (preg_match($regex_sizes, $output, $regs)) {
|
||||
if (preg_match("/displaymatrix: rotation of (90|270).00 degrees/", $output)) {
|
||||
$size = [$regs[2], $regs[1]];
|
||||
} else {
|
||||
$size = [$regs[1], $regs[2]];
|
||||
}
|
||||
} else {
|
||||
$size = [1, 1];
|
||||
}
|
||||
log_debug('graphics', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]");
|
||||
return $size;
|
||||
}
|
||||
|
||||
}
|
6
ext/graphics/theme.php
Normal file
6
ext/graphics/theme.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
class GraphicsTheme extends Themelet
|
||||
{
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ class FlashFileHandler extends DataHandlerExtension
|
|||
{
|
||||
global $config;
|
||||
|
||||
if (!create_thumbnail_ffmpeg($hash)) {
|
||||
if (!Graphics::create_thumbnail_ffmpeg($hash)) {
|
||||
copy("ext/handle_flash/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash));
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -56,6 +56,12 @@ class IcoFileHandler extends DataHandlerExtension
|
|||
|
||||
protected function create_thumb(string $hash, string $type): bool
|
||||
{
|
||||
return create_thumbnail_convert($hash, $type);
|
||||
try {
|
||||
create_image_thumb($hash, $type, Graphics::IMAGICK_ENGINE);
|
||||
return true;
|
||||
} catch (GraphicsException $e) {
|
||||
log_warning("handle_ico", "Could not generate thumbnail. " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,24 +56,22 @@ class PixelFileHandler extends DataHandlerExtension
|
|||
|
||||
protected function create_thumb(string $hash, string $type): bool
|
||||
{
|
||||
global $config;
|
||||
|
||||
$inname = warehouse_path(Image::IMAGE_DIR, $hash);
|
||||
$outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
|
||||
|
||||
$ok = false;
|
||||
|
||||
switch ($config->get_string("thumb_engine")) {
|
||||
default:
|
||||
case 'gd':
|
||||
$ok = $this->make_thumb_gd($inname, $outname);
|
||||
break;
|
||||
case 'convert':
|
||||
$ok = create_thumbnail_convert($hash);
|
||||
break;
|
||||
try {
|
||||
create_image_thumb($hash, $type);
|
||||
return true;
|
||||
} catch (InsufficientMemoryException $e) {
|
||||
$tsize = get_thumbnail_max_size_scaled();
|
||||
$thumb = imagecreatetruecolor($tsize[0], min($tsize[1], 64));
|
||||
$white = imagecolorallocate($thumb, 255, 255, 255);
|
||||
$black = imagecolorallocate($thumb, 0, 0, 0);
|
||||
imagefill($thumb, 0, 0, $white);
|
||||
log_warning("handle_pixel", "Insufficient memory while creating thumbnail: ".$e->getMessage());
|
||||
imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
log_error("handle_pixel", "Error while creating thumbnail: ".$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||
|
@ -90,38 +88,4 @@ class PixelFileHandler extends DataHandlerExtension
|
|||
", 20);
|
||||
}
|
||||
|
||||
// GD thumber {{{
|
||||
private function make_thumb_gd(string $inname, string $outname): bool
|
||||
{
|
||||
global $config;
|
||||
|
||||
try {
|
||||
$info = getimagesize($inname);
|
||||
$tsize = get_thumbnail_size($info[0], $info[1], true);
|
||||
$image = image_resize_gd(
|
||||
$inname,
|
||||
$info,
|
||||
$tsize[0],
|
||||
$tsize[1],
|
||||
$outname,
|
||||
$config->get_string('thumb_type'),
|
||||
$config->get_int('thumb_quality')
|
||||
);
|
||||
} catch (InsufficientMemoryException $e) {
|
||||
$tsize = get_thumbnail_max_size_scaled();
|
||||
$thumb = imagecreatetruecolor($tsize[0], min($tsize[1], 64));
|
||||
$white = imagecolorallocate($thumb, 255, 255, 255);
|
||||
$black = imagecolorallocate($thumb, 0, 0, 0);
|
||||
imagefill($thumb, 0, 0, $white);
|
||||
log_warning("handle_pixel", "Insufficient memory while creating thumbnail: ".$e->getMessage());
|
||||
imagestring($thumb, 5, 10, 24, "Image Too Large :(", $black);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
log_error("handle_pixel", "Error while creating thumbnail: ".$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ class PixelFileHandlerTheme extends Themelet
|
|||
global $config;
|
||||
|
||||
$u_ilink = $image->get_image_link();
|
||||
if ($config->get_bool("image_show_meta") && function_exists("exif_read_data")) {
|
||||
if ($config->get_bool(ImageConfig::SHOW_META) && function_exists(ImageIO::EXIF_READ_FUNCTION)) {
|
||||
# FIXME: only read from jpegs?
|
||||
$exif = @exif_read_data($image->get_image_filename(), 0, true);
|
||||
if ($exif) {
|
||||
|
|
|
@ -35,10 +35,14 @@ class SVGFileHandler extends DataHandlerExtension
|
|||
|
||||
protected function create_thumb(string $hash, string $type): bool
|
||||
{
|
||||
if (!create_thumbnail_convert($hash)) {
|
||||
try {
|
||||
create_image_thumb($hash, $type, Graphics::IMAGICK_ENGINE);
|
||||
return true;
|
||||
} catch (GraphicsException $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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onDisplayingImage(DisplayingImageEvent $event)
|
||||
|
|
|
@ -16,20 +16,21 @@
|
|||
|
||||
class VideoFileHandler extends DataHandlerExtension
|
||||
{
|
||||
const SUPPORTED_MIME = [
|
||||
'video/webm',
|
||||
'video/mp4',
|
||||
'video/ogg',
|
||||
'video/flv',
|
||||
'video/x-flv'
|
||||
];
|
||||
const SUPPORTED_EXT = ["flv", "mp4", "m4v", "ogv", "webm"];
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
{
|
||||
global $config;
|
||||
|
||||
if ($config->get_int("ext_handle_video_version") < 1) {
|
||||
if ($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('thumb_ffmpeg_path', 'ffmpeg');
|
||||
}
|
||||
} else {
|
||||
$config->set_default_string('thumb_ffmpeg_path', '');
|
||||
}
|
||||
|
||||
// This used to set the ffmpeg path. It does not do this anymore, that is now in the base graphic extension.
|
||||
$config->set_int("ext_handle_video_version", 1);
|
||||
log_info("handle_video", "extension installed");
|
||||
}
|
||||
|
@ -41,9 +42,6 @@ class VideoFileHandler extends DataHandlerExtension
|
|||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
{
|
||||
$sb = new SetupBlock("Video Options");
|
||||
$sb->add_label("<br>Path to ffmpeg: ");
|
||||
$sb->add_text_option("thumb_ffmpeg_path");
|
||||
$sb->add_label("<br>");
|
||||
$sb->add_bool_option("video_playback_autoplay", "Autoplay: ");
|
||||
$sb->add_label("<br>");
|
||||
$sb->add_bool_option("video_playback_loop", "Loop: ");
|
||||
|
@ -55,20 +53,19 @@ class VideoFileHandler extends DataHandlerExtension
|
|||
*/
|
||||
protected function create_thumb(string $hash, string $type): bool
|
||||
{
|
||||
return create_thumbnail_ffmpeg($hash);
|
||||
return Graphics::create_thumbnail_ffmpeg($hash);
|
||||
}
|
||||
|
||||
protected function supported_ext(string $ext): bool
|
||||
{
|
||||
$exts = ["flv", "mp4", "m4v", "ogv", "webm"];
|
||||
return in_array(strtolower($ext), $exts);
|
||||
return in_array(strtolower($ext), self::SUPPORTED_EXT);
|
||||
}
|
||||
|
||||
protected function create_image_from_data(string $filename, array $metadata): Image
|
||||
{
|
||||
$image = new Image();
|
||||
|
||||
$size = video_size($filename);
|
||||
$size = Graphics::video_size($filename);
|
||||
$image->width = $size[0];
|
||||
$image->height = $size[1];
|
||||
|
||||
|
@ -103,13 +100,7 @@ class VideoFileHandler extends DataHandlerExtension
|
|||
{
|
||||
return (
|
||||
file_exists($tmpname) &&
|
||||
in_array(getMimeType($tmpname), [
|
||||
'video/webm',
|
||||
'video/mp4',
|
||||
'video/ogg',
|
||||
'video/flv',
|
||||
'video/x-flv'
|
||||
])
|
||||
in_array(getMimeType($tmpname), self::SUPPORTED_MIME)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,30 +9,64 @@
|
|||
*/
|
||||
|
||||
|
||||
abstract class ImageConfig {
|
||||
const THUMB_ENGINE = 'thumb_engine';
|
||||
const THUMB_WIDTH = 'thumb_width';
|
||||
const THUMB_HEIGHT = 'thumb_height';
|
||||
const THUMB_SCALING = 'thumb_scaling';
|
||||
const THUMB_QUALITY = 'thumb_quality';
|
||||
const THUMB_TYPE = 'thumb_type';
|
||||
|
||||
const SHOW_META = 'image_show_meta';
|
||||
const ILINK = 'image_ilink';
|
||||
const TLINK = 'image_tlink';
|
||||
const TIP = 'image_tip';
|
||||
const EXPIRES = 'image_expires';
|
||||
const UPLOAD_COLLISION_HANDLER = 'upload_collision_handler';
|
||||
|
||||
const COLLISION_MERGE = 'merge';
|
||||
const COLLISION_ERROR = 'error';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to handle adding / getting / removing image files from the disk.
|
||||
*/
|
||||
class ImageIO extends Extension
|
||||
{
|
||||
|
||||
const COLLISION_OPTIONS = ['Error'=>ImageConfig::COLLISION_ERROR, 'Merge'=>ImageConfig::COLLISION_MERGE];
|
||||
|
||||
const EXIF_READ_FUNCTION = "exif_read_data";
|
||||
|
||||
|
||||
const THUMBNAIL_ENGINES = [
|
||||
'Built-in GD' => Graphics::GD_ENGINE,
|
||||
'ImageMagick' => Graphics::IMAGICK_ENGINE
|
||||
];
|
||||
|
||||
const THUMBNAIL_TYPES = [
|
||||
'JPEG' => "jpg",
|
||||
'WEBP (Not IE/Safari compatible)' => "webp"
|
||||
];
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_int('thumb_width', 192);
|
||||
$config->set_default_int('thumb_height', 192);
|
||||
$config->set_default_int('thumb_scaling', 100);
|
||||
$config->set_default_int('thumb_quality', 75);
|
||||
$config->set_default_string('thumb_type', 'jpg');
|
||||
$config->set_default_int('thumb_mem_limit', parse_shorthand_int('8MB'));
|
||||
$config->set_default_string('thumb_convert_path', 'convert');
|
||||
$config->set_default_int(ImageConfig::THUMB_WIDTH, 192);
|
||||
$config->set_default_int(ImageConfig::THUMB_HEIGHT, 192);
|
||||
$config->set_default_int(ImageConfig::THUMB_SCALING, 100);
|
||||
$config->set_default_int(ImageConfig::THUMB_QUALITY, 75);
|
||||
$config->set_default_string(ImageConfig::THUMB_TYPE, 'jpg');
|
||||
|
||||
if (function_exists("exif_read_data")) {
|
||||
$config->set_default_bool('image_show_meta', false);
|
||||
if (function_exists(self::EXIF_READ_FUNCTION)) {
|
||||
$config->set_default_bool(ImageConfig::SHOW_META, false);
|
||||
}
|
||||
$config->set_default_string('image_ilink', '');
|
||||
$config->set_default_string('image_tlink', '');
|
||||
$config->set_default_string('image_tip', '$tags // $size // $filesize');
|
||||
$config->set_default_string('upload_collision_handler', 'error');
|
||||
$config->set_default_int('image_expires', (60*60*24*31)); // defaults to one month
|
||||
$config->set_default_string(ImageConfig::ILINK, '');
|
||||
$config->set_default_string(ImageConfig::TLINK, '');
|
||||
$config->set_default_string(ImageConfig::TIP, '$tags // $size // $filesize');
|
||||
$config->set_default_string(ImageConfig::UPLOAD_COLLISION_HANDLER, ImageConfig::COLLISION_ERROR);
|
||||
$config->set_default_int(ImageConfig::EXPIRES, (60*60*24*31)); // defaults to one month
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
|
@ -125,50 +159,36 @@ class ImageIO extends Extension
|
|||
$sb = new SetupBlock("Image Options");
|
||||
$sb->position = 30;
|
||||
// advanced only
|
||||
//$sb->add_text_option("image_ilink", "Image link: ");
|
||||
//$sb->add_text_option("image_tlink", "<br>Thumbnail link: ");
|
||||
$sb->add_text_option("image_tip", "Image tooltip: ");
|
||||
$sb->add_choice_option("upload_collision_handler", ['Error'=>'error', 'Merge'=>'merge'], "<br>Upload collision handler: ");
|
||||
if (function_exists("exif_read_data")) {
|
||||
$sb->add_bool_option("image_show_meta", "<br>Show metadata: ");
|
||||
//$sb->add_text_option(ImageConfig::ILINK, "Image link: ");
|
||||
//$sb->add_text_option(ImageConfig::TLINK, "<br>Thumbnail link: ");
|
||||
$sb->add_text_option(ImageConfig::TIP, "Image tooltip: ");
|
||||
$sb->add_choice_option(ImageConfig::UPLOAD_COLLISION_HANDLER, self::COLLISION_OPTIONS, "<br>Upload collision handler: ");
|
||||
if (function_exists(self::EXIF_READ_FUNCTION)) {
|
||||
$sb->add_bool_option(ImageConfig::SHOW_META, "<br>Show metadata: ");
|
||||
}
|
||||
|
||||
$event->panel->add_block($sb);
|
||||
|
||||
$thumbers = [];
|
||||
$thumbers['Built-in GD'] = "gd";
|
||||
$thumbers['ImageMagick'] = "convert";
|
||||
|
||||
$thumb_types = [];
|
||||
$thumb_types['JPEG'] = "jpg";
|
||||
$thumb_types['WEBP (Not IE/Safari compatible)'] = "webp";
|
||||
|
||||
|
||||
$sb = new SetupBlock("Thumbnailing");
|
||||
$sb->add_choice_option("thumb_engine", $thumbers, "Engine: ");
|
||||
$sb->add_choice_option(ImageConfig::THUMB_ENGINE, self::THUMBNAIL_ENGINES, "Engine: ");
|
||||
$sb->add_label("<br>");
|
||||
$sb->add_choice_option("thumb_type", $thumb_types, "Filetype: ");
|
||||
$sb->add_choice_option(ImageConfig::THUMB_TYPE, self::THUMBNAIL_TYPES, "Filetype: ");
|
||||
|
||||
$sb->add_label("<br>Size ");
|
||||
$sb->add_int_option("thumb_width");
|
||||
$sb->add_int_option(ImageConfig::THUMB_WIDTH);
|
||||
$sb->add_label(" x ");
|
||||
$sb->add_int_option("thumb_height");
|
||||
$sb->add_int_option(ImageConfig::THUMB_HEIGHT);
|
||||
$sb->add_label(" px at ");
|
||||
$sb->add_int_option("thumb_quality");
|
||||
$sb->add_int_option(ImageConfig::THUMB_QUALITY);
|
||||
$sb->add_label(" % quality ");
|
||||
|
||||
$sb->add_label("<br>High-DPI scaling ");
|
||||
$sb->add_int_option("thumb_scaling");
|
||||
$sb->add_int_option(ImageConfig::THUMB_SCALING);
|
||||
$sb->add_label("%");
|
||||
|
||||
if ($config->get_string("thumb_engine") == "convert") {
|
||||
$sb->add_label("<br>ImageMagick Binary: ");
|
||||
$sb->add_text_option("thumb_convert_path");
|
||||
}
|
||||
|
||||
if ($config->get_string("thumb_engine") == "gd") {
|
||||
$sb->add_shorthand_int_option("thumb_mem_limit", "<br>Max memory use: ");
|
||||
}
|
||||
|
||||
$event->panel->add_block($sb);
|
||||
}
|
||||
|
@ -193,8 +213,8 @@ class ImageIO extends Extension
|
|||
*/
|
||||
$existing = Image::by_hash($image->hash);
|
||||
if (!is_null($existing)) {
|
||||
$handler = $config->get_string("upload_collision_handler");
|
||||
if ($handler == "merge" || isset($_GET['update'])) {
|
||||
$handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER);
|
||||
if ($handler == ImageConfig::COLLISION_MERGE || isset($_GET['update'])) {
|
||||
$merged = array_merge($image->get_tag_array(), $existing->get_tag_array());
|
||||
send_event(new TagSetEvent($existing, $merged));
|
||||
if (isset($_GET['rating']) && isset($_GET['update']) && ext_is_live("Ratings")) {
|
||||
|
@ -256,7 +276,7 @@ class ImageIO extends Extension
|
|||
global $page;
|
||||
if (!is_null($image)) {
|
||||
if ($type == "thumb") {
|
||||
$ext = $config->get_string("thumb_type");
|
||||
$ext = $config->get_string(ImageConfig::THUMB_TYPE);
|
||||
if (array_key_exists($ext, MIME_TYPE_MAP)) {
|
||||
$page->set_type(MIME_TYPE_MAP[$ext]);
|
||||
} else {
|
||||
|
@ -289,8 +309,8 @@ class ImageIO extends Extension
|
|||
|
||||
$page->set_file($file);
|
||||
|
||||
if ($config->get_int("image_expires")) {
|
||||
$expires = date(DATE_RFC1123, time() + $config->get_int("image_expires"));
|
||||
if ($config->get_int(ImageConfig::EXPIRES)) {
|
||||
$expires = date(DATE_RFC1123, time() + $config->get_int(ImageConfig::EXPIRES));
|
||||
} else {
|
||||
$expires = 'Fri, 2 Sep 2101 12:42:42 GMT'; // War was beginning
|
||||
}
|
||||
|
|
|
@ -231,8 +231,8 @@ class _SafeOuroborosImage
|
|||
$this->has_notes = false;
|
||||
|
||||
// thumb
|
||||
$this->preview_height = $config->get_int('thumb_height');
|
||||
$this->preview_width = $config->get_int('thumb_width');
|
||||
$this->preview_height = $config->get_int(ImageConfig::THUMB_HEIGHT);
|
||||
$this->preview_width = $config->get_int(ImageConfig::THUMB_WIDTH);
|
||||
$this->preview_url = make_http($img->get_thumb_link());
|
||||
|
||||
// sample (use the full image here)
|
||||
|
@ -481,8 +481,8 @@ class OuroborosAPI extends Extension
|
|||
protected function postCreate(OuroborosPost $post, string $md5 = '')
|
||||
{
|
||||
global $config;
|
||||
$handler = $config->get_string("upload_collision_handler");
|
||||
if (!empty($md5) && !($handler == 'merge')) {
|
||||
$handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER);
|
||||
if (!empty($md5) && !($handler == ImageConfig::COLLISION_MERGE)) {
|
||||
$img = Image::by_hash($md5);
|
||||
if (!is_null($img)) {
|
||||
$this->sendResponse(420, self::ERROR_POST_CREATE_DUPE);
|
||||
|
@ -524,8 +524,8 @@ class OuroborosAPI extends Extension
|
|||
if (!empty($meta['hash'])) {
|
||||
$img = Image::by_hash($meta['hash']);
|
||||
if (!is_null($img)) {
|
||||
$handler = $config->get_string("upload_collision_handler");
|
||||
if ($handler == "merge") {
|
||||
$handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER);
|
||||
if ($handler == ImageConfig::COLLISION_MERGE) {
|
||||
$postTags = is_array($post->tags) ? $post->tags : Tag::explode($post->tags);
|
||||
$merged = array_merge($postTags, $img->get_tag_array());
|
||||
send_event(new TagSetEvent($img, $merged));
|
||||
|
|
|
@ -46,7 +46,7 @@ class ReportImageTheme extends Themelet
|
|||
";
|
||||
}
|
||||
|
||||
$thumb_width = $config->get_int("thumb_width");
|
||||
$thumb_width = $config->get_int(ImageConfig::THUMB_WIDTH);
|
||||
$html = "
|
||||
<table id='reportedimage' class='zebra'>
|
||||
<thead><td width='$thumb_width'>Image</td><td>Reason</td><td width='128'>Action</td></thead>
|
||||
|
|
|
@ -26,8 +26,6 @@ abstract class ResizeConfig
|
|||
*/
|
||||
class ResizeImage extends Extension
|
||||
{
|
||||
const SUPPORTED_EXT = ["jpg","jpeg","png","gif","webp"];
|
||||
|
||||
/**
|
||||
* Needs to be after the data processing extensions
|
||||
*/
|
||||
|
@ -40,17 +38,18 @@ class ResizeImage extends Extension
|
|||
public function onInitExt(InitExtEvent $event)
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_bool('resize_enabled', true);
|
||||
$config->set_default_bool('resize_upload', false);
|
||||
$config->set_default_int('resize_default_width', 0);
|
||||
$config->set_default_int('resize_default_height', 0);
|
||||
$config->set_default_bool(ResizeConfig::ENABLED, true);
|
||||
$config->set_default_bool(ResizeConfig::UPLOAD, false);
|
||||
$config->set_default_string(ResizeConfig::ENGINE, Graphics::GD_ENGINE);
|
||||
$config->set_default_int(ResizeConfig::DEFAULT_WIDTH, 0);
|
||||
$config->set_default_int(ResizeConfig::DEFAULT_HEIGHT, 0);
|
||||
}
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||
{
|
||||
global $user, $config;
|
||||
if ($user->is_admin() && $config->get_bool("resize_enabled")
|
||||
&& in_array($event->image->ext, self::SUPPORTED_EXT)) {
|
||||
if ($user->is_admin() && $config->get_bool(ResizeConfig::ENABLED)
|
||||
&& $this->can_resize_format($event->image->ext)) {
|
||||
/* Add a link to resize the image */
|
||||
$event->add_part($this->theme->get_resize_html($event->image));
|
||||
}
|
||||
|
@ -60,6 +59,7 @@ class ResizeImage extends Extension
|
|||
{
|
||||
$sb = new SetupBlock("Image Resize");
|
||||
$sb->start_table();
|
||||
$sb->add_choice_option(ResizeConfig::ENGINE, Media::IMAGE_MEDIA_ENGINES, "Engine: ", true);
|
||||
$sb->add_bool_option(ResizeConfig::ENABLED, "Allow resizing images: ", true);
|
||||
$sb->add_bool_option(ResizeConfig::UPLOAD, "Resize on upload: ", true);
|
||||
$sb->end_table();
|
||||
|
@ -82,15 +82,15 @@ class ResizeImage extends Extension
|
|||
|
||||
$image_obj = Image::by_id($event->image_id);
|
||||
|
||||
if ($config->get_bool("resize_upload") == true
|
||||
&& in_array($event->type, self::SUPPORTED_EXT)) {
|
||||
if ($config->get_bool(ResizeConfig::UPLOAD) == true
|
||||
&& $this->can_resize_format($event->type)) {
|
||||
$width = $height = 0;
|
||||
|
||||
if ($config->get_int("resize_default_width") !== 0) {
|
||||
$height = $config->get_int("resize_default_width");
|
||||
if ($config->get_int(ResizeConfig::DEFAULT_WIDTH) !== 0) {
|
||||
$height = $config->get_int(ResizeConfig::DEFAULT_WIDTH);
|
||||
}
|
||||
if ($config->get_int("resize_default_height") !== 0) {
|
||||
$height = $config->get_int("resize_default_height");
|
||||
if ($config->get_int(ResizeConfig::DEFAULT_HEIGHT) !== 0) {
|
||||
$height = $config->get_int(ResizeConfig::DEFAULT_HEIGHT);
|
||||
}
|
||||
$isanigif = 0;
|
||||
if ($image_obj->ext == "gif") {
|
||||
|
@ -169,8 +169,16 @@ class ResizeImage extends Extension
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function can_resize_format($format): bool
|
||||
{
|
||||
global $config;
|
||||
$engine = $config->get_string(ResizeConfig::ENGINE);
|
||||
return Graphics::is_input_supported($engine, $format)
|
||||
&& Graphics::is_output_supported($engine, $format);
|
||||
}
|
||||
|
||||
|
||||
// Private functions
|
||||
/* ----------------------------- */
|
||||
private function resize_image(Image $image_obj, int $width, int $height)
|
||||
|
@ -197,7 +205,15 @@ class ResizeImage extends Extension
|
|||
throw new ImageResizeException("Unable to save temporary image file.");
|
||||
}
|
||||
|
||||
image_resize_gd($image_filename, $info, $new_width, $new_height, $tmp_filename);
|
||||
send_event(new GraphicResizeEvent(
|
||||
Graphics::GD_ENGINE,
|
||||
$image_filename,
|
||||
$image_obj->ext,
|
||||
$tmp_filename,
|
||||
$new_width,
|
||||
$new_height,
|
||||
true
|
||||
));
|
||||
|
||||
$new_image = new Image();
|
||||
$new_image->hash = md5_file($tmp_filename);
|
||||
|
|
|
@ -9,8 +9,8 @@ class ResizeImageTheme extends Themelet
|
|||
{
|
||||
global $config;
|
||||
|
||||
$default_width = $config->get_int('resize_default_width');
|
||||
$default_height = $config->get_int('resize_default_height');
|
||||
$default_width = $config->get_int(ResizeConfig::DEFAULT_WIDTH);
|
||||
$default_height = $config->get_int(ResizeConfig::DEFAULT_HEIGHT);
|
||||
|
||||
if (!$default_width) {
|
||||
$default_width = $image->width;
|
||||
|
|
|
@ -130,7 +130,7 @@ class RotateImage extends Extension
|
|||
|
||||
$info = getimagesize($image_filename);
|
||||
|
||||
$memory_use =calc_memory_use($info);
|
||||
$memory_use = Graphics::calc_memory_use($info);
|
||||
$memory_limit = get_memory_limit();
|
||||
|
||||
if ($memory_use > $memory_limit) {
|
||||
|
|
|
@ -30,7 +30,7 @@ class Rule34 extends Extension
|
|||
public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event)
|
||||
{
|
||||
global $config;
|
||||
$image_link = $config->get_string('image_ilink');
|
||||
$image_link = $config->get_string(ImageConfig::ILINK);
|
||||
$url0 = $event->image->parse_link_template($image_link, "url_escape", 0);
|
||||
$url1 = $event->image->parse_link_template($image_link, "url_escape", 1);
|
||||
$html = "<tr><th>Links</th><td><a href='$url0'>Image Only</a> (<a href='$url1'>Backup Server</a>)</td></tr>";
|
||||
|
|
|
@ -39,6 +39,6 @@ class SetupTest extends ShimmiePHPUnitTestCase
|
|||
$this->log_in_as_admin();
|
||||
$this->get_page('setup/advanced');
|
||||
$this->assert_title("Shimmie Setup");
|
||||
$this->assert_text("thumb_quality");
|
||||
$this->assert_text(ImageConfig::THUMB_QUALITY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,50 +33,6 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
const ACTION_BULK_TRANSCODE = "bulk_transcode";
|
||||
|
||||
const CONVERSION_ENGINES = [
|
||||
"GD" => "gd",
|
||||
"ImageMagick" => "convert",
|
||||
];
|
||||
|
||||
const ENGINE_INPUT_SUPPORT = [
|
||||
"gd" => [
|
||||
"bmp",
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"webp",
|
||||
],
|
||||
"convert" => [
|
||||
"bmp",
|
||||
"gif",
|
||||
"jpg",
|
||||
"png",
|
||||
"psd",
|
||||
"tiff",
|
||||
"webp",
|
||||
"ico",
|
||||
]
|
||||
];
|
||||
|
||||
const ENGINE_OUTPUT_SUPPORT = [
|
||||
"gd" => [
|
||||
"jpg",
|
||||
"png",
|
||||
"webp-lossy",
|
||||
],
|
||||
"convert" => [
|
||||
"jpg",
|
||||
"png",
|
||||
"webp-lossy",
|
||||
"webp-lossless",
|
||||
]
|
||||
];
|
||||
|
||||
const LOSSLESS_FORMATS = [
|
||||
"webp-lossless",
|
||||
"png",
|
||||
];
|
||||
|
||||
const INPUT_FORMATS = [
|
||||
"BMP" => "bmp",
|
||||
"GIF" => "gif",
|
||||
|
@ -88,17 +44,12 @@ class TranscodeImage extends Extension
|
|||
"WEBP" => "webp",
|
||||
];
|
||||
|
||||
const FORMAT_ALIASES = [
|
||||
"tif" => "tiff",
|
||||
"jpeg" => "jpg",
|
||||
];
|
||||
|
||||
const OUTPUT_FORMATS = [
|
||||
"" => "",
|
||||
"JPEG (lossy)" => "jpg",
|
||||
"PNG (lossless)" => "png",
|
||||
"WEBP (lossy)" => "webp-lossy",
|
||||
"WEBP (lossless)" => "webp-lossless",
|
||||
"WEBP (lossy)" => Graphics::WEBP_LOSSY,
|
||||
"WEBP (lossless)" => Graphics::WEBP_LOSSLESS,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -113,13 +64,13 @@ class TranscodeImage extends Extension
|
|||
public function onInitExt(InitExtEvent $event)
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_bool('transcode_enabled', true);
|
||||
$config->set_default_bool('transcode_upload', false);
|
||||
$config->set_default_string('transcode_engine', "gd");
|
||||
$config->set_default_int('transcode_quality', 80);
|
||||
$config->set_default_bool(TranscodeConfig::ENABLED, true);
|
||||
$config->set_default_bool(TranscodeConfig::UPLOAD, false);
|
||||
$config->set_default_string(TranscodeConfig::ENGINE, Graphics::GD_ENGINE);
|
||||
$config->set_default_int(TranscodeConfig::QUALITY, 80);
|
||||
|
||||
foreach (array_values(self::INPUT_FORMATS) as $format) {
|
||||
$config->set_default_string('transcode_upload_'.$format, "");
|
||||
$config->set_default_string(TranscodeConfig::UPLOAD_PREFIX.$format, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,8 +78,8 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
global $user, $config;
|
||||
|
||||
if ($user->is_admin() && $config->get_bool("resize_enabled")) {
|
||||
$engine = $config->get_string("transcode_engine");
|
||||
if ($user->is_admin()) {
|
||||
$engine = $config->get_string(TranscodeConfig::ENGINE);
|
||||
if ($this->can_convert_format($engine, $event->image->ext)) {
|
||||
$options = $this->get_supported_output_formats($engine, $event->image->ext);
|
||||
$event->add_part($this->theme->get_transcode_html($event->image, $options));
|
||||
|
@ -140,16 +91,16 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
global $config;
|
||||
|
||||
$engine = $config->get_string("transcode_engine");
|
||||
$engine = $config->get_string(TranscodeConfig::ENGINE);
|
||||
|
||||
|
||||
$sb = new SetupBlock("Image Transcode");
|
||||
$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, self::CONVERSION_ENGINES, "Engine", true);
|
||||
$sb->add_choice_option(TranscodeConfig::ENGINE, Graphics::IMAGE_GRAPHICS_ENGINES, "Engine", true);
|
||||
foreach (self::INPUT_FORMATS as $display=>$format) {
|
||||
if (in_array($format, self::ENGINE_INPUT_SUPPORT[$engine])) {
|
||||
if (in_array($format, Graphics::ENGINE_INPUT_SUPPORT[$engine])) {
|
||||
$outputs = $this->get_supported_output_formats($engine, $format);
|
||||
$sb->add_choice_option(TranscodeConfig::UPLOAD_PREFIX.$format, $outputs, "$display", true);
|
||||
}
|
||||
|
@ -163,23 +114,23 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
global $config, $page;
|
||||
|
||||
if ($config->get_bool("transcode_upload") == true) {
|
||||
if ($config->get_bool(TranscodeConfig::UPLOAD) == true) {
|
||||
$ext = strtolower($event->type);
|
||||
|
||||
$ext = $this->clean_format($ext);
|
||||
$ext = Graphics::normalize_format($ext);
|
||||
|
||||
if ($event->type=="gif"&&is_animated_gif($event->tmpname)) {
|
||||
if ($event->type=="gif"&&Graphics::is_animated_gif($event->tmpname)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array($ext, array_values(self::INPUT_FORMATS))) {
|
||||
$target_format = $config->get_string("transcode_upload_".$ext);
|
||||
$target_format = $config->get_string(TranscodeConfig::UPLOAD_PREFIX.$ext);
|
||||
if (empty($target_format)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$new_image = $this->transcode_image($event->tmpname, $ext, $target_format);
|
||||
$event->set_type($this->determine_ext($target_format));
|
||||
$event->set_type(Graphics::determine_ext($target_format));
|
||||
$event->set_tmpname($new_image);
|
||||
} catch (Exception $e) {
|
||||
log_error("transcode", "Error while performing upload transcode: ".$e->getMessage());
|
||||
|
@ -227,7 +178,7 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
global $user, $config;
|
||||
|
||||
$engine = $config->get_string("transcode_engine");
|
||||
$engine = $config->get_string(TranscodeConfig::ENGINE);
|
||||
|
||||
if ($user->is_admin()) {
|
||||
$event->add_action(self::ACTION_BULK_TRANSCODE, "Transcode", null,"", $this->theme->get_transcode_picker_html($this->get_supported_output_formats($engine)));
|
||||
|
@ -239,7 +190,7 @@ class TranscodeImage extends Extension
|
|||
global $user, $database;
|
||||
|
||||
switch ($event->action) {
|
||||
case "bulk_transcode":
|
||||
case self::ACTION_BULK_TRANSCODE:
|
||||
if (!isset($_POST['transcode_format'])) {
|
||||
return;
|
||||
}
|
||||
|
@ -251,8 +202,9 @@ class TranscodeImage extends Extension
|
|||
$database->beginTransaction();
|
||||
|
||||
$this->transcode_and_replace_image($image, $format);
|
||||
// If a subsequent transcode fails, the database need to have everything about the previous transcodes recorded already,
|
||||
// otherwise the image entries will be stuck pointing to missing image files
|
||||
// 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
|
||||
$database->commit();
|
||||
$total++;
|
||||
} catch (Exception $e) {
|
||||
|
@ -269,54 +221,34 @@ class TranscodeImage extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function clean_format($format): ?string
|
||||
{
|
||||
if (array_key_exists($format, self::FORMAT_ALIASES)) {
|
||||
return self::FORMAT_ALIASES[$format];
|
||||
}
|
||||
return $format;
|
||||
}
|
||||
|
||||
private function can_convert_format($engine, $format): bool
|
||||
{
|
||||
$format = $this->clean_format($format);
|
||||
if (!in_array($format, self::ENGINE_INPUT_SUPPORT[$engine])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return Graphics::is_input_supported($engine, $format);
|
||||
}
|
||||
|
||||
|
||||
private function get_supported_output_formats($engine, ?String $omit_format = null): array
|
||||
{
|
||||
$omit_format = $this->clean_format($omit_format);
|
||||
$omit_format = Graphics::normalize_format($omit_format);
|
||||
$output = [];
|
||||
foreach (self::OUTPUT_FORMATS as $key=>$value) {
|
||||
if ($value=="") {
|
||||
$output[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
if (in_array($value, self::ENGINE_OUTPUT_SUPPORT[$engine])
|
||||
&&(empty($omit_format)||$omit_format!=$this->determine_ext($value))) {
|
||||
if(Graphics::is_output_supported($engine, $value)
|
||||
&&(empty($omit_format)||$omit_format!=Graphics::determine_ext($value))) {
|
||||
$output[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function determine_ext(String $format): String
|
||||
{
|
||||
switch ($format) {
|
||||
case "webp-lossless":
|
||||
case "webp-lossy":
|
||||
return "webp";
|
||||
default:
|
||||
return $format;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function transcode_and_replace_image(Image $image_obj, String $target_format)
|
||||
{
|
||||
$target_format = $this->clean_format($target_format);
|
||||
$original_file = warehouse_path(Image::IMAGE_DIR, $image_obj->hash);
|
||||
|
||||
$tmp_filename = $this->transcode_image($original_file, $image_obj->ext, $target_format);
|
||||
|
@ -327,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 = $this->determine_ext($target_format);
|
||||
$new_image->ext = Graphics::determine_ext($target_format);
|
||||
|
||||
/* Move the new image into the main storage location */
|
||||
$target = warehouse_path(Image::IMAGE_DIR, $new_image->hash);
|
||||
|
@ -346,7 +278,7 @@ class TranscodeImage extends Extension
|
|||
{
|
||||
global $config;
|
||||
|
||||
if ($source_format==$this->determine_ext($target_format)) {
|
||||
if ($source_format==Graphics::determine_ext($target_format)) {
|
||||
throw new ImageTranscodeException("Source and target formats are the same: ".$source_format);
|
||||
}
|
||||
|
||||
|
@ -357,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, self::ENGINE_OUTPUT_SUPPORT[$engine])) {
|
||||
if (!in_array($target_format, Graphics::ENGINE_OUTPUT_SUPPORT[$engine])) {
|
||||
throw new ImageTranscodeException("Engine $engine does not support output format $target_format");
|
||||
}
|
||||
|
||||
|
@ -426,20 +358,20 @@ class TranscodeImage extends Extension
|
|||
global $config;
|
||||
|
||||
$q = $config->get_int("transcode_quality");
|
||||
$convert = $config->get_string("thumb_convert_path");
|
||||
$convert = $config->get_string(GraphicsConfig::CONVERT_PATH);
|
||||
|
||||
if ($convert==null||$convert=="") {
|
||||
throw new ImageTranscodeException("ImageMagick path not configured");
|
||||
}
|
||||
$ext = $this->determine_ext($target_format);
|
||||
$ext = Graphics::determine_ext($target_format);
|
||||
|
||||
$args = " -flatten ";
|
||||
$bg = "none";
|
||||
switch ($target_format) {
|
||||
case "webp-lossless":
|
||||
case Graphics::WEBP_LOSSLESS:
|
||||
$args .= '-define webp:lossless=true';
|
||||
break;
|
||||
case "webp-lossy":
|
||||
case Graphics::WEBP_LOSSY:
|
||||
$args .= '';
|
||||
break;
|
||||
case "png":
|
||||
|
|
Reference in a new issue