Try Tuts+ Premium, Get Cash Back!
Create Instagram Filters With PHP

Create Instagram Filters With PHP

Tutorial Details
  • Program: PHP / ImageMagick
  • Difficulty: Intermediate
  • Estimated Completion Time: 45 minutes

Final Product What You'll Be Creating

In this tutorial, I’ll demonstrate how to create vintage (just like Instagram does) photos with PHP and ImageMagick. Wait? What? Yes, you can do this very thing with PHP and ImageMagick, and that’s just scratching the surface!


We Made Digital Vintage Photos, Before it Was Cool

Once upon a time – technically 22 years ago (5 years before PHP) – ImageMagick was released. Since then, it has evolved to a platform independent software suite that can create, edit, compose, or convert raster images (over 100 formats supported!). You can use it to resize, flip, mirror, rotate, distort, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves. It truly has everything you will ever need, when dealing with image manipulation in web development, video processing, panorama generating, etc. Please note, however: it is not a GUI image editor.

ImageMagick is command-line Photoshop for web.


Image Manipulation With PHP

PHP comes bundled with GD (GIF Draw/Graphics Draw), which is a library for the dynamic creation of images. It can be used for simpler image operation, such as resizing, cropping, adding watermarks, creating thumbnails (Jeffrey wrote about it), applying basic photo filters – you’ve probably used it before. Unfortunately, if you want to create something more complex with GD, like Instagram effects, you can’t. Luckily, though, we have ImageMagick!


GD vs. ImageMagick

These two can’t compare on higher levels, therefore, we will use simple example, like resizing. Let’s imagine that we’ve uploaded a new 1024×768 photo.jpg image, and we want to dynamically resize it to 640×480 pixels.

GD

In the example below, we have to call six functions, and possibly perform some calculations if we have variable aspect ratio.

$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 (short for ImageMagick) has a nice wrapper, called Imagick – a native PHP extension to create and modify images using the ImageMagick API. The only downside is: you will likely have to install it from PECL, which can sometimes be a problem for shared hosting.

$image = new Imagick('photo.jpg');
$image->resizeImage(640, 480, imagick::FILTER_LANCZOS, 0.9);

Even simpler, command-line usage with PHP (this is what we are going to use):

exec('mogrify -resize 640x480 photo.jpg');

That’s it! Excellent.


Installing ImageMagick

Although nearly every good hosting company has ImageMagick installed, you probably don’t have one on a local machine, simply because it isn’t shipped with PHP.
Installing ImageMagick is a cinch, though. Go to the ImageMagick Download page, choose your platform (Unix/Mac/Win), and select recommended package. Simply follow the simple instructions; you can’t make a mistake here.

Once finished, go to your terminal/command-prompt, type in convert and hit Enter, If you receive a list of options instead of “Command not found”, you’re good go! Note that you don’t need to configure anything in PHP.


How Does Instagram Work?

Well, to be honest, I don’t know what system the Instagram team are using for image processing. ImageMagick is also available for iOS; perhaps that is the magic of how Instagram works? To quote Kevin Systrom, Instagram CEO and co-founder:

It’s really a combination of a bunch of different methods. In some cases, we draw on top of images, in others we do pixel math. It really depends on the effect we’re going for.

For instance, Lomo-fi really isn’t much more than the image with boosted contrast. Whereas Toaster is one of the most complex (and slow, yet popular) filters we have with multiple passes and drawing.

I’d give up more info, but it’s our secret sauce :) Maybe some day…

“Maybe some day…” isn’t good enough for us, Mr Systrom. Challenge accepted!


Show Me Teh Codez!

We are going to mimic gotham (return of gotham), toaster (the complex one), nashville (the popular one), lomo (lomo-fi isn’t that good) and kelvin (lord kelvin – original) filters.

Instagraph – the PHP Class

I have created a little PHP wrapper class to make the process of filtering images as simple as possible. In these filters, as you know, we have lots of…

  • colortone: will color tone an image in highlights and/or shadows. For example, we want to change black to purple.
  • vignette: edges of photo fade out or desaturate gradually. We can even reverse this, or use colors for vignette.
  • border: will add a border to the photo. For example, we want a white or black or any color border of a certain width; note that the width of the border will add up to the photo dimensions.
  • frame: will read specified frame and stretch in to fit to photo. We need this for the Nashville and kelvin filters.
  • tempfile: creates temporary file (copy of original image), to work with.
  • output: simply renames the working copy.
  • execute: we will send all commands through this method to prevent errors that can occur while working with the shell.

I’ve made all of these mentioned, so we can skip to fun part. Create a new file, called instagraph.php, and copy & paste the code below.

/**
 * 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 */
    
}

Instagram Filters

We will go over the filters, one by one; I will explain the necessary PHP methods and Imagemagick commands, including examples. Make sure you update your PHP class with these new methods (paste below RESERVED FOR FILTER METHODS comment). The photo frames are provided in the download package; they are just PNG transparent images without extensions. Feel free to make your own! So let’s begin…

Original

Here we simply have a photo of my dogs enjoying the day at the beach. This is straight out of my camera.

terry and linda on the beach

Gotham

The Gotham filter produces a black&white, high contrast image with bluish undertones. In real life, this would be created with a Holga camera and Ilford X2 film.

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

In English: create a working file, load the image into memory, improve brightness a bit, (almost) desaturate, change the remaining colors to deep purple, gamma correction (value below 1 darkens image), add more contrast, add more contrast, and save everything to a file. Add a 20px black border. Simple, eh?

Gotham filter

Toaster

The Toaster filter resembles old Polaroid shots; it features vivid colors with pink/orange glow out of the center. By the words of Instagram CEO, it’s one of the most difficult effects to create; we’ll take his word for it.

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

In English: create a working file, load the image into memory, change blacks to dark red, enhance brightness, desaturate by a fifth, perform gamma correction (make image brighter), add more contrast, add more contrast, save. Lastly, add a grayish vignette (desaturates edges a bit), and an “inverted” orange vignette for color burn effect.

Tip: You can even add a white border for a full effect; just add $this->border($this->_tmp, 'white'); before $this->output();.

Toaster filter

Nashville

Nashville has a nice washed out 80s fashion photo feel. It produces image with a magenta/peach tint. It additionally adds a frame to get that slide look. It’s easily one of the most popular Instagram filters.

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

In English: create a working file, load the image into memory, change blacks to indigo, change whites to peach color, enhance contrast, enhance saturation by half, gamma auto-correction. Add a frame from a PNG file.

Nashville filter

Lomo

Lomography is all about making high contrast photos with vignettes and soft focus (everywhere you go). In real life, they are mostly made with Holga, LOMO LC-A or so called toy cameras (cameras with plastic lens). This effect is pretty easy to recreate; we will simply enhance the red and green channels’ contrast by a third, and add a vignette. Feel free to experiment as you wish.

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

Create a working file, load the image into memory, enhance red channel contrast by a third, enhance red channel again, apply a vignette.

Tip: If you prefer lomo effect without vignette, just comment or remove that section of code.

Lomo filter

Kelvin

Named after Lord Kelvin, this effect applies a strong peach/orange overlay, and adds a washed out photo frame.

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

In English: create a working file, load the image into memory, normalize, enhance brightness by a fifth, desaturate by half, create an peach/orange color overlay, and apply the multiply blending mode. Lastly, add a frame, using the PNG file.

Kelvin filter

How to Use

It’s easy to use these effects! I’ll assume that you saved all the code within instagraph.php file. Now, create a file, called filter.php and copy the code below that suits you.

If you want to apply only one filter on an image, you can do it this way:

require 'instagraph.php';

try
{
    $instagraph = Instagraph::factory('input.jpg', 'output.jpg');
}
catch (Exception $e) 
{
    echo $e->getMessage();
    die;
}

$instagraph->toaster(); // name of the filter

That’s it! Now, if you want to apply all filters to one image, use this code:

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)
}

Now, just open it in your browser and enjoy the results!

Performance

Performance is certainly an important part of every application. Because the average time to apply a filter to an image is roughly 1 second, we can safely say it is pretty fast!


ImageMagick Resources

To learn more about ImageMagick, here’s a list of links to all the commands and options that were used in these filter methods:

  • convert:
  • modulate: vary the brightness, saturation, and hue
  • contrast: enhance or reduce the image contrast
  • size: width and height of image
  • fill: color to use when filling a graphic primitive
  • draw: annotate the image with a graphic primitive
  • compose: set image composite operator
  • channel: apply option to select image channels
  • level: adjust the level of image contrast
  • auto-gamma: automagically adjust gamma level of image
  • gamma: level of gamma correction

Additionally, here’s a list of ImageMagick scripts, tutorials and examples:


Summary

In this tutorial, we learned a bit about Imagemagick, and demonstrated the power of it by creating filters that are similar to the ones generated by Instagram. We created Instagraph!

If you need any help, or need assistance creating additional filters, such as Tilt Shift or Earlybird, let me know within the comments, and I’ll do my best to assist!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Ashvin

    Great Work

  • http://www.joshualogancook.com joshualogancook

    wow your article just saved my nutz.

    Thank you for the hard work emulating instagram’s filters through imagemagick

    One note, your example site you built, instagraph doesn’t work.

  • st

    why these effects spend such long time? I just apply it in Android system and by calling .so file. I also need the other effects method,hope you can provide….

  • KerryH

    Is there any way to make this work with an Image object instead of a written file? I’m wanting to add the filter but continue working with my image object before writing it to file. When I try to pass in my $img as the input and output i get “File not found. Aborting.”

    • KerryH

      lol wow, I think i corrected it to do what i want by simply removing the file_exists() from the construct function!

      • KerryH

        Ok so that only worked for the first go, after that no filter will apply!

      • chris

        So did you figure out how to get the filters working?

    • LZ

      I’m really interested in finding out out if there’s a way to this working with an Image object as well without requiring a saved file. I’m guessing the use of the command line requires a saved file, so I might have to convert the command line sections to using the Imagick library functions, but I’m still really new to using Imagick, so please let me know if I’m wrong and overcomplicating things!

  • Maarten

    Awesome tut! More effects will be definitely appreciated!

  • J.

    It’s really splendid, but I don’t understand why frames don’t work on my install…

    Any idea ?

  • https://apps.facebook.com/fotinhos/ Paulo Souza

    I have based this article to create this application on facebook, it is in beta, but it can be used normally, there are many features that I intend to add yet. https://apps.facebook.com/fotinhos/

  • http://www.sherweb.com SherWeb

    Good tutorial, I’ve never tought we could modify images with PHP, I did’nt know we could do this kind of stuff. very good work !

  • http://www.webdesign.org Stacy Summers

    Awesome tips! thank you for sharing!)
    I’ve learned a lot!

  • Chris

    I think many are missing out installing the extension before they start using it.

    http://stackoverflow.com/questions/9365758/how-to-install-imagemagick-on-windows-7-2

    this has it well covered. anyone who isn’t getting any errors but also not the filter working, check this out.

  • http://www.hificommunications.com J

    First, we really appreciate your hard work and study of these filters. Do you have any other pre-filter settings

    Filters list:
    - Inwell;
    - Tilt Shift;
    - Sigmoidal;
    - Vintage;
    - Hip Blue;
    - Hip Purple.

  • http://ozonostudio.com Uriel Albarrán Oropeza

    Hi i download the script, but i really don’t know how create the tilt shift and earlybird effect, also how i can use my own custom frames?

  • Neena

    Every effects that use colortone function do not work for me, what could be the problem?

  • http://blogmyglasses.com Alex

    I did it for my blog.. It looks amazing :) Thanks!

  • john

    what about earlybird?
    Thanks a lot!

  • Michael

    I just love it ! Would love if you could share the public demo!

  • Neera

    It’s not working

    • http://www.facebook.com/justin.jastin.94 Justin Jastin

      me too, ive try this but its not working

    • awan

      are your server have gd library and image magick enable?

  • Pablo Francisco

    Great tuto. One question, How can I bring a image from a folder via mysql? .Click on image (img src=”‘.$img_url.$row['pic']) and process it? thanks

  • http://www.facebook.com/justin.jastin.94 Justin Jastin

    this code doesnt work for me, why?

    • http://designpalatset.se/ Kenth Hagström

      Do you have the server-side software ImageMagick installed?

  • Chris

    Would it be possible to create a Lichtenstein Ben Day Dots or Color Halftone effect?
    Thanks for any help in advance

  • lbennet

    More filters please, it’s a piece of cake for you.

  • PSG

    Hi the demo page itself isn’t opening up. Don’t know if its coming from your end.

  • tranhueminh89

    Good good ! thank

  • http://twitter.com/codenamepapa Tom

    The instagraph.me domain is being squatted… site is just links.