A simplified Node.js wrapper around GD image manipulation library with extra features:
- Image format autodetection: just
gd.open(file)
instead of choosing between gd.createFromJpeg() or gd.createFromPng() or whatever. - Handy resizing and watermarking shortcuts:
image.resize({width: 100, height:100})
andimage.watermark('logo.png')
. - Reads/writes files, buffers and streams.
- Provides synchronous, asynchronous and transform stream interfaces.
- Has built-in Exif parsing and supports automatic image orientation.
- A drop-in replacement for node-gd. You can just
require('easy-gd')
instead ofrequire('node-gd')
and everything will be working as before.
Because it is fast. Easy-gd uses C++ buindings for libgd that add very little overhead. For example, it resizes images two times faster than gm, which executes graphicsmagick commands in the background.
Node.js 0.8-0.10.
Ubuntu:
sudo apt-get install libgd2-xpm-dev
npm install easy-gd
Mac OS X:
brew install gd
npm install easy-gd
- Resizing images
- Placing a watermark
- Reading/writing image files
- Reading/writing buffers
- Reading/writing streams
- Image transform streams
- Synchronous image processing
- Asynchronous image processing
- Controlling the output format
- Controlling image quality/compression
- Automatic filename extensions
- Reading Exif data
- Automatic image orientation
- Error handling
var gd = require('easy-gd')
var image, resized
image = gd.open('image-800x600.jpg') // Source image size is 800×600
// Resize to feat into 100×100 box, yields 100×75 image
resized = image.resize({width: 100, height: 100})
// Resize by width, yields 200×150 image
resized = image.resize({width: 200})
// Resize by height, yields 267×200 image
resized = image.resize({height: 200})
// Resize and crop to 100×100
resized = image.crop({width: 100, height: 100})
resized = image.resize({width: 100, height: 100, method: 'crop'})
// Resize without resampling; faster but lowers the quality
resized = image.resize({width: 100, height: 100, resample: false})
// Save the resized image
resized.save('resized.jpg')
See also: Reading/writing files, Asynchronous processing, Image transform streams.
var gd = require('easy-gd')
var image, watermarked
image = gd.open('source-image.jpg')
// Place a logo at the center of the image
watermarked = image.watermark('logo.png')
watermarked = image.watermark('logo.png', {x: 0.5, y: 0.5})
// At the left top corner
watermarked = image.watermark('logo.png', {x: 0, y: 0})
// At the right bottom corner
watermarked = image.watermark('logo.png', {x: 1, y: 1})
// Choose the most contrast position for a logo at the bottom
watermarked = image.watermark('logo.png', [{x: 0, y: 1}, {x: 0.5, y: 1}, {x: 1, y: 1}])
// Using gd.Image object as a watermark
var logo = gd.open('logo.png')
watermarked = image.watermark(logo)
// Save the watermarked image
watermarked.save('watermarked.jpg')
See also: Reading/writing files, Reading/writing buffers, Reading/writing streams, Asynchronous processing, Error handling.
var gd = require('easy-gd')
var image = gd.open('image.png')
// Do something to the image
image.save('processed.jpg', {quality: 90})
See also: Reading/writing buffers, Reading/writing streams, Asynchronous processing, Controlling the output format, Error handling.
var gd = require('easy-gd')
// Reading image from buffer
var image = gd.open(imageData)
// Saving image to a buffer
var imageData = image.save()
// Using buffer as a watermark source
var watermarked = image.watermark(imageData)
See also: Reading/writing files, Reading/writing streams, Asynchronous processing, Controlling the output format, Error handling.
var gd = require('easy-gd')
// Reading image from stream
gd.open(stream, function (error, image) {
if (!error) {
// Process the image
}
})
// Saving image to a stream
image.save(stream, function (error) {
if (!error) {
// Some action
}
})
// Using stream as a watermark source
image.watermark(stream, function (error, watermarked) {
if (!error) {
// Process the watermarked image
}
})
See also: Image transform streams, Reading/writing files, Reading/writing buffers, Controlling the output format, Error handling.
All the image manipulation methods called directly on the module object produce chainable transform streams:
var gd = require('easy-gd')
// Making thumbnails
process.stdin
.pipe(gd.crop({width: 100, height: 100}))
.pipe(process.stdout)
// Watermarking
process.stdin
.pipe(gd.watermark('logo.png'))
.pipe(process.stdout)
// Changing image format
process.stdin
.pipe(gd.format('jpeg').quality(90))
.pipe(process.stdout)
// Combine everything
process.stdin
.pipe(
gd.resize({width: 800, height: 600})
.watermark('logo.png', {x:1, y:1})
.options({format: 'jpeg', quality: '90'})
)
.pipe(process.stdout)
See also: Reading/writing files, Reading/writing buffers, Reading/writing streams, Controlling the output format, Error handling.
With easy-gd you can synchronously process files and buffers:
var gd = require('easy-gd')
// Processing files
gd.open('input.png')
.resize({width: 800, height: 600})
.save('output.jpg', {quality: 90})
// Processing buffers
var outputData = gd.open(inputData)
.resize({width: 800, height: 600})
.save({format: 'jpeg', quality: 90})
See also: Asynchronous processing, Error handling.
You can asynchronously process files, buffers and streams by passing additional callback
argument:
var gd = require('easy-gd')
// Processing files
gd.open('input.png', function (error, image) {
if (error) throw error
image.resize({width: 800, height: 600}, function (error, resized) {
if (error) throw error
resized.save('output.jpg', {quality: 90}, function (error) {
if (error) throw error
})
})
})
// Processing buffers
gd.open(inputData, function (error, image) {
if (error) throw error
image.resize({width: 800, height: 600}, function (error, resized) {
if (error) throw error
resized.save({format: 'jpeg', quality: 90}, function (error, outputData) {
if (error) throw error
// Process outputData buffer
})
})
})
// Processing streams
gd.open(inputStream, function (error, image) {
if (error) throw error
image.resize({width: 800, height: 600}, function (error, resized) {
if (error) throw error
resized.save(outputStream, {format: 'jpeg', quality: 90}, function (error) {
if (error) throw error
})
})
})
See also: Image transform streams, Synchronous processing, Error handling.
var gd = require('easy-gd')
// Format is inherited from the source image
var image = gd.open('input.jpg')
var resizedBuffer = image.resize({width: 100}).save() // Saved in JPEG
// Format can be specified explicitly with target filename extension
var image = gd.open('input.jpg')
image.save('output.png') // Saved in PNG
// Format can be specified explicitly with save({format: 'format_name'})
var image = gd.open('input.jpg')
var pngBuffer = image.save({format: 'png'}) // Saved in PNG
// Target file extension has higher priority
var image = gd.open('input.png')
image.save('output.jpg') // Saved in JPEG
Format specification priority: filename extension > save 'format' option > inherited format.
See also: Controlling image quality/compression, Automatic filename extensions, Error handling.
var gd = require('easy-gd')
var image = gd.open('input.jpg')
// Setting JPEG file quality, 0-100
image.save('output.jpg', {quality: 90})
// Setting PNG file compression level, 0-9
image.save('ouput.png', {compression: 6})
// Transform stream options
inputStream.pipe(gd.format('png').compression(6)).pipe(outputStream)
inputStream.pipe(gd.format('jpeg').quality(90)).pipe(outputStream)
inputStream.pipe(gd.options({format: 'jpeg', quality: 90}).pipe(outputStream)
// Buffer saving options
var outputBuffer = image.save({format: 'jpeg', quality: 90})
var outputBuffer = image.save({format: 'png', compression: 6})
See also: Controlling the output format, Automatic filename extensions.
var gd = require('easy-gd')
var image = gd.open('input.jpg')
image.save('output.{ext}', {format: 'png'}) // Writes ouput.png
var image = gd.open('input.jpg')
image
.resize({width: 100})
.save('output.{ext}') // Writes output.jpg since format was inherited
See also: Controlling the output format, Controlling image quality/compression.
Exif data are being parsed automatically for JPEG images.
var gd = require('easy-gd')
var image = gd.open('input.jpg')
// Accessing Exif tags
if (image.exif) {
console.log('%s %s', image.exif.GPSLongitude, image.exif.GPSLatitude)
} else {
console.log('No Exif data')
}
Note: image.exif property will be copied by resize() and other methods, but will not be written to the destination image.
See also: Automatic image orientation.
GD does not process Exif data, resulting rotated images in the output. Easy-gd fixes this by automatically orienting the image.
var gd = require('easy-gd')
// The image gets automatically oriented by Exif data
var image = gd.open('photo.jpg')
// Turn automatic orientation off
var original = gd.open('photo.jpg', {autoOrient: false})
// Automatically orient existing image
var rotated = original.autoOrient()
See also: Reading Exif data.
var gd = require('easy-gd')
// Synchronous methods throw exceptions
try {
var image = gd.open('non-existent.png')
} catch (error) {
console.log('Failed to open the image: %s', error)
}
// Asynchronous methods return errors as the first callback argument;
// null means there was no error
gd.open('non-existent.png', function (error, image) {
if (error) {
console.log('Failed to open the image: %s', error)
return
}
// ...
})
// Every error raised or returned by easy-gd is a descendant or gd.Error
try {
doImageRelatedStuff()
} catch (error) {
if (error instanceof gd.Error) {
console.log('Image processing error: %s', error)
} else {
// Some other error happened
}
}
There are some subclasses you can use to catch specific errors:
- gd.UnknownSourceType - unknown source type.
- gd.EmptySource - empty source file or buffer.
- gd.UnknownImageFormat - unknown image format (or not an image at all).
- gd.IncompleteImage - corrupted or incomplete image.
- gd.UnsupportedOrientation - unsupported image Exif orientation tag value.
- gd.DestinationFormatRequired - destination image format required.
- gd.UnknownDestinationType - unknown destination type.
- gd.FileOpen - file opening error.
- gd.FileDoesNotExist - file does not exist.
- gd.FileWrite - file writing error.
- gd.SynchronousStreamAccess - a stream cannot be read or written synchronously.
- gd.OptionsRequired - options argument should be passed in.