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

Source for file netpbmresize.class.php

Documentation is available at netpbmresize.class.php

  1. <?php
  2. /**
  3.  * NetpbmResize is a php class that works as a wrapper for the netpbm binaries
  4.  * which are easily obtainable thanks to the Gallery project
  5.  * (http://tinyurl.com/25daoc). It is *only* focused on resizing images
  6.  * (by Width, Height, Percentage or Bounding Box) and create square thumbnails.
  7.  * It  supports JPG, GIF and PNG.
  8.  *
  9.  * Its intended audience are php developers who are using images in their
  10.  * applications and need a resizing solution.  Most common use would be an
  11.  * application which needs gallery functionality.
  12.  *
  13.  * @author Favio Manriquez <favio@favrik.com>
  14.  * @access public
  15.  * @see ImageInfo
  16.  */
  17. class NetpbmResize {
  18.     /**
  19.      * Stores the filename of the resized image
  20.      * 
  21.      * @var string resized image filename
  22.      * @access private
  23.      */
  24.     var $OutputImage;
  25.     
  26.     /**
  27.      * Working Directory.  Most commonly: where you are storing or uploading
  28.      * your images.
  29.      *
  30.      * @var string path of working directory
  31.      * @access private
  32.      */
  33.     var $WorkingDir;
  34.     
  35.     /**
  36.      * Stores the command line parameteres of the different netpbm programs.
  37.      * 
  38.      * @var string 
  39.      * @access private
  40.      */
  41.     var $Params;
  42.     
  43.     /**
  44.      * An instance of the class ImageInfo that contains necessary information
  45.      * from the current initialized image. You can initialize an image by
  46.      * calling the method setImageInfo.
  47.      * 
  48.      * @var object instance of ImageInfo class
  49.      * @access private
  50.      * @see setImageInfo()
  51.      * @see ImageInfo
  52.      */
  53.     var $ImageInfo;
  54.    
  55.     /**
  56.      * These strings appear in the filenames of the netpbm programs. This fact
  57.      * is used for calling a program dynamically since the only part of the
  58.      * name that changes is the format to be resized.
  59.      *
  60.      * @var array part of the names of the netpbm programs
  61.      * @access private
  62.      */  
  63.     var $Programs array(=> 'gif''jpeg''png');
  64.     
  65.     /**
  66.      * NetpbmResize doesn't delete the source image so you have to either
  67.      * define an output name (setOutputImage) or the resulting resized image
  68.      * name will contain this suffix. You can also change the suffix.
  69.      *
  70.      * @var string the default suffix of the resized image
  71.      * @access private
  72.      * @see setSuffix()
  73.      */
  74.     var $DefaultSuffix;
  75.     
  76.     /**
  77.      * Constructor.
  78.      *
  79.      * @param string $NetpbmPath path to netpbm binaries WITHOUT trailing slash
  80.      * @param string $Path path to working dir which may include the output filename
  81.      *                WITHOUT trailing slash
  82.      * @access public
  83.      */
  84.     function NetpbmResize($NetpbmPath$Path{
  85.         $this->setPathSeparator();
  86.         $this->setNetpbmPath($NetpbmPath);
  87.         $this->initialize($Path);
  88.         $this->DefaultSuffix '.rs';
  89.     }
  90.  
  91.     /**
  92.      * Should use "const" when leaving PHP4 for good.
  93.      *
  94.      * @param string $Netpbm path to netpbm binaries
  95.      * @return void 
  96.      * @access private
  97.      */
  98.     function setNetpbmPath($Netpbm{
  99.         if (!defined('NETPBM_PATH'and is_dir($Netpbm)) {
  100.             define('NETPBM_PATH'$Netpbm DIR_SLASH);
  101.         }
  102.     }
  103.   
  104.     /**
  105.      * Tries to detect which trailing slash to use: unix like or windows like.
  106.      * 
  107.      * @param void 
  108.      * @return void 
  109.      * @access private
  110.      */  
  111.     function setPathSeparator({
  112.         $slash (eregi("win",$_ENV['OS'])) '\\' '/';
  113.         if (!defined('DIR_SLASH')) {
  114.             define('DIR_SLASH'$slash);
  115.         }
  116.     }
  117.     
  118.     
  119.     /**
  120.      * Set working directory and image info if applicable.
  121.      *
  122.      * @param string $path working directory or absolute path of an image
  123.      * @return void 
  124.      * @access private
  125.      */
  126.     function initialize($Path{
  127.         if (is_dir($Path)) {
  128.             $this->setWorkingDir($Path DIR_SLASH);
  129.         else {
  130.             $this->setImageInfo($Path);
  131.             $this->setWorkingDir(dirname($PathDIR_SLASH);
  132.         }
  133.     }
  134.  
  135.     /**
  136.      * Initializes the ImageInfo object useful for retrieving Image info.
  137.      * 
  138.      * @param string $Image full path to an image file
  139.      * @return void 
  140.      * @see ImageInfo
  141.      * @access public
  142.      */
  143.     function setImageInfo($Image{
  144.         $this->ImageInfo new ImageInfo($Image);
  145.         if (!$this->ImageInfo->validImage()) {
  146.             $this->raiseError('Image format not supported!  Only JPG, GIF or PNG are supported.');
  147.         }
  148.     }
  149.     
  150.     function getWidth({
  151.         return $this->ImageInfo->width();
  152.     }
  153.     
  154.     function getHeight({
  155.         return $this->ImageInfo->height();
  156.     }
  157.     
  158.     /**
  159.      * Sets the default suffix of the the resized image.
  160.      * 
  161.      * @param string $suffix suffix to be used for the resized image
  162.      * @return void 
  163.      * @see $DefaultSuffix
  164.      * @access public
  165.      */
  166.     function setSuffix($suffix{
  167.         $this->DefaultSuffix $suffix;
  168.     }
  169.     
  170.     /**
  171.      * Sets the working directory.
  172.      *
  173.      * @param string $dir working directory
  174.      * @return void 
  175.      * @access public
  176.      */
  177.     function setWorkingDir($dir{
  178.         $this->WorkingDir $dir;
  179.     }
  180.     
  181.     /**
  182.      * Gets the working directory.
  183.      *
  184.      * @param void 
  185.      * @return string working directory
  186.      * @access public
  187.      */
  188.     function getWorkingDir({
  189.         return $this->WorkingDir;
  190.     }
  191.     
  192.     /**
  193.      * Sets the filename of the resized image.
  194.      * 
  195.      * @param string $filename output image filename
  196.      * @return void 
  197.      * @access public
  198.      */
  199.     function setOutputImage($filename{
  200.         $this->OutputImage $filename;
  201.     }
  202.     
  203.     /**
  204.      * Gets the filename of the resized image.
  205.      * 
  206.      * @param void 
  207.      * @return string output image filename
  208.      * @access public
  209.      */
  210.     function getOutputImage({
  211.         return $this->OutputImage;
  212.     }
  213.     
  214.     /**
  215.      * Checks if image is empty, if not sets the image info object
  216.      * 
  217.      * @param string $image image name without path
  218.      * @return void 
  219.      * @access public
  220.      */
  221.     function setImage($image{
  222.         if (!empty($image)) {
  223.             $this->setImageInfo($this->getWorkingDir($image);
  224.         }
  225.     }
  226.     
  227.     /**
  228.      * Returns the nice name (without spaces, special chars, etc.)
  229.      * of the last image processed.
  230.      * 
  231.      * @param void 
  232.      * @return string image name
  233.      * @access public
  234.      */
  235.     function getNiceName({
  236.         return $this->ImageInfo->name();
  237.     }
  238.     
  239.     /**
  240.      * Returns a command name with absolute path prepended.
  241.      *
  242.      * @param string $cmd program name
  243.      * @return string command with path and trailing space
  244.      * @access private
  245.      */
  246.     function command($cmd{
  247.         return NETPBM_PATH $cmd .' ';
  248.     }
  249.     
  250.     /**
  251.      * Uses pnmcut to produce square thumbnails (pnmcut left top width height).
  252.      * First slices the square centered region of the input image and then
  253.      * resizes that to the dimension specified.
  254.      *
  255.      * @param int $size dimension
  256.      * @param string $suffix_op optional suffix for resulting image
  257.      * @return void 
  258.      * @access public
  259.      */
  260.     function squareThumbnail($size$suffix_op ''{
  261.         $suffix empty($suffix_op$size $suffix_op;
  262.         $this->setOutputImage($this->ImageInfo->customName($suffix));
  263.         $this->Params '-width ' $size ' ';
  264.         $cmd $this->getPreCommand($this->getThumbnailCommand($this->getPostCommand();
  265.         $this->setOutputImage('')// reset Output image for next images to be processed
  266.         $this->execute($cmd);
  267.     }
  268.     
  269.     /**
  270.      * Calculates the dimensions required to slice a square from the original
  271.      * image.  This is used as the new source for the resizing program.
  272.      * 
  273.      * @param void 
  274.      * @return string command line to be executed
  275.      * @access private
  276.      */
  277.     function getThumbnailCommand({
  278.         $min ($this->ImageInfo->width($this->ImageInfo->height()) 'height' 'width';
  279.         $max ($this->ImageInfo->width($this->ImageInfo->height()) 'width' 'height';
  280.         $max_value intval (  ($this->ImageInfo->{$max}($this->ImageInfo->{$min}())  2  );
  281.         if ($max == 'width'{
  282.             $top   0;
  283.             $left  $max_value;
  284.             $width $height $this->ImageInfo->height();
  285.         else {
  286.             $top   $max_value;
  287.             $left  0;
  288.             $width $height $this->ImageInfo->width();
  289.         }
  290.         return $this->command('pnmcut'$left .' '$top .' '$width ' ' $height ' | ';
  291.     }
  292.     
  293.     /**
  294.      * Cuts an image section to be taken as the base for a specific width and
  295.      * height resize.
  296.      * 
  297.      * @param int $x target width of image
  298.      * @param int $y target height of image
  299.      * @return string command line to be executed
  300.      * @access private
  301.      */
  302.     function getFixedCut($x$y{
  303.         $width_factor  intval($this->ImageInfo->width($x);
  304.         $height_factor intval($this->ImageInfo->height($y);
  305.         $max max($width_factor$height_factor);
  306.         $difference abs($width_factor $height_factor);
  307.         if ($max == $width_factor{
  308.             $width  $width_factor  $x ($difference $x);
  309.             $height $height_factor $y;
  310.         else {
  311.             $width  $width_factor  $x;
  312.             $height $height_factor $y ($difference $y);
  313.         }
  314.         $left   intval(($this->ImageInfo->width($width2);
  315.         $top    intval(($this->ImageInfo->height($height2);
  316.         return $this->command('pnmcut'$left .' '$top .' '$width ' ' $height ' | ';
  317.     }
  318.     
  319.     /**
  320.      * Generic resize method, it defaults to resize by Bounding Box. The first
  321.      * parameter can also be an array containing different dimensions and
  322.      * suffixes so you can have different resized versions of the original
  323.      * image.
  324.      *
  325.      * @param mixed $pixels pixels to be resized by
  326.      * @param string $image input image filename
  327.      * @return void 
  328.      * @access public
  329.      * @see resizeByBoundingBox()
  330.      */
  331.     function resize($pixels$image ''{
  332.         if (is_array($pixels)) {
  333.             $this->setImage($image);
  334.             foreach ($pixels as $size => $suffix{
  335.                 $this->setOutputImage($this->ImageInfo->customName($suffix));
  336.                 $this->resizeByBoundingBox($size$size);
  337.             }
  338.         else {
  339.             $this->resizeByBoundingBox($pixels$pixels$image);
  340.         }
  341.     }
  342.     
  343.     /**
  344.      * Resizes an image taking width as the base dimension.
  345.      *
  346.      * @param integer $pixels pixels to be resized by
  347.      * @param string $image input image filename
  348.      * @return void 
  349.      * @access public
  350.      */
  351.     function resizeByWidth($pixels$image ''{
  352.         $this->Params '-width ' $pixels ' ';
  353.         $this->process($image);
  354.     }
  355.     
  356.     /**
  357.      * Resizes an image taking height as the base dimension.
  358.      * 
  359.      * @param integer $pixels pixels to be resized by
  360.      * @param string $image input image filename
  361.      * @return void 
  362.      * @access public
  363.      */
  364.     function resizeByHeight($pixels$image ''{
  365.         $this->Params '-height ' $pixels ' ';
  366.         $this->process($image);
  367.     }
  368.     
  369.     /**
  370.      * Resizes an image by a percentage.
  371.      *
  372.      * @param mixed $percentage float or int taken as a percentage
  373.      * @param string $image input image filename
  374.      * @return void 
  375.      * @access public
  376.      */
  377.     function resizeByPercentage($percentage$image ''{
  378.         $this->Params $percentage ' ';
  379.         $this->process($image);
  380.     }
  381.     
  382.     /**
  383.      * This does a bounding box resize.  It will try to fit the image into
  384.      * a box with the columns and rows specified.
  385.      *
  386.      * @param integer $cols number of columns of the bounding box
  387.      * @param integer $rows number of rows of the bounding box
  388.      * @param string $image input image filename without path info
  389.      * @return void 
  390.      * @access public
  391.      */
  392.     function resizeByBoundingBox($cols$rows$image ''{
  393.         $this->Params '-xysize ' $cols ' ' $rows ' ';
  394.         $this->process($image);
  395.     }
  396.     
  397.     /**
  398.      * This does a specific resize.  It resizes the image to the specified
  399.      * dimensions without altering the aspect ratio, but of course the
  400.      * algorithm used centers the new frame and some portions of the image are
  401.      * lost. Also, the original image should be larger than the target image.
  402.      *
  403.      * @param integer $width target width of image
  404.      * @param integer $height target height of image
  405.      * @param string $suffix image suffix to be used
  406.      * @param string $image input image filename without path info
  407.      * @return void 
  408.      * @access public
  409.      */
  410.     function resizeByDimensions($width$height$suffix ''$image ''{
  411.         $this->setImage($image);
  412.         $suffix empty($suffix$width $suffix;
  413.         $this->setOutputImage($this->ImageInfo->customName($suffix));
  414.         $this->Params '-width ' $width ' -height ' $height ' ';
  415.         $cmd $this->getPreCommand($this->getFixedCut($width$height$this->getPostCommand();
  416.         $this->setOutputImage('')// reset Output image for next images to be processed
  417.         $this->execute($cmd);
  418.     }
  419.     
  420.     /**
  421.      * If an image path was passed it will initialize it and resize using that
  422.      * instead.  Compiles the command to be called for resizing.
  423.      *
  424.      * @param string $image image filename to be initialized
  425.      * @return void 
  426.      * @access private
  427.      */
  428.     function process($image ''{
  429.         $this->setImage($image);
  430.         if (!is_a($this->ImageInfo'ImageInfo')) {
  431.             $this->raiseError('You have not setup an Image!');
  432.         }
  433.         $cmd $this->getPreCommand($this->getPostCommand();
  434.         $this->execute($cmd);
  435.     }
  436.     
  437.     /**
  438.      * Executes a command line to resize an image.
  439.      *
  440.      * @param string $cmd command line to be executed
  441.      * @return void 
  442.      * @access private
  443.      */
  444.     function execute($cmd{
  445.         $output array();
  446.         exec($cmd$output$return_var);
  447.         if ($return_var 0{
  448.             $this->raiseError('Error at netpbm execution, full command line: '.$cmd);
  449.         }
  450.     }
  451.     
  452.     /**
  453.      * Compiles the first part of the command line to be executed.
  454.      * 
  455.      * @param void 
  456.      * @return string first part of the command line
  457.      * @access private
  458.      */
  459.     function getPreCommand({
  460.         return $this->command($this->Programs[$this->ImageInfo->type()'topnm'
  461.                 . $this->getWorkingDir($this->ImageInfo->name(' | ';
  462.     }
  463.     
  464.     /**
  465.      * Compiles the last part of the command line to be executed. This is where
  466.      * format based logic occurs and the reason why $this->Programs exist.
  467.      *
  468.      * @param void 
  469.      * @return string last part the command line
  470.      * @access private
  471.      * @see $Programs
  472.      */
  473.     function getPostCommand({
  474.         $Type $this->Programs[$this->ImageInfo->type()];
  475.         $Command $this->command('pnmscale'$this->Params ' | ';
  476.         if ($Type == 'gif'{
  477.             $Command .= $this->command('ppmquant''256 | '
  478.                         .  $this->command('ppmto' $Type'> ';
  479.         else {
  480.             $options ($Type == 'jpeg''--quality=95 ' '';
  481.             $Command .= $this->command('pnmto' $Type$options '> ';
  482.         }
  483.         return $Command  $this->getDestination();
  484.     }
  485.    
  486.     /**
  487.      * Calculates the resized image filaname since it can come from $OutputImage
  488.      * or just be the original filename with a suffix appended.
  489.      * 
  490.      * @param void 
  491.      * @return string final full path of the resized image
  492.      * @access public
  493.      */
  494.     function getDestination({
  495.         $file $this->getOutputImage();
  496.         $OutputFile empty($file
  497.                       ? $this->ImageInfo->customName($this->DefaultSuffix$file;
  498.         $OutputFile .= '.' $this->ImageInfo->extension();
  499.         return $this->getWorkingDir($OutputFile;
  500.     }
  501.     
  502.     /**
  503.      * Triggers an USER error.  This should/could be changed touse a custom
  504.      * error handler.
  505.      *
  506.      * @param string $message message to be displayed in case of user error
  507.      * @return void 
  508.      * @access private
  509.      */
  510.     function raiseError($message{
  511.         trigger_error('NetpbmResize Error: '.$messageE_USER_ERROR);
  512.     }
  513. }
  514.  
  515. /**
  516.  * Stores all the required/useful information of a given image in an array
  517.  * and provides accessor methods to that data.
  518.  * 
  519.  * @author Favio Manriquez <favio@favrik.com>
  520.  * @access public
  521.  * @see NetpbmResize
  522.  */
  523. class ImageInfo {
  524.     /**
  525.      * Used to store and retrieve all the image info.
  526.      * 
  527.      * @var array stores all the image info
  528.      * @access private
  529.      */  
  530.     var $ImageInfo      array();
  531.     
  532.     /**
  533.      * Stores the supported image formats.
  534.      *
  535.      * @var array image formats
  536.      * @access private
  537.      */  
  538.     var $SupportedTypes array(=> 'gif''jpg''png');
  539.     
  540.     /**
  541.      * Constructor.  Uses getimagesize() output as initial data.
  542.      *
  543.      * @param string $image full path of an image
  544.      * @return void 
  545.      * @access public
  546.      */  
  547.     function ImageInfo($Image{
  548.         $size                             getimagesize($Image);
  549.         $this->ImageInfo['width']         $size[0];
  550.         $this->ImageInfo['height']        $size[1];
  551.         $this->ImageInfo['type']          $size[2];
  552.         $this->ImageInfo['mime']          $size['mime'];
  553.         $this->ImageInfo['route']         $Image;
  554.         $this->ImageInfo['original_name'basename($Image);
  555.     }
  556.     
  557.     /**
  558.      * Checks if image is of a supported format.
  559.      * 
  560.      * @param void 
  561.      * @return void 
  562.      * @access private
  563.      */  
  564.     function validImage({
  565.         if (array_key_exists($this->ImageInfo['type']$this->SupportedTypes)) {
  566.             $this->ImageInfo['ext']  $this->SupportedTypes[$this->ImageInfo['type']];
  567.             $this->useNiceName();
  568.             return true;
  569.         }
  570.         return false;
  571.     }
  572.     
  573.     /**
  574.      * Regular expressions taken from gallery.menalto.com. It produces nice
  575.      * filenames. =D
  576.      *
  577.      * @param void 
  578.      * @return void 
  579.      * @access private
  580.      */
  581.     function useNiceName({
  582.         $name urldecode($this->ImageInfo['original_name'])// remove %20 and the like from name
  583.         $tag  $this->ImageInfo['ext'];
  584.         $tempFilename eregi_replace(".$tag$"""$name);// parse out original filename without extension
  585.         $tempFilename eregi_replace(".jpeg$"""$tempFilename);
  586.         $tempFilename ereg_replace("[^[:alnum:]]""_"$tempFilename);// replace multiple non-word characters with a single "_"
  587.         $tempFilename ereg_replace("_+""_"$tempFilename);// Get rid of extra underscores
  588.         $tempFilename ereg_replace("(^_|_$)"""$tempFilename);
  589.         if ($name != $tempFilename{
  590.             $this->renameImage($tempFilename '.' $tag);
  591.         }
  592.         $this->ImageInfo['nice_name'$tempFilename;
  593.         $this->ImageInfo['temp_name'$tempFilename '.tmp.' $tag;
  594.     }
  595.     
  596.     /**
  597.      * Renames an image by copying and deleting.
  598.      * 
  599.      * @param string $NewNameinput image filename
  600.      * @return void 
  601.      * @access private
  602.      */  
  603.     function renameImage($NewName{
  604.         $Filename dirname($this->ImageInfo['route']DIR_SLASH $NewName
  605.         if (!file_exists($Filename)) {
  606.             copy($this->ImageInfo['route']$Filename);
  607.             unlink($this->ImageInfo['route']);
  608.         }
  609.     }
  610.     
  611.     /**
  612.      * Returns the format of the image like GIF, JPG or PNG as an integer.
  613.      * 
  614.      * @param void 
  615.      * @return string image format
  616.      * @access public
  617.      */  
  618.     function type({
  619.         return $this->ImageInfo['type'];
  620.     }
  621.     
  622.     /**
  623.      * Returns the image extension.
  624.      * 
  625.      * @param void 
  626.      * @return string image extension
  627.      * @access public
  628.      */
  629.     function extension({
  630.         return $this->ImageInfo['ext'];
  631.     }
  632.     
  633.     /**
  634.      * Returns the image width.
  635.      * 
  636.      * @param void 
  637.      * @return int image width
  638.      * @access public
  639.      */  
  640.     function width({
  641.         return $this->ImageInfo['width'];
  642.     }
  643.     
  644.     /**
  645.      * Returns the image height.
  646.      * 
  647.      * @param void 
  648.      * @return int image height
  649.      * @access public
  650.      */  
  651.     function height({
  652.         return $this->ImageInfo['height'];
  653.     }
  654.     
  655.     /**
  656.      * Returns the image name after being converted to a nice version.
  657.      * 
  658.      * @param void 
  659.      * @return string nice image filename
  660.      * @access public
  661.      */  
  662.     function name({
  663.         return $this->ImageInfo['nice_name''.' $this->ImageInfo['ext'];
  664.     }
  665.     
  666.     /**
  667.      * Returns the nice image filename with the custom suffix added.
  668.      * 
  669.      * @param string $suffix suffix for image
  670.      * @return string nice image filename with custom suffix added
  671.      * @access public
  672.      */ 
  673.     function customName($suffix{
  674.        return $this->ImageInfo['nice_name'$suffix;
  675.     }
  676.     
  677.     /**
  678.      * Returns the image temp name. Possibly not useful at this point. This
  679.      * could change in the future.
  680.      * 
  681.      * @param void 
  682.      * @return string image temp filename
  683.      * @access public
  684.      */  
  685.     function tempName({
  686.         return $this->ImageInfo['temp_name'];
  687.     }
  688. }
  689. ?>

Documentation generated on Thu, 02 Aug 2007 21:20:13 -0700 by phpDocumentor 1.3.2

SourceForge.net Logo