You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
913 lines
23 KiB
913 lines
23 KiB
<?php
|
|
/**
|
|
* Part of the Fuel framework.
|
|
*
|
|
* @package Fuel
|
|
* @version 1.8
|
|
* @author Fuel Development Team
|
|
* @license MIT License
|
|
* @copyright 2010 - 2016 Fuel Development Team
|
|
* @link http://fuelphp.com
|
|
*/
|
|
|
|
namespace Fuel\Core;
|
|
|
|
abstract class Image_Driver
|
|
{
|
|
protected $image_fullpath = null;
|
|
protected $image_directory = null;
|
|
protected $image_filename = null;
|
|
protected $image_extension = null;
|
|
protected $new_extension = null;
|
|
protected $config = array();
|
|
protected $queued_actions = array();
|
|
protected $accepted_extensions;
|
|
|
|
/**
|
|
* Initialize by loading config
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function _init()
|
|
{
|
|
\Config::load('image', true);
|
|
}
|
|
|
|
public function __construct($config)
|
|
{
|
|
if (is_array($config))
|
|
{
|
|
$this->config = array_merge(\Config::get('image', array()), $config);
|
|
}
|
|
else
|
|
{
|
|
$this->config = \Config::get('image', array());
|
|
}
|
|
$this->debug("Image Class was initialized using the " . $this->config['driver'] . " driver.");
|
|
}
|
|
/**
|
|
* Accepts configuration in either an array (as $index) or a pairing using $index and $value
|
|
*
|
|
* @param string $index The index to be set, or an array of configuration options.
|
|
* @param mixed $value The value to be set if $index is not an array.
|
|
* @return Image_Driver
|
|
*/
|
|
public function config($index = null, $value = null)
|
|
{
|
|
if (is_array($index))
|
|
{
|
|
if (isset($index['driver']))
|
|
{
|
|
throw new \RuntimeException("The driver cannot be changed after initialization!");
|
|
}
|
|
$this->config = array_merge($this->config, $index);
|
|
}
|
|
elseif ($index != null)
|
|
{
|
|
if ($index == 'driver')
|
|
{
|
|
throw new \RuntimeException("The driver cannot be changed after initialization!");
|
|
}
|
|
$this->config[$index] = $value;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the presets set in the config. Additional parameters replace the $1, $2, ect.
|
|
*
|
|
* @param string $name The name of the preset.
|
|
* @return Image_Driver
|
|
*/
|
|
public function preset($name)
|
|
{
|
|
$vars = func_get_args();
|
|
if (isset($this->config['presets'][$name]))
|
|
{
|
|
$old_config = $this->config;
|
|
$this->config = array_merge($this->config, $this->config['presets'][$name]);
|
|
foreach ($this->config['actions'] AS $action)
|
|
{
|
|
$func = $action[0];
|
|
array_shift($action);
|
|
for ($i = 0; $i < count($action); $i++)
|
|
{
|
|
for ($x = count($vars) - 1; $x >= 0; $x--)
|
|
{
|
|
$action[$i] = preg_replace('#\$' . $x . '#', $vars[$x], $action[$i]);
|
|
}
|
|
}
|
|
call_fuel_func_array(array($this, $func), $action);
|
|
}
|
|
$this->config = $old_config;
|
|
}
|
|
else
|
|
{
|
|
throw new \InvalidArgumentException("Could not load preset $name, you sure it exists?");
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Loads the image and checks if its compatible.
|
|
*
|
|
* @param string $filename The file to load
|
|
* @param string $return_data Decides if it should return the images data, or just "$this".
|
|
* @param mixed $force_extension Decides if it should force the extension with this (or false)
|
|
* @return Image_Driver
|
|
*/
|
|
public function load($filename, $return_data = false, $force_extension = false)
|
|
{
|
|
// First check if the filename exists
|
|
$filename = realpath($filename);
|
|
$return = array(
|
|
'filename' => $filename,
|
|
'return_data' => $return_data,
|
|
);
|
|
if (is_file($filename))
|
|
{
|
|
// Check the extension
|
|
$ext = $this->check_extension($filename, false, $force_extension);
|
|
if ($ext !== false)
|
|
{
|
|
$return = array_merge($return, array(
|
|
'image_fullpath' => $filename,
|
|
'image_directory' => dirname($filename),
|
|
'image_filename' => basename($filename),
|
|
'image_extension' => $ext,
|
|
));
|
|
if ( ! $return_data)
|
|
{
|
|
$this->image_fullpath = $filename;
|
|
$this->image_directory = dirname($filename);
|
|
$this->image_filename = basename($filename);
|
|
$this->image_extension = $ext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new \RuntimeException("The library does not support this filetype for $filename.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new \OutOfBoundsException("Image file $filename does not exist.");
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Crops the image using coordinates or percentages.
|
|
*
|
|
* Positive whole numbers or percentages are coordinates from the top left.
|
|
*
|
|
* Negative whole numbers or percentages are coordinates from the bottom right.
|
|
*
|
|
* @param integer $x1 X-Coordinate for first set.
|
|
* @param integer $y1 Y-Coordinate for first set.
|
|
* @param integer $x2 X-Coordinate for second set.
|
|
* @param integer $y2 Y-Coordinate for second set.
|
|
* @return Image_Driver
|
|
*/
|
|
public function crop($x1, $y1, $x2, $y2)
|
|
{
|
|
$this->queue('crop', $x1, $y1, $x2, $y2);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the crop event when the queue is ran.
|
|
*
|
|
* Formats the crop method input for use with driver specific methods
|
|
*
|
|
* @param integer $x1 X-Coordinate for first set.
|
|
* @param integer $y1 Y-Coordinate for first set.
|
|
* @param integer $x2 X-Coordinate for second set.
|
|
* @param integer $y2 Y-Coordinate for second set.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _crop($x1, $y1, $x2, $y2)
|
|
{
|
|
$y1 === null and $y1 = $x1;
|
|
$x2 === null and $x2 = "-" . $x1;
|
|
$y2 === null and $y2 = "-" . $y1;
|
|
|
|
$x1 = $this->convert_number($x1, true);
|
|
$y1 = $this->convert_number($y1, false);
|
|
$x2 = $this->convert_number($x2, true);
|
|
$y2 = $this->convert_number($y2, false);
|
|
|
|
return array(
|
|
'x1' => $x1,
|
|
'y1' => $y1,
|
|
'x2' => $x2,
|
|
'y2' => $y2,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Resize the image. If the width or height is null, it will resize retaining the original aspect ratio.
|
|
*
|
|
* @param integer $width The new width of the image.
|
|
* @param integer $height The new height of the image.
|
|
* @param boolean $keepar If false, allows stretching of the image.
|
|
* @param boolean $pad Adds padding to the image when resizing.
|
|
* @return Image_Driver
|
|
*/
|
|
public function resize($width, $height = null, $keepar = true, $pad = false)
|
|
{
|
|
$this->queue('resize', $width, $height, $keepar, $pad);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Creates a vertical / horizontal or both mirror image.
|
|
*
|
|
* @param mixed $direction 'vertical', 'horizontal', 'both'
|
|
* @return Image_Driver
|
|
*/
|
|
public function flip($direction)
|
|
{
|
|
$this->queue('flip', $direction);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the resize event when the queue is ran.
|
|
*
|
|
* Formats the resize method input for use with driver specific methods.
|
|
*
|
|
* @param integer $width The new width of the image.
|
|
* @param integer $height The new height of the image.
|
|
* @param boolean $keepar If false, allows stretching of the image.
|
|
* @param boolean $pad Adds padding to the image when resizing.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _resize($width, $height = null, $keepar = true, $pad = true)
|
|
{
|
|
if ($height == null or $width == null)
|
|
{
|
|
if ($height == null and substr($width, -1) == '%')
|
|
{
|
|
$height = $width;
|
|
}
|
|
elseif (substr($height, -1) == '%' and $width == null)
|
|
{
|
|
$width = $height;
|
|
}
|
|
else
|
|
{
|
|
$sizes = $this->sizes();
|
|
if ($height == null and $width != null)
|
|
{
|
|
$height = $width * ($sizes->height / $sizes->width);
|
|
}
|
|
elseif ($height != null and $width == null)
|
|
{
|
|
$width = $height * ($sizes->width / $sizes->height);
|
|
}
|
|
else
|
|
{
|
|
throw new \InvalidArgumentException("Width and height cannot be null.");
|
|
}
|
|
}
|
|
}
|
|
|
|
$origwidth = $this->convert_number($width, true);
|
|
$origheight = $this->convert_number($height, false);
|
|
$width = $origwidth;
|
|
$height = $origheight;
|
|
$sizes = $this->sizes();
|
|
$x = 0;
|
|
$y = 0;
|
|
if ($keepar)
|
|
{
|
|
// See which is the biggest ratio
|
|
if (function_exists('bcdiv'))
|
|
{
|
|
$width_ratio = bcdiv($width, $sizes->width, 10);
|
|
$height_ratio = bcdiv($height, $sizes->height, 10);
|
|
$compare = bccomp($width_ratio, $height_ratio, 10);
|
|
if ($compare > -1)
|
|
{
|
|
$height = ceil((float) bcmul($sizes->height, $height_ratio, 10));
|
|
$width = ceil((float) bcmul($sizes->width, $height_ratio, 10));
|
|
}
|
|
else
|
|
{
|
|
$height = ceil((float) bcmul($sizes->height, $width_ratio, 10));
|
|
$width = ceil((float) bcmul($sizes->width, $width_ratio, 10));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$width_ratio = $width / $sizes->width;
|
|
$height_ratio = $height / $sizes->height;
|
|
if ($width_ratio >= $height_ratio)
|
|
{
|
|
$height = ceil($sizes->height * $height_ratio);
|
|
$width = ceil($sizes->width * $height_ratio);
|
|
}
|
|
else
|
|
{
|
|
$height = ceil($sizes->height * $width_ratio);
|
|
$width = ceil($sizes->width * $width_ratio);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($pad)
|
|
{
|
|
$x = floor(($origwidth - $width) / 2);
|
|
$y = floor(($origheight - $height) / 2);
|
|
}
|
|
else
|
|
{
|
|
$origwidth = $width;
|
|
$origheight = $height;
|
|
}
|
|
|
|
return array(
|
|
'width' => $width,
|
|
'height' => $height,
|
|
'cwidth' => $origwidth,
|
|
'cheight' => $origheight,
|
|
'x' => $x,
|
|
'y' => $y,
|
|
);
|
|
}
|
|
|
|
public function crop_resize($width, $height = null)
|
|
{
|
|
is_null($height) and $height = $width;
|
|
$this->queue('crop_resize', $width, $height);
|
|
return $this;
|
|
}
|
|
|
|
protected function _crop_resize($width, $height)
|
|
{
|
|
// Determine the crop size
|
|
$sizes = $this->sizes();
|
|
$width = $this->convert_number($width, true);
|
|
$height = $this->convert_number($height, false);
|
|
|
|
if (function_exists('bcdiv'))
|
|
{
|
|
if (bccomp(bcdiv($sizes->width, $width, 10), bcdiv($sizes->height, $height, 10), 10) < 1)
|
|
{
|
|
$this->_resize($width, 0, true, false);
|
|
}
|
|
else
|
|
{
|
|
$this->_resize(0, $height, true, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ($sizes->width / $width < $sizes->height / $height)
|
|
{
|
|
$this->_resize($width, 0, true, false);
|
|
}
|
|
else
|
|
{
|
|
$this->_resize(0, $height, true, false);
|
|
}
|
|
}
|
|
|
|
$sizes = $this->sizes();
|
|
$y = floor(max(0, $sizes->height - $height) / 2);
|
|
$x = floor(max(0, $sizes->width - $width) / 2);
|
|
$this->_crop($x, $y, $x + $width, $y + $height);
|
|
}
|
|
|
|
/**
|
|
* Rotates the image
|
|
*
|
|
* @param integer $degrees The degrees to rotate, negatives integers allowed.
|
|
* @return Image_Driver
|
|
*/
|
|
public function rotate($degrees)
|
|
{
|
|
$this->queue('rotate', $degrees);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the rotate event when the queue is ran.
|
|
*
|
|
* Formats the rotate method input for use with driver specific methods
|
|
*
|
|
* @param integer $degrees The degrees to rotate, negatives integers allowed.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _rotate($degrees)
|
|
{
|
|
$degrees %= 360;
|
|
if ($degrees < 0)
|
|
{
|
|
$degrees = 360 + $degrees;
|
|
}
|
|
return array(
|
|
'degrees' => $degrees,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Adds a watermark to the image.
|
|
*
|
|
* @param string $filename The filename of the watermark file to use.
|
|
* @param string $position The position of the watermark, ex: "bottom right", "center center", "top left"
|
|
* @param integer $padding The amount of padding (in pixels) from the position.
|
|
* @return Image_Driver
|
|
*/
|
|
public function watermark($filename, $position, $padding = 5)
|
|
{
|
|
$this->queue('watermark', $filename, $position, $padding);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the watermark event when the queue is ran.
|
|
*
|
|
* Formats the watermark method input for use with driver specific methods
|
|
*
|
|
* @param string $filename The filename of the watermark file to use.
|
|
* @param string $position The position of the watermark, ex: "bottom right", "center center", "top left"
|
|
* @param integer $padding The amount of padding (in pixels) from the position.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _watermark($filename, $position, $padding = 5)
|
|
{
|
|
$filename = realpath($filename);
|
|
$return = false;
|
|
if (is_file($filename) and $this->check_extension($filename, false))
|
|
{
|
|
$x = 0;
|
|
$y = 0;
|
|
$wsizes = $this->sizes($filename);
|
|
$sizes = $this->sizes();
|
|
// Get the x and y positions.
|
|
list($ypos, $xpos) = explode(' ', $position);
|
|
switch ($xpos)
|
|
{
|
|
case 'left':
|
|
$x = $padding;
|
|
break;
|
|
case 'middle':
|
|
case 'center':
|
|
$x = ($sizes->width / 2) - ($wsizes->width / 2);
|
|
break;
|
|
case 'right':
|
|
$x = $sizes->width - $wsizes->width - $padding;
|
|
break;
|
|
}
|
|
switch ($ypos)
|
|
{
|
|
case 'top':
|
|
$y = $padding;
|
|
break;
|
|
case 'middle':
|
|
case 'center':
|
|
$y = ($sizes->height / 2) - ($wsizes->height / 2);
|
|
break;
|
|
case 'bottom':
|
|
$y = $sizes->height - $wsizes->height - $padding;
|
|
break;
|
|
}
|
|
$this->debug("Watermark being placed at $x,$y");
|
|
$return = array(
|
|
'filename' => $filename,
|
|
'x' => $x,
|
|
'y' => $y,
|
|
'padding' => $padding,
|
|
);
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Adds a border to the image.
|
|
*
|
|
* @param integer $size The side of the border, in pixels.
|
|
* @param string $color A hexadecimal color.
|
|
* @return Image_Driver
|
|
*/
|
|
public function border($size, $color = null)
|
|
{
|
|
$this->queue('border', $size, $color);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the border event when the queue is ran.
|
|
*
|
|
* Formats the border method input for use with driver specific methods
|
|
*
|
|
* @param integer $size The side of the border, in pixels.
|
|
* @param string $color A hexadecimal color.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _border($size, $color = null)
|
|
{
|
|
empty($color) and $color = $this->config['bgcolor'];
|
|
|
|
return array(
|
|
'size' => $size,
|
|
'color' => $color,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Masks the image using the alpha channel of the image input.
|
|
*
|
|
* @param string $maskimage The location of the image to use as the mask
|
|
* @return Image_Driver
|
|
*/
|
|
public function mask($maskimage)
|
|
{
|
|
$this->queue('mask', $maskimage);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the mask event when the queue is ran.
|
|
*
|
|
* Formats the mask method input for use with driver specific methods
|
|
*
|
|
* @param string $maskimage The location of the image to use as the mask
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _mask($maskimage)
|
|
{
|
|
return array(
|
|
'maskimage' => $maskimage,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Adds rounded corners to the image.
|
|
*
|
|
* @param integer $radius
|
|
* @param integer $sides Accepts any combination of "tl tr bl br" separated by spaces, or null for all sides
|
|
* @param integer $antialias Sets the anti-alias range.
|
|
* @return Image_Driver
|
|
*/
|
|
public function rounded($radius, $sides = null, $antialias = null)
|
|
{
|
|
$this->queue('rounded', $radius, $sides, $antialias);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the rounded event when the queue is ran.
|
|
*
|
|
* Formats the rounded method input for use with driver specific methods
|
|
*
|
|
* @param integer $radius
|
|
* @param integer $sides Accepts any combination of "tl tr bl br" separated by spaces, or null for all sides
|
|
* @param integer $antialias Sets the anti-alias range.
|
|
* @return array An array of variables for the specific driver.
|
|
*/
|
|
protected function _rounded($radius, $sides, $antialias)
|
|
{
|
|
$radius < 0 and $radius = 0;
|
|
$tl = $tr = $bl = $br = $sides == null;
|
|
|
|
if ($sides != null)
|
|
{
|
|
$sides = explode(' ', $sides);
|
|
foreach ($sides as $side)
|
|
{
|
|
if ($side == 'tl' or $side == 'tr' or $side == 'bl' or $side == 'br')
|
|
{
|
|
$$side = true;
|
|
}
|
|
}
|
|
}
|
|
$antialias == null and $antialias = 1;
|
|
|
|
return array(
|
|
'radius' => $radius,
|
|
'tl' => $tl,
|
|
'tr' => $tr,
|
|
'bl' => $bl,
|
|
'br' => $br,
|
|
'antialias' => $antialias,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Turns the image into a grayscale version
|
|
*
|
|
* @return Image_Driver
|
|
*/
|
|
public function grayscale()
|
|
{
|
|
$this->queue('grayscale');
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Executes the grayscale event when the queue is ran.
|
|
*/
|
|
abstract protected function _grayscale();
|
|
|
|
/**
|
|
* Saves the image, and optionally attempts to set permissions
|
|
*
|
|
* @param string $filename The location where to save the image.
|
|
* @param string $permissions Allows unix style permissions
|
|
* @return array
|
|
*/
|
|
public function save($filename = null, $permissions = null)
|
|
{
|
|
if (empty($filename))
|
|
{
|
|
$filename = $this->image_filename;
|
|
}
|
|
|
|
$directory = dirname($filename);
|
|
if ( ! is_dir($directory))
|
|
{
|
|
throw new \OutOfBoundsException("Could not find directory \"$directory\"");
|
|
}
|
|
|
|
if ( ! $this->check_extension($filename, true))
|
|
{
|
|
$filename .= "." . $this->image_extension;
|
|
}
|
|
// Touch the file
|
|
if ( ! touch($filename))
|
|
{
|
|
throw new \RuntimeException("Do not have permission to write to \"$filename\"");
|
|
}
|
|
|
|
// Set the new permissions
|
|
if ($permissions != null and ! chmod($filename, $permissions))
|
|
{
|
|
throw new \RuntimeException("Could not set permissions on the file.");
|
|
}
|
|
|
|
$this->debug("", "Saving image as <code>$filename</code>");
|
|
return array(
|
|
'filename' => $filename,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Saves the file in the original location, adding the append and prepend to the filename.
|
|
*
|
|
* @param string $append The string to append to the filename
|
|
* @param string $prepend The string to prepend to the filename
|
|
* @param string $extension The extension to save the image as, null defaults to the loaded images extension.
|
|
* @param integer $permissions The permissions to attempt to set on the file.
|
|
* @return Image_Driver
|
|
*/
|
|
public function save_pa($append, $prepend = null, $extension = null, $permissions = null)
|
|
{
|
|
$filename = substr($this->image_filename, 0, -(strlen($this->image_extension) + 1));
|
|
$fullpath = $this->image_directory.'/'.$append.$filename.$prepend.'.'.
|
|
($extension !== null ? $extension : $this->image_extension);
|
|
$this->save($fullpath, $permissions);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Outputs the file directly to the user.
|
|
*
|
|
* @param string $filetype The extension type to use. Ex: png, jpg, gif
|
|
* @return array
|
|
* @throws \FuelException
|
|
*/
|
|
public function output($filetype = null)
|
|
{
|
|
if ($filetype == null)
|
|
{
|
|
$filetype = $this->config['filetype'] == null ? $this->image_extension : $this->config['filetype'];
|
|
}
|
|
|
|
if ($this->check_extension($filetype, false))
|
|
{
|
|
if ( ! $this->config['debug'])
|
|
{
|
|
$mimetype = $filetype === 'jpg' ? 'jpeg' : $filetype;
|
|
header('Content-Type: image/' . $mimetype);
|
|
}
|
|
$this->new_extension = $filetype;
|
|
}
|
|
else
|
|
{
|
|
throw new \FuelException("Image extension $filetype is unsupported.");
|
|
}
|
|
|
|
$this->debug('', "Outputting image as $filetype");
|
|
return array(
|
|
'filetype' => $filetype,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns sizes for the currently loaded image, or the image given in the $filename.
|
|
*
|
|
* @param string $filename The location of the file to get sizes for.
|
|
* @return object An object containing width and height variables.
|
|
*/
|
|
abstract public function sizes($filename = null);
|
|
|
|
/**
|
|
* Adds a background to the image using the 'bgcolor' config option.
|
|
*/
|
|
abstract protected function add_background();
|
|
|
|
/**
|
|
* Creates a new color usable by all drivers.
|
|
*
|
|
* @param string $hex The hex code of the color
|
|
* @return array rgba representation of the hex and alpha values.
|
|
*/
|
|
protected function create_hex_color($hex)
|
|
{
|
|
if ($hex == null)
|
|
{
|
|
$red = 0;
|
|
$green = 0;
|
|
$blue = 0;
|
|
$alpha = 0;
|
|
}
|
|
else
|
|
{
|
|
// Check if theres a # in front
|
|
if (substr($hex, 0, 1) == '#')
|
|
{
|
|
$hex = substr($hex, 1);
|
|
}
|
|
|
|
// Break apart the hex
|
|
if (strlen($hex) == 6 or strlen($hex) == 8)
|
|
{
|
|
$red = hexdec(substr($hex, 0, 2));
|
|
$green = hexdec(substr($hex, 2, 2));
|
|
$blue = hexdec(substr($hex, 4, 2));
|
|
$alpha = (strlen($hex) == 8) ? hexdec(substr($hex, 6, 2)) : 255;
|
|
}
|
|
else
|
|
{
|
|
$red = hexdec(substr($hex, 0, 1).substr($hex, 0, 1));
|
|
$green = hexdec(substr($hex, 1, 1).substr($hex, 1, 1));
|
|
$blue = hexdec(substr($hex, 2, 1).substr($hex, 2, 1));
|
|
$alpha = (strlen($hex) > 3) ? hexdec(substr($hex, 3, 1).substr($hex, 3, 1)) : 255;
|
|
}
|
|
}
|
|
|
|
$alpha = floor($alpha / 2.55);
|
|
|
|
return array(
|
|
'red' => $red,
|
|
'green' => $green,
|
|
'blue' => $blue,
|
|
'alpha' => $alpha,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Checks if the extension is accepted by this library, and if its valid sets the $this->image_extension variable.
|
|
*
|
|
* @param string $filename
|
|
* @param boolean $writevar Decides if the extension should be written to $this->image_extension
|
|
* @param mixed $force_extension Decides if the extension should be overridden with this (or false)
|
|
* @return boolean
|
|
*/
|
|
protected function check_extension($filename, $writevar = true, $force_extension = false)
|
|
{
|
|
$return = false;
|
|
|
|
if ($force_extension !== false and in_array($force_extension, $this->accepted_extensions))
|
|
{
|
|
return $force_extension;
|
|
}
|
|
|
|
foreach ($this->accepted_extensions as $ext)
|
|
{
|
|
if (strtolower(substr($filename, strlen($ext) * -1)) == strtolower($ext))
|
|
{
|
|
$writevar and $this->image_extension = $ext;
|
|
$return = $ext;
|
|
}
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Converts percentages, negatives, and other values to absolute integers.
|
|
*
|
|
* @param string $input
|
|
* @param boolean $x Determines if the number relates to the x-axis or y-axis.
|
|
* @return integer The converted number, usable with the image being edited.
|
|
*/
|
|
protected function convert_number($input, $x = null)
|
|
{
|
|
// Sanitize double negatives
|
|
$input = str_replace('--', '', $input);
|
|
|
|
// Depending on php configuration, float are sometimes converted to strings
|
|
// using commas instead of points. This notation can create issues since the
|
|
// conversion from string to float will return an integer.
|
|
// For instance: "1.2" / 10 == 0.12 but "1,2" / 10 == 0.1...
|
|
$input = str_replace(',', '.', $input);
|
|
|
|
$orig = $input;
|
|
$sizes = $this->sizes();
|
|
$size = $x ? $sizes->width : $sizes->height;
|
|
// Convert percentages to absolutes
|
|
if (substr($input, -1) == '%')
|
|
{
|
|
$input = floor((substr($input, 0, -1) / 100) * $size);
|
|
}
|
|
// Negatives are based off the bottom right
|
|
if ($x !== null and $input < 0)
|
|
{
|
|
$input = $size + $input;
|
|
}
|
|
return $input;
|
|
}
|
|
|
|
/**
|
|
* Queues a function to run at a later time.
|
|
*
|
|
* @param string $function The name of the function to be ran, without the leading _
|
|
*/
|
|
protected function queue($function)
|
|
{
|
|
$func = func_get_args();
|
|
$tmpfunc = array();
|
|
for ($i = 0; $i < count($func); $i++)
|
|
{
|
|
$tmpfunc[$i] = var_export($func[$i], true);
|
|
}
|
|
|
|
$this->debug("Queued <code>" . implode(", ", $tmpfunc) . "</code>");
|
|
$this->queued_actions[] = $func;
|
|
}
|
|
|
|
/**
|
|
* Runs all queued actions on the loaded image.
|
|
*
|
|
* @param boolean $clear Decides if the queue should be cleared once completed.
|
|
*/
|
|
public function run_queue($clear = null)
|
|
{
|
|
foreach ($this->queued_actions as $action)
|
|
{
|
|
$tmpfunc = array();
|
|
for ($i = 0; $i < count($action); $i++)
|
|
{
|
|
$tmpfunc[$i] = var_export($action[$i], true);
|
|
}
|
|
$this->debug('', "<b>Executing <code>" . implode(", ", $tmpfunc) . "</code></b>");
|
|
call_user_func_array(array(&$this, '_' . $action[0]), array_slice($action, 1));
|
|
}
|
|
if (($clear === null and $this->config['clear_queue']) or $clear === true)
|
|
{
|
|
$this->queued_actions = array();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reloads the image.
|
|
*
|
|
* @return Image_Driver
|
|
*/
|
|
public function reload()
|
|
{
|
|
$this->debug("Reloading was called!");
|
|
$this->load($this->image_fullpath);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the file extension (type) worked out on construct
|
|
*
|
|
* @return string File extension
|
|
*/
|
|
public function extension()
|
|
{
|
|
return $this->image_extension;
|
|
}
|
|
|
|
/**
|
|
* Used for debugging image output.
|
|
*/
|
|
protected function debug()
|
|
{
|
|
if ($this->config['debug'])
|
|
{
|
|
$messages = func_get_args();
|
|
foreach ($messages as $message)
|
|
{
|
|
echo '<div>' . $message . ' </div>';
|
|
}
|
|
}
|
|
}
|
|
}
|