codingpains/oenyi

View on GitHub
lib/oenyi.js

Summary

Maintainability
A
2 hrs
Test Coverage
var gm = require('gm').subClass({ imageMagick: true });
var nimble = require('nimble');
var deepcopy = require('deepcopy');
var resizer = require('./resizer');
var mockimg = require('./mockimg');
var errors = require('./errors');

var CompressionError = errors.CompressionError;

var Oenyi = function Oenyi(fileName) {
  'use strict';
  return this.init.call(this, fileName);
};

// Private methods;
var doResize;
var doConvertToJPG;
var doCompress;

Oenyi.prototype._queue = null;
Oenyi.prototype._image = null;
Oenyi.prototype._format = null;
Oenyi.prototype._size = null;
Oenyi.prototype._calc = null;

Oenyi.prototype.init = function(fileName) {
  'use strict';
  this._queue = [];
  this._calc = {};

  if (!fileName || fileName === '') {
    this._image = mockimg(fileName);
  } else {
    this._image = gm(fileName);
  }

  return this;
};

doResize = function(params, fn) {
  'use strict';
  var destiny = {width: params.width, height: params.height};
  var oenyi = this;
  var calc;
  var crop;
  var imageFits;

  this._getSize(function(error, original) {
    if (error) return fn(error);

    switch (params.method) {
      case 'cover':
        calc = resizer.resizeByCover(original, destiny);
        if (calc.crop) {
          crop = calc.crop;
          oenyi._image.crop(crop.width, crop.height, crop.x, crop.y);
        }
        break;
      case 'fit':
        imageFits = original.width === destiny.width &&
          original.height === destiny.height;

        calc = resizer.resizeByFitOrContain(original, destiny, imageFits);
        break;
      case 'contain':
        imageFits = original.width <= destiny.width &&
          original.height <= destiny.height;
        calc = resizer.resizeByFitOrContain(original, destiny, imageFits);
        break;
    }

    oenyi._image.resize(calc.resize.width, calc.resize.height);
    oenyi._calc = calc;

    fn(null, oenyi._image);
  });
};

doConvertToJPG = function(fn) {
  'use strict';
  var oenyi = this;
  oenyi._calc.convert = {toFormat: 'jpg'};

  oenyi._getFormat(function(err, format) {
    if (err) return fn(err);

    format = format.toLowerCase();
    if (format === 'jpg') return fn(null, oenyi._image);

    if (format === 'gif') {
      oenyi._image
        .scene(1)
        .coalesce();

      oenyi._calc.convert.fromFormat = 'gif';
      oenyi._calc.convert.scene = 0;
      oenyi._calc.convert.coalesce = true;
    }

    if (format === 'png') {
      oenyi._image.flatten();
      oenyi._calc.convert.fromFormat = 'png';
      oenyi._calc.convert.flatten = true;
    }

    fn(null, oenyi._image);
  });
};

doCompress = function(params, fn) {
  'use strict';
  var formats = ['jpg', 'jpeg', 'png'];
  var oenyi = this;
  this._getFormat(function(error, format) {
    if (error) return fn(error);
    format = format.toLowerCase();

    if (formats.indexOf(format) < 0) {
      return fn(new CompressionError('unsupported format.'));
    }

    oenyi._image.quality(params.quality);
    oenyi._calc.compress = {quality: params.quality};

    fn(null, oenyi._image);
  });
};

Oenyi.prototype._getSize = function(fn) {
  'use strict';
  var oenyi = this;
  if (oenyi._size) return fn(null, oenyi._size);

  oenyi._image.size(function(error, size) {
    if (error) return fn(error);

    oenyi._size = {width: size.width, height: size.height};
    fn(null, oenyi._size);
  });
};

Oenyi.prototype._getFormat = function(fn) {
  'use strict';
  var oenyi = this;
  if (oenyi._format) return fn(null, oenyi._format);

  oenyi._image.format(function(error, format) {
    if (error) return fn(error);

    oenyi._format = format;
    fn(null, format);
  });
};

Oenyi.prototype._enqueue = function(process, args) {
  'use strict';
  var oenyi = this;
  if (!args) {
    args = [];
  }

  var wrapperFunction = function(fn) {
    args.push(fn);
    process.apply(oenyi, args);
  };

  this._queue.push(wrapperFunction);

  return this;
};

Oenyi.prototype.exec = function(fn) {
  'use strict';
  var oenyi = this;
  var calc;

  this._getFormat(function(error) {
    if (error) return fn(error);

    nimble.series(oenyi._queue, function(error, res) {
      oenyi._queue = [];
      if (error) return fn(error);

      calc = deepcopy(oenyi._calc);
      oenyi._calc = {};

      res.pop()
        .toBuffer(oenyi._format, function(error, buff) {
          fn(error, buff, calc);
        });
    });
  });
};

Oenyi.prototype.pipe = function(writable, callback) {
  'use strict';
  var oenyi = this;
  var calc;

  oenyi._getFormat(function(error) {
    if (error) return callback(error);

    nimble.series(oenyi._queue, function(error, res) {
      oenyi._queue = [];

      if (error) return callback(error);

      calc = deepcopy(oenyi._calc);
      oenyi._calc = {};

      res.pop()
        .stream()
        .pipe(writable);

      callback(null, calc);
    });
  });

};

Oenyi.prototype.resize = function(args) {
  'use strict';
  return this._enqueue(doResize, [args]);
};

Oenyi.prototype.toJPG = function() {
  'use strict';
  return this._enqueue(doConvertToJPG);
};

Oenyi.prototype.compress = function(args) {
  'use strict';
  return this._enqueue(doCompress, [args]);
};

module.exports = Oenyi;