Image_Tools
[ class tree: Image_Tools ] [ index: Image_Tools ] [ all elements ]

Source for file Tools.php

Documentation is available at Tools.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3.  
  4. // {{{ Header
  5.  
  6. /**
  7.  * This is a main file of Image_Tools package.
  8.  *
  9.  * PHP versions 4 and 5
  10.  *
  11.  * LICENSE:
  12.  * Copyright (c) 2005-2008
  13.  *  Tobias Schlitt <toby@php.net>,
  14.  *  Firman Wandayandi <firman@php.net>
  15.  *
  16.  * This source file is subject to the BSD License license that is bundled
  17.  * with this package in the file LICENSE.txt.
  18.  * It is also available through the world-wide-web at this URL:
  19.  * http://www.opensource.org/licenses/bsd-license.php
  20.  * If you did not receive a copy of the license and are unable to
  21.  * obtain it through the world-wide-web, please send an email
  22.  * to pear-dev@list.php.net so we can send you a copy immediately.
  23.  *
  24.  * @category    Images
  25.  * @package     Image_Tools
  26.  * @author      Tobias Schlitt <toby@php.net>
  27.  * @author      Firman Wandayandi <firman@php.net>
  28.  * @copyright   Copyright (c) 2003-2008
  29.  *                 Tobias Schlitt <toby@php.net>,
  30.  *                 Firman Wandayandi <firman@php.net>
  31.  * @license     http://www.opensource.org/licenses/bsd-license.php
  32.  *               BSD License
  33.  * @version     CVS: $Id: Tools.php,v 1.13 2008/05/26 09:18:09 firman Exp $
  34.  */
  35.  
  36. // }}}
  37. // {{{ Dependencies
  38.  
  39. /**
  40.  * load PEAR for error handling.
  41.  */
  42. require_once 'PEAR.php';
  43.  
  44. /**
  45.  * load PHP_Compat for PHP backward compatibility.
  46.  */
  47. require_once 'PHP/Compat.php';
  48.  
  49. /**
  50.  * is_a(), since PHP 4.2.0
  51.  */
  52. @PHP_Compat::loadFunction('is_a');
  53.  
  54. /**
  55.  * image_type_to_mime_type, since PHP 4.3.0
  56.  */
  57. @PHP_Compat::loadFunction('image_type_to_mime_type');
  58.  
  59. // }}}
  60. // {{{ Constants
  61.  
  62. /**
  63.  * Image_Tools error, indicating that the given tool was not found.
  64.  *
  65.  * @name    IMAGE_TOOLS_BASE_ERR_CLASS_INVALID
  66.  * @access  public
  67.  */
  68. define('IMAGE_TOOLS_BASE_ERR_CLASS_INVALID'-1);
  69.  
  70. /**
  71.  * Image_Tools error, indicating that the given tool object could not be
  72.  * instanciated.
  73.  *
  74.  * @name    IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FAILED
  75.  * @access  public
  76.  */
  77. define('IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FAILED'-2);
  78.  
  79. /**
  80.  * Image_Tools error, indicating that you may not instanciate
  81.  * the base class Image_Tools directly.
  82.  *
  83.  * @name    IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FAILED
  84.  * @access  public
  85.  */
  86. define('IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FORBIDEN'-3);
  87.  
  88. /**
  89.  * Image_Tools error, indicating that the given option was of a wrong type.
  90.  *
  91.  * @name    IMAGE_TOOLS_BASE_ERR_OPTION_INVALID
  92.  * @access  public
  93.  */
  94. define('IMAGE_TOOLS_BASE_ERR_OPTION_INVALID'-4);
  95.  
  96. /**
  97.  * Image_Tools error, indicating that the given option is not
  98.  * supported by the tool.
  99.  *
  100.  * @name    IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED
  101.  * @access  public
  102.  */
  103. define('IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED'-5);
  104.  
  105. /**
  106.  * Image_Tools error, indicating that the given method is not
  107.  * supported by the tool.
  108.  *
  109.  * @name    IMAGE_TOOLS_BASE_ERR_METHOD_UNSUPPORTED
  110.  * @access  public
  111.  */
  112. define('IMAGE_TOOLS_BASE_ERR_METHOD_UNSUPPORTED'-6);
  113.  
  114. /**
  115.  * Image_Tools error, indicating that the given option is not
  116.  * set.
  117.  *
  118.  * @name    IMAGE_TOOLS_BASE_ERR_OPTION_NOTSET
  119.  * @access  public
  120.  */
  121. define('IMAGE_TOOLS_BASE_ERR_OPTION_NOTSET'-7);
  122.  
  123. /**
  124.  * Image_Tools error, indicating that the HTTP headers have been sent
  125.  * before the display() method was called. Ensure that no output started
  126.  * before that.
  127.  *
  128.  * @name    IMAGE_TOOLS_BASE_ERR_HEADERSEND_FAILED
  129.  * @access  public
  130.  */
  131. define('IMAGE_TOOLS_BASE_ERR_HEADERSEND_FAILED'-8);
  132.  
  133. /**
  134.  * Image_Tools error, indicating that the image type you selected for
  135.  * displaying the image is not supported. Please use a supported image
  136.  * type.
  137.  *
  138.  * @name    IMAGE_TOOLS_BASE_ERR_IMAGETYPE_UNSUPPORTED
  139.  * @access  public
  140.  */
  141. define('IMAGE_TOOLS_BASE_ERR_IMAGETYPE_UNSUPPORTED'-9);
  142.  
  143. /**
  144.  * Image_Tools error, indicating that the image could not be saved.
  145.  * Check the permissions on the desired path first.
  146.  *
  147.  * @name    IMAGE_TOOLS_BASE_ERR_SAVEIMAGE_FAILED
  148.  * @access  public
  149.  */
  150. define('IMAGE_TOOLS_BASE_ERR_SAVEIMAGE_FAILED'-10);
  151.  
  152. /**
  153.  * Image_Tools error, indicating that you called a static method non
  154.  * statically, which may only be called statically.
  155.  *
  156.  * @name    IMAGE_TOOLS_BASE_ERR_NONSTATIC_FAILED
  157.  * @access  public
  158.  */
  159. define('IMAGE_TOOLS_BASE_ERR_NONSTATIC_FAILED'-11);
  160.  
  161. /**
  162.  * Image_Tools error, indicating that you called a static method
  163.  * statically, which may only be called non statically.
  164.  *
  165.  * @name    IMAGE_TOOLS_BASE_ERR_STATIC_FAILED
  166.  * @access  public
  167.  */
  168. define('IMAGE_TOOLS_BASE_ERR_STATIC_FAILED'-12);
  169.  
  170. // }}}
  171. // {{{ Class: Image_Tools
  172.  
  173. /**
  174.  * This is the Image_Tools base class
  175.  * Every image-tool has to derive from this class and implement several methods
  176.  * itself. Other methods are implemented in the base class directly, but may
  177.  * only be called on the sub-classes. The only method being called directly from
  178.  * the base class is the factory() method.
  179.  *
  180.  * @category    Images
  181.  * @package     Image_Tools
  182.  * @author      Tobias Schlitt <toby@php.net>
  183.  * @author      Firman Wandayandi <firman@php.net>
  184.  * @copyright   Copyright (c) 2003-2006
  185.  *                 Tobias Schlitt <toby@php.net>,
  186.  *                 Firman Wandayandi <firman@php.net>
  187.  * @license     http://www.opensource.org/licenses/bsd-license.php
  188.  *               BSD License
  189.  * @version     Release: 1.0.0RC1
  190.  */
  191. {
  192.     // {{{ Properties
  193.  
  194.     /**
  195.      * Contain the options inside all subclasses.
  196.      *
  197.      * @var array 
  198.      * @access protected
  199.      */
  200.     var $options = array();
  201.  
  202.     /**
  203.      * Has to contain all available options of a subclass. The index of
  204.      * the array is the option name, the value is either a PHP variable
  205.      * type (e.g. int, string, float, resource,...) or a class name
  206.      * (e.g. Image_Tools, DB,...). Also allowed the are the special values
  207.      * 'number' and 'mixed'. The structure of that array is as follows:
  208.      *
  209.      * $availableOptions = array(
  210.      *      'foo'   =>  'int',
  211.      *      'bar'   =>  'float',
  212.      *      'db'    =>  'DB',
  213.      *      'img'   =>  'resource'
  214.      * );
  215.      *
  216.      * @var array 
  217.      * @access protected
  218.      */
  219.     var $availableOptions = array();
  220.  
  221.     /**
  222.      * Has to contain all available methods (as the keys of the array)
  223.      * and the expected parameters (in an array) as the values. The structure
  224.      * of this array is as follows:
  225.      *
  226.      * $availableMethods = array(
  227.      *      'myMethod'  =>  array(
  228.      *          'foo'   =>  'int',
  229.      *          'db'    =>  'DB'
  230.      *      'fooBar'    =>  array(
  231.      *          'baz'   =>  'resource',
  232.      *          'bun'   =>  'mixed'
  233.      *      )
  234.      * );
  235.      *
  236.      * @var array 
  237.      * @access protected
  238.      */
  239.     var $availableMethods = array();
  240.  
  241.     /**
  242.      * Contains the version of the specific subclass. A version has to follow the PEAR
  243.      * version naming standard, which can be found here:
  244.      * http://pear.php.net/group/docs/20040226-vn.php
  245.      *
  246.      * @var string 
  247.      * @access protected
  248.      */
  249.     var $version = '';
  250.  
  251.     /**
  252.      * Contains the api-version of the baseclass. The API version has to follow the
  253.      * PEAR version naming standard.
  254.      *
  255.      * @var string 
  256.      * @access protected
  257.      */
  258.     var $apiVersion = '1.0';
  259.  
  260.     /**
  261.      * Result rendered image.
  262.      *
  263.      * @var resource 
  264.      * @access protected
  265.      */
  266.     var $resultImage = null;
  267.  
  268.     // }}}
  269.     // {{{ Constructor
  270.  
  271.     /**
  272.      * Constructor
  273.      *
  274.      * this method has no purpose for Image_Tools, but defines the API for
  275.      * all base classes. Calling this directly with $foo = new Image_Tools(...);
  276.      * will cause an error.
  277.      *
  278.      * @param   array $options optional Options.
  279.      * @access  protected
  280.      * @see     IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FORBIDEN
  281.      */
  282.     function Image_Tools($options = array())
  283.     {
  284.         PEAR::setErrorHandling(PEAR_ERROR_TRIGGER);
  285.         if (is_a($this'Image_Tools'&& !is_subclass_of($this'Image_Tools')) {
  286.             PEAR::raiseError('Cannot instanciate Image_Tools directly',
  287.                              IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FORBIDEN);
  288.         }
  289.  
  290.         $this->set($options);
  291.         PEAR::setErrorHandling(PEAR_ERROR_RETURN);
  292.     }
  293.  
  294.     // }}}
  295.     // {{{ factory()
  296.  
  297.     /**
  298.      * Create a new instance of an image tool
  299.      *
  300.      * This method will create a new image tool, defined by the $tool var,
  301.      * which is a string it will call the constructor of the specific tool
  302.      * and return it (if no error occurs)
  303.      *
  304.      * @param string $tool Tool name
  305.      * @param array $options optional Options
  306.      *
  307.      * @return  object New image tool on success or PEAR_Error on failure
  308.      * @access  public
  309.      * @static
  310.      * @see     IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FAILED,
  311.      *           IMAGE_TOOLS_BASE_ERR_CLASS_INVALID,
  312.      *           IMAGE_TOOLS_BASE_ERR_WRONGOPTIONTYPE,
  313.      *           IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED
  314.      */
  315.     function &factory($tool$options = array())
  316.     {
  317.         if (isset($this&& strtolower(get_class($this)) == 'image_tools'{
  318.             return PEAR::raiseError('This method may only be called statically',
  319.                                     IMAGE_TOOLS_BASE_ERR_NONSTATIC_FAILED);
  320.         }
  321.  
  322.         // Renice the tool name
  323.         $toolParts @explode('_'$tool);
  324.         if (empty($toolParts|| !is_array($toolParts)) {
  325.             $toolParts[$tool;
  326.         }
  327.  
  328.         foreach ($toolParts as $key => $value{
  329.             $toolParts[$keyucfirst($value);
  330.         }
  331.         $tool implode('_'$toolParts);
  332.         $toolPath 'Image/Tools/'.$tool.'.php';
  333.  
  334.         // Include the tool class
  335.         require_once($toolPath);
  336.  
  337.         $className = "Image_Tools_${tool}";
  338.         if (!class_exists($className)) {
  339.             return PEAR::raiseError('File not found ' $toolPath .
  340.                                     ' or undefined class '.$className,
  341.                                     IMAGE_TOOLS_BASE_ERR_CLASS_INVALID);
  342.         }
  343.  
  344.         @$obj =new $className($options);
  345.         if (!is_object($obj|| !is_a($obj$className)) {
  346.             return PEAR::raiseError('Could not instanciate image tool '.$className,
  347.                                     IMAGE_TOOLS_BASE_ERR_INSTANCIATION_FAILED);
  348.         }
  349.         $res $obj->set($options);
  350.         if (PEAR::isError($res)) {
  351.             return $res;
  352.         }
  353.         return $obj;
  354.     }
  355.  
  356.     // }}}
  357.     // {{{ set()
  358.  
  359.     /**
  360.      * Set the option(s)
  361.      * Set a single or multiple options. The parameter of that method may
  362.      * either be a single options array or a key/value pair setting a single
  363.      * option. This method has not to be reimplemented by the Image_Tools
  364.      * sub classes.
  365.      *
  366.      * @param mixed $option A single option name or the options array
  367.      * @param mixed $value Option value if $option is string
  368.      *
  369.      * @return  bool|PEAR_ErrorTRUE on success or PEAR_Error on failure
  370.      * @access  protected
  371.      * @see     IMAGE_TOOLS_BASE_ERR_WRONGOPTIONTYPE,
  372.      *           IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED
  373.      */
  374.     function set($option$value = null)
  375.     {
  376.         if (!isset($this)) {
  377.             return PEAR::raiseError('This method may only be called non statically',
  378.                                     IMAGE_TOOLS_BASE_ERR_STATIC_FAILED);
  379.         }
  380.         if (is_array($option)) {
  381.             foreach ($option as $key => $value{
  382.                 $res $this->set($key@$value);
  383.                 if (PEAR::isError($res)) {
  384.                     return $res;
  385.                 }
  386.             }
  387.             return true;
  388.         }
  389.         $res $this->isValidOption($option@$value);
  390.         if (PEAR::isError($res)) {
  391.             return $res;
  392.         }
  393.         $this->options[$option$value;
  394.         return true;
  395.     }
  396.  
  397.     // }}}
  398.     // {{{ isValidOption()
  399.  
  400.     /**
  401.      * Has the option a valid value?
  402.      * Determines, if the value given is valid for the option.
  403.      *
  404.      * @param mixed $option A single option name
  405.      * @param mixed $value Option value
  406.      *
  407.      * @return  bool|PEAR_ErrorTRUE on acceptans or PEAR_Error on failure
  408.      * @access  protected
  409.      * @see     IMAGE_TOOLS_BASE_ERR_WRONGOPTIONTYPE,
  410.      *           IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED
  411.      */
  412.     function isValidOption($name$value)
  413.     {
  414.         $res $this->supportsOption($name);
  415.         if (PEAR::isError($res)) {
  416.             return $res;
  417.         }
  418.         $type $this->availableOptions[$name];
  419.         switch ($type{
  420.             case 'mixed':
  421.                 return true;
  422.                 break;
  423.             case 'bool':
  424.             case 'int':
  425.             case 'integer':
  426.             case 'float':
  427.             case 'double':
  428.             case 'string':
  429.             case 'array':
  430.             case 'resource':
  431.             case 'object':
  432.                 $typeCheck 'is_'.$type;
  433.                 if ($typeCheck($value)) {
  434.                     return true;
  435.                 }
  436.                 break;
  437.             case 'number':
  438.                 if (is_int($value|| is_float($value)) {
  439.                     return true;
  440.                 }
  441.                 break;
  442.             default:
  443.                 if (is_a($value$type)) {
  444.                     return true;
  445.                 }
  446.                 break;
  447.         }
  448.         return PEAR::raiseError('Wrong type for option ' $name .
  449.                                 '. Requires '$type .', but is ' gettype($value),
  450.                                 IMAGE_TOOLS_BASE_ERR_OPTION_INVALID);
  451.     }
  452.  
  453.     // }}}
  454.     // {{{ get()
  455.  
  456.     /**
  457.      * Get the value of the option
  458.      *
  459.      * returns the value of an option of, an error if the option is not
  460.      * available.
  461.      *
  462.      * @param string $option Option name.
  463.      *
  464.      * @return  mixed|PEAR_ErrorOption value on success or
  465.      *                            PEAR_Error on failure.
  466.      * @access  public
  467.      * @see     IMAGE_TOOLS_BASE_ERR_OPTION_UNSUPPORTED,
  468.      *           IMAGE_TOOLS_BASE_ERR_OPTION_NOTSET,
  469.      *           IMAGE_TOOLS_BASE_ERR_STATIC_FAILED
  470.      */
  471.     function get($option)
  472.     {
  473.         if (!isset($this)) {
  474.             return PEAR::raiseError('This method may only be called non statically',
  475.                                     IMAGE_TOOLS_BASE_ERR_STATIC_FAILED);
  476.         }
  477.         $res $this->supportsOption($option);
  478.         if (PEAR::isError($res)) {
  479.             return $res;
  480.         }
  481.         if (isset($this->options[$option])) {
  482.             return $this->options[$option];
  483.         }
  484.         return PEAR::raiseError('Option '.$option.' not set',
  485.                                 IMAGE_TOOLS_BASE_ERR_OPTION_NOTSET);
  486.     }
  487.  
  488.     // }}}
  489.     // {{{ createImageFromFile()
  490.  
  491.     /**
  492.      * Create a GD image resource from file (JPEG, PNG, WBMP and XBM support).
  493.      *
  494.      * @param string $filename The image filename.
  495.      *
  496.      * @return mixed GD image resource on success, PEAR_Error on failure.
  497.      * @access public
  498.      * @static
  499.      */
  500.     function createImageFromFile($filename)
  501.     {
  502.         if (!is_file($filename|| !is_readable($filename)) {
  503.             return PEAR::raiseError('Unable to open file "' $filename '"');
  504.         }
  505.  
  506.         // determine image format
  507.         list, , $imgTypegetimagesize($filename);
  508.  
  509.         switch ($imgType{
  510.             case IMAGETYPE_JPEG:
  511.                 return imagecreatefromjpeg($filename);
  512.                 break;
  513.             case IMAGETYPE_GIF:
  514.                 return imagecreatefromgif($filename);
  515.                 break;
  516.             case IMAGETYPE_PNG:
  517.                 return imagecreatefrompng($filename);
  518.                 break;
  519.             case IMAGETYPE_WBMP:
  520.                 return imagecreatefromwbmp($filename);
  521.                 break;
  522.             case IMAGETYPE_XBM:
  523.                 return imagecreatefromxbm($filename);
  524.                 break;
  525.             default:
  526.                 return PEAR::raiseError('Unsupport image type');
  527.         }
  528.     }
  529.  
  530.     // }}}
  531.     // {{{ createImageFromString()
  532.  
  533.     /**
  534.      * Create a GD image resource from a string data.
  535.      *
  536.      * @param string $data The string image data.
  537.      *
  538.      * @return mixed GD image resource on success, PEAR_Error on failure.
  539.      * @access public
  540.      * @static
  541.      */
  542.     function createImageFromString($data)
  543.     {
  544.         if (!is_string($data|| empty($data)) {
  545.             PEAR::raiseError('Invalid data value.');
  546.         }
  547.  
  548.         $img imagecreatefromstring($data);
  549.         if ($img === false{
  550.             return PEAR::raiseError('Failed to create image from string data');
  551.         }
  552.         return $img;
  553.     }
  554.  
  555.     // }}}
  556.     // {{{ createImage()
  557.  
  558.     /**
  559.      * Create a GD image resource from given input.
  560.      *
  561.      * This method tried to detect what the input, if it is a file the
  562.      * createImageFromFile will be called, otherwise createImageFromString().
  563.      *
  564.      * @param   mixed $input The input for creating an image resource. The value
  565.      *                        may a string of filename, string of image data or
  566.      *                        GD image resource.
  567.      *
  568.      * @return  resource|PEAR_ErrorAn GD image resource on success or
  569.      *                               PEAR_Error on failure.
  570.      * @access  public
  571.      * @see     createImageFromFile()
  572.      * @see     createImageFromString()
  573.      */
  574.     function createImage($input)
  575.     {
  576.         if (is_file($input)) {
  577.             return Image_Tools::createImageFromFile($input);
  578.         else if (is_string($input)) {
  579.             return Image_Tools::createImageFromString($input);
  580.         else if (Image_Tools::isGDImageResource($input)) {
  581.             return $input;
  582.         }
  583.         return PEAR::raiseError('Invalid source image given, valid to create image resource.');
  584.     }
  585.  
  586.     // }}}
  587.     // {{{ isGDImageResource()
  588.  
  589.     /**
  590.      * Find the whether a value is the GD image resource or not.
  591.      *
  592.      * @param mixed $value Value to evaluate.
  593.      *
  594.      * @return bool TRUE if a value is the GD image resource, otherwise FALSE.
  595.      * @access public
  596.      * @static
  597.      */
  598.     function isGDImageResource($value)
  599.     {
  600.         if (is_resource($value&& get_resource_type($value== 'gd'{
  601.             return true;
  602.         }
  603.         return false;
  604.     }
  605.  
  606.     // }}}
  607.     // {{{ preRender()
  608.  
  609.     /**
  610.      * Function which called before render.
  611.      *
  612.      * Use this method to place any routine before calling render(). This
  613.      * method is optional to extended and returns TRUE as default.
  614.      *
  615.      * @return true|PEAR_Error
  616.      * @access protected
  617.      * @see getResultImage()
  618.      * @since Method available since Release 1.0.0RC1
  619.      */
  620.     function preRender()
  621.     {
  622.         return true;
  623.     }
  624.  
  625.     // }}}
  626.     // {{{ postRender()
  627.  
  628.     /**
  629.      * Function which called after render.
  630.      *
  631.      * Use this method to place any routine after calling render(). This
  632.      * method is optional to extended and return TRUE as default.
  633.      *
  634.      * @return true|PEAR_Error
  635.      * @access protected
  636.      * @see getResultImage()
  637.      * @since Method available since Release 1.0.0RC1
  638.      */
  639.     function postRender()
  640.     {
  641.         return true;
  642.     }
  643.     // }}}
  644.     // {{{ render()
  645.  
  646.     /**
  647.      * Render the result of a tool to the given image
  648.      *
  649.      * Since that's the purpose of all image tools, this method should stay
  650.      * with it's api as is. The rendering itself must be tool specific. The
  651.      * method gets a GD2 image as it's parameter. The creation of images inside
  652.      * Image_Tools is not supported.
  653.      *
  654.      * @access  protected
  655.      * @see     IMAGE_TOOLS_BASE_ERR_STATIC_FAILED
  656.      */
  657.     function render()
  658.     {
  659.         if (!isset($this)) {
  660.             return PEAR::raiseError('This method may only be called non statically',
  661.                                     IMAGE_TOOLS_BASE_ERR_STATIC_FAILED);
  662.         }
  663.     }
  664.  
  665.     // }}}
  666.     // {{{ _render
  667.  
  668.     /**
  669.      * Helper function to combine calls between pre render, render and
  670.      * post render.
  671.      *
  672.      * @return TRUE|PEAR_ErrorTRUE on success or PEAR_Error on failure.
  673.      * @access private
  674.      * @see preRender()
  675.      * @see postRender()
  676.      * @see render()
  677.      * @see getImageResult()
  678.      * @since Method available since Release 1.0.0RC1
  679.      */
  680.     function _render()
  681.     {
  682.         if (!isset($this)) {
  683.             return PEAR::raiseError('This method may only be called non statically',
  684.                                     IMAGE_TOOLS_BASE_ERR_STATIC_FAILED);
  685.         }
  686.  
  687.         // calls the pre render routine
  688.         $res $this->preRender();
  689.         if (PEAR::isError($res)) {
  690.             return $res;
  691.         }
  692.  
  693.         // calls the extended render function
  694.         $res $this->render();
  695.         if (PEAR::isError($res)) {
  696.             return $res