Source for file image.php

Documentation is available at image.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Image
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Class to manipulate an image.
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Image
  17.  * @since       11.3
  18.  */
  19. class JImage
  20. {
  21.     /**
  22.      * @const  integer
  23.      * @since  11.3
  24.      */
  25.     const SCALE_FILL 1;
  26.  
  27.     /**
  28.      * @const  integer
  29.      * @since  11.3
  30.      */
  31.     const SCALE_INSIDE 2;
  32.  
  33.     /**
  34.      * @const  integer
  35.      * @since  11.3
  36.      */
  37.     const SCALE_OUTSIDE 3;
  38.  
  39.     /**
  40.      * @const  integer
  41.      * @since  12.2
  42.      */
  43.     const CROP 4;
  44.  
  45.     /**
  46.      * @const  integer
  47.      * @since  12.3
  48.      */
  49.     const CROP_RESIZE 5;
  50.  
  51.     /**
  52.      * @const  integer
  53.      * @since  3.2
  54.      */
  55.     const SCALE_FIT 6;
  56.  
  57.     /**
  58.      * @var    resource  The image resource handle.
  59.      * @since  11.3
  60.      */
  61.     protected $handle;
  62.  
  63.     /**
  64.      * @var    string  The source image path.
  65.      * @since  11.3
  66.      */
  67.     protected $path = null;
  68.  
  69.     /**
  70.      * @var    array  Whether or not different image formats are supported.
  71.      * @since  11.3
  72.      */
  73.     protected static $formats array();
  74.  
  75.     /**
  76.      * Class constructor.
  77.      *
  78.      * @param   mixed  $source  Either a file path for a source image or a GD resource handler for an image.
  79.      *
  80.      * @since   11.3
  81.      * @throws  RuntimeException
  82.      */
  83.     public function __construct($source null)
  84.     {
  85.         // Verify that GD support for PHP is available.
  86.         if (!extension_loaded('gd'))
  87.         {
  88.             // @codeCoverageIgnoreStart
  89.             JLog::add('The GD extension for PHP is not available.'JLog::ERROR);
  90.             throw new RuntimeException('The GD extension for PHP is not available.');
  91.  
  92.             // @codeCoverageIgnoreEnd
  93.         }
  94.  
  95.         // Determine which image types are supported by GD, but only once.
  96.         if (!isset(self::$formats[IMAGETYPE_JPEG]))
  97.         {
  98.             $info gd_info();
  99.             self::$formats[IMAGETYPE_JPEG($info['JPEG Support']true false;
  100.             self::$formats[IMAGETYPE_PNG($info['PNG Support']true false;
  101.             self::$formats[IMAGETYPE_GIF($info['GIF Read Support']true false;
  102.         }
  103.  
  104.         // If the source input is a resource, set it as the image handle.
  105.         if (is_resource($source&& (get_resource_type($source== 'gd'))
  106.         {
  107.             $this->handle = &$source;
  108.         }
  109.         elseif (!empty($source&& is_string($source))
  110.         {
  111.             // If the source input is not empty, assume it is a path and populate the image handle.
  112.             $this->loadFile($source);
  113.         }
  114.     }
  115.  
  116.     /**
  117.      * Method to return a properties object for an image given a filesystem path.  The
  118.      * result object has values for image width, height, type, attributes, mime type, bits,
  119.      * and channels.
  120.      *
  121.      * @param   string  $path  The filesystem path to the image for which to get properties.
  122.      *
  123.      * @return  stdClass 
  124.      *
  125.      * @since   11.3
  126.      * @throws  InvalidArgumentException
  127.      * @throws  RuntimeException
  128.      */
  129.     public static function getImageFileProperties($path)
  130.     {
  131.         // Make sure the file exists.
  132.         if (!file_exists($path))
  133.         {
  134.             throw new InvalidArgumentException('The image file does not exist.');
  135.         }
  136.  
  137.         // Get the image file information.
  138.         $info getimagesize($path);
  139.  
  140.         if (!$info)
  141.         {
  142.             // @codeCoverageIgnoreStart
  143.             throw new RuntimeException('Unable to get properties for the image.');
  144.  
  145.             // @codeCoverageIgnoreEnd
  146.         }
  147.  
  148.         // Build the response object.
  149.         $properties = (object) array(
  150.             'width' => $info[0],
  151.             'height' => $info[1],
  152.             'type' => $info[2],
  153.             'attributes' => $info[3],
  154.             'bits' => isset($info['bits']$info['bits'null,
  155.             'channels' => isset($info['channels']$info['channels'null,
  156.             'mime' => $info['mime']
  157.         );
  158.  
  159.         return $properties;
  160.     }
  161.  
  162.     /**
  163.      * Method to generate thumbnails from the current image. It allows
  164.      * creation by resizing or cropping the original image.
  165.      *
  166.      * @param   mixed    $thumbSizes      String or array of strings. Example: $thumbSizes = array('150x75','250x150');
  167.      * @param   integer  $creationMethod  1-3 resize $scaleMethod | 4 create croppping | 5 resize then crop
  168.      *
  169.      * @return  array 
  170.      *
  171.      * @since   12.2
  172.      * @throws  LogicException
  173.      * @throws  InvalidArgumentException
  174.      */
  175.     public function generateThumbs($thumbSizes$creationMethod self::SCALE_INSIDE)
  176.     {
  177.         // Make sure the resource handle is valid.
  178.         if (!$this->isLoaded())
  179.         {
  180.             throw new LogicException('No valid image was loaded.');
  181.         }
  182.  
  183.         // Accept a single thumbsize string as parameter
  184.         if (!is_array($thumbSizes))
  185.         {
  186.             $thumbSizes array($thumbSizes);
  187.         }
  188.  
  189.         // Process thumbs
  190.         $generated array();
  191.  
  192.         if (!empty($thumbSizes))
  193.         {
  194.             foreach ($thumbSizes as $thumbSize)
  195.             {
  196.                 // Desired thumbnail size
  197.                 $size explode('x'strtolower($thumbSize));
  198.  
  199.                 if (count($size!= 2)
  200.                 {
  201.                     throw new InvalidArgumentException('Invalid thumb size received: ' $thumbSize);
  202.                 }
  203.  
  204.                 $thumbWidth  $size[0];
  205.                 $thumbHeight $size[1];
  206.  
  207.                 switch ($creationMethod)
  208.                 {
  209.                     // Case for self::CROP
  210.                     case 4:
  211.                         $thumb $this->crop($thumbWidth$thumbHeightnullnulltrue);
  212.                         break;
  213.  
  214.                     // Case for self::CROP_RESIZE
  215.                     case 5:
  216.                         $thumb $this->cropResize($thumbWidth$thumbHeighttrue);
  217.                         break;
  218.  
  219.                     default:
  220.                         $thumb $this->resize($thumbWidth$thumbHeighttrue$creationMethod);
  221.                         break;
  222.                 }
  223.  
  224.                 // Store the thumb in the results array
  225.                 $generated[$thumb;
  226.             }
  227.         }
  228.  
  229.         return $generated;
  230.     }
  231.  
  232.     /**
  233.      * Method to create thumbnails from the current image and save them to disk. It allows creation by resizing
  234.      * or croppping the original image.
  235.      *
  236.      * @param   mixed    $thumbSizes      string or array of strings. Example: $thumbSizes = array('150x75','250x150');
  237.      * @param   integer  $creationMethod  1-3 resize $scaleMethod | 4 create croppping
  238.      * @param   string   $thumbsFolder    destination thumbs folder. null generates a thumbs folder in the image folder
  239.      *
  240.      * @return  array 
  241.      *
  242.      * @since   12.2
  243.      * @throws  LogicException
  244.      * @throws  InvalidArgumentException
  245.      */
  246.     public function createThumbs($thumbSizes$creationMethod self::SCALE_INSIDE$thumbsFolder null)
  247.     {
  248.         // Make sure the resource handle is valid.
  249.         if (!$this->isLoaded())
  250.         {
  251.             throw new LogicException('No valid image was loaded.');
  252.         }
  253.  
  254.         // No thumbFolder set -> we will create a thumbs folder in the current image folder
  255.         if (is_null($thumbsFolder))
  256.         {
  257.             $thumbsFolder dirname($this->getPath()) '/thumbs';
  258.         }
  259.  
  260.         // Check destination
  261.         if (!is_dir($thumbsFolder&& (!is_dir(dirname($thumbsFolder)) || !@mkdir($thumbsFolder)))
  262.         {
  263.             throw new InvalidArgumentException('Folder does not exist and cannot be created: ' $thumbsFolder);
  264.         }
  265.  
  266.         // Process thumbs
  267.         $thumbsCreated array();
  268.  
  269.         if ($thumbs $this->generateThumbs($thumbSizes$creationMethod))
  270.         {
  271.             // Parent image properties
  272.             $imgProperties self::getImageFileProperties($this->getPath());
  273.  
  274.             foreach ($thumbs as $thumb)
  275.             {
  276.                 // Get thumb properties
  277.                 $thumbWidth     $thumb->getWidth();
  278.                 $thumbHeight    $thumb->getHeight();
  279.  
  280.                 // Generate thumb name
  281.                 $filename       pathinfo($this->getPath()PATHINFO_FILENAME);
  282.                 $fileExtension  pathinfo($this->getPath()PATHINFO_EXTENSION);
  283.                 $thumbFileName  $filename '_' $thumbWidth 'x' $thumbHeight '.' $fileExtension;
  284.  
  285.                 // Save thumb file to disk
  286.                 $thumbFileName $thumbsFolder '/' $thumbFileName;
  287.  
  288.                 if ($thumb->toFile($thumbFileName$imgProperties->type))
  289.                 {
  290.                     // Return JImage object with thumb path to ease further manipulation
  291.                     $thumb->path $thumbFileName;
  292.                     $thumbsCreated[$thumb;
  293.                 }
  294.             }
  295.         }
  296.  
  297.         return $thumbsCreated;
  298.     }
  299.  
  300.     /**
  301.      * Method to crop the current image.
  302.      *
  303.      * @param   mixed    $width      The width of the image section to crop in pixels or a percentage.
  304.      * @param   mixed    $height     The height of the image section to crop in pixels or a percentage.
  305.      * @param   integer  $left       The number of pixels from the left to start cropping.
  306.      * @param   integer  $top        The number of pixels from the top to start cropping.
  307.      * @param   boolean  $createNew  If true the current image will be cloned, cropped and returned; else
  308.      *                                the current image will be cropped and returned.
  309.      *
  310.      * @return  JImage 
  311.      *
  312.      * @since   11.3
  313.      * @throws  LogicException
  314.      */
  315.     public function crop($width$height$left null$top null$createNew true)
  316.     {
  317.         // Make sure the resource handle is valid.
  318.         if (!$this->isLoaded())
  319.         {
  320.             throw new LogicException('No valid image was loaded.');
  321.         }
  322.  
  323.         // Sanitize width.
  324.         $width $this->sanitizeWidth($width$height);
  325.  
  326.         // Sanitize height.
  327.         $height $this->sanitizeHeight($height$width);
  328.  
  329.         // Autocrop offsets
  330.         if (is_null($left))
  331.         {
  332.             $left round(($this->getWidth($width2);
  333.         }
  334.  
  335.         if (is_null($top))
  336.         {
  337.             $top round(($this->getHeight($height2);
  338.         }
  339.  
  340.         // Sanitize left.
  341.         $left $this->sanitizeOffset($left);
  342.  
  343.         // Sanitize top.
  344.         $top $this->sanitizeOffset($top);
  345.  
  346.         // Create the new truecolor image handle.
  347.         $handle imagecreatetruecolor($width$height);
  348.  
  349.         // Allow transparency for the new image handle.
  350.         imagealphablending($handlefalse);
  351.         imagesavealpha($handletrue);
  352.  
  353.         if ($this->isTransparent())
  354.         {
  355.             // Get the transparent color values for the current image.
  356.             $rgba imageColorsForIndex($this->handleimagecolortransparent($this->handle));
  357.             $color imageColorAllocate($this->handle$rgba['red']$rgba['green']$rgba['blue']);
  358.  
  359.             // Set the transparent color values for the new image.
  360.             imagecolortransparent($handle$color);
  361.             imagefill($handle00$color);
  362.  
  363.             imagecopyresized($handle$this->handle00$left$top$width$height$width$height);
  364.         }
  365.         else
  366.         {
  367.             imagecopyresampled($handle$this->handle00$left$top$width$height$width$height);
  368.         }
  369.  
  370.         // If we are cropping to a new image, create a new JImage object.
  371.         if ($createNew)
  372.         {
  373.             // @codeCoverageIgnoreStart
  374.             $new new JImage($handle);
  375.  
  376.             return $new;
  377.  
  378.             // @codeCoverageIgnoreEnd
  379.         }
  380.         // Swap out the current handle for the new image handle.
  381.         else
  382.         {
  383.             // Free the memory from the current handle
  384.             $this->destroy();
  385.  
  386.             $this->handle = $handle;
  387.  
  388.             return $this;
  389.         }
  390.     }
  391.  
  392.     /**
  393.      * Method to apply a filter to the image by type.  Two examples are: grayscale and sketchy.
  394.      *
  395.      * @param   string  $type     The name of the image filter to apply.
  396.      * @param   array   $options  An array of options for the filter.
  397.      *
  398.      * @return  JImage 
  399.      *
  400.      * @since   11.3
  401.      * @see     JImageFilter
  402.      * @throws  LogicException
  403.      */
  404.     public function filter($typearray $options array())
  405.     {
  406.         // Make sure the resource handle is valid.
  407.         if (!$this->isLoaded())
  408.         {
  409.             throw new LogicException('No valid image was loaded.');
  410.         }
  411.  
  412.         // Get the image filter instance.
  413.         $filter $this->getFilterInstance($type);
  414.  
  415.         // Execute the image filter.
  416.         $filter->execute($options);
  417.  
  418.         return $this;
  419.     }
  420.  
  421.     /**
  422.      * Method to get the height of the image in pixels.
  423.      *
  424.      * @return  integer 
  425.      *
  426.      * @since   11.3
  427.      * @throws  LogicException
  428.      */
  429.     public function getHeight()
  430.     {
  431.         // Make sure the resource handle is valid.
  432.         if (!$this->isLoaded())
  433.         {
  434.             throw new LogicException('No valid image was loaded.');
  435.         }
  436.  
  437.         return imagesy($this->handle);
  438.     }
  439.  
  440.     /**
  441.      * Method to get the width of the image in pixels.
  442.      *
  443.      * @return  integer 
  444.      *
  445.      * @since   11.3
  446.      * @throws  LogicException
  447.      */
  448.     public function getWidth()
  449.     {
  450.         // Make sure the resource handle is valid.
  451.         if (!$this->isLoaded())
  452.         {
  453.             throw new LogicException('No valid image was loaded.');
  454.         }
  455.  
  456.         return imagesx($this->handle);
  457.     }
  458.  
  459.     /**
  460.      * Method to return the path
  461.      *
  462.      * @return    string 
  463.      *
  464.      * @since    11.3
  465.      */
  466.     public function getPath()
  467.     {
  468.         return $this->path;
  469.     }
  470.  
  471.     /**
  472.      * Method to determine whether or not an image has been loaded into the object.
  473.      *
  474.      * @return  boolean 
  475.      *
  476.      * @since   11.3
  477.      */
  478.     public function isLoaded()
  479.     {
  480.         // Make sure the resource handle is valid.
  481.         if (!is_resource($this->handle|| (get_resource_type($this->handle!= 'gd'))
  482.         {
  483.             return false;
  484.         }
  485.  
  486.         return true;
  487.     }
  488.  
  489.     /**
  490.      * Method to determine whether or not the image has transparency.
  491.      *
  492.      * @return  bool 
  493.      *
  494.      * @since   11.3
  495.      * @throws  LogicException
  496.      */
  497.     public function isTransparent()
  498.     {
  499.         // Make sure the resource handle is valid.
  500.         if (!$this->isLoaded())
  501.         {
  502.             throw new LogicException('No valid image was loaded.');
  503.         }
  504.  
  505.         return (imagecolortransparent($this->handle>= 0);
  506.     }
  507.  
  508.     /**
  509.      * Method to load a file into the JImage object as the resource.
  510.      *
  511.      * @param   string  $path  The filesystem path to load as an image.
  512.      *
  513.      * @return  void 
  514.      *
  515.      * @since   11.3
  516.      * @throws  InvalidArgumentException
  517.      * @throws  RuntimeException
  518.      */
  519.     public function loadFile($path)
  520.     {
  521.         // Destroy the current image handle if it exists
  522.         $this->destroy();
  523.  
  524.         // Make sure the file exists.
  525.         if (!file_exists($path))
  526.         {
  527.             throw new InvalidArgumentException('The image file does not exist.');
  528.         }
  529.  
  530.         // Get the image properties.
  531.         $properties self::getImageFileProperties($path);
  532.  
  533.         // Attempt to load the image based on the MIME-Type
  534.         switch ($properties->mime)
  535.         {
  536.             case 'image/gif':
  537.                 // Make sure the image type is supported.
  538.                 if (empty(self::$formats[IMAGETYPE_GIF]))
  539.                 {
  540.                     // @codeCoverageIgnoreStart
  541.                     JLog::add('Attempting to load an image of unsupported type GIF.'JLog::ERROR);
  542.                     throw new RuntimeException('Attempting to load an image of unsupported type GIF.');
  543.  
  544.                     // @codeCoverageIgnoreEnd
  545.                 }
  546.  
  547.                 // Attempt to create the image handle.
  548.                 $handle imagecreatefromgif($path);
  549.  
  550.                 if (!is_resource($handle))
  551.                 {
  552.                     // @codeCoverageIgnoreStart
  553.                     throw new RuntimeException('Unable to process GIF image.');
  554.  
  555.                     // @codeCoverageIgnoreEnd
  556.                 }
  557.  
  558.                 $this->handle = $handle;
  559.                 break;
  560.  
  561.             case 'image/jpeg':
  562.                 // Make sure the image type is supported.
  563.                 if (empty(self::$formats[IMAGETYPE_JPEG]))
  564.                 {
  565.                     // @codeCoverageIgnoreStart
  566.                     JLog::add('Attempting to load an image of unsupported type JPG.'JLog::ERROR);
  567.                     throw new RuntimeException('Attempting to load an image of unsupported type JPG.');
  568.  
  569.                     // @codeCoverageIgnoreEnd
  570.                 }
  571.  
  572.                 // Attempt to create the image handle.
  573.                 $handle imagecreatefromjpeg($path);
  574.  
  575.                 if (!is_resource($handle))
  576.                 {
  577.                     // @codeCoverageIgnoreStart
  578.                     throw new RuntimeException('Unable to process JPG image.');
  579.  
  580.                     // @codeCoverageIgnoreEnd
  581.                 }
  582.  
  583.                 $this->handle = $handle;
  584.                 break;
  585.  
  586.             case 'image/png':
  587.                 // Make sure the image type is supported.
  588.                 if (empty(self::$formats[IMAGETYPE_PNG]))
  589.                 {
  590.                     // @codeCoverageIgnoreStart
  591.                     JLog::add('Attempting to load an image of unsupported type PNG.'JLog::ERROR);
  592.                     throw new RuntimeException('Attempting to load an image of unsupported type PNG.');
  593.  
  594.                     // @codeCoverageIgnoreEnd
  595.                 }
  596.  
  597.                 // Attempt to create the image handle.
  598.                 $handle imagecreatefrompng($path);
  599.  
  600.                 if (!is_resource($handle))
  601.                 {
  602.                     // @codeCoverageIgnoreStart
  603.                     throw new RuntimeException('Unable to process PNG image.');
  604.  
  605.                     // @codeCoverageIgnoreEnd
  606.                 }
  607.  
  608.                 $this->handle = $handle;
  609.  
  610.                 // Set transparency for non-transparent PNGs.
  611.                 if (!$this->isTransparent())
  612.                 {
  613.                     // Assign to black which is default for transparent PNGs
  614.                     $transparency imagecolorallocatealpha($handle000127);
  615.  
  616.                     imagecolortransparent($handle$transparency);
  617.                 }
  618.  
  619.                 break;
  620.  
  621.             default:
  622.                 JLog::add('Attempting to load an image of unsupported type: ' $properties->mimeJLog::ERROR);
  623.                 throw new InvalidArgumentException('Attempting to load an image of unsupported type: ' $properties->mime);
  624.                 break;
  625.         }
  626.  
  627.         // Set the filesystem path to the source image.
  628.         $this->path = $path;
  629.     }
  630.  
  631.     /**
  632.      * Method to resize the current image.
  633.      *
  634.      * @param   mixed    $width        The width of the resized image in pixels or a percentage.
  635.      * @param   mixed    $height       The height of the resized image in pixels or a percentage.
  636.      * @param   boolean  $createNew    If true the current image will be cloned, resized and returned; else
  637.      *                                  the current image will be resized and returned.
  638.      * @param   integer  $scaleMethod  Which method to use for scaling
  639.      *
  640.      * @return  JImage 
  641.      *
  642.      * @since   11.3
  643.      * @throws  LogicException
  644.      */
  645.     public function resize($width$height$createNew true$scaleMethod self::SCALE_INSIDE)
  646.     {
  647.         // Make sure the resource handle is valid.
  648.         if (!$this->isLoaded())
  649.         {
  650.             throw new LogicException('No valid image was loaded.');
  651.         }
  652.  
  653.         // Sanitize width.
  654.         $width $this->sanitizeWidth($width$height);
  655.  
  656.         // Sanitize height.
  657.         $height $this->sanitizeHeight($height$width);
  658.  
  659.         // Prepare the dimensions for the resize operation.
  660.         $dimensions $this->prepareDimensions($width$height$scaleMethod);
  661.  
  662.         // Instantiate offset.
  663.         $offset new stdClass;
  664.         $offset->$offset->0;
  665.  
  666.         // Center image if needed and create the new truecolor image handle.
  667.         if ($scaleMethod == self::SCALE_FIT)
  668.         {
  669.             // Get the offsets
  670.             $offset->x    round(($width $dimensions->width2);
  671.             $offset->y    round(($height $dimensions->height2);
  672.  
  673.             $handle imagecreatetruecolor($width$height);
  674.  
  675.             // Make image transparent, otherwise cavas outside initial image would default to black
  676.             if (!$this->isTransparent())
  677.             {
  678.                 $transparency imagecolorAllocateAlpha($this->handle000127);
  679.                 imagecolorTransparent($this->handle$transparency);
  680.             }
  681.         }
  682.         else
  683.         {
  684.             $handle imagecreatetruecolor($dimensions->width$dimensions->height);
  685.         }
  686.  
  687.         // Allow transparency for the new image handle.
  688.         imagealphablending($handlefalse);
  689.         imagesavealpha($handletrue);
  690.  
  691.         if ($this->isTransparent())
  692.         {
  693.             // Get the transparent color values for the current image.
  694.             $rgba imageColorsForIndex($this->handleimagecolortransparent($this->handle));
  695.             $color imageColorAllocateAlpha($this->handle$rgba['red']$rgba['green']$rgba['blue']$rgba['alpha']);
  696.  
  697.             // Set the transparent color values for the new image.
  698.             imagecolortransparent($handle$color);
  699.             imagefill($handle00$color);
  700.  
  701.             imagecopyresized($handle$this->handle$offset->x$offset->y00$dimensions->width$dimensions->height$this->getWidth()$this->getHeight());
  702.         }
  703.         else
  704.         {
  705.             imagecopyresampled($handle$this->handle$offset->x$offset->y00$dimensions->width$dimensions->height$this->getWidth()$this->getHeight());
  706.         }
  707.  
  708.         // If we are resizing to a new image, create a new JImage object.
  709.         if ($createNew)
  710.         {
  711.             // @codeCoverageIgnoreStart
  712.             $new new JImage($handle);
  713.  
  714.             return $new;
  715.  
  716.             // @codeCoverageIgnoreEnd
  717.         }
  718.         // Swap out the current handle for the new image handle.
  719.         else
  720.         {
  721.             // Free the memory from the current handle
  722.             $this->destroy();
  723.  
  724.             $this->handle = $handle;
  725.  
  726.             return $this;
  727.         }
  728.     }
  729.  
  730.     /**
  731.      * Method to crop an image after resizing it to maintain
  732.      * proportions without having to do all the set up work.
  733.      *
  734.      * @param   integer  $width      The desired width of the image in pixels or a percentage.
  735.      * @param   integer  $height     The desired height of the image in pixels or a percentage.
  736.      * @param   integer  $createNew  If true the current image will be cloned, resized, cropped and returned.
  737.      *
  738.      * @return  object  JImage Object for chaining.
  739.      *
  740.      * @since   12.3
  741.      */
  742.     public function cropResize($width$height$createNew true)
  743.     {
  744.         $width   $this->sanitizeWidth($width$height);
  745.         $height  $this->sanitizeHeight($height$width);
  746.  
  747.         if (($this->getWidth($width($this->getHeight($height))
  748.         {
  749.             $this->resize($width0false);
  750.         }
  751.         else
  752.         {
  753.             $this->resize(0$heightfalse);
  754.         }
  755.  
  756.         return $this->crop($width$heightnullnull$createNew);
  757.     }
  758.  
  759.     /**
  760.      * Method to rotate the current image.
  761.      *
  762.      * @param   mixed    $angle       The angle of rotation for the image
  763.      * @param   integer  $background  The background color to use when areas are added due to rotation
  764.      * @param   boolean  $createNew   If true the current image will be cloned, rotated and returned; else
  765.      *                                 the current image will be rotated and returned.
  766.      *
  767.      * @return  JImage 
  768.      *
  769.      * @since   11.3
  770.      * @throws  LogicException
  771.      */
  772.     public function rotate($angle$background = -1$createNew true)
  773.     {
  774.         // Make sure the resource handle is valid.
  775.         if (!$this->isLoaded())
  776.         {
  777.             throw new LogicException('No valid image was loaded.');
  778.         }
  779.  
  780.         // Sanitize input
  781.         $angle = (float) $angle;
  782.  
  783.         // Create the new truecolor image handle.
  784.         $handle imagecreatetruecolor($this->getWidth()$this->getHeight());
  785.  
  786.         // Allow transparency for the new image handle.
  787.         imagealphablending($handlefalse);
  788.         imagesavealpha($handletrue);
  789.  
  790.         // Copy the image
  791.         imagecopy($handle$this->handle0000$this->getWidth()$this->getHeight());
  792.  
  793.         // Rotate the image
  794.         $handle imagerotate($handle$angle$background);
  795.  
  796.         // If we are resizing to a new image, create a new JImage object.
  797.         if ($createNew)
  798.         {
  799.             // @codeCoverageIgnoreStart
  800.             $new new JImage($handle);
  801.  
  802.             return $new;
  803.  
  804.             // @codeCoverageIgnoreEnd
  805.         }
  806.         // Swap out the current handle for the new image handle.
  807.         else
  808.         {
  809.             // Free the memory from the current handle
  810.             $this->destroy();
  811.  
  812.             $this->handle = $handle;
  813.  
  814.             return $this;
  815.         }
  816.     }
  817.  
  818.     /**
  819.      * Method to write the current image out to a file.
  820.      *
  821.      * @param   string   $path     The filesystem path to save the image.
  822.      * @param   integer  $type     The image type to save the file as.
  823.      * @param   array    $options  The image type options to use in saving the file.
  824.      *
  825.      * @return  boolean 
  826.      *
  827.      * @see     http://www.php.net/manual/image.constants.php
  828.      * @since   11.3
  829.      * @throws  LogicException
  830.      */
  831.     public function toFile($path$type IMAGETYPE_JPEGarray $options array())
  832.     {
  833.         // Make sure the resource handle is valid.
  834.         if (!$this->isLoaded())
  835.         {
  836.             throw new LogicException('No valid image was loaded.');
  837.         }
  838.  
  839.         switch ($type)
  840.         {
  841.             case IMAGETYPE_GIF:
  842.                 return imagegif($this->handle$path);
  843.                 break;
  844.  
  845.             case IMAGETYPE_PNG:
  846.                 return imagepng($this->handle$path(array_key_exists('quality'$options)) $options['quality'0);
  847.                 break;
  848.  
  849.             case IMAGETYPE_JPEG:
  850.             default:
  851.                 return imagejpeg($this->handle$path(array_key_exists('quality'$options)) $options['quality'100);
  852.         }
  853.     }
  854.  
  855.     /**
  856.      * Method to get an image filter instance of a specified type.
  857.      *
  858.      * @param   string  $type  The image filter type to get.
  859.      *
  860.      * @return  JImageFilter 
  861.      *
  862.      * @since   11.3
  863.      * @throws  RuntimeException
  864.      */
  865.     protected function getFilterInstance($type)
  866.     {
  867.         // Sanitize the filter type.
  868.         $type strtolower(preg_replace('#[^A-Z0-9_]#i'''$type));
  869.  
  870.         // Verify that the filter type exists.
  871.         $className 'JImageFilter' ucfirst($type);
  872.  
  873.         if (!class_exists($className))
  874.         {
  875.             JLog::add('The ' ucfirst($type' image filter is not available.'JLog::ERROR);
  876.             throw new RuntimeException('The ' ucfirst($type' image filter is not available.');
  877.         }
  878.  
  879.         // Instantiate the filter object.
  880.         $instance new $className($this->handle);
  881.  
  882.         // Verify that the filter type is valid.
  883.         if (!($instance instanceof JImageFilter))
  884.         {
  885.             // @codeCoverageIgnoreStart
  886.             JLog::add('The ' ucfirst($type' image filter is not valid.'JLog::ERROR);
  887.             throw new RuntimeException('The ' ucfirst($type' image filter is not valid.');
  888.  
  889.             // @codeCoverageIgnoreEnd
  890.         }
  891.  
  892.         return $instance;
  893.     }
  894.  
  895.     /**
  896.      * Method to get the new dimensions for a resized image.
  897.      *
  898.      * @param   integer  $width        The width of the resized image in pixels.
  899.      * @param   integer  $height       The height of the resized image in pixels.
  900.      * @param   integer  $scaleMethod  The method to use for scaling
  901.      *
  902.      * @return  stdClass 
  903.      *
  904.      * @since   11.3
  905.      * @throws  InvalidArgumentException  If width, height or both given as zero
  906.      */
  907.     protected function prepareDimensions($width$height$scaleMethod)
  908.     {
  909.         // Instantiate variables.
  910.         $dimensions new stdClass;
  911.  
  912.         switch ($scaleMethod)
  913.         {
  914.             case self::SCALE_FILL:
  915.                 $dimensions->width = (int) round($width);
  916.                 $dimensions->height = (int) round($height);
  917.                 break;
  918.  
  919.             case self::SCALE_INSIDE:
  920.             case self::SCALE_OUTSIDE:
  921.             case self::SCALE_FIT:
  922.                 $rx ($width 0($this->getWidth($width0;
  923.                 $ry ($height 0($this->getHeight($height0;
  924.  
  925.                 if ($scaleMethod != self::SCALE_OUTSIDE)
  926.                 {
  927.                     $ratio max($rx$ry);
  928.                 }
  929.                 else
  930.                 {
  931.                     $ratio min($rx$ry);
  932.                 }
  933.  
  934.                 $dimensions->width = (int) round($this->getWidth($ratio);
  935.                 $dimensions->height = (int) round($this->getHeight($ratio);
  936.                 break;
  937.  
  938.             default:
  939.                 throw new InvalidArgumentException('Invalid scale method.');
  940.                 break;
  941.         }
  942.  
  943.         return $dimensions;
  944.     }
  945.  
  946.     /**
  947.      * Method to sanitize a height value.
  948.      *
  949.      * @param   mixed  $height  The input height value to sanitize.
  950.      * @param   mixed  $width   The input width value for reference.
  951.      *
  952.      * @return  integer 
  953.      *
  954.      * @since   11.3
  955.      */
  956.     protected function sanitizeHeight($height$width)
  957.     {
  958.         // If no height was given we will assume it is a square and use the width.
  959.         $height ($height === null$width $height;
  960.  
  961.         // If we were given a percentage, calculate the integer value.
  962.         if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/'$height))
  963.         {
  964.             $height = (int) round($this->getHeight(* (float) str_replace('%'''$height100);
  965.         }
  966.         // Else do some rounding so we come out with a sane integer value.
  967.         else
  968.         {
  969.             $height = (int) round((float) $height);
  970.         }
  971.  
  972.         return $height;
  973.     }
  974.  
  975.     /**
  976.      * Method to sanitize an offset value like left or top.
  977.      *
  978.      * @param   mixed  $offset  An offset value.
  979.      *
  980.      * @return  integer 
  981.      *
  982.      * @since   11.3
  983.      */
  984.     protected function sanitizeOffset($offset)
  985.     {
  986.         return (int) round((float) $offset);
  987.     }
  988.  
  989.     /**
  990.      * Method to sanitize a width value.
  991.      *
  992.      * @param   mixed  $width   The input width value to sanitize.
  993.      * @param   mixed  $height  The input height value for reference.
  994.      *
  995.      * @return  integer 
  996.      *
  997.      * @since   11.3
  998.      */
  999.     protected function sanitizeWidth($width$height)
  1000.     {
  1001.         // If no width was given we will assume it is a square and use the height.
  1002.         $width ($width === null$height $width;
  1003.  
  1004.         // If we were given a percentage, calculate the integer value.
  1005.         if (preg_match('/^[0-9]+(\.[0-9]+)?\%$/'$width))
  1006.         {
  1007.             $width = (int) round($this->getWidth(* (float) str_replace('%'''$width100);
  1008.         }
  1009.         // Else do some rounding so we come out with a sane integer value.
  1010.         else
  1011.         {
  1012.             $width = (int) round((float) $width);
  1013.         }
  1014.  
  1015.         return $width;
  1016.     }
  1017.  
  1018.     /**
  1019.      * Method to destroy an image handle and
  1020.      * free the memory associated with the handle
  1021.      *
  1022.      * @return  boolean  True on success, false on failure or if no image is loaded
  1023.      *
  1024.      * @since   12.3
  1025.      */
  1026.     public function destroy()
  1027.     {
  1028.         if ($this->isLoaded())
  1029.         {
  1030.             return imagedestroy($this->handle);
  1031.         }
  1032.  
  1033.         return false;
  1034.     }
  1035.  
  1036.     /**
  1037.      * Method to call the destroy() method one last time
  1038.      * to free any memory when the object is unset
  1039.      *
  1040.      * @see     JImage::destroy()
  1041.      * @since   12.3
  1042.      */
  1043.     public function __destruct()
  1044.     {
  1045.         $this->destroy();
  1046.     }
  1047. }

Documentation generated on Tue, 19 Nov 2013 15:05:16 +0100 by phpDocumentor 1.4.3