Skip to content

Instantly share code, notes, and snippets.

@kjunine
Created July 30, 2014 06:00
Show Gist options
  • Save kjunine/b32860fc5dcb47635996 to your computer and use it in GitHub Desktop.
Save kjunine/b32860fc5dcb47635996 to your computer and use it in GitHub Desktop.
Image Handling with gm & GraphicsMagic + ImageMagic
'use strict';
var fs = require('fs'),
path = require('path'),
exec = require('child_process').exec,
_ = require('lodash'),
Bluebird = require('bluebird'),
gm = require('gm');
var readImageInfo = function(filepath) {
var deferred = Bluebird.defer();
// NOTE identity is from imagemagick
// %m: format, %w: width, %h: height, %b: filesize in byte, %z: depth, %x: density
var command = 'identify -format "%m %w %h %b %z %x\\n" "' + filepath + '"';
exec(command, function(err, result) {
if (err) return deferred.reject(err);
var lines = result.split('\n');
lines.pop();
var infos = _.map(lines, function(line) {
var tokens = line.split(' ');
return {
format: tokens[0],
width: parseInt(tokens[1]),
height: parseInt(tokens[2]),
filesize: parseInt(tokens[3]),
depth: parseInt(tokens[4]),
density: parseFloat(tokens[5])
};
});
var info = infos[infos.length - 1];
info = {
filepath: filepath,
format: info.format,
width: _.max(infos, 'width').width,
height: _.max(infos, 'height').height,
filesize: info.filesize,
depth: info.depth,
density: info.density
};
deferred.resolve(info);
});
return deferred.promise;
};
var createFull = function(src, dest, options) {
var quality = options.quality || 75;
var maxWidth = options.maxWidth || 3000;
var maxHeight = options.maxHeight || maxWidth;
var format = options.format || 'JPEG';
var deferred = Bluebird.defer();
gm(src)
.quality(quality)
.resize(maxWidth, maxHeight, '>')
.setFormat(format)
.write(dest, function(err) {
if (err) return deferred.reject(err);
deferred.resolve(dest);
});
return deferred.promise;
};
var createThumbnail = function(src, dest, options) {
var quality = options.quality || 75;
var cropWidth = options.cropWidth || 1024;
var cropHeight = options.cropHeight || cropWidth;
var cropX = options.cropX || 0;
var cropY = options.cropY || 0;
var maxWidth = options.maxWidth || 128;
var maxHeight = options.maxHeight || maxWidth;
var format = options.format || 'JPEG';
var deferred = Bluebird.defer();
gm(src)
.quality(quality)
.crop(cropWidth, cropHeight, cropX, cropY)
.resize(maxWidth, maxHeight, '>')
.strip()
.setFormat(format)
.write(dest, function(err) {
if (err) return deferred.reject(err);
deferred.resolve(dest);
});
return deferred.promise;
};
var openStreams = function(original, options) {
var fullpath = original + '.full';
var thumpath = original + '.thum';
var quality = options.quality || 75;
var maxWidth = options.maxWidth || 3000;
var maxHeight = options.maxHeight || 3000;
var forceJpeg = options.forceJpeg || false;
var withThumbnail = options.withThumbnail || false;
var thumbnailResolution = options.thumbnailResolution || 128;
var thumbnailQuality = options.thumbnailQuality || quality;
var thumbnailForceJpeg = options.forceJpeg || forceJpeg;
return readImageInfo(original)
.then(function(info) {
var all = [
createFull(original, fullpath, {
quality: quality,
maxWidth: maxWidth,
maxHeight: maxHeight,
format: forceJpeg ? 'JPEG': info.format
})
.then(function(filepath) {
return readImageInfo(filepath);
})
];
if (withThumbnail) {
var width = info.width;
var height = info.height;
var cropSize = Math.min(width, height);
var cropX = cropSize < width ? (width - cropSize) / 2 : 0;
var cropY = cropSize < height ? (height - cropSize) / 2 : 0;
all.push(
createThumbnail(original, thumpath, {
quality: thumbnailQuality,
cropWidth: cropSize,
cropHeight: cropSize,
cropX: cropX,
cropY: cropY,
maxWidth: thumbnailResolution,
maxHeight: thumbnailResolution,
format: thumbnailForceJpeg ? 'JPEG': info.format
})
.then(function(filepath) {
return readImageInfo(filepath);
})
);
}
return Bluebird.all(all);
})
.spread(function(fullinfo, thuminfo) {
var result = {
full: {
info: fullinfo,
stream: fs.createReadStream(fullpath)
},
clear: function(includeOriginal) {
if (includeOriginal) fs.unlink(original);
fs.unlink(fullpath);
fs.unlink(thumpath);
}
};
if (thuminfo) {
result.thumbnail = {
info: thuminfo,
stream: fs.createReadStream(thumpath)
};
}
return result;
});
};
var traverse = function(directory, callback) {
var dir = path.join(__dirname, directory);
fs.readdirSync(dir)
.forEach(function (file) {
if (/\.(gif|png|jpg|jpeg)$/.test(file)) {
callback(path.join(dir, file));
}
});
};
var rename = function(file, keyword) {
var name = path.basename(file);
return path.join(__dirname, keyword, name);
};
var handle = function(file) {
openStreams(file, {
forceJpeg: false,
withThumbnail: true,
thumbnailResolution: 128
}).then(function(result) {
if (result.full) {
console.log('info:', result.full.info);
result.full.stream.pipe(fs.createWriteStream(rename(file, 'fulls')));
}
if (result.thumbnail) {
console.log('info:', result.thumbnail.info);
result.thumbnail.stream.pipe(fs.createWriteStream(rename(file, 'thumbnails')));
}
result.clear();
}).catch(function(err) {
console.error('error for file:', file, err);
});
};
traverse('images', handle);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment