Image_GD
Kohana_Image_GD
Image
Kohana_Image

Class Contents

Class declared in MODPATH/image/classes/image/gd.php on line 3.

Constants

NONE
integer 1
WIDTH
integer 2
HEIGHT
integer 3
AUTO
integer 4
INVERSE
integer 5
HORIZONTAL
integer 17
VERTICAL
integer 18

Properties

public static $default_driver
string(2) "GD"
public $file
public $height
public $type
public $width

Methods

public __construct( )
Kohana_Image_GD

Source Code
public function __construct($file)
{
	if ( ! Image_GD::$_checked)
	{
		// Run the install check
		Image_GD::check();
	}

	parent::__construct($file);

	// Set the image creation function name
	switch ($this->type)
	{
		case IMAGETYPE_JPEG:
			$create = 'imagecreatefromjpeg';
		break;
		case IMAGETYPE_GIF:
			$create = 'imagecreatefromgif';
		break;
		case IMAGETYPE_PNG:
			$create = 'imagecreatefrompng';
		break;
	}

	if ( ! isset($create) OR ! function_exists($create))
	{
		throw new Kohana_Exception('Installed GD does not support :type images',
			array(':type' => image_type_to_extension($this->type, FALSE)));
	}

	// Save function for future use
	$this->_create_function = $create;

	// Save filename for lazy loading
	$this->_image = $this->file;
}

public __destruct( )
Kohana_Image_GD

Source Code
public function __destruct()
{
	if (is_resource($this->_image))
	{
		// Free all resources
		imagedestroy($this->_image);
	}
}

protected _create( )
Kohana_Image_GD

Source Code
protected function _create($width, $height)
{
	// Create an empty image
	$image = imagecreatetruecolor($width, $height);

	// Do not apply alpha blending
	imagealphablending($image, FALSE);

	// Save alpha levels
	imagesavealpha($image, TRUE);

	return $image;
}

protected _do_background( )
Kohana_Image_GD

Source Code
protected function _do_background($r, $g, $b, $opacity)
{
	// Loads image if not yet loaded
	$this->_load_image();

	// Convert an opacity range of 0-100 to 127-0
	$opacity = round(abs(($opacity * 127 / 100) - 127));

	// Create a new background
	$background = $this->_create($this->width, $this->height);

	// Allocate the color
	$color = imagecolorallocatealpha($background, $r, $g, $b, $opacity);

	// Fill the image with white
	imagefilledrectangle($background, 0, 0, $this->width, $this->height, $color);

	// Alpha blending must be enabled on the background!
	imagealphablending($background, TRUE);

	// Copy the image onto a white background to remove all transparency
	if (imagecopy($background, $this->_image, 0, 0, 0, 0, $this->width, $this->height))
	{
		// Swap the new image for the old one
		imagedestroy($this->_image);
		$this->_image = $background;
	}
}

protected _do_crop( )
Kohana_Image_GD

Source Code
protected function _do_crop($width, $height, $offset_x, $offset_y)
{
	// Create the temporary image to copy to
	$image = $this->_create($width, $height);

	// Loads image if not yet loaded
	$this->_load_image();

	// Execute the crop
	if (imagecopyresampled($image, $this->_image, 0, 0, $offset_x, $offset_y, $width, $height, $width, $height))
	{
		// Swap the new image for the old one
		imagedestroy($this->_image);
		$this->_image = $image;

		// Reset the width and height
		$this->width  = imagesx($image);
		$this->height = imagesy($image);
	}
}

protected _do_flip( )
Kohana_Image_GD

Source Code
protected function _do_flip($direction)
{
	// Create the flipped image
	$flipped = $this->_create($this->width, $this->height);

	// Loads image if not yet loaded
	$this->_load_image();

	if ($direction === Image::HORIZONTAL)
	{
		for ($x = 0; $x < $this->width; $x++)
		{
			// Flip each row from top to bottom
			imagecopy($flipped, $this->_image, $x, 0, $this->width - $x - 1, 0, 1, $this->height);
		}
	}
	else
	{
		for ($y = 0; $y < $this->height; $y++)
		{
			// Flip each column from left to right
			imagecopy($flipped, $this->_image, 0, $y, 0, $this->height - $y - 1, $this->width, 1);
		}
	}

	// Swap the new image for the old one
	imagedestroy($this->_image);
	$this->_image = $flipped;

	// Reset the width and height
	$this->width  = imagesx($flipped);
	$this->height = imagesy($flipped);
}

protected _do_reflection( )
Kohana_Image_GD

Source Code
protected function _do_reflection($height, $opacity, $fade_in)
{
	if ( ! Image_GD::$_bundled)
	{
		throw new Kohana_Exception('This method requires :function, which is only available in the bundled version of GD',
			array(':function' => 'imagefilter'));
	}

	// Loads image if not yet loaded
	$this->_load_image();

	// Convert an opacity range of 0-100 to 127-0
	$opacity = round(abs(($opacity * 127 / 100) - 127));

	if ($opacity < 127)
	{
		// Calculate the opacity stepping
		$stepping = (127 - $opacity) / $height;
	}
	else
	{
		// Avoid a "divide by zero" error
		$stepping = 127 / $height;
	}

	// Create the reflection image
	$reflection = $this->_create($this->width, $this->height + $height);

	// Copy the image to the reflection
	imagecopy($reflection, $this->_image, 0, 0, 0, 0, $this->width, $this->height);

	for ($offset = 0; $height >= $offset; $offset++)
	{
		// Read the next line down
		$src_y = $this->height - $offset - 1;

		// Place the line at the bottom of the reflection
		$dst_y = $this->height + $offset;

		if ($fade_in === TRUE)
		{
			// Start with the most transparent line first
			$dst_opacity = round($opacity + ($stepping * ($height - $offset)));
		}
		else
		{
			// Start with the most opaque line first
			$dst_opacity = round($opacity + ($stepping * $offset));
		}

		// Create a single line of the image
		$line = $this->_create($this->width, 1);

		// Copy a single line from the current image into the line
		imagecopy($line, $this->_image, 0, 0, 0, $src_y, $this->width, 1);

		// Colorize the line to add the correct alpha level
		imagefilter($line, IMG_FILTER_COLORIZE, 0, 0, 0, $dst_opacity);

		// Copy a the line into the reflection
		imagecopy($reflection, $line, 0, $dst_y, 0, 0, $this->width, 1);
	}

	// Swap the new image for the old one
	imagedestroy($this->_image);
	$this->_image = $reflection;

	// Reset the width and height
	$this->width  = imagesx($reflection);
	$this->height = imagesy($reflection);
}

protected _do_render( )
Kohana_Image_GD

Source Code
protected function _do_render($type, $quality)
{
	// Loads image if not yet loaded
	$this->_load_image();

	// Get the save function and IMAGETYPE
	list($save, $type) = $this->_save_function($type, $quality);

	// Capture the output
	ob_start();

	// Render the image
	$status = isset($quality) ? $save($this->_image, NULL, $quality) : $save($this->_image, NULL);

	if ($status === TRUE AND $type !== $this->type)
	{
		// Reset the image type and mime type
		$this->type = $type;
		$this->mime = image_type_to_mime_type($type);
	}

	return ob_get_clean();
}

protected _do_resize( )
Kohana_Image_GD

Source Code
protected function _do_resize($width, $height)
{
	// Presize width and height
	$pre_width = $this->width;
	$pre_height = $this->height;

	// Loads image if not yet loaded
	$this->_load_image();

	// Test if we can do a resize without resampling to speed up the final resize
	if ($width > ($this->width / 2) AND $height > ($this->height / 2))
	{
		// The maximum reduction is 10% greater than the final size
		$reduction_width  = round($width  * 1.1);
		$reduction_height = round($height * 1.1);

		while ($pre_width / 2 > $reduction_width AND $pre_height / 2 > $reduction_height)
		{
			// Reduce the size using an O(2n) algorithm, until it reaches the maximum reduction
			$pre_width /= 2;
			$pre_height /= 2;
		}

		// Create the temporary image to copy to
		$image = $this->_create($pre_width, $pre_height);

		if (imagecopyresized($image, $this->_image, 0, 0, 0, 0, $pre_width, $pre_height, $this->width, $this->height))
		{
			// Swap the new image for the old one
			imagedestroy($this->_image);
			$this->_image = $image;
		}
	}

	// Create the temporary image to copy to
	$image = $this->_create($width, $height);

	// Execute the resize
	if (imagecopyresampled($image, $this->_image, 0, 0, 0, 0, $width, $height, $pre_width, $pre_height))
	{
		// Swap the new image for the old one
		imagedestroy($this->_image);
		$this->_image = $image;

		// Reset the width and height
		$this->width  = imagesx($image);
		$this->height = imagesy($image);
	}
}

protected _do_rotate( )
Kohana_Image_GD

Source Code
protected function _do_rotate($degrees)
{
	if ( ! Image_GD::$_bundled)
	{
		throw new Kohana_Exception('This method requires :function, which is only available in the bundled version of GD',
			array(':function' => 'imagerotate'));
	}

	// Loads image if not yet loaded
	$this->_load_image();

	// Transparent black will be used as the background for the uncovered region
	$transparent = imagecolorallocatealpha($this->_image, 0, 0, 0, 127);

	// Rotate, setting the transparent color
	$image = imagerotate($this->_image, 360 - $degrees, $transparent, 1);

	// Save the alpha of the rotated image
	imagesavealpha($image, TRUE);

	// Get the width and height of the rotated image
	$width  = imagesx($image);
	$height = imagesy($image);

	if (imagecopymerge($this->_image, $image, 0, 0, 0, 0, $width, $height, 100))
	{
		// Swap the new image for the old one
		imagedestroy($this->_image);
		$this->_image = $image;

		// Reset the width and height
		$this->width  = $width;
		$this->height = $height;
	}
}

protected _do_save( )
Kohana_Image_GD

Source Code
protected function _do_save($file, $quality)
{
	// Loads image if not yet loaded
	$this->_load_image();

	// Get the extension of the file
	$extension = pathinfo($file, PATHINFO_EXTENSION);

	// Get the save function and IMAGETYPE
	list($save, $type) = $this->_save_function($extension, $quality);

	// Save the image to a file
	$status = isset($quality) ? $save($this->_image, $file, $quality) : $save($this->_image, $file);

	if ($status === TRUE AND $type !== $this->type)
	{
		// Reset the image type and mime type
		$this->type = $type;
		$this->mime = image_type_to_mime_type($type);
	}

	return TRUE;
}

protected _do_sharpen( )
Kohana_Image_GD

Source Code
protected function _do_sharpen($amount)
{
	if ( ! Image_GD::$_bundled)
	{
		throw new Kohana_Exception('This method requires :function, which is only available in the bundled version of GD',
			array(':function' => 'imageconvolution'));
	}

	// Loads image if not yet loaded
	$this->_load_image();

	// Amount should be in the range of 18-10
	$amount = round(abs(-18 + ($amount * 0.08)), 2);

	// Gaussian blur matrix
	$matrix = array
	(
		array(-1,   -1,    -1),
		array(-1, $amount, -1),
		array(-1,   -1,    -1),
	);

	// Perform the sharpen
	if (imageconvolution($this->_image, $matrix, $amount - 8, 0))
	{
		// Reset the width and height
		$this->width  = imagesx($this->_image);
		$this->height = imagesy($this->_image);
	}
}

protected _do_watermark( )
Kohana_Image_GD

Source Code
protected function _do_watermark(Image $watermark, $offset_x, $offset_y, $opacity)
{
	if ( ! Image_GD::$_bundled)
	{
		throw new Kohana_Exception('This method requires :function, which is only available in the bundled version of GD',
			array(':function' => 'imagelayereffect'));
	}

	// Loads image if not yet loaded
	$this->_load_image();

	// Create the watermark image resource
	$overlay = imagecreatefromstring($watermark->render());

	// Get the width and height of the watermark
	$width  = imagesx($overlay);
	$height = imagesy($overlay);

	if ($opacity < 100)
	{
		// Convert an opacity range of 0-100 to 127-0
		$opacity = round(abs(($opacity * 127 / 100) - 127));

		// Allocate transparent white
		$color = imagecolorallocatealpha($overlay, 255, 255, 255, $opacity);

		// The transparent image will overlay the watermark
		imagelayereffect($overlay, IMG_EFFECT_OVERLAY);

		// Fill the background with transparent white
		imagefilledrectangle($overlay, 0, 0, $width, $height, $color);
	}

	// Alpha blending must be enabled on the background!
	imagealphablending($this->_image, TRUE);

	if (imagecopy($this->_image, $overlay, $offset_x, $offset_y, 0, 0, $width, $height))
	{
		// Destroy the overlay image
		imagedestroy($overlay);
	}
}

protected _load_image( )
Kohana_Image_GD

Source Code
protected function _load_image()
{
	if ( ! is_resource($this->_image))
	{
		// Gets create function
		$create = $this->_create_function;

		// Open the temporary image
		$this->_image = $create($this->file);

		// Preserve transparency when saving
		imagesavealpha($this->_image, TRUE);
	}
}

protected _save_function( )
Kohana_Image_GD

Source Code
protected function _save_function($extension, & $quality)
{
	switch (strtolower($extension))
	{
		case 'jpg':
		case 'jpeg':
			// Save a JPG file
			$save = 'imagejpeg';
			$type = IMAGETYPE_JPEG;
		break;
		case 'gif':
			// Save a GIF file
			$save = 'imagegif';
			$type = IMAGETYPE_GIF;

			// GIFs do not a quality setting
			$quality = NULL;
		break;
		case 'png':
			// Save a PNG file
			$save = 'imagepng';
			$type = IMAGETYPE_PNG;

			// Use a compression level of 9 (does not affect quality!)
			$quality = 9;
		break;
		default:
			throw new Kohana_Exception('Installed GD does not support :type images',
				array(':type' => $extension));
		break;
	}

	return array($save, $type);
}

public static check( )
Kohana_Image_GD

Source Code
public static function check()
{
	if ( ! function_exists('gd_info'))
	{
		throw new Kohana_Exception('GD is either not installed or not enabled, check your configuration');
	}

	if (defined('GD_BUNDLED'))
	{
		// Get the version via a constant, available in PHP 5.
		Image_GD::$_bundled = GD_BUNDLED;
	}
	else
	{
		// Get the version information
		$info = gd_info();

		// Extract the bundled status
		Image_GD::$_bundled = (bool) preg_match('/\bbundled\b/i', $info['GD Version']);
	}

	if (defined('GD_VERSION'))
	{
		// Get the version via a constant, available in PHP 5.2.4+
		$version = GD_VERSION;
	}
	else
	{
		// Get the version information
		$info = gd_info();

		// Extract the version number
		preg_match('/\d+\.\d+(?:\.\d+)?/', $info['GD Version'], $matches);

		// Get the major version
		$version = $matches[0];
	}

	if ( ! version_compare($version, '2.0.1', '>='))
	{
		throw new Kohana_Exception('Image_GD requires GD version :required or greater, you have :version',
			array('required' => '2.0.1', ':version' => $version));
	}

	return Image_GD::$_checked = TRUE;
}

public __toString( )
Kohana_Image

Source Code
public function __toString()
{
	try
	{
		// Render the current image
		return $this->render();
	}
	catch (Exception $e)
	{
		if (is_object(Kohana::$log))
		{
			// Get the text of the exception
			$error = Kohana::exception_text($e);

			// Add this exception to the log
			Kohana::$log->add(Kohana::ERROR, $error);
		}

		// Showing any kind of error will be "inside" image data
		return '';
	}
}

public background( )
Kohana_Image

Source Code
public function background($color, $opacity = 100)
{
	if ($color[0] === '#')
	{
		// Remove the pound
		$color = substr($color, 1);
	}

	if (strlen($color) === 3)
	{
		// Convert shorthand into longhand hex notation
		$color = preg_replace('/./', '$0$0', $color);
	}

	// Convert the hex into RGB values
	list ($r, $g, $b) = array_map('hexdec', str_split($color, 2));

	// The opacity must be in the range of 0 to 100
	$opacity = min(max($opacity, 0), 100);

	$this->_do_background($r, $g, $b, $opacity);

	return $this;
}

public crop( )
Kohana_Image

Source Code
public function crop($width, $height, $offset_x = NULL, $offset_y = NULL)
{
	if ($width > $this->width)
	{
		// Use the current width
		$width = $this->width;
	}

	if ($height > $this->height)
	{
		// Use the current height
		$height = $this->height;
	}

	if ($offset_x === NULL)
	{
		// Center the X offset
		$offset_x = round(($this->width - $width) / 2);
	}
	elseif ($offset_x === TRUE)
	{
		// Bottom the X offset
		$offset_x = $this->width - $width;
	}
	elseif ($offset_x < 0)
	{
		// Set the X offset from the right
		$offset_x = $this->width - $width + $offset_x;
	}

	if ($offset_y === NULL)
	{
		// Center the Y offset
		$offset_y = round(($this->height - $height) / 2);
	}
	elseif ($offset_y === TRUE)
	{
		// Bottom the Y offset
		$offset_y = $this->height - $height;
	}
	elseif ($offset_y < 0)
	{
		// Set the Y offset from the bottom
		$offset_y = $this->height - $height + $offset_y;
	}

	// Determine the maximum possible width and height
	$max_width  = $this->width  - $offset_x;
	$max_height = $this->height - $offset_y;

	if ($width > $max_width)
	{
		// Use the maximum available width
		$width = $max_width;
	}

	if ($height > $max_height)
	{
		// Use the maximum available height
		$height = $max_height;
	}

	$this->_do_crop($width, $height, $offset_x, $offset_y);

	return $this;
}

public static factory( )
Kohana_Image

Source Code
public static function factory($file, $driver = NULL)
{
	if ($driver === NULL)
	{
		// Use the default driver
		$driver = Image::$default_driver;
	}

	// Set the class name
	$class = 'Image_'.$driver;

	return new $class($file);
}

public flip( )
Kohana_Image

Source Code
public function flip($direction)
{
	if ($direction !== Image::HORIZONTAL)
	{
		// Flip vertically
		$direction = Image::VERTICAL;
	}

	$this->_do_flip($direction);

	return $this;
}

public reflection( )
Kohana_Image

Source Code
public function reflection($height = NULL, $opacity = 100, $fade_in = FALSE)
{
	if ($height === NULL OR $height > $this->height)
	{
		// Use the current height
		$height = $this->height;
	}

	// The opacity must be in the range of 0 to 100
	$opacity = min(max($opacity, 0), 100);

	$this->_do_reflection($height, $opacity, $fade_in);

	return $this;
}

public render( )
Kohana_Image

Source Code
public function render($type = NULL, $quality = 100)
{
	if ($type === NULL)
	{
		// Use the current image type
		$type = image_type_to_extension($this->type, FALSE);
	}

	return $this->_do_render($type, $quality);
}

public resize( )
Kohana_Image

Source Code
public function resize($width = NULL, $height = NULL, $master = NULL)
{
	if ($master === NULL)
	{
		// Choose the master dimension automatically
		$master = Image::AUTO;
	}
	// Image::WIDTH and Image::HEIGHT depricated. You can use it in old projects,
	// but in new you must pass empty value for non-master dimension
	elseif ($master == Image::WIDTH AND ! empty($width))
	{
		$master = Image::AUTO;

		// Set empty height for backvard compatibility
		$height = NULL;
	}
	elseif ($master == Image::HEIGHT AND ! empty($height))
	{
		$master = Image::AUTO;

		// Set empty width for backvard compatibility
		$width = NULL;
	}

	if (empty($width))
	{
		if ($master === Image::NONE)
		{
			// Use the current width
			$width = $this->width;
		}
		else
		{
			// If width not set, master will be height
			$master = Image::HEIGHT;
		}
	}

	if (empty($height))
	{
		if ($master === Image::NONE)
		{
			// Use the current height
			$height = $this->height;
		}
		else
		{
			// If height not set, master will be width
			$master = Image::WIDTH;
		}
	}

	switch ($master)
	{
		case Image::AUTO:
			// Choose direction with the greatest reduction ratio
			$master = ($this->width / $width) > ($this->height / $height) ? Image::WIDTH : Image::HEIGHT;
		break;
		case Image::INVERSE:
			// Choose direction with the minimum reduction ratio
			$master = ($this->width / $width) > ($this->height / $height) ? Image::HEIGHT : Image::WIDTH;
		break;
	}

	switch ($master)
	{
		case Image::WIDTH:
			// Recalculate the height based on the width proportions
			$height = $this->height * $width / $this->width;
		break;
		case Image::HEIGHT:
			// Recalculate the width based on the height proportions
			$width = $this->width * $height / $this->height;
		break;
	}

	// Convert the width and height to integers, minimum value is 1px
	$width  = max(round($width), 1);
	$height = max(round($height), 1);

	$this->_do_resize($width, $height);

	return $this;
}

public rotate( )
Kohana_Image

Source Code
public function rotate($degrees)
{
	// Make the degrees an integer
	$degrees = (int) $degrees;

	if ($degrees > 180)
	{
		do
		{
			// Keep subtracting full circles until the degrees have normalized
			$degrees -= 360;
		}
		while($degrees > 180);
	}

	if ($degrees < -180)
	{
		do
		{
			// Keep adding full circles until the degrees have normalized
			$degrees += 360;
		}
		while($degrees < -180);
	}

	$this->_do_rotate($degrees);

	return $this;
}

public save( )
Kohana_Image

Source Code
public function save($file = NULL, $quality = 100)
{
	if ($file === NULL)
	{
		// Overwrite the file
		$file = $this->file;
	}

	if (is_file($file))
	{
		if ( ! is_writable($file))
		{
			throw new Kohana_Exception('File must be writable: :file',
				array(':file' => Kohana::debug_path($file)));
		}
	}
	else
	{
		// Get the directory of the file
		$directory = realpath(pathinfo($file, PATHINFO_DIRNAME));

		if ( ! is_dir($directory) OR ! is_writable($directory))
		{
			throw new Kohana_Exception('Directory must be writable: :directory',
				array(':directory' => Kohana::debug_path($directory)));
		}
	}

	// The quality must be in the range of 1 to 100
	$quality = min(max($quality, 1), 100);

	return $this->_do_save($file, $quality);
}

public sharpen( )
Kohana_Image

Source Code
public function sharpen($amount)
{
	// The amount must be in the range of 1 to 100
	$amount = min(max($amount, 1), 100);

	$this->_do_sharpen($amount);

	return $this;
}

public watermark( )
Kohana_Image

Source Code
public function watermark(Image $watermark, $offset_x = NULL, $offset_y = NULL, $opacity = 100)
{
	if ($offset_x === NULL)
	{
		// Center the X offset
		$offset_x = round(($this->width - $watermark->width) / 2);
	}
	elseif ($offset_x === TRUE)
	{
		// Bottom the X offset
		$offset_x = $this->width - $watermark->width;
	}
	elseif ($offset_x < 0)
	{
		// Set the X offset from the right
		$offset_x = $this->width - $watermark->width + $offset_x;
	}

	if ($offset_y === NULL)
	{
		// Center the Y offset
		$offset_y = round(($this->height - $watermark->height) / 2);
	}
	elseif ($offset_y === TRUE)
	{
		// Bottom the Y offset
		$offset_y = $this->height - $watermark->height;
	}
	elseif ($offset_y < 0)
	{
		// Set the Y offset from the bottom
		$offset_y = $this->height - $watermark->height + $offset_y;
	}

	// The opacity must be in the range of 1 to 100
	$opacity = min(max($opacity, 1), 100);

	$this->_do_watermark($watermark, $offset_x, $offset_y, $opacity);

	return $this;
}