UNPKG

3.52 kBJavaScriptView Raw
1// compare
2
3var exec = require('child_process').exec;
4var utils = require('./utils');
5
6/**
7 * Compare two images uses graphicsmagicks `compare` command.
8 *
9 * gm.compare(img1, img2, 0.4, function (err, equal, equality) {
10 * if (err) return handle(err);
11 * console.log('The images are equal: %s', equal);
12 * console.log('There equality was %d', equality);
13 * });
14 *
15 * @param {String} orig Path to an image.
16 * @param {String} compareTo Path to another image to compare to `orig`.
17 * @param {Number|Object} [options] Options object or the amount of difference to tolerate before failing - defaults to 0.4
18 * @param {Function} cb(err, Boolean, equality, rawOutput)
19 */
20
21module.exports = exports = function (proto) {
22 function compare(orig, compareTo, options, cb) {
23 orig = utils.escape(orig);
24 compareTo = utils.escape(compareTo);
25
26 var isImageMagick = this._options && this._options.imageMagick;
27 // compare binary for IM is `compare`, for GM it's `gm compare`
28 var bin = isImageMagick ? '' : 'gm ';
29 var execCmd = bin + 'compare -metric mse ' + orig + ' ' + compareTo;
30 var tolerance = 0.4
31 // outputting the diff image
32 if (typeof options === 'object') {
33 if (options.file) {
34 if (typeof options.file !== 'string') {
35 throw new TypeError('The path for the diff output is invalid');
36 }
37 // graphicsmagick defaults to red
38 var highlightColorOption = options.highlightColor
39 ? ' -highlight-color ' + options.highlightColor + ' '
40 : ' ';
41 var highlightStyleOption = options.highlightStyle
42 ? ' -highlight-style ' + options.highlightStyle + ' '
43 : ' ';
44 var diffFilename = utils.escape(options.file);
45 // For IM, filename is the last argument. For GM it's `-file <filename>`
46 var diffOpt = isImageMagick ? diffFilename : ('-file ' + diffFilename);
47 execCmd += highlightColorOption + highlightStyleOption + ' ' + diffOpt;
48 }
49
50 if (options.tolerance) {
51 if (typeof options.tolerance !== 'number') {
52 throw new TypeError('The tolerance value should be a number');
53 }
54 tolerance = options.tolerance;
55 }
56 } else {
57 // For ImageMagick diff file is required but we don't care about it, so null it out
58 isImageMagick && (execCmd += ' null:');
59
60 if (typeof options == 'function') {
61 cb = options; // tolerance value not provided, flip the cb place
62 } else {
63 tolerance = options
64 }
65 }
66
67 exec(execCmd, function (err, stdout, stderr) {
68 // ImageMagick returns err code 2 if err, 0 if similar, 1 if dissimilar
69 if (isImageMagick) {
70 if (!err) {
71 return cb(null, 0 <= tolerance, 0, stdout);
72 }
73 if (err.code === 1) {
74 err = null;
75 stdout = stderr;
76 }
77 }
78 if (err) {
79 return cb(err);
80 }
81 // Since ImageMagick similar gives err code 0 and no stdout, there's really no matching
82 // Otherwise, output format for IM is `12.00 (0.123)` and for GM it's `Total: 0.123`
83 var regex = isImageMagick ? /\((\d+\.?[\d\-\+e]*)\)/m : /Total: (\d+\.?\d*)/m;
84 var match = regex.exec(stdout);
85 if (!match) {
86 err = new Error('Unable to parse output.\nGot ' + stdout);
87 return cb(err);
88 }
89
90 var equality = parseFloat(match[1]);
91 cb(null, equality <= tolerance, equality, stdout);
92 });
93 }
94
95 if (proto) {
96 proto.compare = compare;
97 }
98 return compare;
99};
100