parser

Classes for Working with Images Using the NConvert and ImageMagick Utilities

Author: Kulikov Denis [November 18, 2013]
Version: 1.11
Tags: Graph

This is a copy of the article taken from the author's site. The copy may become outdated, so it's recommended to try the original source first.

For all its wonderfulness, Parser has a very limited set of functions for working with images. Nevertheless, when building sites with this language, the need periodically comes up to resize an image, rotate it, or save it in another format.

Well, as usual, if Parser can't do something, you have to call an external script that can do what's needed and make use of its output. And that's where the wonderful nconvert utility comes to the rescue (thanks to Eugene Spearance for the tip). The utility can do a whole lot, so for the maniacs out there, the possibilities for working with images are now limited only by their maniacal imagination :). Since I'm not a maniac myself, the class described here implements the main capabilities needed for working with pictures.

A little later, Misha v.3 suggested making the class more universal and combining it with ImageMagick as well. To do this, only the methods defining the class's interface were kept in the original Img.p. Everything responsible for calling external scripts, along with some other specific bits, was moved out into the corresponding NConvert.p and ImageMagick.p classes, which are descendants of the Img class.

What's the point of all this? So that it's not agonizingly painful when, moving to a different host, you discover there's no ImageMagick there, or no suitable version of nconvert for that OS. In that case, if you're using the described set of classes, all you need to do is hook up NConvert.p instead of the ImageMagick.p you were using (or vice versa) and that's it. Nothing else in the code needs to change. And don't think you'll never have to move. As soon as you think that, you definitely will have to! :)

So, what can the class do and how do you work with it

First you need to decide which external program you're going to use

Creating the object

That's where the differences end. From this point on, we can use the methods of the $oImg object, which have a common interface regardless of which external program we're using.

Notes:

  • In the examples below, $sFileSrc and $sFileDest are the source and destination files respectively (the path is given relative to the web-space root).
  • The jpeg, gif, png, bmp, and tiff formats are supported for conversion.
  • If the source image's format isn't forced explicitly, it's determined from the destination file's extension.
  • By default, quality 80% is used when converting to jpg, and 64 colors when converting to gif
  • The default values can be overridden when creating the object, using the $.iColors $.iQuality $.bKeepRatio $.bRemoveMeta parameters

Getting information about an image

^oImg.info[$sFileSrc]
Returns the following hash
	$.sFormat	- format
	$.iWidth	- width (px)
	$.iHeight	- height (px)
	$.sCompression	- compression
	$.iColors	- number of colors
	$.iXdpi		- horizontal resolution (dpi)
	$.iYdpi		- vertical resolution (dpi)
	$.sOrientation

When using ImageMagick, the following field may also be present:
	$.sQuality

Converting an image to the required format

^oImg.convert[$sFileSrc;$sFileDest;$sFormat;$hParams]

Here
$sFormat - output format
$hParams - a hash with the following fields
	$.bRemoveMeta	- flag for removing metadata
	$.iQuality	- quality for jpg and png.
	$.iColors	- number of colors (256, 216, 128, 64, 32, 16, or 8)

Resizing an image

^oImg.resize[$sFileSrc;$sFileDest;$sWidth;$sHeight;$hParams]

Here
$sWidth and $sHeight - the width and height of the resulting image, respectively
$hParams - a hash with the following fields
	$.bKeepRatio	- flag for preserving the aspect ratio (0 by default)
	$.sResizeType	- resize type
		incr	: only enlarge
		decr	: only shrink
	$.bRemoveMeta	- flag for removing metadata
	$.sFormat	- output format
	$.iQuality	- quality for jpg and png
	$.iColors	- number of colors (256, 216, 128, 64, 32, 16, or 8)
	$.sResampleType	- algorithm used when resizing
		lz,lanczos	: Lanczos (default)
		g,gaussian	: Gaussian
		m,mitchell	: Mitchell

#	NConvert only
		q, quick	: Quick resize
		l, linear	: Bi-linear (linear)
		h, hermite	: Hermite
		b, bell		: Bell
		bs, bspline	: Bspline

Cropping a rectangular area (crop)

^oImg.crop[$sFileSrc;$sFileDest;$iX;$iY;$iCropWidth;$iCropHeight;$hParams]

Here
$iX		- x-coordinate of the top-left corner
$iY		- y-coordinate of the top-left corner
$iCropWidth	- width of the area
$iCropHeight	- height of the area
$hParams - a hash with the following fields
	$.sFormat	- output format
	$.bRemoveMeta	- flag for removing metadata
	$.iQuality	- quality for jpg and png
	$.iColors	- number of colors (256, 216, 128, 64, 32, 16, or 8)

Applying a "watermark"

^oImg.watermark[$sFileSrc;$sFileDest;$sWMFile;$hParams]

Here
$sWMFile - the image being overlaid (a semi-transparent png works best)
$hParams - a hash with the following fields
	$.iX		- x-coordinate of the top-left corner of the overlaid image
	$.iY		- y-coordinate of the top-left corner of the overlaid image
	$.sPosition	- position of the overlaid image
		top-left, left-top		: top-left
		top-center, center-top		: top-center
		top-right, right-top		: top-right
		center-left, left-center	: center-left
		center				: center
		center-right, right-center	: center-right
		bottom-left, left-bottom	: bottom-left
		bottom-center, center-bottom	: bottom-center
		bottom-right, right-bottom	: bottom-right
	$.sFormat	- output format (except gif)
	$.bRemoveMeta	- flag for removing metadata
	$.iQuality	- quality for jpg and png
Specify either the position or the coordinates

Note:
When using ImageMagick, don't forget to specify, when creating the object, the name of the script responsible for this transformation

^use[ImageMagick.p]
$oImg[^ImageMagick::create[
#	Path to convert from the ImageMagick package
	$.sScriptPath[/../data/bin/ImageMagick]
#	Name of the file itself
	$.sScriptName[convert]
#	Name of the composite file for @watermark[] (if used)
	$.hScriptName[
		$.watermark[composite]
	]
]]

Rotating an image

^oImg.rotate[$sFileSrc;$sFileDest;$iAngle;$hParams]

Here
$iAngle - angle in degrees
$hParams - a hash with the following fields
	$.sBGColor	- background color (format "R,G,B")
	$.sFormat	- output format
	$.bRemoveMeta	- flag for removing metadata
	$.iQuality	- quality for jpg and png
	$.iColors	- number of colors (256, 216, 128, 64, 32, 16, or 8)

Rotating a JPEG without quality loss

^oImg.rotateJPG[$sFileSrc;$iAngle]

Here $iAngle - the rotation angle in degrees (+/-90, 180, +/-270)
As a result, the original file gets replaced.

This method only works when using NConvert.
It's not implemented in the ImageMagick class, since the library of the same name has no equivalent functionality.

Many thanks to Misha v.3 for the criticism and helpful advice

If anyone uses other utilities for working with images, then welcome :)

And that's really it.

Download:

Img.zip (18.10.2013  5.9 KB)
Archive with the Img, ImageMagick, and NConvert classes

ImageResize.zip (31.05.2011  1.2 KB)
Archive with the ImageResize class, which simplifies resizing images