Location: PHPKode > scripts > Image Functions > image-functions/class.image.php
<?php

//
// class.image.php
// version 1.1.1, 2005-02-20
//
// Description
//
// A PHP library of helpful image processing methods.  This class does not
// need to be instantiated.
//
// Author
//
// Andrew Collington, 2005
// hide@address.com, http://php.amnuts.com/
//
// Feedback
//
// There is message board at the following address:
//
//    http://php.amnuts.com/forums/index.php
//
// Please use that to post up any comments, questions, bug reports, etc.  You
// can also use the board to show off your use of the script.
//
// License
//
// This class is available free of charge for personal or non-profit work.  If
// you are using it in a commercial setting, please contact hide@address.com for
// payment and licensing terms.
//
// Support
//
// If you like this script, or any of my others, then please take a moment
// to consider giving a donation.  This will encourage me to make updates and
// create new scripts which I would make available to you.  If you would like
// to donate anything, then there is a link from my website to PayPal.
//
// Examples
//
//     $img = imagecreatefromjpeg('original.jpg');
//     Image::colourise($img, '4c63f2');
//     imagejpeg($img, 'processed.jpg', 90);
//
//     $img = imagecreatefromjpeg('original.jpg');
//     Image::threshold($img, 128);
//     imagejpeg($img, 'processed.jpg', 90);
//
//     $img = imagecreatefromjpeg('original.jpg');
//     Image::greyscale($img);
//     imagejpeg($img, 'processed.jpg', 90);
//
//     $hex = '#45F2C3';
//     $hls = Image::rgb2hls(Image::hex2rgb($hex));
//     $hls[0] = 192;
//     $hls[2] = 0.15;
//     echo Image::rgb2hex(Image::hls2rgb($hls));
//
//     print_r(Image::colourRange('#cccccc', '#ffffff', 10));
//        

class Image
{
    /**
     * Gathers the GD version information
     *
     * Sometimes a check for the GD version like this:
     *
     *     (function_exists('imagecreatetruecolor')) ? 2 : 1;
     *
     * can fail.  This method retrieves the GD information based on what PHP
     * reports to be installed.  It can return the parsed version as an array,
     * or just the major version if you want to do a simple check.
     *
     * @return int|array
     * @param  bool $justMajor
     * @access public
     */
    function getGDVersion($justMajor = true)
    {
        static $version = array();
        
        if (empty($version)) {
            ob_start();
            phpinfo();
            $buffer = ob_get_contents();
            ob_end_clean();
            if (preg_match('|<B>GD Version</B></td><TD ALIGN="left">([^<]*)</td>|i', $buffer, $matches)) {
                $version = explode('.', $matches[1]);
            } else if (preg_match('|GD Version </td><td class="v">bundled \(([^ ]*)|i', $buffer, $matches)) {
                $version = explode('.', $matches[1]);
            } else if (preg_match('|GD Version </td><td class="v">([^ ]*)|i', $buffer, $matches)) {
                $version = explode('.', $matches[1]);
            }
        }
        return ($justMajor) ? $version[0] : $version;
    }

    /**
     * Return an RGB colour value array of the pixel at given location.
     *
     * The array is returned as: array(0 => r, 1 => g, 2 => b)
     *
     * @return array
     * @param  resource &$im a reference to the image
     * @param  int $x coordinate
     * @param  int $y coordinate
     * @access public
     */
    function getPixelRGB(&$im, $x, $y)
    {
        $rgb = imagecolorat($im, $x, $y);
        return array(($rgb >> 16) & 0xFF, ($rgb >> 8) & 0xFF, $rgb & 0xFF);
    }

    /**
     * A simple metric for colour distance in RGB space
     *
     * The arrays are expected to be of the format: 
     * array(0 => r, 1 => g, 2 => b)
     * 
     * @return float
     * @param  array $rgb1
     * @param  array $rgb2
     * @access public
     */
    function colourDistance($rgb1, $rgb2)
    {
        return sqrt(3 * ($rgb2[0] - $rgb1[0]) * ($rgb2[0] - $rgb1[0]) + 4 * ($rgb2[1] - $rgb1[1]) * 
                        ($rgb2[1] - $rgb1[1]) + 2 * ($rgb2[2] - $rgb1[2]) * ($rgb2[2] - $rgb1[2]));
    }

    /**
     * Convert a hex colour string into an rgb array.
     *
     * Handles colour string in the following formats:
     *
     *     o #44FF55
     *     o 4FF55
     *     o #4F5
     *     o 4F5
     * 
     * @return array
     * @param  string $hex
     * @access public
     */
    function hex2rgb($hex)
    {
        $hex = @preg_replace('/^#/', '', $hex);
        if (strlen($hex) == 3) {
            $v = explode(':', chunk_split($hex, 1, ':'));
            return array(16 * hexdec($v[0]) + hexdec($v[0]), 16 * hexdec($v[1]) + hexdec($v[1]), 16 * hexdec($v[2]) + hexdec($v[2]));
        } else {
            $v = explode(':', chunk_split($hex, 2, ':'));
            return array(hexdec($v[0]), hexdec($v[1]), hexdec($v[2]));
        }
    }

    /**
     * Convert an rgb array into a hex colour string.
     *
     * Handles colour string in the following formats:
     *
     *     o #44FF55
     *     o 4FF55
     *     o #4F5
     *     o 4F5
     * 
     * @return array
     * @param  string $hex
     * @access public
     */
    function rgb2hex($rgb, $adHash = true)
    {
        return sprintf("%s%02X%02X%02X", ($adHash ? '#' : ''), $rgb[0], $rgb[1], $rgb[2]);
    }

    /**
     * Convert an RGB array into HLS colour space.
     *
     * Expects array(r, g, b) where r, g, b in [0,255].  The HLS array is
     * returned as array(h, l, s) where h is in [0,360], l and s in [0,1].
     *
     * Function adapted from 'Computer Graphics: Principles and Practice',
     * by Foley, van Dam, Feiner and Hughes.  Chapter 13; Achromatic and 
     * Colored Light.
     *
     * @return array
     * @param  array $rgb
     * @access public
     */
    function rgb2hls($rgb)
    {
        for ($c=0; $c<3; $c++) {
            $rgb[$c] = $rgb[$c] / 255;
        }
        
        $hls = array(0, 0, 0);
        $max = max($rgb);
        $min = min($rgb);

        $hls[1] = ($max + $min) / 2;
        if ($max == $min) {
            $hls[0] = null;
            $hls[2] = 0;
        } else {
            $delta = $max - $min;
            $hls[2] = ($hls[1] <= 0.5) ? ($delta / ($max + $min)) : ($delta / (2 - ($max + $min)));

            if ($rgb[0] == $max) {
                $hls[0] = ($rgb[1] - $rgb[2]) / $delta;
            } else if ($rgb[1] == $max) {
                $hls[0] = 2 + ($rgb[2] - $rgb[0]) / $delta;
            } else {
                $hls[0] = 4 + ($rgb[0] - $rgb[1]) / $delta;
            }

            $hls[0] *= 60;
            if ($hls[0] < 0) {
                $hls[0] += 360;
            }
            if ($hls[0] > 360) {
                $hls[0] -= 360;
            }
        }
        ksort($hls);
        return $hls;
    }

    /**
     * Convert HLS colour space array to RGB colour space.
     *
     * Expects HLS array  as array(h, l, s) where h in [0,360], l and s each
     * in [0,1].  Returns array(r, g, b) where r, g, and b each in [0, 255]
     *
     * Function adapted from 'Computer Graphics: Principles and Practice',
     * by Foley, van Dam, Feiner and Hughes.  Chapter 13; Achromatic and 
     * Colored Light.
     *
     * @return array
     * @param  array $hls
     * @access public
     */
    function hls2rgb($hls)
    {
        $rgb = array(0, 0, 0);
        
        $m2 = ($hls[1] <= 0.5) ? ($hls[1] * (1 + $hls[2])) : ($hls[1] + $hls[2] * (1 - $hls[1]));
        $m1 = 2 * $hls[1] - $m2;

        if (!$hls[2]) {
            if ($hls[0] === null) {
                $rgb[0] = $rgb[1] = $rgb[2] = $hls[1];
            } else {
                return false;
            }
        } else {
            $rgb[0] = Image::_hVal($m1, $m2, $hls[0] + 120);
            $rgb[1] = Image::_hVal($m1, $m2, $hls[0]);
            $rgb[2] = Image::_hVal($m1, $m2, $hls[0] - 120);
        }
        
        for ($c=0; $c<3; $c++) {
            $rgb[$c] = round($rgb[$c] * 255);
        }
        return $rgb;
    }

    /**
     * Hue value checker for HSL colour space routine.
     *
     * @return float
     * @param  float $n1
     * @param  float $n2
     * @param  float $h
     * @access private
     * @see    Image::hls2rgb()
     */
    function _hVal($n1, $n2, $h)
    {
        if ($h > 360) {
            $h -= 360;
        } else if ($h < 0) {
            $h += 360;
        }

        if ($h < 60) {
            return $n1 + ($n2 - $n1) * $h / 60;
        } else if ($h < 180) {
            return $n2;
        } else if ($h < 240) {
            return $n1 + ($n2 - $n1) * (240 - $h) / 60;
        } else {
            return $n1;
        }
    }

    /**
     * Convert an RGB array into HSV (aka HSB) colour space.
     *
     * Expects array(r, g, b) where r, g, b in [0,255].  The HSV array is
     * returned as array(h, s, v) where h is in [0,360], s and v in [0,1].
     *
     * Function adapted from 'Computer Graphics: Principles and Practice',
     * by Foley, van Dam, Feiner and Hughes.  Chapter 13; Achromatic and 
     * Colored Light.
     *
     * @return array
     * @param  array $rgb
     * @access public
     */
    function rgb2hsv($rgb)
    {
        for ($c=0; $c<3; $c++) {
            $rgb[$c] = $rgb[$c] / 255;
        }
        
        $hsv = array(0, 0, 0);
        $max = max($rgb);
        $min = min($rgb);

        $hsv[2] = $max;
        $hsv[1] = ($max) ? (($max - $min) / $max) : 0;

        if (!$hsv[1]) {
            $hsv[0] = null;
        } else {
            $delta = $max - $min;
            if ($rgb[0] == $max) {
                $hsv[0] = ($rgb[1] - $rgb[2]) / $delta;
            } else if ($rgb[1] == $max) {
                $hsv[0] = 2 + ($rgb[2] - $rgb[0]) / $delta;
            } else {
                $hsv[0] = 4 + ($rgb[0] - $rgb[1]) / $delta;
            }

            $hsv[0] *= 60;
            if ($hsv[0] < 0) {
                $hsv[0] += 360;
            }
        }
        ksort($hsv);
        return $hsv;
    }
    
    /**
     * Convert HSV colour space array to RGB colour space.
     *
     * Expects HLS array  as array(h, s, v) where h in [0,360], s and v each
     * in [0,1].  Returns array(r, g, b) where r, g, and b each in [0, 255]
     *
     * Function adapted from 'Computer Graphics: Principles and Practice',
     * by Foley, van Dam, Feiner and Hughes.  Chapter 13; Achromatic and 
     * Colored Light.
     *
     * @return array
     * @param  array $hsv
     * @access public
     */
    function hsv2rgb($hsv)
    {
        if (!$hsv[1]) {
            if ($hsv[0] === null) {
                $rgb[0] = $rgb[1] = $rgb[2] = $hsv[2];
            } else {
                return false;
            }
        } else {
            if ($hsv[0] == 360) {
                $hsv[0] = 0;
            }
            $hsv[0] /= 60;
            $i = floor($hsv[0]);
            $f = $hsv[0] - $i;
            $p = $hsv[2] * (1 - $hsv[1]);
            $q = $hsv[2] * (1 - ($hsv[1] * $f));
            $t = $hsv[2] * (1 - ($hsv[1] * (1 - $f)));
            switch ($i) {
                case 0:
                    $rgb[0] = $hsv[2];
                    $rgb[1] = $t;
                    $rgb[2] = $p;
                    break;
                case 1:
                    $rgb[0] = $q;
                    $rgb[1] = $hsv[2];
                    $rgb[2] = $p;
                    break;
                case 2:
                    $rgb[0] = $p;
                    $rgb[1] = $hsv[2];
                    $rgb[2] = $t;
                    break;
                case 3:
                    $rgb[0] = $p;
                    $rgb[1] = $q;
                    $rgb[2] = $hsv[2];
                    break;
                case 4:
                    $rgb[0] = $t;
                    $rgb[1] = $p;
                    $rgb[2] = $hsv[2];
                    break;
                case 5:
                    $rgb[0] = $hsv[2];
                    $rgb[1] = $p;
                    $rgb[2] = $q;
                    break;
            }
        }
        for ($c=0; $c<3; $c++) {
            $rgb[$c] = round($rgb[$c] * 255);
        }
        return $rgb;
    }

    /**
     * Converts an image resource into a grey-scale version
     *
     * @return void
     * @param  resource &$im a reference to the image
     * @access public
     */
    function greyscale(&$im)
    {
        $sx = imagesx($im);
        $sy = imagesy($im);
        for ($x = 0; $x < $sx; $x++) {
            for ($y = 0; $y < $sy; $y++) {
                $rgb = Image::getPixelRGB($im, $x, $y);
                $colour = ($rgb[0] + $rgb[1] + $rgb[2]) / 3;
                imagesetpixel($im, $x, $y, imagecolorallocate($im, $colour, $colour, $colour));
            }
        } 
    }

    /**
     * Converts an image resource into a threshold black/white version.
     *
     * The threshold level is a value from 0 to 255 (black to white), and any
     * pixel with a colour below that value will be turned black, and any
     * pixel above that value will be turned white.
     *
     * @return void
     * @param  resource &$im a reference to the image
     * @param  int $level
     * @access public
     */
    function threshold(&$im, $level = 128)
    {
        $sx = imagesx($im);
        $sy = imagesy($im);
        $black = imagecolorallocate($im, 0, 0, 0);
        $white = imagecolorallocate($im, 255, 255, 255);
        for ($x = 0; $x < $sx; $x++) {
            for ($y = 0; $y < $sy; $y++) {
                $rgb = Image::getPixelRGB($im, $x, $y);
                $intensity = ($rgb[0] + $rgb[1] + $rgb[2]) / 3;
                imagesetpixel($im, $x, $y, ($intensity < $level ? $black : $white));
            }
        }
    }

    /**
     * Colourises an image based on given colour.
     *
     * The colour to use as the shade/tint can be passed and as hex colour
     * string or as an RGB array.
     *
     * @return void
     * @param  resource &$im a reference to the image
     * @param  string|array $setColour
     * @access public
     */
    function colourise(&$im, $setColour)
    {
        if (is_string($setColour)) {
            $hls = Image::rgb2hls(Image::hex2rgb($setColour));
        } else {
            $hls = Image::rgb2hls($setColour);
        }
        
        $sx = imagesx($im);
        $sy = imagesy($im);
        for ($x = 0; $x < $sx; $x++) {
            for ($y = 0; $y < $sy; $y++) {
                $rgb = Image::getPixelRGB($im, $x, $y);
                $pxhls = Image::rgb2hls($rgb);
                $pxhls[0] = $hls[0];
                $pxhls[2] = $hls[2];
                $rgb = Image::hls2rgb($pxhls);
                imagesetpixel($im, $x, $y, imagecolorallocate($im, $rgb[0], $rgb[1], $rgb[2]));
            }
        } 
    }

    /**
     * @see Image::colourise()
     */
    function colorize(&$im, $setColour)
    {
        Image::colourise($im, $setColour);
    }

    /**
     * Sepia tone an image.
     *
     * @return void
     * @param  resource &$im a reference to the image
     * @access public
     */
    function sepia(&$im)
    {
        $sx = imagesx($im);
        $sy = imagesy($im);
        for ($x = 0; $x < $sx; $x++) {
            for ($y = 0; $y < $sy; $y++) {
                $rgb = Image::getPixelRGB($im, $x, $y);
                $pxhls = Image::rgb2hls($rgb);
                $pxhls[0] = 0.30;
                $pxhls[2] = 0.25;
                $rgb = Image::hls2rgb($pxhls);
                imagesetpixel($im, $x, $y, imagecolorallocate($im, $rgb[0], $rgb[1], $rgb[2]));
            }
        } 
    }

    /**
     * Get a range of colours over a certain number of steps,
     *
     * Given two different colours, this method will give you a range of
     * colours over a certain number of steps from the first colour to the
     * second.  If the two input colours are in hex format, then the array
     * returned will consist of hex values.  If the two colours are passed
     * as arrays, then the returned array will consist of arrays.  If there
     * is a mix of hex and rgb arrays then the returned array will also be
     * returned in that format.
     *
     * If the $trueSteps parameter is true, then the range will go from
     * colour one to colour two in $steps, returning $steps + 1 colours.
     * If set to false, it will just return $steps colours (as most people
     * might expect).
     *
     * @return array
     * @param  string|array $startColour
     * @param  string|array $endColour
     * @param  int          $steps
     * @param  boolean      $trueSteps
     * @access public
     */
    function colourRange($startColour, $endColour, $steps, $trueSteps = false)
    {
        $range = array();
        $saveType = 0;
        if (is_array($startColour) && is_array($endColour)) {
            $saveType = 1;
        } else if (is_string($startColour) && is_array($endColour)) {
            $saveType = 2;
        } else if (is_array($startColour) && is_string($endColour)) {
            $saveType = 3;
        }
        $s = (is_string($startColour)) ? Image::hex2rgb($startColour) : $startColour;
        $e = (is_string($endColour))   ? Image::hex2rgb($endColour)   : $endColour;
        if (!$trueSteps) {
            --$steps;
        }

        for ($i = 0; $i <= $steps; $i++) {
            $rgb = array();
            $rgb[0] = round($s[0] + ($i * ($e[0] - $s[0]) / $steps));
            $rgb[1] = round($s[1] + ($i * ($e[1] - $s[1]) / $steps));
            $rgb[2] = round($s[2] + ($i * ($e[2] - $s[2]) / $steps));
            switch($saveType) {
            case 3:
                $range[] = array($rgb, Image::rgb2hex($rgb));
                break;
            case 2:
                $range[] = array(Image::rgb2hex($rgb), $rgb);
                break;
            case 1:
                $range[] = $rgb;
                break;
            default:
                $range[] = Image::rgb2hex($rgb);
                break;
            }
        }
        return $range;
    }

    /**
     * @see Image::colourRange()
     */
    function colorRange($startColour, $endColour, $steps, $trueSteps = false)
    {
        return Image::colourRange($startColour, $endColour, $steps, $trueSteps);
    }

}

?>
Return current item: Image Functions