UNPKG

lens-core

Version:

Core module for lens-filter

287 lines (260 loc) 10.2 kB
(function(global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory() : typeof define === 'function' && define.amd ? define(factory) : factory(); })(this, function() { 'use strict'; function e(e, t, n) { e.addEventListener('message', function(r) { var o = r.data, a = o.id; if ('RPC' === o.type && null != a) if (o.method) { var s = t[o.method]; null == s ? e.postMessage({ type: 'RPC', id: a, error: 'NO_SUCH_METHOD' }) : Promise.resolve() .then(function() { return s.apply(null, o.params); }) .then(function(t) { e.postMessage({ type: 'RPC', id: a, result: t }); }) .catch(function(t) { e.postMessage({ type: 'RPC', id: a, error: '' + t }); }); } else { var i = n[a]; if (null == i) throw Error('Unknown callback ' + a); delete n[a], o.error ? i[1](Error(o.error)) : i[0](o.result); } }); } function workerize(t, n) { var r = this, o = {}, a = '__xpo' + Math.random() .toString() .substring(2) + '__'; 'function' == typeof t && (t = '(' + Function.prototype.toString.call(t) + ')(' + a + ')'), (t = (function(e, t, n) { return ( (e = (e = e.replace( /^(\s*)export\s+default\s+/m, function(e, r) { return ( (n.default = !0), '' + r + t + '.default=' ); } )).replace( /^(\s*)export\s+((?:async\s*)?function(?:\s*\*)?|const|let|var)(\s+)([a-zA-Z$_][a-zA-Z0-9$_]*)/gm, function(e, r, o, a, s) { return ( (n[s] = !0), '' + r + t + '.' + s + '=' + o + a + s ); } )), 'var ' + t + '={};\n' + e + '\n' + t + ';' ); })(t, a, o) + '\n(' + Function.prototype.toString.call(e) + ')(self,' + a + ',{})'); var s, i = URL.createObjectURL(new Blob([t])), l = new Worker(i, n), c = l.terminate, u = {}, p = 0; for (s in ((l.kill = function(e) { l.postMessage({ type: 'KILL', signal: e }), setTimeout(l.terminate); }), (l.terminate = function() { URL.revokeObjectURL(i), c.call(r); }), (l.call = function(e, t) { return new Promise(function(n, r) { var o = 'rpc' + ++p; (u[o] = [n, r]), l.postMessage({ type: 'RPC', id: o, method: e, params: t }); }); }), (l.rpcMethods = {}), e(l, l.rpcMethods, u), (l.expose = function(e) { l[s] = function() { return l.call(e, [].slice.call(arguments)); }; }), o)) s in l || l.expose(s); return l; } /** * It returns a canvas with the given width and height * @param {Number} w - width * @param {Number} h - height * @returns {Object} */ function getCanvas(w, h) { const canvas = document.createElement('canvas'); canvas.width = w; canvas.height = h; return canvas; } /** * Given a ImageData it returns the dataURL * @param {ImageData} imageData * @returns {String} */ function convertImageDataToCanvasURL(imageData) { const canvas = window.document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = imageData.width; canvas.height = imageData.height; ctx.putImageData(imageData, 0, 0); return canvas.toDataURL(); } /** * Given a worker file with the transformation the work is split * between the configured number of workers and the transformation is applied * returning a Promise * @param {Object} data - image data * @param {Function} transform - transformation function * @param {Object} options - object to be passed to the transform function * @param {Number} nWorkers - number of workers to transform the image * @returns {Promise} */ function applyFilter({ data, transform, options, nWorkers }) { const worker = workerize(` var transform = ${transform}; export function execute(canvas, index, length, options) { canvas.data = transform({ data: canvas.data, length: length, options: options }); return { result: canvas, index: index }; } `); // Drawing the source image into the target canvas const canvas = getCanvas(data.width, data.height); const context = canvas.getContext('2d'); context.putImageData(data, 0, 0); // Minimium 1 worker nWorkers = nWorkers || 1; // Height of the picture chunck for every worker const blockSize = Math.floor(canvas.height / nWorkers); return new Promise(resolve => { let finished = 0; let height; for (let index = 0; index < nWorkers; index++) { // In the last worker we have to make sure we process whatever is missing height = blockSize; if (index + 1 === nWorkers) { height = canvas.height - blockSize * index; } // Getting the picture const canvasData = context.getImageData( 0, blockSize * index, canvas.width, height ); const length = height * canvas.width * 4; worker .execute(canvasData, index, length, options) .then(response => { // Copying back canvas data to canvas // If the first webworker (index 0) returns data, apply it at pixel (0, 0) onwards // If the second webworker (index 1) returns data, apply it at pixel (0, canvas.height/4) onwards, and so on context.putImageData( response.result, 0, blockSize * response.index ); finished++; if (finished === nWorkers) { resolve( context.getImageData( 0, 0, canvas.width, canvas.height ) ); } }); } }); } // exports.getCanvas = getCanvas; // exports.convertImageDataToCanvasURL = convertImageDataToCanvasURL; // exports.applyFilter = applyFilter; const transform = ({ data, length, options }) => { const hex = options.color.charAt(0) === '#' ? options.color.substr(1) : options.color; const colorRGB = { r: parseInt(hex.substr(0, 2), 16), g: parseInt(hex.substr(2, 2), 16), b: parseInt(hex.substr(4, 2), 16) }; for (let i = 0; i < length; i += 4) { data[i] -= (data[i] - colorRGB.r) * (options.level / 100); data[i + 1] -= (data[i + 1] - colorRGB.g) * (options.level / 100); data[i + 2] -= (data[i + 2] - colorRGB.b) * (options.level / 100); } return data; }; window.onload = function() { const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const context = canvas.getContext('2d'); context.drawImage(img, 0, 0); const data = context.getImageData(0, 0, img.width, img.height); const options = { color: '#008080', level: 50 }; const nWorkers = 4; return applyFilter({ data, transform, options, nWorkers }).then( results => { const target = document.querySelectorAll('#target-1')[0]; const image = document.createElement('img'); image.setAttribute( 'src', convertImageDataToCanvasURL(results) ); target.appendChild(image); } ); }; img.src = 'dummy.jpg'; }; }); //# sourceMappingURL=bundle.js.map