2013-05-06 2 views
10

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

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

Gradient Transparent image fade PHP

+0

http://stackoverflow.com/questions/6615602/radial-gradients-with-opacity-in-php?rq=1 # answer-6615727 –

+0

Использование CSS: http://stackoverflow.com/a/4527735/738201 – Chad

+0

В худшем случае вы можете построить градиент окружности PNG с использованием примитивов GD, но вместо применения сдвига цвета примените сдвиг непрозрачности. Затем наложите PNG поверх текущего изображения. У меня нет кода для этого, но он может дать вам несколько новых идей по поисковым фразам. – halfer

ответ

3

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

<?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(); 
?> 

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

+0

Hey Hugo Этот код не работает для меня. Не уверен в снижении голосов. –

+0

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

+0

Пробовал обычный файл PNG и получил следующее: 'PHP Неустранимая ошибка: исключение исключений« Исключение »с сообщением« Изображение невозможно обработать » –

17

Введение

Я думаю, вы должны получить 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

виньетка с Г. Д.

Ну, если вы вынуждены использовать ГБ ... Использование может использовать этот cool vignette 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); 
} 

Faster 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, если не по крайней мере, леди картина мило.

+0

haha ​​true и спасибо за ответ, но градиент изображения исчезает до белого, не прозрачного. Это просто невозможно? Если вы заметите, что маргинальное изображение в сообщении может исчезнуть на любом фоне. –

+0

Вы можете легко изменить фон в версии GB .... Можете ли вы использовать Imagemagic? – Baba

0

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

Так что я написал этот небольшой скрипт, который:

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

сценарий

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; 
} 
+0

Учитывая эту статью (несколько месяцев назад, но все же) http://thenextweb.com/apps/2012/10/01/internet-explorer-8-falls-25-market-share-firefox-15-passes-10- mark-chrome-loses-users/на IE8 более или менее 25%. Таким образом, даже с существенным снижением до 15%, которое, я сомневаюсь, произошло, вы говорите многим людям, что они недостаточно хороши для вашего сайта. И учитывая, что canvas/javascript очень медленный на устройствах Android и более старых устройствах iOS, я бы определенно не использовал javascript для таких вещей. –