Fun with PHP Graphics - Leslie Steward

PHP Image Tweaker

This is a live chronicle of me playing around trying to figure out a way to resize an image, add a border, padding, and dropshadow using PHP. I figured if you could just pass in a url to a web address it could return a modified image without doing some tricky css stuff. Turns out it wasn't all that tricky. Got it done in under a workday. Anyways, the code is at the bottom in case you want to skip the silly images.

This is my first generated image:

hello world

This is an existing image run through php:

hello world

Awesome.

Here's the exif information:

Array
(
    [FileName] => cat-vs-domokun.jpg
    [FileDateTime] => 1433739320
    [FileSize] => 28157
    [FileType] => 2
    [MimeType] => image/jpeg
    [SectionsFound] => 
    [COMPUTED] => Array
        (
            [html] => width="500" height="375"
            [Height] => 375
            [Width] => 500
            [IsColor] => 1
        )

)

This is the existing image resized:

hello shrunken world

Now with dropshadow. From here.

drop shadow

Sweeeet.

How about a border?

bordered goodness

Hell yes.

Now we can mash it all together.

all together now

Now the best part. You just pass the parameters in the url.

pretty.php?src=cat-vs-domokun.jpg

it's like magic!

OMFG!

Or you can make it brutally ugly!

pretty.php?src=cat-vs-domokun.jpg&resize=0.3&padding=30&matcolor=ff99ff&backgroundcolor=ccffff&bordercolor=f00&format=jpeg

oh dear lord

WHY!?

Great, huh! Here's the code. Thanks to php.net, O'reilly's PHP cookbook, and other various internets.


  // Grab the user defined variables
  $src = isset($_REQUEST['src'])
      ? urldecode($_REQUEST['src'])
      : null;
  $padding = isset($_REQUEST['padding']) && ctype_digit($_REQUEST['padding'])
      ? $_REQUEST['padding']
      : 5;
  $matcolor = isset($_REQUEST['matcolor'])
      ? html2rgb("#" . $_REQUEST['matcolor'])
      : html2rgb("#eeeeee");
  $backgroundcolor = isset($_REQUEST['backgroundcolor'])
      ? html2rgb("#" . $_REQUEST['backgroundcolor'])
      : html2rgb("#ffffff");
  $bordercolor = isset($_REQUEST['bordercolor'])
      ? html2rgb("#" . $_REQUEST['bordercolor'])
      : html2rgb("#cccccc");
  $resize = isset($_REQUEST['resize'])
      ? floatval($_REQUEST['resize'])
      : 1.0;
  $format = isset($_REQUEST['format'])
      ? htmlentities($_REQUEST['format'])
      : "png";
  
  // Create a new image based on user input.
  if(isset($src) && file_exists($src)) {
    $image = imagecreatefromjpeg($src);
    $image = resizeImage($image, $resize);
    $image = addBorder($image, $padding, $matcolor, $bordercolor);
    $image = addShadow($image, $backgroundcolor);
    // Draw this masterpiece.
    if($format == "jpeg"){
      header("Content-type: image/jpeg");
      imagejpeg($image, "", 100);
    }
    elseif ($format == "png") {
      header("Content-type: image/png");
      imagepng($image, "", 0);
    }
    // Clean up the image resources.
    imagedestroy($image);
  }
  
  /**
   * Convert a hex string to an array of (red, green, blue).
   * @author http://www.anyexample.com/programming/php/
   *     php_convert_rgb_from_to_html_hex_color.xml
   * @param   $color  The color string in the format #ffffff.
   * @return  An array with the RGB values as integers.
   */
  function html2rgb($color) {
    if ($color[0] == '#')
      $color = substr($color, 1);
    if (strlen($color) == 6)
      list($r, $g, $b) = array($color[0].$color[1],
                               $color[2].$color[3],
                               $color[4].$color[5]);
    elseif (strlen($color) == 3)
      list($r, $g, $b) = array($color[0].$color[0],
                               $color[1].$color[1],
                               $color[2].$color[2]);
    else
        return false;
    $r = hexdec($r);
    $g = hexdec($g);
    $b = hexdec($b);
    return array("r" => $r, "g" => $g, "b" => $b);
  }
  
  /**
   * Add a border to a php image resource. The original image is surrounded by mat
   * with a color $border_background. Around that is a one pixel border.
   * @author Leslie Steward
   * @param $original_image     A php image resource.
   * @param $border_padding     The width in pixels from the image to the border.
   * @param $border_background  An array with the background color in RGB.
   * @param $border_color       An array with the border color in RGB.
   * @return                    An image with a border and mat (padding).
   */
  function addBorder($original_image, $border_padding = 5,
      $border_background =  array("r" => 255, "g" => 255, "b" => 255),
      $border_color = array("r" => 0, "g" => 0, "b" => 0)){
    // unfortunatly, you can't change this without more codework
    $border_size = 1;
  
    // create new canvas for bordered picture
    $original_width = imagesx($original_image);
    $original_height = imagesy($original_image);   
    $width = $original_width + $border_padding * 2 + $border_size * 2;
    $height = $original_height + $border_padding * 2 + $border_size * 2;
    $border_image = imagecreatetruecolor($width, $height);
  
    // fill with background
    $background_color = imagecolorallocate($border_image, $border_background['r'],
        $border_background['g'], $border_background['b']); 
    imagefill($border_image, 0, 0, $background_color);
    
    // draw a border
    $border_color_allocated = imageColorAllocate($border_image,
        $border_color['r'],$border_color['g'], $border_color['b']);
    ImageRectangle($border_image, 0, 0, $width - $border_size,
        $height - $border_size, $border_color_allocated);
  
    // overlay the original image on top of the drop shadow
    ImageCopyMerge($border_image, $original_image, $border_padding + $border_size,
        $border_padding + $border_size, 0,0,
        $original_width, $original_height, 100);
  
    return $border_image;
  }
  
  /**
   * Add a dropshadow to a php image resource.
   * @author http://www.codewalkers.com/c/a/Miscellaneous/
   *     Adding-Drop-Shadows-with-PHP/6/
   * @param $original_image   A php image resource.
   * @param $background_color An array with the background color in RGB.
   * @return                  An php image resource with a drop shadow.
   */
  function addShadow($original_image,
      $background_color = array("r" => 255, "g" => 255, "b" => 255)){
  
    // offset of drop shadow from top left
    define("DS_OFFSET",  5);
    // number of steps from black to background color
    define("DS_STEPS", 10);
    // distance between steps
    define("DS_SPREAD", 1);
  
    // create new canvas for shadowed picture
    $original_width = imagesx($original_image);
    $original_height = imagesy($original_image);    
    $width = $original_width + DS_OFFSET;
    $height = $original_height + DS_OFFSET;
    $shadow_image = imagecreatetruecolor($width, $height);
  
    // determine the offset between colors
    $step_offset = array(
        "r" => ($background_color["r"] / DS_STEPS),
        "g" => ($background_color["g"] / DS_STEPS),
        "b" => ($background_color["b"] / DS_STEPS));
  
    // calculate and allocate the needed colors
    $current_color = $background_color;
    for ($i = 0; $i <= DS_STEPS; $i++) {
      $colors[$i] = imagecolorallocate($shadow_image,
          round($current_color["r"]),
          round($current_color["g"]),
          round($current_color["b"]));
  
      $current_color["r"] -= $step_offset["r"];
      $current_color["g"] -= $step_offset["g"];
      $current_color["b"] -= $step_offset["b"];
    }
    
    // floodfill the canvas with the background color
    imagefilledrectangle($shadow_image, 0,0, $width, $height, $colors[0]);
  
    // draw overlapping rectangles to create a drop shadow effect
    for ($i = 0; $i < count($colors); $i++) {
      imagefilledrectangle($shadow_image, DS_OFFSET, DS_OFFSET,
          $width, $height, $colors[$i]);
      $width -= DS_SPREAD;
      $height -= DS_SPREAD;
    }
  
    // overlay the original image on top of the drop shadow
    imagecopymerge($shadow_image, $original_image, 0,0, 0,0, 
        $original_width, $original_height, 100);
  
    return $shadow_image;
  }
  
  /**
   * Resize a php image resource to a specific percentage of the original.
   * @author Leslie Steward
   * @param   $original_image   A php image resource to resize.
   * @param   $percent          The percentage of the original size. Ex: 0.75
   * @return  A resized php image resource. 
   */
  function resizeImage($original_image, $percent = 1){
  
    if($percent == 1)
      return $original_image;
    
    $original_width = imagesx($original_image);
    $original_height = imagesy($original_image);
  
    $new_width = $original_width * $percent;
    $new_height = $original_height * $percent;
    
    $image = imageCreateTrueColor($new_width, $new_height);
    imageCopyResampled($image, $original_image, 0, 0, 0, 0,
        $new_width, $new_height, $original_width, $original_height);
  
    return $image;
  }

  

Yeah, there are probably a few mistakes, but I've got other things to do. Just send me a message and I'll fix them.