Mixer

Powerful PHP class to mix images and text together using GD or Imagick

Mixer is a fully namespaced PHP class (built on top of great Imagine library) which eases the task of mixing images and text together. It offers pre-defined objects with display properties that can be set using syntax similar to CSS. The class nicely abstracts positioning and text handling nuances which you might stumbled upon while working with raw GD or Imagick functions. It can be used to generate all kinds of memes or motivation images for instance :P

Requirements:

Object supports following properties:

  • width
  • height
  • padding
  • background

To construct Image object, you pass image file as an constructor argument and optionally an array of properties:

use Mixer\Shape\Image;

$i = new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.5.jpg', array(
    'padding' => 20,
));
$i->show(); // will set appropriate headers and send an image to the browser

When you do not specify width and height, default image dimensions will be used. When you do, image will be zoom-cropped (towards center) to match provided dimensions:

use Mixer\Shape\Image;

$i = new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.4.jpg', array(
    'padding' => 10,
    'width' => 100,
    'height' => 100,
));

When you specify only one dimension, other will be calculated proportionally.

Object supports following properties:

  • width
  • height
  • padding
  • background
  • color
  • font
  • size
  • align
  • valign
  • outline

To construct Text object, you pass text string as an constructor argument, FontStore instance and optionally an array of properties:

use Mixer\Shape\Text;

$t = new Text('Lorem Ipsum', $fontStore, array(
    'font' => 'times',
    'color' => '#000',
    'background' => '#fff',
    'padding' => 20,
));
$t->show();

Note that if you do not set font property, it will be randomly picked from passed FontStore object.

Here are some examples how text can be aligned horizontally and vertically:

If you supply both width and height font size will be decreased automatically in order to fit text into resulting bounding box (if neccessary):

You can enable text outline by passing outline property like in the following example (integer defines outline width):

use Mixer\Shape\Text;

$t = new Text('Lorem Ipsum', $fontStore, array(
    'font' => 'impact',
    'color' => '#fff',
    'background' => '#fff',
    'padding' => 20,
    'size' => 36,
    'outline' => '4 #000',
));
$t->show();

To manually enforce new line just insert new line character \n in passed text:

use Mixer\Shape\Text;

$t = new Text("First line\nSecond line", $fontStore);

Object supports following properties:

  • padding
  • background

Composition object allows to easily mix together Image objects, Text objects and other Composition objects. Every composition needs initial element which is passed as first constructor argument, followed by an array of properties:

use Mixer\Shape\Image;
use Mixer\Shape\Composition;

// let's setup some composition elements
$i1 = new Image('img' . DIRECTORY_SEPARATOR . 'lima.landscape.1.jpg', array(
    'width' => 300,
    'padding' => 10,
    'background' => '#fff',
));
$i2 = new Image('img' . DIRECTORY_SEPARATOR . 'lima.landscape.2.jpg', array(
    'padding' => 10,
    'background' => '#999',
));
$i3 = new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.3.jpg', array(
    'padding' => 10,
    'background' => '#ccc',
));

// let's create composition and paste elements
$c = new Composition($i1, array(
    'padding' => 20,
));
$c->paste($i2, 'bottom');
$c->paste($i3, 'right');
$c->show();

When you paste new element into the composition, it will be resized proportionally (by default) to fit respective side (top, bottom, left, right). You can always disable proportional resizing by passing false as a third param to Composition::paste() method.

Pasting Text objects

There is one thing to remember when pasting Text objects. Let's create sample Text object:

$t = new Text("Adriana Lima is a Brazilian model and actress", $fontStore, array(
    'font' => 'novecentowide',
    'padding' => 20,
));

Now, let's create new composition by taking some portrait-oriented photo as initial element and pasting our Text object below the photo:

$c = new Composition(new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.5.jpg'));
$c->paste($t, 'bottom');

During the paste, Text object bounding box's width and height was scaled proportionally to fit photo's width. That's why resulting font size was automatically reduced in order to fit the text into new bounding box. That is not intended behavior in some cases. If we would like to keep our original font size we have to let Text object "grow" to the new width by using resetHeight() method before pasting and passing false to disable proportional resizing:

$c = new Composition(new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.5.jpg'));
$t->resetHeight();
$c->paste($t, 'bottom', false);

You can resize any object using setWidth() and setHeight() methods. Note that if object has not been rendered object's padding will not change after resize:

$i = new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.1.jpg', array(
    'width' => 300,
    'padding' => 20,
));

// Picture on the left
$i->show();

// Picture in the middle
$i->setWidth(150, true);
$i->show();

// Picture on the right
$i->render();
$i->setWidth(150, true);
$i->show();

By default, Mixer will use Imagick if available. However, you can enforce your preferred engine globally using following construct before creating any object:

use Mixer\Engine;

Engine::setDefault(Engine::ENGINE_GD); // or Engine::ENGINE_IMAGICK

You can also enforce engine per object basis:

use Mixer\Engine;
use Mixer\Image;

$i1 = new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.1.jpg', array(
    'engine' => Engine::factory(Engine::ENGINE_GD),
));

Remember though that you can only mix objects created using the same engine!

FontStore holds any font that you may use when creating Text objects and allows you to easily alias given font with short and friendly name. In order to create any Text object, you must instantiate FontStore object first and pass it as an argument to each Text object constructor function. When creating FontStore object, you pass filesystem path to the directory where font files (.ttf, .otf) are placed. After that you can perform aliasing:

use Mixer\FontStore;

$fontStore = new FontStore(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fonts');
$fontStore->add('times', 'times.ttf');
$fontStore->add('arial', 'arial.ttf');
$fontStore->add('novecentowide', 'Novecentowide-Bold.otf');

Utility class which finds average color for Image, Text or Composition. Simply pass appropriate object as constructor argument:

use Mixer\ImageColor;

$imageColor = new ImageColor(new Image('img' . DIRECTORY_SEPARATOR . 'lima.portrait.5.jpg'));
$averageColor = $imageColor->getAverageColor(); // $averageColor is now a Imagine's Color object
echo $averageColor; // which outputs hex code (ie. #a1866d) while casting to string
echo $averageColor->getValue('red'); // but also has some nice helper methods

$averageColor2 = $imageColor->getAverageColorByResize(); // alternative average color sampling algorithm

ImageColor class has also handy static method getContrastColor() which finds optimal text color (white or black) for given background color:

use Mixer\ImageColor;

echo ImageColor::getContrastColor('#000') // returns #ffffff
name object description
getWidth($inner = false) Image, Text, Composition Returns object width (with padding). Pass true to get object inner width (without padding).
getHeight($inner = false) Image, Text, Composition Returns object height (with padding). Pass true to get object inner height (without padding).
setWidth($newWidth, $proportional = false) Image, Text, Composition Sets object new width. If you pass true as second param, height will be adjusted proportionally to the new width.
setHeight($newHeight, $proportional = false) Image, Text, Composition Sets object new height. If you pass true as second param, width will be adjusted proportionally to the new height.
show($format = 'jpg') Image, Text, Composition Renders object (if not already rendered), sets appropriate headers and sends an image to the browser. Allows to pass in output format.
save($file, $options = []) Image, Text, Composition Saves object to file. Pass in filename with correct extension (either .jpg, .png or .gif). You can specify $options in order to set quality of saved images:
$options['jpeg_quality'] (from 0 to 100)
$options['png_compression_level'] (from 0 to 9)
render() Image, Text, Composition Renders object into Imagine handle.
getHandle() Image, Text, Composition Returns Imagine handle (if null you need to call render() before).
paste($object, $position, $proportional = true) Composition Pastes new object into the composition. Pass 'top', 'bottom', 'right', 'left' as $position param.
pasteInside($object, $position) Composition Pastes new object inside the composition. Pass an array with x and y as $position param.

You can pass integers: array(10, 10).

Alternatively you can pass position keywords (the same as when using CSS background-position): array('center', 'center').
name object default value type description
width Image, Text not set integer Pass integer to set total object width (with padding).
height Image, Text not set integer Pass integer to set total object height (with padding).
padding Image, Text, Composition 0 integer/string Pass integer to set equal padding on each side or alternatively you can pass string similar to CSS shorthand: '20 10' or '20 5 10 30'.
background Image, Text, Composition '#000' string To set background color, pass hex color string: '#fc0'.
To create linear gradient, pass two colors separated by whitespace: '#fc0 #f00'.
You can alter opacity of each color by appending comma and value (0-100) after hex color in following way: '#fc0,80'.
color Text '#fff' string Defines text color. Pass hex color string: '#fc0'.
Optionally you can include opacity modifier after comma, see background property above.
font Text not set string Defines text font. Pass friendly font name (alias) that you have defined inside FontStore instance.
size Text 16 integer Defines text font size in points.
align Text 'left' string Defines text align. Available values: 'left', 'center' or 'right'.
valign Text 'top' string Defines text vertical align. Available values: 'top', 'middle' or 'bottom'.
outline Text '0 #000' string/integer Defines text outline. Pass integer to set outline width only. Pass string with outline width and color to set both: '5 #fc0' (order does not matter).

At the moment the class is not open-source. If you would like to use it in your project - write me an e-mail describing general details. I may send you zipped archive (together with MotivationImage class) for free or ask for small donation via PayPal or Bitcoin to support project development.