282 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /*
 | |
|  * Name: Resize Image
 | |
|  * Author: jgen <jgen.tech@gmail.com>
 | |
|  * Description: Allows admins to resize images.
 | |
|  * 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.
 | |
|  * Documentation:
 | |
|  *  This extension allows admins to resize images.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * This class is just a wrapper around SCoreException.
 | |
|  */
 | |
| class ImageResizeException extends SCoreException {
 | |
| 	var $error;
 | |
| 
 | |
| 	public function __construct($error) {
 | |
| 		$this->error = $error;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *	This class handles image resize requests.
 | |
|  */
 | |
| 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);		
 | |
| 	}
 | |
| 
 | |
| 	public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) {
 | |
| 		global $user, $config;
 | |
| 		if($user->is_admin() && $config->get_bool("resize_enabled")) {
 | |
| 			/* Add a link to resize the image */
 | |
| 			$event->add_part($this->theme->get_resize_html($event->image->id));
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	public function onSetupBuilding(SetupBuildingEvent $event) {
 | |
| 		$sb = new SetupBlock("Image Resize");
 | |
| 		$sb->add_bool_option("resize_enabled", "Allow resizing images: ");
 | |
| 		$sb->add_bool_option("resize_upload", "<br>Resize on upload: ");
 | |
| 		$sb->add_label("<br>Preset/Default Width: ");
 | |
| 		$sb->add_int_option("resize_default_width");
 | |
| 		$sb->add_label(" px");
 | |
| 		$sb->add_label("<br>Preset/Default Height: ");
 | |
| 		$sb->add_int_option("resize_default_height");
 | |
| 		$sb->add_label(" px");
 | |
| 		$sb->add_label("<br>(enter 0 for no default)");
 | |
| 		$event->panel->add_block($sb);
 | |
| 	}
 | |
| 	
 | |
| 	public function onDataUpload(DataUploadEvent $event) {
 | |
| 		global $config;
 | |
| 		$image_obj = Image::by_id($event->image_id);
 | |
| 		//No auto resizing for gifs due to animated gif causing errors :(
 | |
| 		//Also PNG resizing seems to be completely broken.
 | |
| 		if($config->get_bool("resize_upload") == true && ($image_obj->ext == "jpg")){
 | |
| 			$width = $height = 0;
 | |
| 
 | |
| 			if ($config->get_int("resize_default_width") !== 0) {
 | |
| 				$height = $config->get_int("resize_default_width");
 | |
| 			}
 | |
| 			if ($config->get_int("resize_default_height") !== 0) {
 | |
| 				$height = $config->get_int("resize_default_height");
 | |
| 			}
 | |
| 
 | |
| 			try {
 | |
| 				$this->resize_image($event->image_id, $width, $height);
 | |
| 			} catch (ImageResizeException $e) {
 | |
| 				$this->theme->display_resize_error($page, "Error Resizing", $e->error);
 | |
| 			}
 | |
| 
 | |
| 			//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));
 | |
| 
 | |
| 			log_info("resize", "Image #{$event->image_id} has been resized to: ".$width."x".$height);
 | |
| 			//TODO: Notify user that image has been resized.
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function onPageRequest(PageRequestEvent $event) {
 | |
| 		global $page, $user;
 | |
| 
 | |
| 		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']) ? $_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($page, "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_id, $width, $height);
 | |
| 						
 | |
| 						//$this->theme->display_resize_page($page, $image_id);
 | |
| 						
 | |
| 						$page->set_mode("redirect");
 | |
| 						$page->set_redirect(make_link("post/view/".$image_id));
 | |
| 						
 | |
| 					} catch (ImageResizeException $e) {
 | |
| 						$this->theme->display_resize_error($page, "Error Resizing", $e->error);
 | |
| 					}
 | |
| 				} else {
 | |
| 					/* Display options for resizing */
 | |
| 					$this->theme->display_resize_page($page, $image_id);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	
 | |
| 	// Private functions
 | |
| 	
 | |
| 	/*
 | |
| 		This function could be made much smaller by using the ImageReplaceEvent
 | |
| 		ie: Pretend that we are replacing the image with a resized copy.
 | |
| 	*/
 | |
| 	private function resize_image($image_id, $width, $height) {
 | |
| 		global $config;
 | |
| 		global $user;
 | |
| 		global $page;
 | |
| 		global $database;
 | |
| 		
 | |
| 		if ( ($height <= 0) && ($width <= 0) ) {
 | |
| 			throw new ImageResizeException("Invalid options for height and width. ($width x $height)");
 | |
| 		}
 | |
| 		
 | |
| 		$image_obj = Image::by_id($image_id);
 | |
| 		$hash = $image_obj->hash;
 | |
| 		if (is_null($hash)) {
 | |
| 			throw new ImageResizeException("Image does not have a hash associated with it.");
 | |
| 		}
 | |
| 		
 | |
| 		$image_filename  = warehouse_path("images", $hash);
 | |
| 		$info = getimagesize($image_filename);
 | |
| 		/* Get the image file type */
 | |
| 		$pathinfo = pathinfo($image_obj->filename);
 | |
| 		$filetype = strtolower($pathinfo['extension']);
 | |
| 		
 | |
| 		if (($image_obj->width != $info[0] ) || ($image_obj->height != $info[1])) {
 | |
| 			throw new ImageResizeException("The image size does not match what is in the database! - Aborting Resize.");
 | |
| 		}
 | |
| 		
 | |
| 		/* Check memory usage limits */
 | |
| 		$memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
 | |
| 		$memory_limit = get_memory_limit();
 | |
| 		
 | |
| 		if ($memory_use > $memory_limit) {
 | |
| 			throw new ImageResizeException("The image is too large to resize given the memory limits. ($memory_use > $memory_limit)");
 | |
| 		}
 | |
| 		
 | |
| 		/* Calculate the new size of the image */
 | |
| 		if ( $height > 0 && $width > 0 ) {
 | |
| 			$new_height = $height;
 | |
| 			$new_width = $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 );
 | |
| 
 | |
| 			$new_width  = round( $image_obj->width * $factor );
 | |
| 			$new_height = round( $image_obj->height * $factor );			
 | |
| 		}
 | |
| 		
 | |
| 		/* Attempt to load the image */
 | |
| 		switch ( $info[2] ) {
 | |
| 		  case IMAGETYPE_GIF:   $image = imagecreatefromgif($image_filename);   break;
 | |
| 		  case IMAGETYPE_JPEG:  $image = imagecreatefromjpeg($image_filename);  break;
 | |
| 		  /* FIXME: PNG support seems to be broken.
 | |
| 		  case IMAGETYPE_PNG:   $image = imagecreatefrompng($image_filename);   break;*/
 | |
| 		  default:
 | |
| 			throw new ImageResizeException("Unsupported image type.");
 | |
| 		}
 | |
| 		
 | |
| 		/* Resize and resample the image */
 | |
| 		$image_resized = imagecreatetruecolor( $new_width, $new_height );
 | |
| 		
 | |
| 		if ( ($info[2] == IMAGETYPE_GIF) || ($info[2] == IMAGETYPE_PNG) ) {
 | |
| 		  $transparency = imagecolortransparent($image);
 | |
| 
 | |
| 		  if ($transparency >= 0) {
 | |
| 			$transparent_color  = imagecolorsforindex($image, $trnprt_indx);
 | |
| 			$transparency       = imagecolorallocate($image_resized, $trnprt_color['red'], $trnprt_color['green'], $trnprt_color['blue']);
 | |
| 			imagefill($image_resized, 0, 0, $transparency);
 | |
| 			imagecolortransparent($image_resized, $transparency);
 | |
| 		  }
 | |
| 		  elseif ($info[2] == IMAGETYPE_PNG) {
 | |
| 			imagealphablending($image_resized, false);
 | |
| 			$color = imagecolorallocatealpha($image_resized, 0, 0, 0, 127);
 | |
| 			imagefill($image_resized, 0, 0, $color);
 | |
| 			imagesavealpha($image_resized, true);
 | |
| 		  }
 | |
| 		}
 | |
| 		imagecopyresampled($image_resized, $image, 0, 0, 0, 0, $new_width, $new_height, $image_obj->width, $image_obj->height);
 | |
| 		
 | |
| 		/* Temp storage while we resize */
 | |
| 		$tmp_filename = tempnam("/tmp", 'shimmie_resize');
 | |
| 		if (empty($tmp_filename)) {
 | |
| 			throw new ImageResizeException("Unable to save temporary image file.");
 | |
| 		}
 | |
| 		
 | |
| 		/* Output to the same format as the original image */
 | |
| 		switch ( $info[2] ) {
 | |
| 		  case IMAGETYPE_GIF:   imagegif($image_resized, $tmp_filename);    break;
 | |
| 		  case IMAGETYPE_JPEG:  imagejpeg($image_resized, $tmp_filename);   break;
 | |
| 		  case IMAGETYPE_PNG:   imagepng($image_resized, $tmp_filename);    break;
 | |
| 		  default:
 | |
| 			throw new ImageResizeException("Unsupported image type.");
 | |
| 		}
 | |
| 		
 | |
| 		/* Move the new image into the main storage location */
 | |
| 		$new_hash = md5_file($tmp_filename);
 | |
| 		$new_size = filesize($tmp_filename);
 | |
| 		$target = warehouse_path("images", $new_hash);
 | |
| 		if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true);
 | |
| 		if(!@copy($tmp_filename, $target)) {
 | |
| 			throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
 | |
| 		}
 | |
| 		$new_filename = 'resized-'.$image_obj->filename;
 | |
| 		
 | |
| 		/* Remove temporary file */
 | |
| 		@unlink($tmp_filename);
 | |
| 
 | |
| 		/* Delete original image and thumbnail */
 | |
| 		log_debug("image", "Removing image with hash ".$hash);
 | |
| 		$image_obj->remove_image_only();
 | |
| 		
 | |
| 		/* Generate new thumbnail */
 | |
| 		send_event(new ThumbnailGenerationEvent($new_hash, $filetype));
 | |
| 		
 | |
| 		/* Update the database */
 | |
| 		$database->Execute(
 | |
| 				"UPDATE images SET 
 | |
| 					filename = :filename, filesize = :filesize,	hash = :hash, width = :width, height = :height
 | |
| 				WHERE 
 | |
| 					id = :id
 | |
| 				",
 | |
| 				array(
 | |
| 					"filename"=>$new_filename, "filesize"=>$new_size, "hash"=>$new_hash,
 | |
| 					"width"=>$new_width, "height"=>$new_height,	"id"=>$image_id
 | |
| 				)
 | |
| 		);
 | |
| 		
 | |
| 		log_info("resize", "Resized Image #{$image_id} - New hash: {$new_hash}");
 | |
| 	}
 | |
| }
 | |
| ?>
 |