Raster drawing with Imager#

Imager is the raster workhorse: create an image, draw on it, filter it, save it. It is actively maintained, it links its own copies of the format libraries so PNG, JPEG, TIFF, GIF, and WEBP all work out of the box, and its drawing primitives are the ones from the algorithms chapter running at C speed. If you are starting a raster project on Perl today and have no reason to prefer something else, start here.

Every drawing method returns false on failure and sets errstr, so the idiom is to check and report:

use Imager;

my $img = Imager->new(xsize => 400, ysize => 300, channels => 4)
    or die Imager->errstr;

channels => 4 asks for RGBA (red, green, blue, alpha); use 3 for opaque RGB. The alpha channel is what lets the compositing from the foundations chapter work when you draw one image onto another.

Colors#

Anywhere a method takes color =>, you can pass a name, a hex string, an Imager::Color object, or a plain array reference:

my $red   = Imager::Color->new('red');
my $red2  = Imager::Color->new('#FF0000');
my $red3  = Imager::Color->new(255, 0, 0);
my $trans = Imager::Color->new(255, 0, 0, 128);   # 50% alpha

$img->box(color => [0, 128, 255], filled => 1);   # array-ref, no object

The array-reference form is the least ceremony for a one-off color and is what most of the examples below use.

The primitives#

Note the parameter names carefully, because they are not all the same shape. Boxes use corner coordinates xmin/ymin/xmax/ymax; circles and arcs use a center x/y with a radius r; arcs add start and end degrees d1/d2.

# fill the whole canvas white first
$img->box(color => 'white', filled => 1);

# a line; aa => 1 requests anti-aliasing
$img->line(x1 => 0, y1 => 0, x2 => 399, y2 => 299,
           color => [255, 0, 0], aa => 1);

# an outlined box (no fill) and a filled one
$img->box(xmin => 20, ymin => 20, xmax => 120, ymax => 90,
          color => 'black');
$img->box(xmin => 140, ymin => 20, xmax => 240, ymax => 90,
          color => [200, 220, 255], filled => 1);

# a filled circle: center (200,150), radius 60
$img->circle(x => 200, y => 150, r => 60, color => [0, 128, 255]);

# an arc is a pie slice from d1 to d2 degrees
$img->arc(x => 200, y => 150, r => 80, d1 => 0, d2 => 120,
          color => 'yellow');

# a polygon from a list of [x, y] points
$img->polygon(points => [[300, 40], [380, 40], [340, 110]],
              color => [120, 200, 120]);

# a polyline is an open path; it takes no fill
$img->polyline(points => [[300, 130], [340, 200], [380, 130]],
               color => 'black', aa => 1);

# flood fill from a seed point out to a border
$img->flood_fill(x => 5, y => 5, color => [245, 245, 245]);

Two traps worth stating once. box is filled only when you pass filled => 1 (or a fill => pattern); without it you get an outline. polyline draws an open path and does not accept fill, unlike polygon which closes and can fill. When a shape comes out as an outline you expected filled, or a fill silently does nothing, one of these two is why.

Loading, scaling, and saving#

Reading and writing infer the format from the filename extension, or you can force it with type =>:

my $photo = Imager->new;
$photo->read(file => 'input.jpg') or die $photo->errstr;

# scale by a factor, or to fit a box
my $thumb = $photo->scale(scalefactor => 0.25);
my $fit   = $photo->scale(xpixels => 200, ypixels => 200, type => 'min');

$thumb->write(file => 'thumb.png') or die $thumb->errstr;

scale returns a new image; it does not modify the original. The type => 'min' form scales so the image fits inside the given box preserving aspect ratio; 'max' fills the box (cropping the overflow when you then crop); 'nonprop' ignores aspect ratio and stretches to exactly the pixels you named.

Filters#

filter applies an effect in place, named by type =>. The convolution from the algorithms chapter is here as built-in Gaussian blur and unsharp masking, plus a general conv for your own kernel:

# Gaussian blur; larger stddev is more blur
$img->filter(type => 'gaussian', stddev => 2.5);

# unsharp mask to sharpen; both params optional
$img->filter(type => 'unsharpmask', stddev => 2.0, scale => 1.0);

# your own 1-D convolution coefficients (a horizontal blur here)
$img->filter(type => 'conv', coef => [0.25, 0.5, 0.25]);

# contrast, mosaic (pixelate), and inversion are all filters too
$img->filter(type => 'contrast', intensity => 1.4);
$img->filter(type => 'mosaic', size => 8);
$img->filter(type => 'hardinvert');

The full set includes gaussian, gaussian2 (separate x and y deviations), conv, unsharpmask, contrast, mosaic, noise, hardinvert, autolevels, postlevels, and the procedural texture generators fountain, gradgen, radnoise, and turbnoise. Reach for the named filter before writing your own pixel loop; only drop to a conv coefficient list or manual access when nothing built in fits.

A complete program#

Putting it together: a small poster with a background, some shapes, a blur pass, and a saved thumbnail.

use strict;
use warnings;
use Imager;

my $img = Imager->new(xsize => 400, ysize => 300, channels => 4)
    or die Imager->errstr;

$img->box(color => [30, 30, 60], filled => 1);              # dark bg
$img->circle(x => 120, y => 150, r => 70, color => [255, 200, 60]);
$img->circle(x => 260, y => 150, r => 70, color => [60, 200, 255]);
$img->filter(type => 'gaussian', stddev => 1.2);           # soften
$img->line(x1 => 0, y1 => 250, x2 => 399, y2 => 250,
           color => 'white', aa => 1);

$img->write(file => 'poster.png') or die $img->errstr;
$img->scale(scalefactor => 0.5)->write(file => 'poster-thumb.png')
    or die $img->errstr;

When Imager is the wrong tool#

Imager is raster, so it has the raster limitation: it has a fixed resolution, and scaling past it degrades. For resolution-independent output (a logo that must print crisply at any size, a diagram destined for the web as markup) you want a vector tool, covered in Cairo and SVG. For an existing codebase built on GD or ImageMagick, or for their specific strengths, see the next chapter. And when the drawing needs to appear in a live window rather than a file, that is the GUI toolkits chapter. For everything that is ”make or modify a bitmap on disk“, Imager is the answer.