Pull to refresh

Создаём Instagram фильтры с помощью PHP и ImageMagick

Reading time5 min
Views20K
Original author: Dejan Marjanovic
image

В этой статье я покажу как создать некоторые эффекты на фотографиях (как на 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 класс, чтобы сделать процесс фильтрации изображений как можно более простым.
  1. colortone: воля цветового тона изображения в светах и/или тени.
  2. vignette: края изображения обесцвечиваются.
  3. border: добавляет границы к фотографии.
  4. frame: будет читать заданный кадр в соответствии с фото.
  5. tempfile: создает временный файл (копия оригинального изображения).
  6. output: переименование рабочего файла
  7. 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 */
 
}  


Посмотрим что получается


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

image

Фильтр 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 секунду, мы можем с уверенностью сказать что это очень быстро!
Tags:
Hubs:
+61
Comments19

Articles