UNPKG

blink-diff

Version:

A lightweight image comparison tool

251 lines (209 loc) 4.93 kB
// Copyright 2015 Yahoo! Inc. // Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms. var fs = require('fs'); var Base = require('./base'); var PNGImage = require('pngjs-image'); var utils = require('preceptor-core').utils; var Rect = require('./atoms/rect'); var Structure = require('./structure/structure'); /** * @class Image * @extends Base * @module Configuration * * @property {PNGImage} _image * @property {Structure} _structure * @property {Rect} _crop * * @property {boolean} _alreadyCropped * @property {PNGImage} _croppedImage */ var Image = Base.extend( /** * Image constructor * * @param {object} options * @param {string|PNGImage} options.image Image * @param {object|Structure} options.structure Structure of the image as a DOM * @param {object|Rect} [options.crop] Cropping of the image * @constructor */ function (options) { this.__super(options); options = utils.deepExtend({ structure: null, image: null, crop: {} }, [options]); if (options.structure) { this.setStructure(options.structure); } this.setImage(options.image); this.setCropRect(options.crop); }, { /** * Gets the image * * @method getImage * @return {PNGImage} */ getImage: function () { return this._image; }, /** * Sets the image * * @method setImage * @param {string|PNGImage} image */ setImage: function (image) { if (typeof image == 'string') { image = this._readImage(image); } else if (typeof image == 'buffer') { image = this._loadImage(image); } if (image instanceof PNGImage) { this._image = image; this._alreadyCropped = false; this._croppedImage = null; } else { throw new Error('Unknown image format.'); } }, /** * Reads the image from the FS * * @param {string} path * @return {PNGImage} * @private */ _readImage: function (path) { this.log('Read image: ' + path); return this._loadImage(fs.readFileSync(path)); }, /** * Loads the image from a buffer * * @param {Buffer} blob * @return {PNGImage} * @private */ _loadImage: function (blob) { var decoder, data, headerChunk, structureChunk, width, height, image, Decoder = PNGImage.Decoder; this.log('Load image'); decoder = new Decoder(); data = decoder.decode(blob, { strict: false }); headerChunk = decoder.getHeaderChunk(); width = headerChunk.getWidth(); height = headerChunk.getHeight(); // Load structure when embedded if (decoder.hasChunksOfType('stRT')) { structureChunk = decoder.getFirstChunk('stRT'); if ((structureChunk.getDataType() == 'BLDF') && (structureChunk.getMajor() == 1) && (structureChunk.getMinor() == 0) && structureChunk.getContent()) { this.log('Found structural data'); this.setStructure(structureChunk.getContent()); } } image = new PNG({ width: width, height: height }); data.copy(image.data, 0, 0, data.length); return new PNGImage(image); }, /** * Gets the structure of the image as a DOM * * @method getStructure * @return {Structure} */ getStructure: function () { return this._structure; }, /** * Sets the structure of the image as a DOM * * @method setStructure * @return {object|Structure} */ setStructure: function (value) { this._structure = this._parseObject(value, Structure, 'structure'); }, /** * Is image cropped? * * @method isCropped * @return {boolean} */ isCropped: function () { return !!this._crop; }, /** * Gets the cropping rectangle * * @method getCropRect * @return {Rect} */ getCropRect: function () { return this._crop; }, /** * Sets the cropping rectangle * * @method setCropRect * @param {object|Rect} value */ setCropRect: function (value) { this._crop = this._parseObject(value, Rect, 'rect'); this._alreadyCropped = false; this._croppedImage = null; }, /** * Gets the processed image * * @method getProcessedImage * @return {PNGImage} */ getProcessedImage: function () { var rect, coord; if (!this.isCropped()) { return PNGImage.copyImage(this.getImage()); } if (!this._alreadyCropped) { this.log('Cropping image'); rect = this.getCropRect().clone(); rect.limitCoordinates({ left: 0, top: 0, width: this.getImage().getWidth(), height: this.getImage().getHeight() }); coord = rect.getCoordinates(); this._croppedImage = PNGImage.copyImage(this.getImage()); this._croppedImage.clip(coord.x, coord.y, coord.width, coord.height); this._alreadyCropped = true; } return this._croppedImage; } }, { /** * @property TYPE * @type {string} * @static */ TYPE: 'CONFIGURATION_IMAGE' } ); module.exports = Image;