Support for image manipulation using Imagick.
Class declared in MODPATH/image/classes/image/imagick.php on line 3.
integer 1
integer 2
integer 3
integer 4
integer 5
integer 6
integer 17
integer 18
string
$default_driverlink to thisdefault driver: GD, ImageMagick, etc
string(2) "GD"
string
$filelink to thisimage file path
integer
$heightlink to thisimage height
string
$mimelink to thismime type of the image
integer
$typelink to thisone of the IMAGETYPE_* constants
integer
$widthlink to thisimage width
$_checkedlink to thisbool FALSE
Imagick
$imlink to thisimage magick object
Runs Image_Imagick::check and loads the image.
void
public
function
__construct(
$file
)
{
if
( ! Image_Imagick::
$_checked
)
{
// Run the install check
Image_Imagick::check();
}
parent::__construct(
$file
);
$this
->im =
new
Imagick;
$this
->im->readImage(
$file
);
if
( !
$this
->im->getImageAlphaChannel())
{
// Force the image to have an alpha channel
$this
->im->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
}
}
Destroys the loaded image to free up resources.
void
public
function
__destruct()
{
$this
->im->clear();
$this
->im->destroy();
}
Checks if ImageMagick is enabled.
boolean
public
static
function
check()
{
if
( !
extension_loaded
(
'imagick'
))
{
throw
new
Kohana_Exception(
'Imagick is not installed, or the extension is not loaded'
);
}
return
Image_Imagick::
$_checked
= TRUE;
}
Render the current image.
echo
$image
;
The output of this function is binary and must be rendered with the appropriate Content-Type header or it will not be displayed correctly!
string
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(Log::ERROR,
$error
);
}
// Showing any kind of error will be "inside" image data
return
''
;
}
}
Set the background color of an image. This is only useful for images with alpha transparency.
// Make the image background black
$image
->background(
'#000'
);
// Make the image background black with 50% opacity
$image
->background(
'#000'
, 50);
string
$color
required - Hexadecimal color valueinteger
$opacity
= integer 100 - Background opacity: 0-100$this
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
;
}
Crop an image to the given size. Either the width or the height can be omitted and the current width or height will be used.
If no offset is specified, the center of the axis will be used. If an offset of TRUE is specified, the bottom of the axis will be used.
// Crop the image to 200x200 pixels, from the center
$image
->crop(200, 200);
integer
$width
required - New widthinteger
$height
required - New heightmixed
$offset_x
= NULL - Offset from the leftmixed
$offset_y
= NULL - Offset from the top$this
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
;
}
Loads an image and prepares it for manipulation.
$image
= Image::factory(
'upload/test.jpg'
);
string
$file
required - Image file pathstring
$driver
= NULL - Driver type: GD, ImageMagick, etcImage
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
);
}
Flip the image along the horizontal or vertical axis.
// Flip the image from top to bottom
$image
->flip(Image::HORIZONTAL);
// Flip the image from left to right
$image
->flip(Image::VERTICAL);
integer
$direction
required - Direction: Image::HORIZONTAL, Image::VERTICAL$this
public
function
flip(
$direction
)
{
if
(
$direction
!== Image::HORIZONTAL)
{
// Flip vertically
$direction
= Image::VERTICAL;
}
$this
->_do_flip(
$direction
);
return
$this
;
}
Add a reflection to an image. The most opaque part of the reflection will be equal to the opacity setting and fade out to full transparent. Alpha transparency is preserved.
// Create a 50 pixel reflection that fades from 0-100% opacity
$image
->reflection(50);
// Create a 50 pixel reflection that fades from 100-0% opacity
$image
->reflection(50, 100, TRUE);
// Create a 50 pixel reflection that fades from 0-60% opacity
$image
->reflection(50, 60, TRUE);
By default, the reflection will be go from transparent at the top to opaque at the bottom.
integer
$height
= NULL - Reflection heightinteger
$opacity
= integer 100 - Reflection opacity: 0-100boolean
$fade_in
= bool FALSE - TRUE to fade in, FALSE to fade out$this
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
;
}
Render the image and return the binary string.
// Render the image at 50% quality
$data
=
$image
->render(NULL, 50);
// Render the image as a PNG
$data
=
$image
->render(
'png'
);
string
$type
= NULL - Image type to return: png, jpg, gif, etcinteger
$quality
= integer 100 - Quality of image: 1-100string
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
);
}
Resize the image to the given size. Either the width or the height can be omitted and the image will be resized proportionally.
// Resize to 200 pixels on the shortest side
$image
->resize(200, 200);
// Resize to 200x200 pixels, keeping aspect ratio
$image
->resize(200, 200, Image::INVERSE);
// Resize to 500 pixel width, keeping aspect ratio
$image
->resize(500, NULL);
// Resize to 500 pixel height, keeping aspect ratio
$image
->resize(NULL, 500);
// Resize to 200x500 pixels, ignoring aspect ratio
$image
->resize(200, 500, Image::NONE);
integer
$width
= NULL - New widthinteger
$height
= NULL - New heightinteger
$master
= NULL - Master dimension$this
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 deprecated. 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 backward compatibility
$height
= NULL;
}
elseif
(
$master
== Image::HEIGHT AND !
empty
(
$height
))
{
$master
= Image::AUTO;
// Set empty width for backward 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
;
case
Image::PRECISE:
// Resize to precise size
$ratio
=
$this
->width /
$this
->height;
if
(
$width
/
$height
>
$ratio
)
{
$height
=
$this
->height *
$width
/
$this
->width;
}
else
{
$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
;
}
Rotate the image by a given amount.
// Rotate 45 degrees clockwise
$image
->rotate(45);
// Rotate 90% counter-clockwise
$image
->rotate(-90);
integer
$degrees
required - Degrees to rotate: -360-360$this
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
;
}
Save the image. If the filename is omitted, the original image will be overwritten.
// Save the image as a PNG
$image
->save(
'saved/cool.png'
);
// Overwrite the original image
$image
->save();
If the file exists, but is not writable, an exception will be thrown.
If the file does not exist, and the directory is not writable, an exception will be thrown.
string
$file
= NULL - New image pathinteger
$quality
= integer 100 - Quality of image: 1-100boolean
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'
=> 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'
=> 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
);
}
Sharpen the image by a given amount.
// Sharpen the image by 20%
$image
->sharpen(20);
integer
$amount
required - Amount to sharpen: 1-100$this
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
;
}
Add a watermark to an image with a specified opacity. Alpha transparency will be preserved.
If no offset is specified, the center of the axis will be used. If an offset of TRUE is specified, the bottom of the axis will be used.
// Add a watermark to the bottom right of the image
$mark
= Image::factory(
'upload/watermark.png'
);
$image
->watermark(
$mark
, TRUE, TRUE);
Image
$watermark
required - Watermark Image instanceinteger
$offset_x
= NULL - Offset from the leftinteger
$offset_y
= NULL - Offset from the topinteger
$opacity
= integer 100 - Opacity of watermark: 1-100$this
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
;
}
Execute a background.
integer
$r
required - Redinteger
$g
required - Greeninteger
$b
required - Blueinteger
$opacity
required - Opacityvoid
protected
function
_do_background(
$r
,
$g
,
$b
,
$opacity
)
{
// Create a RGB color for the background
$color
= sprintf(
'rgb(%d, %d, %d)'
,
$r
,
$g
,
$b
);
// Create a new image for the background
$background
=
new
Imagick;
$background
->newImage(
$this
->width,
$this
->height,
new
ImagickPixel(
$color
));
if
( !
$background
->getImageAlphaChannel())
{
// Force the image to have an alpha channel
$background
->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
}
// Clear the background image
$background
->setImageBackgroundColor(
new
ImagickPixel(
'transparent'
));
// NOTE: Using setImageOpacity will destroy current alpha channels!
$background
->evaluateImage(Imagick::EVALUATE_MULTIPLY,
$opacity
/ 100, Imagick::CHANNEL_ALPHA);
// Match the colorspace between the two images before compositing
$background
->setColorspace(
$this
->im->getColorspace());
if
(
$background
->compositeImage(
$this
->im, Imagick::COMPOSITE_DISSOLVE, 0, 0))
{
// Replace the current image with the new image
$this
->im =
$background
;
return
TRUE;
}
return
FALSE;
}
Execute a crop.
integer
$width
required - New widthinteger
$height
required - New heightinteger
$offset_x
required - Offset from the leftinteger
$offset_y
required - Offset from the topvoid
protected
function
_do_crop(
$width
,
$height
,
$offset_x
,
$offset_y
)
{
if
(
$this
->im->cropImage(
$width
,
$height
,
$offset_x
,
$offset_y
))
{
// Reset the width and height
$this
->width =
$this
->im->getImageWidth();
$this
->height =
$this
->im->getImageHeight();
// Trim off hidden areas
$this
->im->setImagePage(
$this
->width,
$this
->height, 0, 0);
return
TRUE;
}
return
FALSE;
}
Execute a flip.
integer
$direction
required - Direction to flipvoid
protected
function
_do_flip(
$direction
)
{
if
(
$direction
=== Image::HORIZONTAL)
{
return
$this
->im->flopImage();
}
else
{
return
$this
->im->flipImage();
}
}
Execute a reflection.
integer
$height
required - Reflection heightinteger
$opacity
required - Reflection opacityboolean
$fade_in
required - TRUE to fade out, FALSE to fade invoid
protected
function
_do_reflection(
$height
,
$opacity
,
$fade_in
)
{
// Clone the current image and flip it for reflection
$reflection
=
$this
->im->
clone
();
$reflection
->flipImage();
// Crop the reflection to the selected height
$reflection
->cropImage(
$this
->width,
$height
, 0, 0);
$reflection
->setImagePage(
$this
->width,
$height
, 0, 0);
// Select the fade direction
$direction
=
array
(
'transparent'
,
'black'
);
if
(
$fade_in
)
{
// Change the direction of the fade
$direction
=
array_reverse
(
$direction
);
}
// Create a gradient for fading
$fade
=
new
Imagick;
$fade
->newPseudoImage(
$reflection
->getImageWidth(),
$reflection
->getImageHeight(), vsprintf(
'gradient:%s-%s'
,
$direction
));
// Apply the fade alpha channel to the reflection
$reflection
->compositeImage(
$fade
, Imagick::COMPOSITE_DSTOUT, 0, 0);
// NOTE: Using setImageOpacity will destroy alpha channels!
$reflection
->evaluateImage(Imagick::EVALUATE_MULTIPLY,
$opacity
/ 100, Imagick::CHANNEL_ALPHA);
// Create a new container to hold the image and reflection
$image
=
new
Imagick;
$image
->newImage(
$this
->width,
$this
->height +
$height
,
new
ImagickPixel);
// Force the image to have an alpha channel
$image
->setImageAlphaChannel(Imagick::ALPHACHANNEL_SET);
// Force the background color to be transparent
// $image->setImageBackgroundColor(new ImagickPixel('transparent'));
// Match the colorspace between the two images before compositing
$image
->setColorspace(
$this
->im->getColorspace());
// Place the image and reflection into the container
if
(
$image
->compositeImage(
$this
->im, Imagick::COMPOSITE_SRC, 0, 0)
AND
$image
->compositeImage(
$reflection
, Imagick::COMPOSITE_OVER, 0,
$this
->height))
{
// Replace the current image with the reflected image
$this
->im =
$image
;
// Reset the width and height
$this
->width =
$this
->im->getImageWidth();
$this
->height =
$this
->im->getImageHeight();
return
TRUE;
}
return
FALSE;
}
Execute a render.
string
$type
required - Image type: png, jpg, gif, etcinteger
$quality
required - Qualitystring
protected
function
_do_render(
$type
,
$quality
)
{
// Get the image format and type
list(
$format
,
$type
) =
$this
->_get_imagetype(
$type
);
// Set the output image type
$this
->im->setFormat(
$format
);
// Set the output quality
$this
->im->setImageCompressionQuality(
$quality
);
// Reset the image type and mime type
$this
->type =
$type
;
$this
->mime = image_type_to_mime_type(
$type
);
return
(string)
$this
->im;
}
Execute a resize.
integer
$width
required - New widthinteger
$height
required - New heightvoid
protected
function
_do_resize(
$width
,
$height
)
{
if
(
$this
->im->scaleImage(
$width
,
$height
))
{
// Reset the width and height
$this
->width =
$this
->im->getImageWidth();
$this
->height =
$this
->im->getImageHeight();
return
TRUE;
}
return
FALSE;
}
Execute a rotation.
integer
$degrees
required - Degrees to rotatevoid
protected
function
_do_rotate(
$degrees
)
{
if
(
$this
->im->rotateImage(
new
ImagickPixel(
'transparent'
),
$degrees
))
{
// Reset the width and height
$this
->width =
$this
->im->getImageWidth();
$this
->height =
$this
->im->getImageHeight();
// Trim off hidden areas
$this
->im->setImagePage(
$this
->width,
$this
->height, 0, 0);
return
TRUE;
}
return
FALSE;
}
Execute a save.
string
$file
required - New image filenameinteger
$quality
required - Qualityboolean
protected
function
_do_save(
$file
,
$quality
)
{
// Get the image format and type
list(
$format
,
$type
) =
$this
->_get_imagetype(
pathinfo
(
$file
, PATHINFO_EXTENSION));
// Set the output image type
$this
->im->setFormat(
$format
);
// Set the output quality
$this
->im->setImageCompressionQuality(
$quality
);
if
(
$this
->im->writeImage(
$file
))
{
// Reset the image type and mime type
$this
->type =
$type
;
$this
->mime = image_type_to_mime_type(
$type
);
return
TRUE;
}
return
FALSE;
}
Execute a sharpen.
integer
$amount
required - Amount to sharpenvoid
protected
function
_do_sharpen(
$amount
)
{
//IM not support $amount under 5 (0.15)
$amount
= (
$amount
< 5) ? 5 :
$amount
;
// Amount should be in the range of 0.0 to 3.0
$amount
= (
$amount
* 3.0) / 100;
return
$this
->im->sharpenImage(0,
$amount
);
}
Execute a watermarking.
Image
$image
required - Watermarking Imageinteger
$offset_x
required - Offset from the leftinteger
$offset_y
required - Offset from the topinteger
$opacity
required - Opacity of watermarkvoid
protected
function
_do_watermark(Image
$image
,
$offset_x
,
$offset_y
,
$opacity
)
{
// Convert the Image intance into an Imagick instance
$watermark
=
new
Imagick;
$watermark
->readImageBlob(
$image
->render(),
$image
->file);
if
(
$watermark
->getImageAlphaChannel() !== Imagick::ALPHACHANNEL_ACTIVATE)
{
// Force the image to have an alpha channel
$watermark
->setImageAlphaChannel(Imagick::ALPHACHANNEL_OPAQUE);
}
if
(
$opacity
< 100)
{
// NOTE: Using setImageOpacity will destroy current alpha channels!
$watermark
->evaluateImage(Imagick::EVALUATE_MULTIPLY,
$opacity
/ 100, Imagick::CHANNEL_ALPHA);
}
// Match the colorspace between the two images before compositing
// $watermark->setColorspace($this->im->getColorspace());
// Apply the watermark to the image
return
$this
->im->compositeImage(
$watermark
, Imagick::COMPOSITE_DISSOLVE,
$offset_x
,
$offset_y
);
}
Get the image type and format for an extension.
string
$extension
required - Image extension: png, jpg, etcstring
- IMAGETYPE_* constant
protected
function
_get_imagetype(
$extension
)
{
// Normalize the extension to a format
$format
=
strtolower
(
$extension
);
switch
(
$format
)
{
case
'jpg'
:
case
'jpeg'
:
$type
= IMAGETYPE_JPEG;
break
;
case
'gif'
:
$type
= IMAGETYPE_GIF;
break
;
case
'png'
:
$type
= IMAGETYPE_PNG;
break
;
default
:
throw
new
Kohana_Exception(
'Installed ImageMagick does not support :type images'
,
array
(
':type'
=>
$extension
));
break
;
}
return
array
(
$format
,
$type
);
}