Skip to content

Commit

Permalink
new identify parser
Browse files Browse the repository at this point in the history
properly handles nested output
more getter tests

closes aheckmann#20
  • Loading branch information
aheckmann committed Jan 6, 2012
1 parent 710ee0f commit 3304511
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 108 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ examples/imgs/*
!examples/imgs/original.png
!examples/imgs/original.gif
!examples/imgs/morpher.jpg
!examples/imgs/photo.JPG
*.swp
*.swo
Binary file added examples/imgs/photo.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function gm (source, height, color) {
* Augment the prototype.
*/

require("./lib/getters")(gm.prototype);
require("./lib/getters")(gm);
require("./lib/args")(gm.prototype);
require("./lib/drawing")(gm.prototype);
require("./lib/convenience")(gm.prototype);
Expand Down
211 changes: 122 additions & 89 deletions lib/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,123 +5,156 @@
* Extend proto.
*/

module.exports = function (proto) {
module.exports = function (gm) {

;['size', 'format', 'depth', 'color', 'res', 'filesize'].forEach(function (getter) {
var proto = gm.prototype;

proto[getter] = function (opts, callback) {
if (!callback) callback = opts, opts = {};

var self = this;
if (self.data[getter]) {
callback.call(self, null, self.data[getter]);
return self;
}
;['size', 'format', 'depth', 'color', 'res', 'filesize'].forEach(function (getter) {
proto[getter] = function (opts, callback) {
if (!callback) callback = opts, opts = {};

self.identify(opts, function (err, stdout, stderr, cmd) {
if (err) {
return callback.call(self, err, stdout, stderr, cmd);
var self = this;
if (self.data[getter]) {
callback.call(self, null, self.data[getter]);
return self;
}

callback.call(self, null, self.data[getter]);
});
self.identify(opts, function (err, stdout, stderr, cmd) {
if (err) {
return callback.call(self, err, stdout, stderr, cmd);
}

return self;
}
});
callback.call(self, null, self.data[getter]);
});

proto.identify = function identify (opts, callback) {
if (!callback) callback = opts, opts = {};

var self = this;

if (!callback) return self;

self.bufferStream = !! opts.bufferStream;
return self;
}
});

if (self._identifying) {
self._iq.push(callback);
return self;
}
proto.identify = function identify (opts, callback) {
if (!callback) callback = opts, opts = {};

if (Object.keys(self.data).length) {
callback.call(self, null, self.data);
return self;
}
var self = this;

self._iq = [callback];
self._identifying = true;
if (!callback) return self;

var args = ['identify', '-ping', '-verbose', self.sourceStream ? '-' : self.source];
self.bufferStream = !! opts.bufferStream;

self._exec("gm", args, function (err, stdout, stderr) {
if (err) {
return callback.call(self, err, stdout, stderr, cmd);
if (self._identifying) {
self._iq.push(callback);
return self;
}

stdout = (stdout||"").trim().replace(/\r\n|\r/g, "\n");
if (Object.keys(self.data).length) {
callback.call(self, null, self.data);
return self;
}

var parts = stdout.split("\n")
, len = parts.length
, rgx = /^( *)(.*)/
, data = self.data
, result
, keyval
, i = 0;
self._iq = [callback];
self._identifying = true;

var handle = {};
var args = ['identify', '-ping', '-verbose', self.sourceStream ? '-' : self.source];

handle.Geometry = function Geometry (val) {
var split = val.split("x");
data.size = {
width: parseInt(split[0], 10)
, height: parseInt(split[1], 10)
self._exec("gm", args, function (err, stdout, stderr) {
if (err) {
return callback.call(self, err, stdout, stderr, cmd);
}
};

handle.Format = function Format (val) {
data.format = val.split(" ")[0];
};
stdout = (stdout||"").trim().replace(/\r\n|\r/g, "\n");

var parts = stdout.split("\n");

// skip the first line (its just the filename)
parts.shift();

var len = parts.length
, rgx = /^( *)([^:]+): *(.*)$/
, out = { indent: {} }
, level = null
, lastkey
, i = 0
, res
, o

for (; i < len; ++i) {
res = rgx.exec(parts[i]);
if (!res) continue

var indent = res[1].length
, key = res[2] ? res[2].trim() : ''
, val = res[3] ? res[3].trim() : null

// first iteration?
if (!level) {
level = indent
o = out.root = out.indent[level] = self.data;
} else if (indent < level) {
// outdent
o = out.indent[indent];
} else if (indent > level) {
// dropping into a nested object
out.indent[level] = o;
// wierd format, key/val pair with nested children. discard the val
o = o[lastkey] = {};
}

level = indent;

if (val) {
o[key] = val;

if (key in helper) {
helper[key](o, val);
}
}

lastkey = key;
}

handle.Depth = function Depth (val) {
data.depth = parseInt(val, 10);
};
var idx = self._iq.length;

handle.Colors = function Colors (val) {
data.color = parseInt(val, 10);
};
while (idx--) {
self._iq[idx].call(self, null, self.data);
}

handle.Resolution = function Resolution (val) {
data.res = val;
};
self._identifying = false;
});

handle.Filesize = function Filesize (val) {
data.filesize = val;
};
return self;
}

for (; i < len; ++i) {
result = rgx.exec(parts[i]);
if (!result) continue;
if (2 !== result[1].length) continue;
/**
* helpers.
*/

var keyval = result[2].split(":");
if (keyval.length <= 1) continue;
var helper = gm.identifyHelpers = {};

if (keyval[0] in handle) {
handle[keyval[0]](keyval[1].trim());
} else {
data[keyval[0]] = keyval[1].trim();
}
helper.Geometry = function Geometry (o, val) {
var split = val.split("x");
o.size = {
width: parseInt(split[0], 10)
, height: parseInt(split[1], 10)
}
};

var idx = self._iq.length;
helper.Format = function Format (o, val) {
o.format = val.split(" ")[0];
};

while (idx--) {
self._iq[idx].call(self, null, self.data);
}
helper.Depth = function Depth (o, val) {
o.depth = parseInt(val, 10);
};

self._identifying = false;
});
helper.Colors = function Colors (o, val) {
o.color = parseInt(val, 10);
};

helper.Resolution = function Resolution (o, val) {
o.res = val;
};

helper.Filesize = function Filesize (o, val) {
o.filesize = val;
};

return self;
}}
}
15 changes: 11 additions & 4 deletions test/getterColor.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

module.exports = function (gm, dir, finish) {
var assert = require('assert')

module.exports = function (_, dir, finish, gm) {

gm(dir + '/blue.gif').color(function (err, color) {
if (err) return finish(err);

assert.equal(2, color)
assert.equal(this.data.Colors['0'], '( 0, 0,255)\t blue');
assert.equal(this.data.Colors['1'], '( 0, 0, 0)\t black');
finish();

gm
.color(function gettercolor (err) {
finish(err);
});
}
9 changes: 7 additions & 2 deletions test/getterDepth.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

var assert = require('assert')

module.exports = function (gm, dir, finish) {

gm
.depth(function getterdepth (err) {
finish(err);
.depth(function getterdepth (err, depth) {
if (err) return finish(err);
assert.equal(8, depth);
assert.equal('8 bits-per-pixel component', this.data.Depth);
finish();
});
}
8 changes: 6 additions & 2 deletions test/getterFilesize.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

var assert = require('assert')

module.exports = function (gm, dir, finish) {

gm
.filesize(function getterfilesize (err) {
finish(err);
.filesize(function getterfilesize (err, size) {
if (err) return finish(err);
assert.ok(size === this.data.Filesize, this.data.filesize)
finish();
});
}
11 changes: 9 additions & 2 deletions test/getterFormat.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

var assert = require('assert');

module.exports = function (gm, dir, finish) {

gm
.format(function getterformat (err) {
finish(err);
.format(function getterformat (err, format) {
if (err) return finish(err);

assert.equal(format, 'JPEG');
assert.equal(this.data.Format, 'JPEG (Joint Photographic Experts Group JFIF format)');

finish();
});
}
25 changes: 21 additions & 4 deletions test/getterIdentify.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

module.exports = function (gm, dir, finish) {
var assert = require('assert')

gm
.identify(function getteridentify (err) {
finish(err);
module.exports = function (_, dir, finish, gm) {

gm(dir + '/photo.JPG').identify(function (err) {
if (err) return finish(err);
console.error(this.data);

var d = this.data;

assert.equal(d.Orientation, 'TopLeft');
assert.equal(d['JPEG-Quality'], 96);
assert.equal(d['Channel Statistics'].Red['Standard Deviation'], '71.70 (0.2812)');

var ex = d['Profile-EXIF'];
assert.equal(ex.Make, 'Apple');
assert.equal(ex.Model, 'iPad 2');
assert.equal(ex['GPS Info'], 558);
assert.equal(ex['GPS Longitude'], '80/1,4970/100,0/1');
assert.equal(ex['GPS Time Stamp'], '15/1,23/1,945/1');

finish();
});
}
8 changes: 6 additions & 2 deletions test/getterRes.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@

// gm - Copyright Aaron Heckmann <[email protected]> (MIT Licensed)

var assert = require('assert')

module.exports = function (gm, dir, finish) {

gm
.res(function getterres (err) {
finish(err);
.res(function getterres (err, res) {
if (err) return finish(err);
assert.ok(res === this.data.Resolution, this.data.res)
finish();
});
}
Loading

0 comments on commit 3304511

Please sign in to comment.