Skip to content
masterexploder edited this page Sep 13, 2010 · 1 revision

Plugin development really isn’t too tough, at least that’s the general goal.

Getting Started

Let’s take a look at the basic, suggested plugin base code. For this example, we’ll deconstruct the reflection plugin:

<?php

class GdReflectionLib
{
	/**
	 * Instance of GdThumb passed to this class
	 * 
	 * @var GdThumb
	 */
	protected $parentInstance;
}

$pt = PhpThumb::getInstance();
$pt->registerPlugin('GdReflectionLib', 'gd');
?>

We’ve basically got two things here. The first is the actual plugin class. Any public functions in this class will become callable from a PHP Thumb object (we’ll add one momentarily). I’ve also added a member variable called “parentInstance”. This will be our local reference to the PHP Thumb object this plugin is augmenting. We’ve also got two lines at the bottom of the file. These register the actual plugin. Without these lines, your functions will not become available, as the plugin won’t be registered when PHP Thumb objects are created. In this particular example, we’ve registered the object for GD implementations of the PHP Thumb library.

Writing the Plugin

Moving on, let’s create our public function, and add some other member variables:

<?php

class GdReflectionLib
{
	/**
	 * Instance of GdThumb passed to this class
	 * 
	 * @var GdThumb
	 */
	protected $parentInstance;
	protected $currentDimensions;
	protected $workingImage;
	protected $newImage;
	protected $options;
	
	public function createReflection ($percent, $reflection, $white, $border, $borderColor, &$that)
	{
		// bring stuff from the parent class into this class...
		$this->parentInstance 		= $that;
		$this->currentDimensions 	= $this->parentInstance->getCurrentDimensions();
		$this->workingImage		= $this->parentInstance->getWorkingImage();
		$this->newImage			= $this->parentInstance->getOldImage();
		$this->options			= $this->parentInstance->getOptions();

		...
	}
}

?>

When creating public functions on your plugins, it’s important to ALWAYS add the “&$that” param as the last argument on your function signature. The end-user will never provide this parameter, but the core code will pass it along. Basically, $that is the PHP Thumb object (in this case the GdThumb object), and this is what provides you access to all the parent functionality and member variables via getters and setters.

Another thing I’ve done is created local member variables that hold values from the parent class. You don’t really need to do this, but you’ll find it’s a lot easier to do things like $this->currentDimensions instead of $this->parentInstance->getCurrentDimensions() over and over again in your code. I’ve also only created member variables for the information I’ll actually be using in my functionality.

At this point you can create any other functions on the class you’d like. In the case of the reflection plugin, I’ve got a couple protected functions that help create the reflection. You can take a look at the actual reflection plugin in the distributed release to get a bit more insight into how this all works, but it’s pretty much what you’d expect in any class.

Finally, we need to make sure any local changes get pushed back to the parent class. In the case of the reflection plugin, I need to pass up the manipulated image as well as the new dimensions. So, my function now looks like:

<?php
class GdReflectionLib
{
	/**
	 * Instance of GdThumb passed to this class
	 * 
	 * @var GdThumb
	 */
	protected $parentInstance;
	protected $currentDimensions;
	protected $workingImage;
	protected $newImage;
	protected $options;
	
	public function createReflection ($percent, $reflection, $white, $border, $borderColor, &$that)
	{
		// bring stuff from the parent class into this class...
		$this->parentInstance 		= $that;
		$this->currentDimensions 	= $this->parentInstance->getCurrentDimensions();
		$this->workingImage		= $this->parentInstance->getWorkingImage();
		$this->newImage			= $this->parentInstance->getOldImage();
		$this->options			= $this->parentInstance->getOptions();
		
		// actual functionality omitted for brevity		

		$this->parentInstance->setOldImage($this->workingImage);
		$this->currentDimensions['width'] 	= $width;
		$this->currentDimensions['height']	= $newHeight;
		$this->parentInstance->setCurrentDimensions($this->currentDimensions);
		
		return $that;
	}
}
?>

As you can see, it’s just a matter of assigning the new values via the setters available on the parent instance. I also return the parent instance to allow for proper function chaining.

And that’s about all there is too it!

A Real Example

While this code may eventually become outdated, here’s the full reflection plugin (at the time of writing) for reference:

<?php
/**
 * GD Reflection Lib Plugin Definition File
 * 
 * This file contains the plugin definition for the GD Reflection Lib for PHP Thumb
 * 
 * PHP Version 5 with GD 2.0+
 * PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
 * Copyright (c) 2009, Ian Selby/Gen X Design
 * 
 * Author(s): Ian Selby <[email protected]>
 * 
 * Licensed under the MIT License
 * Redistributions of files must retain the above copyright notice.
 * 
 * @author Ian Selby <[email protected]>
 * @copyright Copyright (c) 2009 Gen X Design
 * @link http://phpthumb.gxdlabs.com
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
 * @version 3.0
 * @package PhpThumb
 * @filesource
 */

/**
 * GD Reflection Lib Plugin
 * 
 * This plugin allows you to create those fun Apple(tm)-style reflections in your images
 * 
 * @package PhpThumb
 * @subpackage Plugins
 */
class GdReflectionLib
{
	/**
	 * Instance of GdThumb passed to this class
	 * 
	 * @var GdThumb
	 */
	protected $parentInstance;
	protected $currentDimensions;
	protected $workingImage;
	protected $newImage;
	protected $options;
	
	public function createReflection ($percent, $reflection, $white, $border, $borderColor, &$that)
	{
		// bring stuff from the parent class into this class...
		$this->parentInstance 		= $that;
		$this->currentDimensions 	= $this->parentInstance->getCurrentDimensions();
		$this->workingImage			= $this->parentInstance->getWorkingImage();
		$this->newImage				= $this->parentInstance->getOldImage();
		$this->options				= $this->parentInstance->getOptions();
		
		$width				= $this->currentDimensions['width'];
		$height				= $this->currentDimensions['height'];
		$reflectionHeight 	= intval($height * ($reflection / 100));
		$newHeight			= $height + $reflectionHeight;
		$reflectedPart		= $height * ($percent / 100);
		
		$this->workingImage = imagecreatetruecolor($width, $newHeight);
		
		imagealphablending($this->workingImage, true);
		
		$colorToPaint = imagecolorallocatealpha($this->workingImage,255,255,255,0);
        imagefilledrectangle($this->workingImage,0,0,$width,$newHeight,$colorToPaint);
		
		imagecopyresampled
		(
            $this->workingImage,
            $this->newImage,
            0,
            0,
            0,
            $reflectedPart,
            $width,
            $reflectionHeight,
            $width,
            ($height - $reflectedPart)
		);
		
		$this->imageFlipVertical();
		
		imagecopy($this->workingImage, $this->newImage, 0, 0, 0, 0, $width, $height);
		
		imagealphablending($this->workingImage, true);
		
		for ($i = 0; $i < $reflectionHeight; $i++) 
		{
            $colorToPaint = imagecolorallocatealpha($this->workingImage, 255, 255, 255, ($i/$reflectionHeight*-1+1)*$white);
			
            imagefilledrectangle($this->workingImage, 0, $height + $i, $width, $height + $i, $colorToPaint);
        }
		
		if($border == true) 
		{
            $rgb 			= $this->hex2rgb($borderColor, false);
            $colorToPaint 	= imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]);
			
            imageline($this->workingImage, 0, 0, $width, 0, $colorToPaint); //top line
            imageline($this->workingImage, 0, $height, $width, $height, $colorToPaint); //bottom line
            imageline($this->workingImage, 0, 0, 0, $height, $colorToPaint); //left line
            imageline($this->workingImage, $width-1, 0, $width-1, $height, $colorToPaint); //right line
        }
		
		if ($this->parentInstance->getFormat() == 'PNG')
		{
			$colorTransparent = imagecolorallocatealpha
			(
				$this->workingImage, 
				$this->options['alphaMaskColor'][0], 
				$this->options['alphaMaskColor'][1], 
				$this->options['alphaMaskColor'][2], 
				0
			);
			
			imagefill($this->workingImage, 0, 0, $colorTransparent);
			imagesavealpha($this->workingImage, true);
		}
		
		$this->parentInstance->setOldImage($this->workingImage);
		$this->currentDimensions['width'] 	= $width;
		$this->currentDimensions['height']	= $newHeight;
		$this->parentInstance->setCurrentDimensions($this->currentDimensions);
		
		return $that;
	}
	
	/**
	 * Flips the image vertically
	 * 
	 */
	protected function imageFlipVertical ()
	{
		$x_i = imagesx($this->workingImage);
	    $y_i = imagesy($this->workingImage);

	    for ($x = 0; $x < $x_i; $x++) 
		{
	        for ($y = 0; $y < $y_i; $y++) 
			{
	            imagecopy($this->workingImage, $this->workingImage, $x, $y_i - $y - 1, $x, $y, 1, 1);
	        }
	    }
	}
	
	/**
	 * Converts a hex color to rgb tuples
	 * 
	 * @return mixed 
	 * @param string $hex
	 * @param bool $asString
	 */
	protected function hex2rgb ($hex, $asString = false) 
	{
        // strip off any leading #
        if (0 === strpos($hex, '#')) 
		{
           $hex = substr($hex, 1);
        } 
		elseif (0 === strpos($hex, '&H')) 
		{
           $hex = substr($hex, 2);
        }

        // break into hex 3-tuple
        $cutpoint = ceil(strlen($hex) / 2)-1;
        $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3);

        // convert each tuple to decimal
        $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0);
        $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0);
        $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0);

        return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb);
    }
}

$pt = PhpThumb::getInstance();
$pt->registerPlugin('GdReflectionLib', 'gd');
?>
Clone this wiki locally