/**
* @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
* @fileoverview Add filter module
*/
import {isUndefined, extend, forEach, filter} from 'tui-code-snippet';
import Promise from 'core-js/library/es6/promise';
import fabric from 'fabric/dist/fabric.require';
import Component from '../interface/component';
import Mask from '../extension/mask';
import consts from '../consts';
import Blur from '../extension/blur';
import Sharpen from '../extension/sharpen';
import Emboss from '../extension/emboss';
import ColorFilter from '../extension/colorFilter';
const {rejectMessages} = consts;
const {filters} = fabric.Image;
filters.Mask = Mask;
filters.Blur = Blur;
filters.Sharpen = Sharpen;
filters.Emboss = Emboss;
filters.ColorFilter = ColorFilter;
/**
* Filter
* @class Filter
* @param {Graphics} graphics - Graphics instance
* @extends {Component}
* @ignore
*/
class Filter extends Component {
constructor(graphics) {
super(consts.componentNames.FILTER, graphics);
}
/**
* Add filter to source image (a specific filter is added on fabric.js)
* @param {string} type - Filter type
* @param {Object} [options] - Options of filter
* @returns {Promise}
*/
add(type, options) {
return new Promise((resolve, reject) => {
const sourceImg = this._getSourceImage();
const canvas = this.getCanvas();
let imgFilter = this._getFilter(sourceImg, type);
if (!imgFilter) {
imgFilter = this._createFilter(sourceImg, type, options);
}
if (!imgFilter) {
reject(rejectMessages.invalidParameters);
}
this._changeFilterValues(imgFilter, options);
this._apply(sourceImg, () => {
canvas.renderAll();
resolve({
type,
action: 'add'
});
});
});
}
/**
* Remove filter to source image
* @param {string} type - Filter type
* @returns {Promise}
*/
remove(type) {
return new Promise((resolve, reject) => {
const sourceImg = this._getSourceImage();
const canvas = this.getCanvas();
if (!sourceImg.filters.length) {
reject(rejectMessages.unsupportedOperation);
}
this._removeFilter(sourceImg, type);
this._apply(sourceImg, () => {
canvas.renderAll();
resolve({
type,
action: 'remove'
});
});
});
}
/**
* Whether this has the filter or not
* @param {string} type - Filter type
* @returns {boolean} true if it has the filter
*/
hasFilter(type) {
return !!this._getFilter(this._getSourceImage(), type);
}
/**
* Get a filter options
* @param {string} type - Filter type
* @returns {Object} filter options or null if there is no that filter
*/
getOptions(type) {
const sourceImg = this._getSourceImage();
const imgFilter = this._getFilter(sourceImg, type);
if (!imgFilter) {
return null;
}
return extend({}, imgFilter.options);
}
/**
* Change filter values
* @param {Object} imgFilter object of filter
* @param {Object} options object
* @private
*/
_changeFilterValues(imgFilter, options) {
forEach(options, (value, key) => {
if (!isUndefined(imgFilter[key])) {
imgFilter[key] = value;
}
});
forEach(imgFilter.options, (value, key) => {
if (!isUndefined(options[key])) {
imgFilter.options[key] = options[key];
}
});
}
/**
* Apply filter
* @param {fabric.Image} sourceImg - Source image to apply filter
* @param {function} callback - Executed function after applying filter
* @private
*/
_apply(sourceImg, callback) {
sourceImg.applyFilters(callback);
}
/**
* Get source image on canvas
* @returns {fabric.Image} Current source image on canvas
* @private
*/
_getSourceImage() {
return this.getCanvasImage();
}
/**
* Create filter instance
* @param {fabric.Image} sourceImg - Source image to apply filter
* @param {string} type - Filter type
* @param {Object} [options] - Options of filter
* @returns {Object} Fabric object of filter
* @private
*/
_createFilter(sourceImg, type, options) {
let filterObj;
// capitalize first letter for matching with fabric image filter name
const fabricType = this._getFabricFilterType(type);
const ImageFilter = fabric.Image.filters[fabricType];
if (ImageFilter) {
filterObj = new ImageFilter(options);
filterObj.options = options;
sourceImg.filters.push(filterObj);
}
return filterObj;
}
/**
* Get applied filter instance
* @param {fabric.Image} sourceImg - Source image to apply filter
* @param {string} type - Filter type
* @returns {Object} Fabric object of filter
* @private
*/
_getFilter(sourceImg, type) {
let imgFilter = null;
if (sourceImg) {
const fabricType = this._getFabricFilterType(type);
const {length} = sourceImg.filters;
let item, i;
for (i = 0; i < length; i += 1) {
item = sourceImg.filters[i];
if (item.type === fabricType) {
imgFilter = item;
break;
}
}
}
return imgFilter;
}
/**
* Remove applied filter instance
* @param {fabric.Image} sourceImg - Source image to apply filter
* @param {string} type - Filter type
* @private
*/
_removeFilter(sourceImg, type) {
const fabricType = this._getFabricFilterType(type);
sourceImg.filters = filter(sourceImg.filters, value => value.type !== fabricType);
}
/**
* Change filter class name to fabric's, especially capitalizing first letter
* @param {string} type - Filter type
* @example
* 'grayscale' -> 'Grayscale'
* @returns {string} Fabric filter class name
*/
_getFabricFilterType(type) {
return type.charAt(0).toUpperCase() + type.slice(1);
}
}
module.exports = Filter;
|