andy's php projects
Script and site usage:
All of the scripts on this site are provided free for non-commercial, personal or non-profit use. If you wish to use any of these in a commercial system, please refer to the payment plan.

Support:
Support for each of the scripts is given, free of charge, on the message board. Each script has its own message board which can be accessed by clicking on the 'project forum' link (beneath the description of each project).


Proudly hosted with Dreamhost

Save $20 when signing up for Dreamhost by using the promo code amnuts20


If you find these scripts useful to you, appreciate the free support, or are just an all round nice person, then why not donate a little dosh to encourage me to continue? Every little helps!

Zend Certified Engineer logo


Image Masking

This is a class allows you to apply a mask to an image much like you could do in PhotoShop, Gimp, or any other such image manipulation programme. The mask is converted to grayscale so it's best to use black/white patterns. If the mask is smaller than the image then the mask can be placed in various positions (top left, left, top right, left, centre, right, bottom left, bottom, bottom right) or the mask can be resized to the dimensions of the image.

Requires GD 2.0.1+

Because of the nature of the class, masking large images may take some time. So it's best used on thumbnails and the like.

class.imagemask.php

The main class file.

<?php

//
// class.imagemask.php
// version 1.0.0, 19th January, 2004
//
// Description
//
// This is a class allows you to apply a mask to an image much like you could
// do in PhotoShop, Gimp, or any other such image manipulation programme.  The
// mask is converted to grayscale so it's best to use black/white patterns.
// If the mask is smaller than the image then the mask can be placed in various
// positions (top left, left, top right, left, centre, right, bottom left,
// bottom, bottom right) or the mask can be resized to the dimensions of the
// image.
//
// Requirements
//
// This class NEEDS GD 2.0.1+ (preferrably the version bundled with PHP)
//
// Notes
//
// This class has to copy an image one pixel at a time.  Please bare in mind
// that this process may take quite some time on large images, so it's probably
// best that it's used on thumbnails and smaller images.
//
// Author
//
// Andrew Collington, 2004
// php@amnuts.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.
//
// 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.
//
// Example of use
//
//    require 'class.imagemask.php';
//    $im = new imageMask('ffffff');
//    $im->maskOption(mdCENTRE);
//    if ($im->loadImage(dirname(__FILE__) . "/pictures/{$_POST['file']}"))
//    {
//        if ($im->applyMask(dirname(__FILE__) . "/masks/{$_POST['mask']}"))
//        {
//            $im->showImage('png');
//        }
//    }
//


define('mdTOPLEFT',     0);
define('mdTOP',         1);
define('mdTOPRIGHT',    2);
define('mdLEFT',        3);
define('mdCENTRE',      4);
define('mdCENTER',      4);
define('mdRIGHT',       5);
define('mdBOTTOMLEFT',  6);
define('mdBOTTOM',      7);
define('mdBOTTOMRIGHT'8);
define('mdRESIZE',      9);


class 
imageMask
{
    var 
$_colours;
    var 
$_img;
    var 
$_mask;
    var 
$_bgc;
    var 
$_showDebug;
    var 
$_maskDynamic;
    
    
    
/**
    * @return imageMask
    * @param string $bg
    * @desc Class constructor.  Pass the background colour as an HTML colour string.
    */
    
function imageMask($bg 'FFFFFF')
    {
        
$this->setDebugging(false);
        
$this->maskOption(mdCENTER);
        
$this->_colours = array();
        
$this->_img     = array();
        
$this->_mask    = array();
        
$this->_bgc     $this->_htmlHexToBinArray($bg);
    }
    
    
    
/**
    * @return void
    * @param bool $do
    * @desc Toggles debugging
    */
    
function setDebugging($do false)
    {
        
$this->_showDebug = ($do === true) ? true false;
    }
    
    
    
/**
    * @return bool
    * @param string $filename
    * @desc Load an image from the file system - method based on file extension
    */
    
function loadImage($filename)
    {
        return (
$this->_realLoadImage($filename$this->_img['orig']));
    }
    
    
    
/**
    * @return bool
    * @param string $string
    * @desc Load an image from a string (eg. from a database table)
    */
    
function loadImageFromString($string)
    {
        
$this->_img['orig'] = @ImageCreateFromString($string);
        if (
$this->_img['orig'])
        {
            return 
true;
        }
        else
        {
            
$this->_debug('loadImageFromString''The original image could not be loaded.');
            return 
false;
        }
    }
    
    
    
/**
    * @return bool
    * @param string $filename
    * @param int $quality
    * @desc Save the masked image
    */
    
function saveImage($filename$quality 100)
    {
        if (
$this->_img['final'] == null)
        {
            
$this->_debug('saveImage''There is no processed image to save.');
            return 
false;
        }
        
        
$ext strtolower($this->_getExtension($filename));
        
$func "image$ext";
        
        if (!@
function_exists($func))
        {
            
$this->_debug('saveImage'"That file cannot be saved with the function '$func'.");
            return 
false;
        }
        
        
$saved = ($ext == 'png') ? $func($this->_img['final'], $filename) : $func($this->_img['final'], $filename$quality);
        if (
$saved == false)
        {
            
$this->_debug('saveImage'"Could not save the output file '$filename' as a $ext.");
            return 
false;
        }
        
        return 
true;
    }
    
    
    
/**
    * @return bool
    * @param string $type
    * @param int $quality
    * @desc Shows the masked image without any saving
    */
    
function showImage($type 'png'$quality 100)
    {
        
$type strtolower($type);
        if (
$this->_img['final'] == null)
        {
            
$this->_debug('showImage''There is no processed image to show.');
        }
        else if (
$type == 'png')
        {
            
header('Content-type: image/png');
            echo @
imagepng($this->_img['final']);
            return 
true;
        }
        else if (
$type == 'jpg' || $type == 'jpeg')
        {
            
header('Content-type: image/jpeg');
            echo @
imagejpeg($this->_img['final'], ''$quality);
            return 
true;
        }
        else
        {
            
$this->_debug('showImage'"Could not show the output file as a $type.");
        }
        return 
false;
    }
    
    
    
/**
    * @return void
    * @param int $do
    * @desc Set the mask overlay option (position or resize to image size)
    */
    
function maskOption($do mdCENTER)
    {
        
$this->_maskDynamic $do;
    }
    
    
    
/**
    * @return bool
    * @param string $filename
    * @desc Apply the mask to the image
    */
    
function applyMask($filename)
    {
        if (
$this->_img['orig'])
        {
            if (
$this->_generateInitialOutput())
            {
                if (
$this->_realLoadImage($filename$this->_mask['orig']))
                {
                    if (
$this->_getMaskImage())
                    {
                        
$sx imagesx($this->_img['final']);
                        
$sy imagesy($this->_img['final']);
                        
                        
set_time_limit(120);
                        for (
$x 0$x $sx$x++)
                        {
                            for (
$y 0$y $sy$y++)
                            {
                                
$thres $this->_pixelAlphaThreshold($this->_mask['gray'], $x$y);
                                if (!
in_array($thresarray_keys($this->_colours))) {
                                    
$this->_colours[$thres] = imagecolorallocatealpha($this->_img['final'], $this->_bgc[0], $this->_bgc[1], $this->_bgc[2], $thres);
                                }
                                
imagesetpixel($this->_img['final'], $x$y$this->_colours[$thres]);
                            }
                        }
                        return 
true;
                    }
                    else
                    {
                        
$this->_debug('applyMask''The grayscale mask could not be created.');
                    }
                }
            }
        }
        else
        {
            
$this->_debug('applyMask''The original image has not been loaded.');
        }
        return 
false;
    }
    
    
    
/**
    * @return bool
    * @param string $filename
    * @param pointer $img
    * @desc Enter description here...
    */
    
function _realLoadImage($filename, &$img)
    {
        if (!@
file_exists($filename))
        {
            
$this->_debug('_realLoadImage'"The supplied filename '$filename' does not point to a readable file.");
            return 
false;
        }
        
        
$ext  strtolower($this->_getExtension($filename));
        
$func "imagecreatefrom$ext";
        
        if (!@
function_exists($func))
        {
            
$this->_debug('_realLoadImage'"That file cannot be loaded with the function '$func'.");
            return 
false;
        }
        
        
$img = @$func($filename);
        return (
$img) ? true false;
    }
    
    
    
/**
    * @return bool
    * @desc Copies the original image into the final image ready for the mask overlay
    */
    
function _generateInitialOutput()
    {
        if (
$this->_img['orig'])
        {
            
$isx imagesx($this->_img['orig']);
            
$isy imagesy($this->_img['orig']);
            
$this->_img['final'] = imagecreatetruecolor($isx$isy);
            if (
$this->_img['final'])
            {
                
imagealphablending($this->_img['final'], true);
                
imagecopyresampled($this->_img['final'], $this->_img['orig'], 0000$isx$isy$isx$isy);
                return 
true;
            }
            else
            {
                
$this->_debug('_generateInitialOutput''The final image (without the mask) could not be created.');
            }
        }
        else
        {
            
$this->_debug('_generateInitialOutput''The original image has not been loaded.');
        }
        return 
false;
    }
    
    
    
/**
    * @return bool
    * @desc Creates the mask image and determines position and size of mask
    *       based on the _maskOption value and image size.  If the image is
    *       smaller than the mask (and the mask isn't set to resize) then the
    *       mask defaults to the top-left position and will be cut off.
    */
    
function _getMaskImage()
    {
        
$isx imagesx($this->_img['final']);
        
$isy imagesy($this->_img['final']);
        
$msx imagesx($this->_mask['orig']);
        
$msy imagesy($this->_mask['orig']);
        
        
$this->_mask['gray'] = imagecreatetruecolor($isx$isy);
        
imagefill($this->_mask['gray'], 00imagecolorallocate($this->_mask['gray'], 000));
        
        if (
$this->_mask['gray'])
        {
            switch(
$this->_maskDynamic)
            {
                case 
mdTOPLEFT:
                    
$sx $sy 0;
                    break;
                case 
mdTOP:
                    
$sx ceil(($isx $msx) / 2);
                    
$sy 0;
                    break;
                case 
mdTOPRIGHT:
                    
$sx = ($isx $msx);
                    
$sy 0;
                    break;
                case 
mdLEFT:
                    
$sx 0;
                    
$sy ceil(($isy $msy) / 2);
                    break;
                case 
mdCENTRE:
                    
$sx ceil(($isx $msx) / 2);
                    
$sy ceil(($isy $msy) / 2);
                    break;
                case 
mdRIGHT:
                    
$sx = ($isx $msx);
                    
$sy ceil(($isy $msy) / 2);
                    break;
                case 
mdBOTTOMLEFT:
                    
$sx 0;
                    
$sy = ($isy $msy);
                    break;
                case 
mdBOTTOM:
                    
$sx ceil(($isx $msx) / 2);
                    
$sy = ($isy $msy);
                    break;
                case 
mdBOTTOMRIGHT:
                    
$sx = ($isx $msx);
                    
$sy = ($isy $msy);
                    break;
            }
            if (
$isx $msx)
            {
                
$sx 0;
            }
            if (
$isy $msy)
            {
                
$sy 0;
            }
            if (
$this->_maskDynamic == mdRESIZE)
            {
                
$this->_mask['temp'] = imagecreatetruecolor($isx$isy);
                
imagecopyresampled($this->_mask['temp'], $this->_mask['orig'], 0000$isx$isy$msx$msy);
                
imagecopymergegray($this->_mask['gray'], $this->_mask['temp'], 0000$isx$isy100);
                
imagedestroy($this->_mask['temp']);
            }
            else
            {
                
imagecopymergegray($this->_mask['gray'], $this->_mask['orig'], $sx$sy00$msx$msy100);
            }
            return 
true;
        }
        return 
false;
    }
    
    
    
/**
    * @return int
    * @param resource $img
    * @param int $x
    * @param int $y
    * @desc Determines the colour value of a pixel and returns the required value for the alpha overlay
    */
    
function _pixelAlphaThreshold($img$x$y)
    {
        
        
$rgb imagecolorat($img$x$y);
        
$r   = ($rgb >> 16) & 0xFF;
        
$g   = ($rgb >> 8) & 0xFF;
        
$b   $rgb 0xFF;
        
$ret round(($r $g $b) / 6);
        return (
$ret 1) ? ($ret 1) : 0;
    }
    
    
    
/**
    * @return array
    * @param string $hex
    * @desc Converts an HTML hex colour value to an array of integers
    */
    
function _htmlHexToBinArray($hex)
    {
        
$hex = @preg_replace('/^#/'''$hex);
        for (
$i=0$i<3$i++)
        {
            
$foo substr($hex2*$i2);
            
$rgb[$i] = 16 hexdec(substr($foo01)) + hexdec(substr($foo11));
        }
        return 
$rgb;
    }
    
    
    
/**
    * @return string
    * @param string $filename
    * @desc Get the extension of a file name
    */
    
function _getExtension($filename)
    {
        
$ext  = @strtolower(@substr($filename, (@strrpos($filename".") ? @strrpos($filename".") + : @strlen($filename)), @strlen($filename)));
        return (
$ext == 'jpg') ? 'jpeg' $ext;
    }
    
    
    
/**
    * @return void
    * @param string $function
    * @param string $string
    * @desc Shows debugging information
    */
    
function _debug($function$string)
    {
        if (
$this->_showDebug)
        {
            echo 
"<p><strong style=\"color:#FF0000\">Error in function $function:</strong> $string</p>\n";
        }
    }
    
    
}

?>
13.66kb in size
last modified May 6, 2006 at 9:55pm
9148 views, 8560 downloads

demomask-blob.png

An example mask.

7.35kb in size
last modified May 6, 2006 at 9:55pm
7580 views, 8923 downloads

demomask-frame1.png

An example mask.

19.78kb in size
last modified May 6, 2006 at 9:55pm
7192 views, 6762 downloads

demomask-frame2.png

An example mask.

17.15kb in size
last modified May 6, 2006 at 9:55pm
7692 views, 10221 downloads

test.imagemask.php

A test file.

375b in size
last modified May 6, 2006 at 9:55pm
8513 views, 7094 downloads
list all projects :: this project's forum :: script in action
added Jan 18, 2004 at 7:34am :: updated Jan 18, 2004 at 7:34am :: 5 files :: 42706 views

© Andrew Collington, 2002-2007.