UNPKG

26.3 kBMarkdownView Raw
1
2# gm [![Build Status](https://travis-ci.org/aheckmann/gm.png?branch=master)](https://travis-ci.org/aheckmann/gm) [![NPM Version](https://img.shields.io/npm/v/gm.svg?style=flat)](https://www.npmjs.org/package/gm)
3
4GraphicsMagick and ImageMagick for node
5
6## Bug Reports
7
8When reporting bugs please include the version of graphicsmagick/imagemagick you're using (gm -version/convert -version) as well as the version of this module and copies of any images you're having problems with.
9
10## Getting started
11First download and install [GraphicsMagick](http://www.graphicsmagick.org/) or [ImageMagick](http://www.imagemagick.org/). In Mac OS X, you can simply use [Homebrew](http://mxcl.github.io/homebrew/) and do:
12
13 brew install imagemagick
14 brew install graphicsmagick
15
16If you want WebP support with ImageMagick, you must add the WebP option:
17
18 brew install imagemagick --with-webp
19
20then either use npm:
21
22 npm install gm
23
24or clone the repo:
25
26 git clone git://github.com/aheckmann/gm.git
27
28
29## Use ImageMagick instead of gm
30
31Subclass `gm` to enable ImageMagick
32
33```js
34var fs = require('fs')
35 , gm = require('gm').subClass({imageMagick: true});
36
37// resize and remove EXIF profile data
38gm('/path/to/my/img.jpg')
39.resize(240, 240)
40...
41```
42
43
44## Basic Usage
45
46```js
47var fs = require('fs')
48 , gm = require('gm');
49
50// resize and remove EXIF profile data
51gm('/path/to/my/img.jpg')
52.resize(240, 240)
53.noProfile()
54.write('/path/to/resize.png', function (err) {
55 if (!err) console.log('done');
56});
57
58// some files would not be resized appropriately
59// http://stackoverflow.com/questions/5870466/imagemagick-incorrect-dimensions
60// you have two options:
61// use the '!' flag to ignore aspect ratio
62gm('/path/to/my/img.jpg')
63.resize(240, 240, '!')
64.write('/path/to/resize.png', function (err) {
65 if (!err) console.log('done');
66});
67
68// use the .resizeExact with only width and/or height arguments
69gm('/path/to/my/img.jpg')
70.resizeExact(240, 240)
71.write('/path/to/resize.png', function (err) {
72 if (!err) console.log('done');
73});
74
75// obtain the size of an image
76gm('/path/to/my/img.jpg')
77.size(function (err, size) {
78 if (!err)
79 console.log(size.width > size.height ? 'wider' : 'taller than you');
80});
81
82// output all available image properties
83gm('/path/to/img.png')
84.identify(function (err, data) {
85 if (!err) console.log(data)
86});
87
88// pull out the first frame of an animated gif and save as png
89gm('/path/to/animated.gif[0]')
90.write('/path/to/firstframe.png', function (err) {
91 if (err) console.log('aaw, shucks');
92});
93
94// auto-orient an image
95gm('/path/to/img.jpg')
96.autoOrient()
97.write('/path/to/oriented.jpg', function (err) {
98 if (err) ...
99})
100
101// crazytown
102gm('/path/to/my/img.jpg')
103.flip()
104.magnify()
105.rotate('green', 45)
106.blur(7, 3)
107.crop(300, 300, 150, 130)
108.edge(3)
109.write('/path/to/crazy.jpg', function (err) {
110 if (!err) console.log('crazytown has arrived');
111})
112
113// annotate an image
114gm('/path/to/my/img.jpg')
115.stroke("#ffffff")
116.drawCircle(10, 10, 20, 10)
117.font("Helvetica.ttf", 12)
118.drawText(30, 20, "GMagick!")
119.write("/path/to/drawing.png", function (err) {
120 if (!err) console.log('done');
121});
122
123// creating an image
124gm(200, 400, "#ddff99f3")
125.drawText(10, 50, "from scratch")
126.write("/path/to/brandNewImg.jpg", function (err) {
127 // ...
128});
129```
130
131## Streams
132
133```js
134// passing a stream
135var readStream = fs.createReadStream('/path/to/my/img.jpg');
136gm(readStream, 'img.jpg')
137.write('/path/to/reformat.png', function (err) {
138 if (!err) console.log('done');
139});
140
141
142// passing a downloadable image by url
143
144var request = require('request');
145var url = "www.abc.com/pic.jpg"
146
147gm(request(url))
148.write('/path/to/reformat.png', function (err) {
149 if (!err) console.log('done');
150});
151
152
153// can also stream output to a ReadableStream
154// (can be piped to a local file or remote server)
155gm('/path/to/my/img.jpg')
156.resize('200', '200')
157.stream(function (err, stdout, stderr) {
158 var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
159 stdout.pipe(writeStream);
160});
161
162// without a callback, .stream() returns a stream
163// this is just a convenience wrapper for above.
164var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
165gm('/path/to/my/img.jpg')
166.resize('200', '200')
167.stream()
168.pipe(writeStream);
169
170// pass a format or filename to stream() and
171// gm will provide image data in that format
172gm('/path/to/my/img.jpg')
173.stream('png', function (err, stdout, stderr) {
174 var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
175 stdout.pipe(writeStream);
176});
177
178// or without the callback
179var writeStream = fs.createWriteStream('/path/to/my/reformatted.png');
180gm('/path/to/my/img.jpg')
181.stream('png')
182.pipe(writeStream);
183
184// combine the two for true streaming image processing
185var readStream = fs.createReadStream('/path/to/my/img.jpg');
186gm(readStream)
187.resize('200', '200')
188.stream(function (err, stdout, stderr) {
189 var writeStream = fs.createWriteStream('/path/to/my/resized.jpg');
190 stdout.pipe(writeStream);
191});
192
193// GOTCHA:
194// when working with input streams and any 'identify'
195// operation (size, format, etc), you must pass "{bufferStream: true}" if
196// you also need to convert (write() or stream()) the image afterwards
197// NOTE: this buffers the readStream in memory!
198var readStream = fs.createReadStream('/path/to/my/img.jpg');
199gm(readStream)
200.size({bufferStream: true}, function(err, size) {
201 this.resize(size.width / 2, size.height / 2)
202 this.write('/path/to/resized.jpg', function (err) {
203 if (!err) console.log('done');
204 });
205});
206
207```
208
209## Buffers
210
211```js
212// A buffer can be passed instead of a filepath as well
213var buf = require('fs').readFileSync('/path/to/image.jpg');
214
215gm(buf, 'image.jpg')
216.noise('laplacian')
217.write('/path/to/out.jpg', function (err) {
218 if (err) return handle(err);
219 console.log('Created an image from a Buffer!');
220});
221
222/*
223A buffer can also be returned instead of a stream
224The first argument to toBuffer is optional, it specifies the image format
225*/
226gm('img.jpg')
227.resize(100, 100)
228.toBuffer('PNG',function (err, buffer) {
229 if (err) return handle(err);
230 console.log('done!');
231})
232```
233
234## Custom Arguments
235
236If `gm` does not supply you with a method you need or does not work as you'd like, you can simply use `gm().in()` or `gm().out()` to set your own arguments.
237
238- `gm().command()` - Custom command such as `identify` or `convert`
239- `gm().in()` - Custom input arguments
240- `gm().out()` - Custom output arguments
241
242The command will be formatted in the following order:
243
2441. `command` - ie `convert`
2452. `in` - the input arguments
2463. `source` - stdin or an image file
2474. `out` - the output arguments
2485. `output` - stdout or the image file to write to
249
250For example, suppose you want the following command:
251
252```bash
253gm "convert" "label:Offline" "PNG:-"
254```
255
256However, using `gm().label()` may not work as intended for you:
257
258```js
259gm()
260.label('Offline')
261.stream();
262```
263
264would yield:
265
266```bash
267gm "convert" "-label" "\"Offline\"" "PNG:-"
268```
269
270Instead, you can use `gm().out()`:
271
272```js
273gm()
274.out('label:Offline')
275.stream();
276```
277
278which correctly yields:
279
280```bash
281gm "convert" "label:Offline" "PNG:-"
282```
283
284### Custom Identify Format String
285
286When identifying an image, you may want to use a custom formatting string instead of using `-verbose`, which is quite slow.
287You can use your own [formatting string](http://www.imagemagick.org/script/escape.php) when using `gm().identify(format, callback)`.
288For example,
289
290```js
291gm('img.png').format(function (err, format) {
292
293})
294
295// is equivalent to
296
297gm('img.png').identify('%m', function (err, format) {
298
299})
300```
301
302since `%m` is the format option for getting the image file format.
303
304## Platform differences
305
306Please document and refer to any [platform or ImageMagick/GraphicsMagick issues/differences here](https://github.com/aheckmann/gm/wiki/GraphicsMagick-and-ImageMagick-versions).
307
308## Examples:
309
310 Check out the [examples](http://github.com/aheckmann/gm/tree/master/examples/) directory to play around.
311 Also take a look at the [extending gm](http://wiki.github.com/aheckmann/gm/extending-gm)
312 page to see how to customize gm to your own needs.
313
314## Constructor:
315
316 There are a few ways you can use the `gm` image constructor.
317
318 - 1) `gm(path)` When you pass a string as the first argument it is interpreted as the path to an image you intend to manipulate.
319 - 2) `gm(stream || buffer, [filename])` You may also pass a ReadableStream or Buffer as the first argument, with an optional file name for format inference.
320 - 3) `gm(width, height, [color])` When you pass two integer arguments, gm will create a new image on the fly with the provided dimensions and an optional background color. And you can still chain just like you do with pre-existing images too. See [here](http://github.com/aheckmann/gm/blob/master/examples/new.js) for an example.
321
322The links below refer to an older version of gm but everything should still work, if anyone feels like updating them please make a PR
323
324## Methods
325
326 - getters
327 - [size](http://aheckmann.github.com/gm/docs.html#getters) - returns the size (WxH) of the image
328 - [orientation](http://aheckmann.github.com/gm/docs.html#getters) - returns the EXIF orientation of the image
329 - [format](http://aheckmann.github.com/gm/docs.html#getters) - returns the image format (gif, jpeg, png, etc)
330 - [depth](http://aheckmann.github.com/gm/docs.html#getters) - returns the image color depth
331 - [color](http://aheckmann.github.com/gm/docs.html#getters) - returns the number of colors
332 - [res](http://aheckmann.github.com/gm/docs.html#getters) - returns the image resolution
333 - [filesize](http://aheckmann.github.com/gm/docs.html#getters) - returns image filesize
334 - [identify](http://aheckmann.github.com/gm/docs.html#getters) - returns all image data available. Takes an optional format string.
335
336 - manipulation
337 - [adjoin](http://aheckmann.github.com/gm/docs.html#adjoin)
338 - [affine](http://aheckmann.github.com/gm/docs.html#affine)
339 - [antialias](http://aheckmann.github.com/gm/docs.html#antialias)
340 - [append](http://aheckmann.github.com/gm/docs.html#append)
341 - [authenticate](http://aheckmann.github.com/gm/docs.html#authenticate)
342 - [autoOrient](http://aheckmann.github.com/gm/docs.html#autoOrient)
343 - [average](http://aheckmann.github.com/gm/docs.html#average)
344 - [backdrop](http://aheckmann.github.com/gm/docs.html#backdrop)
345 - [bitdepth](http://aheckmann.github.com/gm/docs.html#bitdepth)
346 - [blackThreshold](http://aheckmann.github.com/gm/docs.html#blackThreshold)
347 - [bluePrimary](http://aheckmann.github.com/gm/docs.html#bluePrimary)
348 - [blur](http://aheckmann.github.com/gm/docs.html#blur)
349 - [border](http://aheckmann.github.com/gm/docs.html#border)
350 - [borderColor](http://aheckmann.github.com/gm/docs.html#borderColor)
351 - [box](http://aheckmann.github.com/gm/docs.html#box)
352 - [channel](http://aheckmann.github.com/gm/docs.html#channel)
353 - [charcoal](http://aheckmann.github.com/gm/docs.html#charcoal)
354 - [chop](http://aheckmann.github.com/gm/docs.html#chop)
355 - [clip](http://aheckmann.github.com/gm/docs.html#clip)
356 - [coalesce](http://aheckmann.github.com/gm/docs.html#coalesce)
357 - [colors](http://aheckmann.github.com/gm/docs.html#colors)
358 - [colorize](http://aheckmann.github.com/gm/docs.html#colorize)
359 - [colorMap](http://aheckmann.github.com/gm/docs.html#colorMap)
360 - [colorspace](http://aheckmann.github.com/gm/docs.html#colorspace)
361 - [comment](http://aheckmann.github.com/gm/docs.html#comment)
362 - [compose](http://aheckmann.github.com/gm/docs.html#compose)
363 - [compress](http://aheckmann.github.com/gm/docs.html#compress)
364 - [contrast](http://aheckmann.github.com/gm/docs.html#contrast)
365 - [convolve](http://aheckmann.github.com/gm/docs.html#convolve)
366 - [createDirectories](http://aheckmann.github.com/gm/docs.html#createDirectories)
367 - [crop](http://aheckmann.github.com/gm/docs.html#crop)
368 - [cycle](http://aheckmann.github.com/gm/docs.html#cycle)
369 - [deconstruct](http://aheckmann.github.com/gm/docs.html#deconstruct)
370 - [delay](http://aheckmann.github.com/gm/docs.html#delay)
371 - [define](http://aheckmann.github.com/gm/docs.html#define)
372 - [density](http://aheckmann.github.com/gm/docs.html#density)
373 - [despeckle](http://aheckmann.github.com/gm/docs.html#despeckle)
374 - [dither](http://aheckmann.github.com/gm/docs.html#dither)
375 - [displace](http://aheckmann.github.com/gm/docs.html#dither)
376 - [display](http://aheckmann.github.com/gm/docs.html#display)
377 - [dispose](http://aheckmann.github.com/gm/docs.html#dispose)
378 - [dissolve](http://aheckmann.github.com/gm/docs.html#dissolve)
379 - [edge](http://aheckmann.github.com/gm/docs.html#edge)
380 - [emboss](http://aheckmann.github.com/gm/docs.html#emboss)
381 - [encoding](http://aheckmann.github.com/gm/docs.html#encoding)
382 - [enhance](http://aheckmann.github.com/gm/docs.html#enhance)
383 - [endian](http://aheckmann.github.com/gm/docs.html#endian)
384 - [equalize](http://aheckmann.github.com/gm/docs.html#equalize)
385 - [extent](http://aheckmann.github.com/gm/docs.html#extent)
386 - [file](http://aheckmann.github.com/gm/docs.html#file)
387 - [filter](http://aheckmann.github.com/gm/docs.html#filter)
388 - [flatten](http://aheckmann.github.com/gm/docs.html#flatten)
389 - [flip](http://aheckmann.github.com/gm/docs.html#flip)
390 - [flop](http://aheckmann.github.com/gm/docs.html#flop)
391 - [foreground](http://aheckmann.github.com/gm/docs.html#foreground)
392 - [frame](http://aheckmann.github.com/gm/docs.html#frame)
393 - [fuzz](http://aheckmann.github.com/gm/docs.html#fuzz)
394 - [gamma](http://aheckmann.github.com/gm/docs.html#gamma)
395 - [gaussian](http://aheckmann.github.com/gm/docs.html#gaussian)
396 - [geometry](http://aheckmann.github.com/gm/docs.html#geometry)
397 - [gravity](http://aheckmann.github.com/gm/docs.html#gravity)
398 - [greenPrimary](http://aheckmann.github.com/gm/docs.html#greenPrimary)
399 - [highlightColor](http://aheckmann.github.com/gm/docs.html#highlightColor)
400 - [highlightStyle](http://aheckmann.github.com/gm/docs.html#highlightStyle)
401 - [iconGeometry](http://aheckmann.github.com/gm/docs.html#iconGeometry)
402 - [implode](http://aheckmann.github.com/gm/docs.html#implode)
403 - [intent](http://aheckmann.github.com/gm/docs.html#intent)
404 - [interlace](http://aheckmann.github.com/gm/docs.html#interlace)
405 - [label](http://aheckmann.github.com/gm/docs.html#label)
406 - [lat](http://aheckmann.github.com/gm/docs.html#lat)
407 - [level](http://aheckmann.github.com/gm/docs.html#level)
408 - [list](http://aheckmann.github.com/gm/docs.html#list)
409 - [limit](http://aheckmann.github.com/gm/docs.html#limit)
410 - [log](http://aheckmann.github.com/gm/docs.html#log)
411 - [loop](http://aheckmann.github.com/gm/docs.html#loop)
412 - [lower](http://aheckmann.github.com/gm/docs.html#lower)
413 - [magnify](http://aheckmann.github.com/gm/docs.html#magnify)
414 - [map](http://aheckmann.github.com/gm/docs.html#map)
415 - [matte](http://aheckmann.github.com/gm/docs.html#matte)
416 - [matteColor](http://aheckmann.github.com/gm/docs.html#matteColor)
417 - [mask](http://aheckmann.github.com/gm/docs.html#mask)
418 - [maximumError](http://aheckmann.github.com/gm/docs.html#maximumError)
419 - [median](http://aheckmann.github.com/gm/docs.html#median)
420 - [minify](http://aheckmann.github.com/gm/docs.html#minify)
421 - [mode](http://aheckmann.github.com/gm/docs.html#mode)
422 - [modulate](http://aheckmann.github.com/gm/docs.html#modulate)
423 - [monitor](http://aheckmann.github.com/gm/docs.html#monitor)
424 - [monochrome](http://aheckmann.github.com/gm/docs.html#monochrome)
425 - [morph](http://aheckmann.github.com/gm/docs.html#morph)
426 - [mosaic](http://aheckmann.github.com/gm/docs.html#mosaic)
427 - [motionBlur](http://aheckmann.github.com/gm/docs.html#motionBlur)
428 - [name](http://aheckmann.github.com/gm/docs.html#name)
429 - [negative](http://aheckmann.github.com/gm/docs.html#negative)
430 - [noise](http://aheckmann.github.com/gm/docs.html#noise)
431 - [noop](http://aheckmann.github.com/gm/docs.html#noop)
432 - [normalize](http://aheckmann.github.com/gm/docs.html#normalize)
433 - [noProfile](http://aheckmann.github.com/gm/docs.html#profile)
434 - [opaque](http://aheckmann.github.com/gm/docs.html#opaque)
435 - [operator](http://aheckmann.github.com/gm/docs.html#operator)
436 - [orderedDither](http://aheckmann.github.com/gm/docs.html#orderedDither)
437 - [outputDirectory](http://aheckmann.github.com/gm/docs.html#outputDirectory)
438 - [paint](http://aheckmann.github.com/gm/docs.html#paint)
439 - [page](http://aheckmann.github.com/gm/docs.html#page)
440 - [pause](http://aheckmann.github.com/gm/docs.html#pause)
441 - [pen](http://aheckmann.github.com/gm/docs.html#pen)
442 - [ping](http://aheckmann.github.com/gm/docs.html#ping)
443 - [pointSize](http://aheckmann.github.com/gm/docs.html#pointSize)
444 - [preview](http://aheckmann.github.com/gm/docs.html#preview)
445 - [process](http://aheckmann.github.com/gm/docs.html#process)
446 - [profile](http://aheckmann.github.com/gm/docs.html#profile)
447 - [progress](http://aheckmann.github.com/gm/docs.html#progress)
448 - [quality](http://aheckmann.github.com/gm/docs.html#quality)
449 - [raise](http://aheckmann.github.com/gm/docs.html#raise)
450 - [rawSize](http://aheckmann.github.com/gm/docs.html#rawSize)
451 - [randomThreshold](http://aheckmann.github.com/gm/docs.html#randomThreshold)
452 - [recolor](http://aheckmann.github.com/gm/docs.html#recolor)
453 - [redPrimary](http://aheckmann.github.com/gm/docs.html#redPrimary)
454 - [region](http://aheckmann.github.com/gm/docs.html#region)
455 - [remote](http://aheckmann.github.com/gm/docs.html#remote)
456 - [render](http://aheckmann.github.com/gm/docs.html#render)
457 - [repage](http://aheckmann.github.com/gm/docs.html#repage)
458 - [resample](http://aheckmann.github.com/gm/docs.html#resample)
459 - [resize](http://aheckmann.github.com/gm/docs.html#resize)
460 - [roll](http://aheckmann.github.com/gm/docs.html#roll)
461 - [rotate](http://aheckmann.github.com/gm/docs.html#rotate)
462 - [sample](http://aheckmann.github.com/gm/docs.html#sample)
463 - [samplingFactor](http://aheckmann.github.com/gm/docs.html#samplingFactor)
464 - [scale](http://aheckmann.github.com/gm/docs.html#scale)
465 - [scene](http://aheckmann.github.com/gm/docs.html#scene)
466 - [scenes](http://aheckmann.github.com/gm/docs.html#scenes)
467 - [screen](http://aheckmann.github.com/gm/docs.html#screen)
468 - [segment](http://aheckmann.github.com/gm/docs.html#segment)
469 - [sepia](http://aheckmann.github.com/gm/docs.html#sepia)
470 - [set](http://aheckmann.github.com/gm/docs.html#set)
471 - [setFormat](http://aheckmann.github.com/gm/docs.html#setformat)
472 - [shade](http://aheckmann.github.com/gm/docs.html#shade)
473 - [shadow](http://aheckmann.github.com/gm/docs.html#shadow)
474 - [sharedMemory](http://aheckmann.github.com/gm/docs.html#sharedMemory)
475 - [sharpen](http://aheckmann.github.com/gm/docs.html#sharpen)
476 - [shave](http://aheckmann.github.com/gm/docs.html#shave)
477 - [shear](http://aheckmann.github.com/gm/docs.html#shear)
478 - [silent](http://aheckmann.github.com/gm/docs.html#silent)
479 - [solarize](http://aheckmann.github.com/gm/docs.html#solarize)
480 - [snaps](http://aheckmann.github.com/gm/docs.html#snaps)
481 - [stegano](http://aheckmann.github.com/gm/docs.html#stegano)
482 - [stereo](http://aheckmann.github.com/gm/docs.html#stereo)
483 - [strip](http://aheckmann.github.com/gm/docs.html#strip) _imagemagick only_
484 - [spread](http://aheckmann.github.com/gm/docs.html#spread)
485 - [swirl](http://aheckmann.github.com/gm/docs.html#swirl)
486 - [textFont](http://aheckmann.github.com/gm/docs.html#textFont)
487 - [texture](http://aheckmann.github.com/gm/docs.html#texture)
488 - [threshold](http://aheckmann.github.com/gm/docs.html#threshold)
489 - [thumb](http://aheckmann.github.com/gm/docs.html#thumb)
490 - [tile](http://aheckmann.github.com/gm/docs.html#tile)
491 - [transform](http://aheckmann.github.com/gm/docs.html#transform)
492 - [transparent](http://aheckmann.github.com/gm/docs.html#transparent)
493 - [treeDepth](http://aheckmann.github.com/gm/docs.html#treeDepth)
494 - [trim](http://aheckmann.github.com/gm/docs.html#trim)
495 - [type](http://aheckmann.github.com/gm/docs.html#type)
496 - [update](http://aheckmann.github.com/gm/docs.html#update)
497 - [units](http://aheckmann.github.com/gm/docs.html#units)
498 - [unsharp](http://aheckmann.github.com/gm/docs.html#unsharp)
499 - [usePixmap](http://aheckmann.github.com/gm/docs.html#usePixmap)
500 - [view](http://aheckmann.github.com/gm/docs.html#view)
501 - [virtualPixel](http://aheckmann.github.com/gm/docs.html#virtualPixel)
502 - [visual](http://aheckmann.github.com/gm/docs.html#visual)
503 - [watermark](http://aheckmann.github.com/gm/docs.html#watermark)
504 - [wave](http://aheckmann.github.com/gm/docs.html#wave)
505 - [whitePoint](http://aheckmann.github.com/gm/docs.html#whitePoint)
506 - [whiteThreshold](http://aheckmann.github.com/gm/docs.html#whiteThreshold)
507 - [window](http://aheckmann.github.com/gm/docs.html#window)
508 - [windowGroup](http://aheckmann.github.com/gm/docs.html#windowGroup)
509
510 - drawing primitives
511 - [draw](http://aheckmann.github.com/gm/docs.html#draw)
512 - [drawArc](http://aheckmann.github.com/gm/docs.html#drawArc)
513 - [drawBezier](http://aheckmann.github.com/gm/docs.html#drawBezier)
514 - [drawCircle](http://aheckmann.github.com/gm/docs.html#drawCircle)
515 - [drawEllipse](http://aheckmann.github.com/gm/docs.html#drawEllipse)
516 - [drawLine](http://aheckmann.github.com/gm/docs.html#drawLine)
517 - [drawPoint](http://aheckmann.github.com/gm/docs.html#drawPoint)
518 - [drawPolygon](http://aheckmann.github.com/gm/docs.html#drawPolygon)
519 - [drawPolyline](http://aheckmann.github.com/gm/docs.html#drawPolyline)
520 - [drawRectangle](http://aheckmann.github.com/gm/docs.html#drawRectangle)
521 - [drawText](http://aheckmann.github.com/gm/docs.html#drawText)
522 - [fill](http://aheckmann.github.com/gm/docs.html#fill)
523 - [font](http://aheckmann.github.com/gm/docs.html#font)
524 - [fontSize](http://aheckmann.github.com/gm/docs.html#fontSize)
525 - [stroke](http://aheckmann.github.com/gm/docs.html#stroke)
526 - [strokeWidth](http://aheckmann.github.com/gm/docs.html#strokeWidth)
527 - [setDraw](http://aheckmann.github.com/gm/docs.html#setDraw)
528
529 - image output
530 - **write** - writes the processed image data to the specified filename
531 - **stream** - provides a `ReadableStream` with the processed image data
532 - **toBuffer** - returns the image as a `Buffer` instead of a stream
533
534##compare
535
536Graphicsmagicks `compare` command is exposed through `gm.compare()`. This allows us to determine if two images can be considered "equal".
537
538Currently `gm.compare` only accepts file paths.
539
540 gm.compare(path1, path2 [, options], callback)
541
542```js
543gm.compare('/path/to/image1.jpg', '/path/to/another.png', function (err, isEqual, equality, raw, path1, path2) {
544 if (err) return handle(err);
545
546 // if the images were considered equal, `isEqual` will be true, otherwise, false.
547 console.log('The images were equal: %s', isEqual);
548
549 // to see the total equality returned by graphicsmagick we can inspect the `equality` argument.
550 console.log('Actual equality: %d', equality);
551
552 // inspect the raw output
553 console.log(raw);
554
555 // print file paths
556 console.log(path1, path2);
557})
558```
559
560You may wish to pass a custom tolerance threshold to increase or decrease the default level of `0.4`.
561
562
563```js
564gm.compare('/path/to/image1.jpg', '/path/to/another.png', 1.2, function (err, isEqual) {
565 ...
566})
567```
568
569To output a diff image, pass a configuration object to define the diff options and tolerance.
570
571
572```js
573var options = {
574 file: '/path/to/diff.png',
575 highlightColor: 'yellow',
576 tolerance: 0.02
577}
578gm.compare('/path/to/image1.jpg', '/path/to/another.png', options, function (err, isEqual, equality, raw) {
579 ...
580})
581```
582
583##composite
584
585GraphicsMagick supports compositing one image on top of another. This is exposed through `gm.composite()`. Its first argument is an image path with the changes to the base image, and an optional mask image.
586
587Currently, `gm.composite()` only accepts file paths.
588
589 gm.composite(other [, mask])
590
591```js
592gm('/path/to/image.jpg')
593.composite('/path/to/second_image.jpg')
594.geometry('+100+150')
595.write('/path/to/composite.png', function(err) {
596 if(!err) console.log("Written composite image.");
597});
598```
599
600##montage
601
602GraphicsMagick supports montage for combining images side by side. This is exposed through `gm.montage()`. Its only argument is an image path with the changes to the base image.
603
604Currently, `gm.montage()` only accepts file paths.
605
606 gm.montage(other)
607
608```js
609gm('/path/to/image.jpg')
610.montage('/path/to/second_image.jpg')
611.geometry('+100+150')
612.write('/path/to/montage.png', function(err) {
613 if(!err) console.log("Written montage image.");
614});
615```
616
617## Contributors
618[https://github.com/aheckmann/gm/contributors](https://github.com/aheckmann/gm/contributors)
619
620## Inspiration
621http://github.com/quiiver/magickal-node
622
623## Plugins
624[https://github.com/aheckmann/gm/wiki](https://github.com/aheckmann/gm/wiki)
625
626## License
627
628(The MIT License)
629
630Copyright (c) 2010 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
631
632Permission is hereby granted, free of charge, to any person obtaining
633a copy of this software and associated documentation files (the
634'Software'), to deal in the Software without restriction, including
635without limitation the rights to use, copy, modify, merge, publish,
636distribute, sublicense, and/or sell copies of the Software, and to
637permit persons to whom the Software is furnished to do so, subject to
638the following conditions:
639
640The above copyright notice and this permission notice shall be
641included in all copies or substantial portions of the Software.
642
643THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
644EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
645MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
646IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
647CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
648TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
649SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.