Как я могу получить прозрачный прозрачный градиент, применяемый к изображению с помощью PHP?

Как можно указать изображение и применить радиальный прозрачный градиент, где он исчезает радиально. У меня нет установленного Imagemagick.

Маргинальный пример:

Gradient Transparent image fade PHP

Ответ 1

Благодаря функции, связанной с @Baba, я смог изменить script, чтобы обеспечить эффект полупрозрачной виньетки.

<?php
class PhotoEffect
{
  private $_photoLocation;
  private $_width;
  private $_height;
  private $_type;

  private $_originalImage;
  private $_afterImage;

  /**
   * Load image URL in constructor
   */
  final public function __construct($photoLocation)
  {
    $this->_photoLocation = $photoLocation;
    if (!$size = @getimagesize($this->_photoLocation)){
      throw new Exception('Image cannot be handled');
    }
    $this->_width = $size[0];
    $this->_height = $size[1];
    $this->_type = $size[2];


    switch ( $this->_type ) {
      case IMAGETYPE_GIF:
        $this->_originalImage = imagecreatefromgif($this->_photoLocation);
      break;
      case IMAGETYPE_JPEG:
        $this->_originalImage = imagecreatefromjpeg($this->_photoLocation);
      break;
      case IMAGETYPE_PNG:
        $this->_originalImage = imagecreatefrompng($this->_photoLocation);
      break;
      default:
        throw new Exception('Unknown image type');
    }
  }

  /**
   * Destroy created images
   */
  final private function __destruct() {
     if (!empty($this->_originalImage))
     {
       imagedestroy($this->_originalImage);
     }

     if (!empty($this->_afterImage))
     {
       imagedestroy($this->_afterImage);
     }
   }

  /**
   * Apply vignette effect
   */
  final public function Vignette($sharp=0.4, $level=1, $alpha=1)
  {
    if (empty($this->_originalImage))
    {
      throw new Exception('No image');
    }

    if (!is_numeric($sharp) || !($sharp>=0 && $sharp<=10))
    {
      throw new Exception('sharp must be between 0 and 10');            
    }

    if (!is_numeric($level) || !($level>=0 && $level<=1))
    {
      throw new Exception('level must be between 0 and 10');            
    }

    if (!is_numeric($alpha) || !($alpha>=0 && $alpha<=10))
    {
      throw new Exception('alpha must be between 0 and 1');         
    }

    $this->_afterImage = imagecreatetruecolor($this->_width, $this->_height);
    imagesavealpha($this->_afterImage, true);
    $trans_colour = imagecolorallocatealpha($this->_afterImage, 0, 0, 0, 127);
    imagefill($this->_afterImage, 0, 0, $trans_colour);


    for($x = 0; $x < $this->_width; ++$x){
      for($y = 0; $y < $this->_height; ++$y){  
        $index = imagecolorat($this->_originalImage, $x, $y);
        $rgb = imagecolorsforindex($this->_originalImage, $index);

        $l = sin(M_PI / $this->_width * $x) * sin(M_PI / $this->_height * $y);
        $l = pow($l, $sharp);

        $l = 1 - $level * (1 - $l);

        $rgb['red'] *= $l;
        $rgb['green'] *= $l;
        $rgb['blue'] *= $l;
        $rgb['alpha'] = 127 - (127 * ($l*$alpha));


        $color = imagecolorallocatealpha($this->_afterImage, $rgb['red'], $rgb['green'], $rgb['blue'], $rgb['alpha']);

        imagesetpixel($this->_afterImage, $x, $y, $color);  
      }
    }

  }


  /**
   * Ouput PNG with correct header
   */
  final public function OutputPng()
  {
    if (empty($this->_afterImage))
    {
      if (empty($this->_originalImage))
      {
        throw new Exception('No image');
      }
      $this->_afterImage = $this->_originalImage;
    }

    header('Content-type: image/png');
    imagepng($this->_afterImage);
  }

  /**
   * Save PNG
   */
  final public function SavePng($filename)
  {
    if (empty($filename)) {
        throw new Exception('Filename is required');
    }

    if (empty($this->_afterImage))
    {
      if (empty($this->_originalImage))
      {
        throw new Exception('No image');
      }
      $this->_afterImage = $this->_originalImage;
    }

    imagepng($this->_afterImage, $filename);
  }

}


/**
 * How to use
 */
$effect = new PhotoEffect('test.jpg');
$effect->Vignette();
$effect->OutputPng();
?>

Работая phpfiddle с единственным изображением, которое я мог найти на их сервере, поэтому не так уж и много.

Ответ 2

Введение

Я думаю, вы должны установить Imagemagick, потому что то, что вам нужно, это простой эффект vignette, вы можете легко сделать так, чтобы ImageMagic (convert input.jpg -background black -vignette 70x80 output.png) без необходимости зацикливать каждый пиксель, который может быть очень медленным при работе с большими изображениями

Оригинальное изображение

$file = __DIR__ . "/golf.jpg";

enter image description here

Эффект 1

$image = new imagick($file);
$image->vignetteImage(20, 20, 40, - 20);
header("Content-Type: image/png");
echo $image;

enter image description here

Эффект 2

$image = new imagick($file);
$image->vignetteImage(100, 100, 200, 200);
header("Content-Type: image/png");
echo $image;

enter image description here

виньетка с GD

Хорошо, если вы вынуждены использовать GB... Использование может использовать эту классную виньетку script

function vignette($im) {
    $width = imagesx($im);
    $height = imagesy($im);

    $effect = function ($x, $y, &$rgb) use($width, $height) {
        $sharp = 0.4; // 0 - 10 small is sharpnes,
        $level = 0.7; // 0 - 1 small is brighter
        $l = sin(M_PI / $width * $x) * sin(M_PI / $height * $y);
        $l = pow($l, $sharp);
        $l = 1 - $level * (1 - $l);
        $rgb['red'] *= $l;
        $rgb['green'] *= $l;
        $rgb['blue'] *= $l;
    };

    for($x = 0; $x < imagesx($im); ++ $x) {
        for($y = 0; $y < imagesy($im); ++ $y) {
            $index = imagecolorat($im, $x, $y);
            $rgb = imagecolorsforindex($im, $index);
            $effect($x, $y, $rgb);
            $color = imagecolorallocate($im, $rgb['red'], $rgb['green'], $rgb['blue']);

            imagesetpixel($im, $x, $y, $color);
        }
    }
    return (true);
}

Более быстрый подход к виньетированию GD

Лучшее приближение, используемое в GD Filter testing, было бы... создать маску и поверх нее

    $overlay = 'vignette_white.png';
    $png = imagecreatefrompng($overlay);
    imagecopyresampled($filter, $png, 0, 0, 0, 0, $width, $height, $width, $height);

Единственным недостатком является то, что изображение должно быть того же размера с маской, чтобы эффект выглядел круто.

Заключение

Если это то, что вы подразумеваете под radial transparent gradient, тогда я советую вам получить ImageMagic, если не по крайней мере леди, картина милая.

Ответ 3

Я знаю, что это вопрос, связанный с PHP, но вы можете добиться приятных прозрачных градиентов с использованием элемента canvas javascript и html5.

Итак, я написал этот маленький script, который:

  • обнаруживает браузеры, поддерживающие элемент canvas, если браузер не поддерживает холст (к счастью, осталось всего несколько процентов пользователей), тогда отображается полное изображение.
  • создает холст и добавляет элемент после изображения
  • аргументы в функции create_gradient() могут быть изменены для настраиваемых форм
  • он работает со всеми популярными форматами изображений (проверен с .jpg,.bmp,.gif,.png)
  • вы можете добавить еще "colorstops (grd.addColorStop()), чтобы изменить поток градиента

script

window.onload = function() {
    if ( typeof CanvasRenderingContext2D !== 'function' ) {
        document.getElementById('gradient-image').style.visibility = "visible";
        return;
    }

    var image = document.getElementById('gradient-image');

    // these are the default values, change them for custom shapes
    create_gradient( image, image.width/2, image.height/2, image.height/4, image.width/2, image.height/2, image.height/2 );
}

function create_gradient( image, start_x, start_y, start_r, end_x, end_y, end_r ){

    var canvas = document.createElement('canvas');

    var parent = image.parentNode;
    if ( parent.lastchild == image ) parent.appendChild(canvas);
    else parent.insertBefore(canvas, image.nextSibling);

    canvas.width  = image.width;
    canvas.height = image.height;

    var context = canvas.getContext('2d');

    var grd = context.createRadialGradient( start_x, start_y, start_r, end_x, end_y, end_r );
    grd.addColorStop(0, 'rgba(0,0,0,1)' );
    // grd.addColorStop(0.2, 'rgba(0,0,0,0.8)' );
    grd.addColorStop(1, 'rgba(0,0,0,0)' );

    context.fillStyle = grd;
    context.fillRect(0, 0, image.width, image.height);

    var grd_data = context.getImageData(0, 0, image.width, image.height);

    context.drawImage( image, 0, 0);
    var img_data = context.getImageData(0, 0, image.width, image.height);

    var grd_pixel = grd_data.data;
    var img_pixel = img_data.data;
    var length = img_data.data.length

    for ( i = 3; i < length; i += 4 ) {
        img_pixel[i] = grd_pixel[i];
    }
    context.putImageData(img_data, 0, 0);
}

HTML

<img id="gradient-image"src="">

CSS

#gradient-image {
    position: absolute;
    visibility: hidden;
}