В этой статье я покажу как создать некоторые эффекты на фотографиях (как на Instagram) с помощью PHP и ImageMagick.
Обработка изображений с помощью PHP
PHP поставляется в комплекте с GD (GIF Draw / Graphics Draw). Её используют для простых операций с изображениями, такие как изменение размера, обрезка, добавление водяных знаков, создание миниатюр. К сожалению, если вы хотите создать что-то более сложное с GD не получится. К счастью, у нас есть ImageMagick!
GD vs. ImageMagick
Посмотрим на примере ресайза изображения.
GD:
$im = imagecreatefromjpeg('photo.jpg');
$ox = imagesx($im);
$oy = imagesy($im);
$nx = 640;
$ny = 480;
$nm = imagecreatetruecolor($nx, $ny);
imagecopyresized($nm,$im,0,0,0,0,$nx,$ny,$ox,$oy);
imagejpeg($nm, 'photo.jpg');
ImageMagick:
IM (сокращенно от ImageMagick) имеет хорошую оболочку, называется Imagick — родное расширение PHP для создания и редактирования изображений с помощью ImageMagick API. Единственный минус: устанавливается из PECL, который иногда может быть проблемой для виртуального
$image = new Imagick('photo.jpg');
$image->resizeImage(640, 480, imagick::FILTER_LANCZOS, 0.9);
А с применением командной строки еще проще:
exec('mogrify -resize 640x480 photo.jpg');
Установка ImageMagick
Пройдите по ссылке, выберите платформу (Unix / Mac / Win) и выберите рекомендуемый пакет.
После завершения установки перейдите к терминалу/командной строке, введите convert и нажмите Enter, если вы получите список вариантов, а не «Команда не найдена», то все отлично! Обратите внимание, что вам не нужно ничего настраивать в PHP.
Instagraph — класс PHP
Я создал небольшой скрипт, PHP класс, чтобы сделать процесс фильтрации изображений как можно более простым.
- colortone: воля цветового тона изображения в светах и/или тени.
- vignette: края изображения обесцвечиваются.
- border: добавляет границы к фотографии.
- frame: будет читать заданный кадр в соответствии с фото.
- tempfile: создает временный файл (копия оригинального изображения).
- output: переименование рабочего файла
- execute: посыл команды
Создайте новый файл с именем instagraph.php и вставьте следующий код.
/**
* Instagram filters with PHP and ImageMagick
*
* @package Instagraph
* @author Webarto <dejan.marjanovic@gmail.com>
* @copyright NetTuts+
* @license http://creativecommons.org/licenses/by-nc/3.0/ CC BY-NC
*/
class Instagraph
{
public $_image = NULL;
public $_output = NULL;
public $_prefix = 'IMG';
private $_width = NULL;
private $_height = NULL;
private $_tmp = NULL;
public static function factory($image, $output)
{
return new Instagraph($image, $output);
}
public function __construct($image, $output)
{
if(file_exists($image))
{
$this->_image = $image;
list($this->_width, $this->_height) = getimagesize($image);
$this->_output = $output;
}
else
{
throw new Exception('File not found. Aborting.');
}
}
public function tempfile()
{
# copy original file and assign temporary name
$this->_tmp = $this->_prefix.rand();
copy($this->_image, $this->_tmp);
}
public function output()
{
# rename working temporary file to output filename
rename($this->_tmp, $this->_output);
}
public function execute($command)
{
# remove newlines and convert single quotes to double to prevent errors
$command = str_replace(array("n", "'"), array('', '"'), $command);
$command = escapeshellcmd($command);
# execute convert program
exec($command);
}
/** ACTIONS */
public function colortone($input, $color, $level, $type = 0)
{
$args[0] = $level;
$args[1] = 100 - $level;
$negate = $type == 0? '-negate': '';
$this->execute("convert
{$input}
( -clone 0 -fill '$color' -colorize 100% )
( -clone 0 -colorspace gray $negate )
-compose blend -define compose:args=$args[0],$args[1] -composite
{$input}");
}
public function border($input, $color = 'black', $width = 20)
{
$this->execute("convert $input -bordercolor $color -border {$width}x{$width} $input");
}
public function frame($input, $frame)
{
$this->execute("convert $input ( '$frame' -resize {$this->_width}x{$this->_height}! -unsharp 1.5×1.0+1.5+0.02 ) -flatten $input");
}
public function vignette($input, $color_1 = 'none', $color_2 = 'black', $crop_factor = 1.5)
{
$crop_x = floor($this->_width * $crop_factor);
$crop_y = floor($this->_height * $crop_factor);
$this->execute("convert
( {$input} )
( -size {$crop_x}x{$crop_y}
radial-gradient:$color_1-$color_2
-gravity center -crop {$this->_width}x{$this->_height}+0+0 +repage )
-compose multiply -flatten
{$input}");
}
/** RESERVED FOR FILTER METHODS */
}
Посмотрим что получается
Оригинал изображения:
Фильтр Gotham
Готэм-фильтр приводит изображение в черно-белое. Высокий контраст изображения с голубоватым оттенком.
public function gotham()
{
$this->tempfile();
$this->execute("convert $this->_tmp -modulate 120,10,100 -fill '#222b6d' -colorize 20 -gamma 0.5 -contrast -contrast $this->_tmp");
$this->border($this->_tmp);
$this->output();
}
Фильтр Toaster
Напоминает старые снимки Polaroid, он имеет яркие цвета вместе с розовым/оранжевым свечением от центра. По словам генерального директора Instagram, это один из самых сложных эффектов.
public function toaster()
{
$this->tempfile();
$this->colortone($this->_tmp, '#330000', 100, 0);
$this->execute("convert $this->_tmp -modulate 150,80,100 -gamma 1.2 -contrast -contrast $this->_tmp");
$this->vignette($this->_tmp, 'none', 'LavenderBlush3');
$this->vignette($this->_tmp, '#ff9966', 'none');
$this->output();
}
Вы даже можете добавить белую рамку для полного эффекта, просто добавьте
$this->border($this->_tmp, 'white'); перед $this->output();
Фильтр Nashville
public function nashville()
{
$this->tempfile();
$this->colortone($this->_tmp, '#222b6d', 100, 0);
$this->colortone($this->_tmp, '#f7daae', 100, 1);
$this->execute("convert $this->_tmp -contrast -modulate 100,150,100 -auto-gamma $this->_tmp");
$this->frame($this->_tmp, __FUNCTION__);
$this->output();
}
Фильтр Lomo
public function lomo()
{
$this->tempfile();
$command = "convert {$this->_tmp} -channel R -level 33% -channel G -level 33% $this->_tmp";
$this->execute($command);
$this->vignette($this->_tmp);
$this->output();
}
Фильтр Kelvin
public function kelvin()
{
$this->tempfile();
$this->execute("convert
( $this->_tmp -auto-gamma -modulate 120,50,100 )
( -size {$this->_width}x{$this->_height} -fill 'rgba(255,153,0,0.5)' -draw 'rectangle 0,0 {$this->_width},{$this->_height}' )
-compose multiply
$this->_tmp");
$this->frame($this->_tmp, __FUNCTION__);
$this->output();
}
Как это использовать?
Я предполагаю что вы сохранили весь код в файл instagraph.php. Теперь создайте файл с именем filter.php и скопируйте следующий код.
Если вы хотите применить только один фильтр, вы можете сделать это следующим образом:
require 'instagraph.php';
try
{
$instagraph = Instagraph::factory('input.jpg', 'output.jpg');
}
catch (Exception $e)
{
echo $e->getMessage();
die;
}
$instagraph->toaster(); // имя фильтра
Вот и все! Если вы хотите применить все фильтры используйте этот код:
require 'instagraph.php';
try
{
$instagraph = Instagraph::factory('input.jpg', 'output.jpg');
}
catch (Exception $e)
{
echo $e->getMessage();
die;
}
// loop through all filters
foreach(array('gotham', 'toaster', 'nashville', 'lomo', 'kelvin') as $method)
{
$instagraph->_output = $method.'.jpg'; // we have to change output file to prevent overwrite
$instagraph->$method(); // apply current filter (from array)
}
Производительность
Производительность, безусловно, является важной частью в любой области применения. Применение фильтра к изображению составляет примерно 1 секунду, мы можем с уверенностью сказать что это очень быстро!
Автор: Isis