ImageMagick: Rounded-corner PHP function

I’ve converted my rounded-corner bash script into a PHP function that’ll use the Image Magick command line tools to do the same. With some added functionality to handle automatically creating thumbnails and applying a background color to the source image itself. This also allows for the insertion of basic pre-processing and post-processing arguments to IM.

For more information and output examples see. the bash version.

To see an example of thumbnails generated with some pre-processing done:

First Preprocessor Test

This is a sample done with thumbnail pre-processing. That is processing done before the rounded corners are made.

With this sample, I switched colorspace to HSL and then set the hue and saturation to a constant before applying the glass-bubble rounded corners.

Known bug: sometimes the glass-bubble method will add a single pixel to the width, which is transparent. I believe passing -trim in the postprocessing option may trim that off for you, though I have not thoroughly tested it.

Also: I have no idea if this will work on a Windows server.

/**
 * Produce a thumbnail with rounded corners as specificed in options.
 * @param String $in Input file name.
 * @param String $out Output file name.
 * @param Integer $width Width constraint of desired thumbnail. Omit with empty string.
 * @param Integer $height Height of desired thumbnail. Omit with empty string.
 * @param Array $options An array of options as such:
 *  method: plain or glass-bubble (Default: plain)
 *  radius: requested radius (Default: min($width, $height) * 0.2)
 *   if it calculates 0, this will default to 14.
 *  image-background: Background color applied to the image itself. (Default: '#000000')
 *  background: Background color behind an image (for the corners) (Default: transparent)
 *   A note for this: jpg output doesn't really like transparent.
 *  convertcommand: Override the path to the convert command. (default: convert)
 *  preprocessing: Additional preprocessing arguments you'd like to send IM for the preproc img
 *  postprocessing: Additional postprocessing arguments "" for the output thumbnail.
 * @return Mixed String if error (contains error message) or array of image information.
 */
function rounded_thumbnail_im($in, $out, $width, $height, $options = array())
{
   $convertcommand = 'convert';
   $method = 'plain';
   $imgback = '#000000';
   $back = 'transparent';
   $radius = floor(min($width, $height) * 0.2);
   $preprocessing = '';
   $postprocessing = '';
   if($radius == 0)
   {
      $radius = 14;
   }
   if(isset($options['method']))
   {
      if(in_array($options['method'], array('plain', 'glass-bubble')))
      {
         $method = $options['method'];
      }
   }
   
   if(isset($options['image-background'])) $options['imgback'] = $options['image-background'];
   if(isset($options['background'])) $options['back'] = $options['background'];
   
   foreach(array('imgback', 'back', 'convertcommand', 
   'radius', 'preprocessing', 'postprocessing') as $key)
   {
      if(isset($options[$key]))
      {
         $$key = $options[$key];
      }
   }
   
   if(!is_file($in))
   {
      return "$in is not a file.";
   }

   $swidth = escapeshellarg($width);
   $sheight = escapeshellarg($height);
   $sradius = intval($radius);
   $sinfile = escapeshellarg($in);
   $soutfile = escapeshellarg($out);
   $sbackground = escapeshellarg($back);
   $simgbackground = escapeshellarg($imgback);
   $spreproc = escapeshellcmd($preprocessing);
   $spostproc = escapeshellcmd($postprocessing);
   
   $sconv = escapeshellarg($convertcommand);
   
   //Build preprocessor command.
   $resize = '';
   if($width != '' || $height != '')
   {
      $resize = "-resize {$swidth}x{$sheight}";
   }
   $preprocess = "$sconv $sinfile $resize -background $simgbackground -flatten $spreproc png:-";
   
   //Post process:
   if($back != 'transparent')
   {
      $backgroundproc = "png:- | $sconv png:- -background $sbackground -flatten $spostproc";
   }
   else
   {
      if($postprocessing == '')
      {
         $backgroundproc = "";
      }
      else
      {
         $backgroundproc = "png:- | $sconv png:- -background transparent $spostproc";
      }
   }
   
   //Perform smashy smashy
   if($method == 'plain')
   {
      $command="$preprocess | $sconv \\( png:- 
      \\( +clone  -alpha extract 
         -draw \"fill black polygon 0,0 0,$sradius $sradius,0 fill white circle $sradius,$sradius $sradius,0\" 
         \\( +clone -flip \\) -compose Multiply -composite 
         \\( +clone -flop \\) -compose Multiply -composite 
      \\) -alpha off -compose CopyOpacity -composite \\) $backgroundproc $soutfile";
      $command = preg_replace('/[\r\n]+/', '', $command);
      //echo $command;
      system($command);
      if(is_file($out) && filesize($out) > 100)
      {
         return getimagesize($out);
      }
      else
      {
         return 'Plain rounded-corner conversion failed.';
      }
   }
   else if ($method == 'glass-bubble')
   {
      //Removes the stream to standard out from the preprocess command.
      //So we can use it slightly differently.
      $preprocess = preg_replace('/png\:-$/', '', $preprocess);
      $nfile = tempnam(sys_get_temp_dir(), 'GBb');
      $snfile = escapeshellarg('png:'.$nfile);
      system($cmd = "$preprocess $snfile");
      //echo "$cmd\n";
      $command="$sconv $snfile -alpha off -fill white -colorize 100% 
      -draw \"fill black polygon 0,0 0,$sradius $sradius,0 fill white circle $sradius,$sradius $sradius,0\" 
      \\( +clone -flip \\) -compose Multiply -composite 
      \\( +clone -flop \\) -compose Multiply -composite 
      -background Gray50 -alpha Shape  png:- |
      $sconv png:- -bordercolor None -border 1x1 
          -alpha Extract -blur 0x10  -shade 130x30 -alpha On 
          -background gray50 -alpha background -auto-level 
          -function polynomial  3.5,-5.05,2.05,0.3 
          \\( +clone -alpha extract  -blur 0x3 \\) 
          -channel RGB -compose multiply -composite 
          +channel +compose -chop 1x1 
          png:- |
       $sconv \\( $snfile -alpha Set png:- 
          \\( -clone 0,1 -alpha Opaque -compose Hardlight -composite \\) 
          -delete 0 -compose In -composite \\) $backgroundproc $soutfile 2>> debug.txt";
      $command = preg_replace('/[\r\n]+/', '', $command);
      //echo $command,"\n";
      system($command);
      
      if(is_file($nfile))
      {
         unlink($nfile);
      }
      if(is_file($out) && filesize($out) > 100)
      {
         return getimagesize($out);
      }
      else
      {
         return 'Glass-bubble rounded-corner conversion failed.';
      }      
   }
}

Leave a Reply

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>