<?php
/**
* Moc10 Library
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.TXT.
* It is also available through the world-wide-web at this URL:
* http://www.moc10phplibrary.com/LICENSE.TXT
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to hide@address.com so we can send you a copy immediately.
*
* @category Moc10
* @package Moc10_Image
* @author Nick Sagona, III <hide@address.com>
* @copyright Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
* @license http://www.moc10phplibrary.com/LICENSE.TXT New BSD License
*/
/**
* Moc10_Image
*
* @category Moc10
* @package Moc10_Image
* @author Nick Sagona, III <hide@address.com>
* @copyright Copyright (c) 2009-2011 Moc 10 Media, LLC. (http://www.moc10media.com)
* @license http://www.moc10phplibrary.com/LICENSE.TXT New BSD License
* @version 1.9.7
*/
class Moc10_Image extends Moc10_File
{
/**
* Image width
* @var int|string
*/
public $width;
/**
* Image height
* @var int|string
*/
public $height;
/**
* Image channels
* @var int|string
*/
public $channels;
/**
* Image quality
* @var int|string
*/
protected $_quality;
/**
* Array of allowed file types.
* @var array
*/
protected $_allowed = array('gif' => 'image/gif',
'jpe' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png');
/**
* Language object
* @var Moc10_Language
*/
protected $_lang = null;
/**
* Constructor
*
* Instantiate an image file object based on either a pre-existing image file on disk, or a new image file.
*
* @param string $img
* @param boolean $up
* @param array $typ
* @param int|string $w
* @param int|string $h
* @param int|string $r
* @param int|string $g
* @param int|string $b
* @throws Exception
* @return void
*/
public function __construct($img, $up = false, $typ = null, $w = null, $h = null, $r = null, $g = null, $b = null)
{
$this->_lang = new Moc10_Language();
parent::__construct($img, $up, $typ);
if (file_exists($this->fullpath)) {
// If image exists, get image info and store in an array.
$imgSize = getimagesize($img);
// Set image object properties.
$this->width = $imgSize[0];
$this->height = $imgSize[1];
if (isset($imgSize['channels'])) {
$this->channels = $imgSize['channels'];
} else {
$this->channels = null;
}
$this->_quality = null;
} else {
// If image does not exists, check to make sure the width and height properties of the new image have been passed.
if (is_null($w) || is_null($h)) {
throw new Exception($this->_lang->__('Error: You must define a width and height for a new image object.'));
} else {
// Set image object properties.
$this->width = $w;
$this->height = $h;
$this->channels = null;
$this->_quality = null;
// Create a new image
$new = imagecreate($w, $h);
$color = null;
// Allocate the background color.
if (!is_null($r) && !is_null($g) && !is_null($b)) {
$color = imagecolorallocate($new, $r, $g, $b);
} else {
$color = imagecolorallocate($new, 0, 0, 0);
}
// Set the quality and create a new, blank image file.
$this->_setQuality(90);
$this->_createImage($new, $this->fullpath, $this->_quality);
unset($color);
}
}
}
/**
* Resize the image object, allowing for the largest dimension to be scaled to the value of the $px argument.
* For example, if the value of $px = 200, and the image is 800px X 600px, then the image will be scaled to 200px X 150px.
* The $q argument is an optional argument for the quality of the image that must range between 0 (lowest) and 100 (highest.)
* The $to argument is an optional argument to save the altered image to another image file without overwriting the original.
*
* @param int|string $px
* @param int|string $q
* @param string $to
* @return void
*/
public function resize($px, $q = null, $to = null)
{
// Determine whether or not the image is landscape or portrait and set the scale, new width and new height accordingly,
// with the largest dimension being scaled to the value of the $px argument.
$scale = ($this->width > $this->height) ? ($px / $this->width) : ($px / $this->height);
$wid = round($this->width * $scale);
$hgt = round($this->height * $scale);
if (is_null($to)) {
// Save the image with the new dimensions.
if (!is_null($q)) {
$this->_save($wid, $hgt, $q);
} else {
$this->_save($wid, $hgt);
}
// Save the image to a new image file with the new dimensions.
} else {
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
$new = imagecreatetruecolor($wid, $hgt);
// Create a new, blank image file and copy the image over, saving it in it's proper format.
$image = $this->_createNew();
imagecopyresampled($new, $image, 0, 0, 0, 0, $wid, $hgt, $this->width, $this->height);
$this->_createImage($new, $to, $this->_quality);
clearstatcache();
}
}
/**
* Scale the image object, allowing for the dimensions to be scaled proportionally to the value of the $scl argument.
* For example, if the value of $scl = 0.50, and the image is 800px X 600px, then the image will be scaled to 400px X 300px.
* The $q argument is an optional argument for the quality of the image that must range between 0 (lowest) and 100 (highest.)
* The $to argument is an optional argument to save the altered image to another image file without overwriting the original.
*
* @param int|string $scl
* @param int|string $q
* @param string $to
* @return void
*/
public function scale($scl, $q = null, $to = null)
{
// Determine the new width and height of the image based on the value of the $scl argument.
$wid = round($this->width * $scl);
$hgt = round($this->height * $scl);
if (is_null($to)) {
// Save the image with the new dimensions.
if (!is_null($q)) {
$this->_save($wid, $hgt, $q);
} else {
$this->_save($wid, $hgt);
}
// Save the image to a new image file with the new dimensions.
} else {
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
$new = imagecreatetruecolor($wid, $hgt);
// Create a new, blank image file and copy the image over, saving it in it's proper format.
$image = $this->_createNew();
imagecopyresampled($new, $image, 0, 0, 0, 0, $wid, $hgt, $this->width, $this->height);
$this->_createImage($new, $to, $this->_quality);
clearstatcache();
}
}
/**
* Crop the image object to a square image whose dimensions are based on the value of the $px argument.
* The optional $x and $y arguments allow for the adjustment of the crop to select a certain area of the image to be cropped.
* For example, if the values of $px = 50, $x = 20, $y = 0 are passed, then a 50px X 50px image will be created from the
* original image, with its origins starting at the (20, 0) x-y coordinates. The $q argument is an optional argument for
* the quality of the image that must range between 0 (lowest) and 100 (highest.) The $to argument is an optional argument
* to save the altered image to another image file without overwriting the original.
*
* @param int|string $px
* @param int|string $x
* @param int|string $y
* @param int|string $q
* @param string $to
* @return void
*/
public function crop($px, $x = 0, $y = 0, $q = null, $to = null)
{
// Determine whether or not the image is landscape or portrait and set the scale, new width and new height accordingly,
// with the smallest dimension being scaled to the value of the $px argument to allow for a complete crop.
$scale = ($this->width > $this->height) ? ($px / $this->height) : ($px / $this->width);
$wid = round($this->width * $scale);
$hgt = round($this->height * $scale);
if (is_null($to)) {
// Save the image with the new dimensions.
if (!is_null($q)) {
$this->_save($wid, $hgt, $q);
} else {
$this->_save($wid, $hgt);
}
// Open a new image to the crop dimensions.
$new = imagecreatetruecolor($px, $px);
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
// Create a new, blank image file and copy the image over, saving it in it's proper format.
$image = $this->_createNew();
imagecopy($new, $image, 0, 0, $x, $y, $px, $px);
$this->_createImage($new, $this->fullpath, $this->_quality);
// Redefine the image object properties with the newly set values.
clearstatcache();
$this->width = $px;
$this->height = $px;
$this->size = filesize($this->fullpath);
// Save the image to a new image file with the new dimensions.
} else {
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
$new = imagecreatetruecolor($px, $px);
// Create a new, blank image file and copy the image over, saving it in it's proper format.
$image = $this->_createNew();
imagecopyresampled($new, $image, 0, 0, $x, $y, $wid, $hgt, $this->width, $this->height);
$this->_createImage($new, $to, $this->_quality);
clearstatcache();
}
}
/**
* Create text within the an image object and output it. A true-type font file is required for the font argument. The size,
* rotation and position can be set by those respective arguments. The RGB color of the text can be set by the respective
* optional arguments. This is a useful method for creating CAPTCHA images or rendering sensitive information to the user
* that cannot or should not be rendered by HTML (i.e. email addresses.) The $to argument is an optional argument to save
* the altered image to another image file without overwriting the original.
*
* @param string $str
* @param int|string $size
* @param int|string $x
* @param int|string $y
* @param int|string $rotate
* @param string $font
* @param int|string $r
* @param int|string $g
* @param int|string $b
* @param string $to
* @param int|string $q
* @return void
*/
public function text($str, $size, $x, $y, $rotate = null, $font = null, $r = null, $g = null, $b = null, $to = null, $q = null)
{
// Set the image and font color.
$image = $this->_createNew();
if (!is_null($r) && !is_null($g) && !is_null($b)) {
$color = imagecolorallocate($image, $r, $g, $b);
} else {
$color = imagecolorallocate($image, 0, 0, 0);
}
// Write text to the image.
if (!is_null($font)) {
imagettftext($image, $size, $rotate, $x, $y, $color, $font, $str);
} else {
imagestring($image, $size, $x, $y, $str, $color);
}
// Output the image
if (is_null($to)) {
// Begin output of headers.
header('Content-type: ' . $this->mime);
if ($this->mime == 'image/gif') {
// Output the GIF image file.
imagegif($image);
} else if ($this->mime == 'image/png') {
// Output the PNG image file.
imagepng($image);
} else if ($this->mime == 'image/jpeg') {
// Output the JPG image file.
imagejpeg($image);
}
// Destroy the image resource.
imagedestroy($image);
// Else, save the image to a new image file.
} else {
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
$this->_createImage($image, $to, $this->_quality);
}
}
/**
* Convert the image object to the new specified image type.
*
* @param string $type
* @param int|string $q
* @throws Exception
* @return void
*/
public function convert($type, $q = null)
{
if (!is_null($this->_perm['file']) && ($this->_perm['file'] != 777)) {
throw new Exception($this->_lang->__('Error: Permission denied.'));
} else {
$type = strtolower($type);
// Check if the requested image type is supported.
if (!array_key_exists($type, $this->_allowed)) {
throw new Exception($this->_lang->__('Error: That image type is not supported. Only GIF, JPG and PNG image types are supported.'));
}
// Check if the image is already the requested image type.
if ($this->ext == $type) {
throw new Exception($this->_lang->__('Error: This image file is already a %1 image file.', strtoupper($type)));
}
// Open a new image, maintaining the GIF image's palette and transparency where applicable.
if ($this->mime == 'image/gif') {
$image = $this->_createNew();
imageinterlace($image, 0);
// Change the type of the image object to the new, requested image type.
$this->ext = $type;
$this->mime = $this->_allowed[$this->ext];
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
// Redefine the image object properties with the new values.
$this->fullpath = $this->dir . $this->filename . '.' . $this->ext;
$this->basename = basename($this->fullpath);
// Create and save the image in it's new, proper format.
$this->_createImage($image, $this->fullpath, $this->_quality);
// Else, open a new true color image.
} else {
$new = imagecreatetruecolor($this->width, $this->height);
// Create a new, blank image file and copy the image over.
$image = $this->_createNew();
// Change the type of the image object to the new, requested image type.
$this->ext = $type;
$this->mime = $this->_allowed[$this->ext];
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
// Redefine the image object properties with the new values.
$this->fullpath = $this->dir . $this->filename . '.' . $this->ext;
$this->basename = basename($this->fullpath);
// Create and save the image in it's new, proper format.
imagecopyresampled($new, $image, 0, 0, 0, 0, $this->width, $this->height, $this->width, $this->height);
$this->_createImage($new, $this->fullpath, $this->_quality);
}
clearstatcache();
$this->size = filesize($this->fullpath);
chmod($this->fullpath, 0777);
}
}
/**
* Return the number of colors in the palette of indexed images. Returns 0 for true color images.
*
* @return int
*/
public function colorTotal()
{
// Set the image and get the total number of colors.
$image = $this->_createNew();
$colors = imagecolorstotal($image);
// Destroy the image resource.
imagedestroy($image);
return $colors;
}
/**
* Return all of the colors in the palette in an array format, omitting any repeats. It is strongly advised that this method only be used
* for smaller image files, preferably with small palettes, as any large images with many colors will cause this method to run slowly.
* Default format of the values in the returned array is the 6-digit HEX value, but if 'RGB' is passed, then the format of the values
* in the returned array will be 'R,G,B', i.e. '235,123,12'.
*
* @param string $format
* @return array
*/
public function getColors($format = 'HEX')
{
// Initialize the colors array and the image resource.
$colors = array();
$image = $this->_createNew();
// Loop through each pixel of the image, recording the color result in the color array.
for ($h = 0; $h < $this->height; $h++) {
for ($w = 0; $w < $this->width; $w++) {
// Get the color index at the pixel location, translating into human readable form.
$color_index = imagecolorat($image, $w, $h);
$color_trans = imagecolorsforindex($image, $color_index);
// Convert to the proper HEX or RGB format.
if ($format == 'HEX') {
$rgb = sprintf('%02s', dechex($color_trans['red'])) . sprintf('%02s', dechex($color_trans['green'])) . sprintf('%02s', dechex($color_trans['blue']));
} else {
$rgb = $color_trans['red'] . "," . $color_trans['green'] . "," . $color_trans['blue'];
}
// If the color is not already in the array, add to it.
if (!in_array($rgb, $colors)) {
$colors[] = $rgb;
}
}
}
// Destroy the image resource.
imagedestroy($image);
// Return the colors array.
return $colors;
}
/**
* Set the image quality based on the type of image.
*
* @param int|string $q
* @return void
*/
protected function _setQuality($q)
{
if ($this->mime == 'image/png') {
$this->_quality = 10 - round($q / 10);
} else if ($this->mime == 'image/jpeg') {
$this->_quality = round($q);
} else {
$this->_quality = null;
}
}
/**
* Create a blank image based on the current image type of the image object.
*
* @return image resource
*/
protected function _createNew()
{
if ($this->mime == 'image/gif') {
// Create a blank GIF image file.
$img = imagecreatefromgif($this->fullpath);
} else if ($this->mime == 'image/png') {
// Create a blank PNG image file.
$img = imagecreatefrompng($this->fullpath);
} else if ($this->mime == 'image/jpeg') {
// Create a blank JPG image file.
$img = imagecreatefromjpeg($this->fullpath);
}
return $img;
}
/**
* Create and save the new image file in the correct format.
*
* @param string $new
* @param string $img
* @param int|string $q
* @return void
*/
protected function _createImage($new, $img, $q = null)
{
if ($this->mime == 'image/gif') {
// Create and save the new GIF image file.
imagegif($new, $img);
} else if ($this->mime == 'image/png') {
// Create and save the new PNG image file.
imagepng($new, $img, $q);
} else if ($this->mime == 'image/jpeg') {
// Create and save the new JPG image file.
imagejpeg($new, $img, $q);
}
}
/**
* Save the image object using with any newly defined properties.
*
* @param int|string $w
* @param int|string $h
* @param int|string $q
* @throws Exception
* @return void
*/
protected function _save($w, $h, $q = null)
{
if (!is_null($this->_perm['file']) && ($this->_perm['file'] != 777)) {
throw new Exception($this->_lang->__('Error: Permission denied.'));
} else {
// Open a new image.
$new = imagecreatetruecolor($w, $h);
// Set the image quality.
if (!is_null($q)) {
$this->_setQuality($q);
} else {
$this->_setQuality(90);
}
// Create a new, blank image file and copy the image over, saving it in it's proper format.
$image = $this->_createNew();
imagecopyresampled($new, $image, 0, 0, 0, 0, $w, $h, $this->width, $this->height);
$this->_createImage($new, $this->fullpath, $this->_quality);
// Redefine the image object properties with the newly set values.
clearstatcache();
$this->width = $w;
$this->height = $h;
$this->size = filesize($this->fullpath);
}
}
}