You are here

function image_gd_perspective in ImageCache Actions 7

GD toolkit specific implementation of the image Perspective effect.

Parameters

stdClass $image: Image object containing the image resource to operate on.

array $data: The current configuration for this image effect, contains the keys: distortion, vanish, symmetry and opposite_distortion options.

Return value

bool True on success, false otherwise.

File

canvasactions/canvasactions.inc, line 1465

Code

function image_gd_perspective(stdClass $image, $data) {
  $width = $image->info['width'];
  $height = $image->info['height'];
  $distortion = $data['distortion'];
  $opposite_distortion = $data['symmetry'] === 'symmetrical' ? $distortion : $data['opposite_distortion'];

  // To reduce distortion, we work with a temporary hires version of the image.
  // @todo: during processing we have 2 resources this size: this might crash on memory limits: warn and/or prevent.
  $multiplier = 3;
  $hires_width = $width * $multiplier;
  $hires_height = $height * $multiplier;
  $hires_source_image = imagecreatetruecolor($hires_width, $hires_height);
  $transparent_white = imagecolorallocatealpha($hires_source_image, 255, 255, 255, 127);
  imagealphablending($hires_source_image, FALSE);
  imagefilledrectangle($hires_source_image, 0, 0, $hires_width, $hires_height, $transparent_white);
  imagesavealpha($hires_source_image, TRUE);
  imagecopyresized($hires_source_image, $image->resource, 0, 0, 0, 0, $hires_width, $hires_height, $width, $height);
  imagedestroy($image->resource);

  // Creating a hires target canvas to apply the perspective effect on.
  $hires_target_image = imagecreatetruecolor($hires_width, $hires_height);
  $transparent_white = imagecolorallocatealpha($hires_target_image, 255, 255, 255, 127);

  // We don't want to blend: the transparent background we set is only for the
  // parts that do not get covered.
  imagealphablending($hires_target_image, FALSE);
  imagefilledrectangle($hires_target_image, 0, 0, $hires_width, $hires_height, $transparent_white);

  // Building perspective effect with help four point distortion methods.
  // On each step found new distortion point by right triangle formula.
  switch ($data['vanish']) {
    case 'top':
      $left = round($hires_width * $distortion / 100);
      $right = round($hires_width - $hires_width * (100 - $opposite_distortion) / 100);
      $tg_beta_left = $left / $hires_height;
      $tg_beta_right = $right / $hires_height;
      for ($y = 0; $y < $hires_height; $y++) {
        $new_left = ($hires_height - $y) * $tg_beta_left;
        $new_right = ($hires_height - $y) * $tg_beta_right;
        $new_width = $hires_width - $new_left - $new_right;
        imagecopyresampled($hires_target_image, $hires_source_image, $new_left, $y, 0, $y, $new_width, 1, $hires_width, 1);
      }
      break;
    case 'bottom':
      $left = round($hires_width * $distortion / 100);
      $right = round($hires_width - $hires_width * (100 - $opposite_distortion) / 100);
      $tg_beta_left = $left / $hires_height;
      $tg_beta_right = $right / $hires_height;
      for ($y = $hires_height; $y > 0; $y--) {
        $new_left = $y * $tg_beta_left;
        $new_right = $y * $tg_beta_right;
        $new_width = $hires_width - $new_left - $new_right;
        imagecopyresampled($hires_target_image, $hires_source_image, $new_left, $y, 0, $y, $new_width, 1, $hires_width, 1);
      }
      break;
    case 'right':
      $top = round($hires_height * $distortion / 100);
      $bottom = round($hires_height - $hires_height * (100 - $opposite_distortion) / 100);
      $tg_beta_top = $top / $hires_width;
      $tg_beta_bottom = $bottom / $hires_width;
      for ($x = $hires_width; $x > 0; $x--) {
        $new_top = $x * $tg_beta_top;
        $new_bottom = $x * $tg_beta_bottom;
        $new_height = $hires_height - $new_top - $new_bottom;
        imagecopyresampled($hires_target_image, $hires_source_image, $x, $new_top, $x, 0, 1, $new_height, 1, $hires_height);
      }
      break;
    case 'left':
      $top = round($hires_height * $distortion / 100);
      $bottom = round($hires_height - $hires_height * (100 - $opposite_distortion) / 100);
      $tg_beta_top = $top / $hires_width;
      $tg_beta_bottom = $bottom / $hires_width;
      for ($x = 0; $x < $hires_width; $x++) {
        $new_top = ($hires_width - $x) * $tg_beta_top;
        $new_bottom = ($hires_width - $x) * $tg_beta_bottom;
        $new_height = $hires_height - $new_top - $new_bottom;
        imagecopyresampled($hires_target_image, $hires_source_image, $x, $new_top, $x, 0, 1, $new_height, 1, $hires_height);
      }
      break;
  }
  imagedestroy($hires_source_image);
  imagealphablending($hires_target_image, FALSE);
  imagesavealpha($hires_target_image, TRUE);

  // Return image with perspective effect to original size.
  $target_image = imagecreatetruecolor($width, $height);
  imagealphablending($target_image, FALSE);
  imagecopyresampled($target_image, $hires_target_image, 0, 0, 0, 0, $width, $height, $hires_width, $hires_height);
  imagedestroy($hires_target_image);
  imagesavealpha($target_image, TRUE);
  $image->resource = $target_image;
  return TRUE;
}