2011-09-04 03:13:41 +00:00
|
|
|
<?php
|
|
|
|
/*
|
2011-09-04 15:17:14 +00:00
|
|
|
* Name: Resize Image
|
2011-09-04 03:13:41 +00:00
|
|
|
* Author: jgen <jgen.tech@gmail.com>
|
2011-09-04 15:17:14 +00:00
|
|
|
* Description: Allows admins to resize images.
|
2011-09-04 03:13:41 +00:00
|
|
|
* License: GPLv2
|
|
|
|
* Version: 0.1
|
|
|
|
* Notice:
|
|
|
|
* The image resize and resample code is based off of the "smart_resize_image"
|
|
|
|
* function copyright 2008 Maxim Chernyak, released under a MIT-style license.
|
2011-09-04 15:17:14 +00:00
|
|
|
* Documentation:
|
|
|
|
* This extension allows admins to resize images.
|
2011-09-04 03:13:41 +00:00
|
|
|
*/
|
2019-06-27 04:00:49 +00:00
|
|
|
|
|
|
|
abstract class ResizeConfig
|
|
|
|
{
|
|
|
|
const ENABLED = 'resize_enabled';
|
|
|
|
const UPLOAD = 'resize_upload';
|
|
|
|
const ENGINE = 'resize_engine';
|
|
|
|
const DEFAULT_WIDTH = 'resize_default_width';
|
|
|
|
const DEFAULT_HEIGHT = 'resize_default_height';
|
|
|
|
}
|
|
|
|
|
2011-09-04 03:13:41 +00:00
|
|
|
/**
|
|
|
|
* This class handles image resize requests.
|
|
|
|
*/
|
2019-05-28 16:59:38 +00:00
|
|
|
class ResizeImage extends Extension
|
|
|
|
{
|
2019-06-13 16:45:34 +00:00
|
|
|
/**
|
|
|
|
* Needs to be after the data processing extensions
|
|
|
|
*/
|
|
|
|
public function get_priority(): int
|
|
|
|
{
|
|
|
|
return 55;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
public function onInitExt(InitExtEvent $event)
|
|
|
|
{
|
|
|
|
global $config;
|
2019-06-18 18:45:59 +00:00
|
|
|
$config->set_default_bool(ResizeConfig::ENABLED, true);
|
|
|
|
$config->set_default_bool(ResizeConfig::UPLOAD, false);
|
2019-06-21 20:23:59 +00:00
|
|
|
$config->set_default_string(ResizeConfig::ENGINE, GraphicsEngine::GD);
|
2019-06-18 18:45:59 +00:00
|
|
|
$config->set_default_int(ResizeConfig::DEFAULT_WIDTH, 0);
|
|
|
|
$config->set_default_int(ResizeConfig::DEFAULT_HEIGHT, 0);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2011-09-04 03:13:41 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
|
|
|
{
|
|
|
|
global $user, $config;
|
2019-06-18 18:45:59 +00:00
|
|
|
if ($user->is_admin() && $config->get_bool(ResizeConfig::ENABLED)
|
|
|
|
&& $this->can_resize_format($event->image->ext)) {
|
2019-05-28 16:59:38 +00:00
|
|
|
/* Add a link to resize the image */
|
|
|
|
$event->add_part($this->theme->get_resize_html($event->image));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function onSetupBuilding(SetupBuildingEvent $event)
|
|
|
|
{
|
|
|
|
$sb = new SetupBlock("Image Resize");
|
2019-06-27 04:00:49 +00:00
|
|
|
$sb->start_table();
|
2019-06-18 18:45:59 +00:00
|
|
|
$sb->add_choice_option(ResizeConfig::ENGINE, Media::IMAGE_MEDIA_ENGINES, "Engine: ", true);
|
2019-06-27 04:00:49 +00:00
|
|
|
$sb->add_bool_option(ResizeConfig::ENABLED, "Allow resizing images: ", true);
|
|
|
|
$sb->add_bool_option(ResizeConfig::UPLOAD, "Resize on upload: ", true);
|
|
|
|
$sb->end_table();
|
|
|
|
$sb->start_table();
|
|
|
|
$sb->add_table_header("Preset/Default Dimensions");
|
|
|
|
$sb->add_label("<tr><th>Width</th><td>");
|
|
|
|
$sb->add_int_option(ResizeConfig::DEFAULT_WIDTH);
|
|
|
|
$sb->add_label("</td><td>px</td></tr>");
|
|
|
|
$sb->add_label("<tr><th>Height</th><td>");
|
|
|
|
$sb->add_int_option(ResizeConfig::DEFAULT_HEIGHT);
|
|
|
|
$sb->add_label("</td><td>px</td></tr>");
|
|
|
|
$sb->add_label("<tr><td></td><td>(enter 0 for no default)</td></tr>");
|
|
|
|
$sb->end_table();
|
2019-05-28 16:59:38 +00:00
|
|
|
$event->panel->add_block($sb);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function onDataUpload(DataUploadEvent $event)
|
|
|
|
{
|
|
|
|
global $config, $page;
|
2011-09-04 03:13:41 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
$image_obj = Image::by_id($event->image_id);
|
2014-04-25 21:39:06 +00:00
|
|
|
|
2019-06-18 18:45:59 +00:00
|
|
|
if ($config->get_bool(ResizeConfig::UPLOAD) == true
|
|
|
|
&& $this->can_resize_format($event->type)) {
|
2019-05-28 16:59:38 +00:00
|
|
|
$width = $height = 0;
|
2012-02-15 23:46:42 +00:00
|
|
|
|
2019-06-18 18:45:59 +00:00
|
|
|
if ($config->get_int(ResizeConfig::DEFAULT_WIDTH) !== 0) {
|
|
|
|
$height = $config->get_int(ResizeConfig::DEFAULT_WIDTH);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2019-06-18 18:45:59 +00:00
|
|
|
if ($config->get_int(ResizeConfig::DEFAULT_HEIGHT) !== 0) {
|
|
|
|
$height = $config->get_int(ResizeConfig::DEFAULT_HEIGHT);
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
$isanigif = 0;
|
|
|
|
if ($image_obj->ext == "gif") {
|
2019-06-15 16:18:52 +00:00
|
|
|
$image_filename = warehouse_path(Image::IMAGE_DIR, $image_obj->hash);
|
2019-05-28 16:59:38 +00:00
|
|
|
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) && $isanigif < 2) {
|
|
|
|
$chunk = fread($fh, 1024 * 100);
|
|
|
|
$isanigif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($isanigif == 0) {
|
|
|
|
try {
|
|
|
|
$this->resize_image($image_obj, $width, $height);
|
|
|
|
} catch (ImageResizeException $e) {
|
|
|
|
$this->theme->display_resize_error($page, "Error Resizing", $e->error);
|
|
|
|
}
|
2012-01-24 05:49:03 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
//Need to generate thumbnail again...
|
|
|
|
//This only seems to be an issue if one of the sizes was set to 0.
|
|
|
|
$image_obj = Image::by_id($event->image_id); //Must be a better way to grab the new hash than setting this again..
|
|
|
|
send_event(new ThumbnailGenerationEvent($image_obj->hash, $image_obj->ext, true));
|
2012-01-24 05:49:03 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
log_info("resize", "Image #{$event->image_id} has been resized to: ".$width."x".$height);
|
|
|
|
//TODO: Notify user that image has been resized.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-24 05:49:03 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
public function onPageRequest(PageRequestEvent $event)
|
|
|
|
{
|
|
|
|
global $page, $user;
|
2012-01-24 05:49:03 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
if ($event->page_matches("resize") && $user->is_admin()) {
|
|
|
|
// Try to get the image ID
|
|
|
|
$image_id = int_escape($event->get_arg(0));
|
|
|
|
if (empty($image_id)) {
|
|
|
|
$image_id = isset($_POST['image_id']) ? int_escape($_POST['image_id']) : null;
|
|
|
|
}
|
|
|
|
if (empty($image_id)) {
|
|
|
|
throw new ImageResizeException("Can not resize Image: No valid Image ID given.");
|
|
|
|
}
|
|
|
|
|
|
|
|
$image = Image::by_id($image_id);
|
|
|
|
if (is_null($image)) {
|
|
|
|
$this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id");
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Check if options were given to resize an image. */
|
|
|
|
if (isset($_POST['resize_width']) || isset($_POST['resize_height'])) {
|
|
|
|
|
|
|
|
/* get options */
|
|
|
|
|
|
|
|
$width = $height = 0;
|
|
|
|
|
|
|
|
if (isset($_POST['resize_width'])) {
|
|
|
|
$width = int_escape($_POST['resize_width']);
|
|
|
|
}
|
|
|
|
if (isset($_POST['resize_height'])) {
|
|
|
|
$height = int_escape($_POST['resize_height']);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attempt to resize the image */
|
|
|
|
try {
|
|
|
|
$this->resize_image($image, $width, $height);
|
|
|
|
|
|
|
|
//$this->theme->display_resize_page($page, $image_id);
|
|
|
|
|
2019-06-19 01:58:28 +00:00
|
|
|
$page->set_mode(PageMode::REDIRECT);
|
2019-05-28 16:59:38 +00:00
|
|
|
$page->set_redirect(make_link("post/view/".$image_id));
|
|
|
|
} catch (ImageResizeException $e) {
|
|
|
|
$this->theme->display_resize_error($page, "Error Resizing", $e->error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-18 18:45:59 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
// Private functions
|
|
|
|
/* ----------------------------- */
|
|
|
|
private function resize_image(Image $image_obj, int $width, int $height)
|
|
|
|
{
|
|
|
|
global $database;
|
|
|
|
|
|
|
|
if (($height <= 0) && ($width <= 0)) {
|
|
|
|
throw new ImageResizeException("Invalid options for height and width. ($width x $height)");
|
|
|
|
}
|
|
|
|
|
|
|
|
$hash = $image_obj->hash;
|
2019-06-15 16:18:52 +00:00
|
|
|
$image_filename = warehouse_path(Image::IMAGE_DIR, $hash);
|
2019-06-09 18:22:48 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
$info = getimagesize($image_filename);
|
|
|
|
if (($image_obj->width != $info[0]) || ($image_obj->height != $info[1])) {
|
|
|
|
throw new ImageResizeException("The current image size does not match what is set in the database! - Aborting Resize.");
|
|
|
|
}
|
2014-04-27 23:29:36 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
list($new_height, $new_width) = $this->calc_new_size($image_obj, $width, $height);
|
2011-09-04 03:13:41 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/* Temp storage while we resize */
|
|
|
|
$tmp_filename = tempnam("/tmp", 'shimmie_resize');
|
|
|
|
if (empty($tmp_filename)) {
|
|
|
|
throw new ImageResizeException("Unable to save temporary image file.");
|
|
|
|
}
|
2019-06-09 18:22:48 +00:00
|
|
|
|
2019-06-18 18:45:59 +00:00
|
|
|
send_event(new GraphicResizeEvent(
|
2019-06-21 20:23:59 +00:00
|
|
|
GraphicsEngine::GD,
|
2019-06-18 18:45:59 +00:00
|
|
|
$image_filename,
|
|
|
|
$image_obj->ext,
|
|
|
|
$tmp_filename,
|
|
|
|
$new_width,
|
|
|
|
$new_height,
|
|
|
|
true
|
|
|
|
));
|
2019-06-09 18:22:48 +00:00
|
|
|
|
|
|
|
$new_image = new Image();
|
|
|
|
$new_image->hash = md5_file($tmp_filename);
|
|
|
|
$new_image->filesize = filesize($tmp_filename);
|
|
|
|
$new_image->filename = 'resized-'.$image_obj->filename;
|
|
|
|
$new_image->width = $new_width;
|
|
|
|
$new_image->height = $new_height;
|
|
|
|
$new_image->ext = $image_obj->ext;
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/* Move the new image into the main storage location */
|
2019-06-15 16:18:52 +00:00
|
|
|
$target = warehouse_path(Image::IMAGE_DIR, $new_image->hash);
|
2019-05-28 16:59:38 +00:00
|
|
|
if (!@copy($tmp_filename, $target)) {
|
|
|
|
throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove temporary file */
|
|
|
|
@unlink($tmp_filename);
|
2014-04-01 23:29:31 +00:00
|
|
|
|
2019-06-09 18:22:48 +00:00
|
|
|
send_event(new ImageReplaceEvent($image_obj->id, $new_image));
|
2019-05-28 16:59:38 +00:00
|
|
|
|
2019-06-09 18:22:48 +00:00
|
|
|
log_info("resize", "Resized Image #{$image_obj->id} - New hash: {$new_image->hash}");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2015-09-27 00:03:58 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
/**
|
|
|
|
* #return int[]
|
|
|
|
*/
|
|
|
|
private function calc_new_size(Image $image_obj, int $width, int $height): array
|
|
|
|
{
|
|
|
|
/* Calculate the new size of the image */
|
|
|
|
if ($height > 0 && $width > 0) {
|
|
|
|
$new_height = $height;
|
|
|
|
$new_width = $width;
|
|
|
|
return [$new_height, $new_width];
|
|
|
|
} else {
|
|
|
|
// Scale the new image
|
|
|
|
if ($width == 0) {
|
|
|
|
$factor = $height / $image_obj->height;
|
|
|
|
} elseif ($height == 0) {
|
|
|
|
$factor = $width / $image_obj->width;
|
|
|
|
} else {
|
|
|
|
$factor = min($width / $image_obj->width, $height / $image_obj->height);
|
|
|
|
}
|
2015-09-27 00:03:58 +00:00
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
$new_width = round($image_obj->width * $factor);
|
|
|
|
$new_height = round($image_obj->height * $factor);
|
|
|
|
return [$new_height, $new_width];
|
|
|
|
}
|
|
|
|
}
|
2011-09-04 03:13:41 +00:00
|
|
|
}
|