image-filter-core
Advanced tools
Comparing version 1.0.0 to 2.0.0
{ | ||
"name": "image-filter-core", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "Core module for image-filter", | ||
"main": "src/index.js", | ||
"scripts": { | ||
"test": "./node_modules/.bin/karma start", | ||
"eslint": "eslint src/**/*.js", | ||
"test": "karma start", | ||
"codecov": "cat coverage/*/lcov.info | codecov", | ||
@@ -35,2 +36,3 @@ "serve": "http-server sandbox" | ||
"codecov.io": "^0.1.6", | ||
"eslint": "^3.13.0", | ||
"http-server": "^0.9.0", | ||
@@ -52,5 +54,4 @@ "karma": "^0.13.22", | ||
"dependencies": { | ||
"es6-promise": "^4.0.5", | ||
"webworkify": "^1.2.1" | ||
"es6-promise": "^4.0.5" | ||
} | ||
} |
@@ -6,5 +6,17 @@ ![build status](https://travis-ci.org/canastro/image-filter-threshold.svg?branch=master) | ||
# image-filter-core | ||
Core module used by image-filter's modules that exports helper functions. | ||
Small library that relies on webworkers to apply image transformations. | ||
There are several modules that use `image-filter-core`, such as: | ||
* [image-filters](https://www.npmjs.com/package/image-filters) | ||
* [image-filter-brightness](https://www.npmjs.com/package/image-filter-brightness) | ||
* [image-filter-contrast](https://www.npmjs.com/package/image-filter-contrast) | ||
* [image-filter-grayscale](https://www.npmjs.com/package/image-filter-grayscale) | ||
* [image-filter-threshold](https://www.npmjs.com/package/image-filter-threshold) | ||
* [image-filter-sepia](https://www.npmjs.com/package/image-filter-sepia) | ||
* [image-filter-invert](https://www.npmjs.com/package/image-filter-invert) | ||
* [image-filter-gamma](https://www.npmjs.com/package/image-filter-gamma) | ||
* [image-filter-colorize](https://www.npmjs.com/package/image-filter-colorize) | ||
But you can easily create your own transformation function and rely on `image-filter-core` to handle the webworkers and to split the work. | ||
## Install | ||
@@ -16,5 +28,5 @@ ``` | ||
## Methods | ||
### getCanvas | ||
### # getCanvas() | ||
It returns a canvas with the given width and height | ||
``` | ||
```js | ||
var imageFilterCore = require('image-filter-core'); | ||
@@ -24,5 +36,5 @@ var canvas = imageFilterCore.getCanvas(100, 100); | ||
### convertImageDataToCanvasURL | ||
### # convertImageDataToCanvasURL() | ||
Given a ImageData it returns the dataURL | ||
``` | ||
```js | ||
var imageFilterCore = require('image-filter-core'); | ||
@@ -32,17 +44,26 @@ var canvasURL = imageFilterCore.convertImageDataToCanvasURL(imageData); | ||
### apply | ||
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 | ||
### # apply() | ||
Provide the ImageData, the transformation function, the options to be passed to the transformation function and the number of workers to split the work. | ||
``` | ||
var webworkify = require('webworkify'); | ||
```js | ||
var imageFilterCore = require('image-filter-core'); | ||
var worker = require('./transformation-worker'); | ||
var imageData = imageFilterCore.apply( | ||
worker, | ||
nWorkers, | ||
canvas, | ||
context, | ||
params | ||
); | ||
imageFilterCore.apply(data, transform, options, nWorkers) | ||
.then(function (imageData) { | ||
// Do whatever you want with imageData | ||
}); | ||
``` | ||
The transform function receives ImageData, the length of data to transform and the options that the developer provided to image-fiter-core, example transformation function for the threshold effect: | ||
```js | ||
function transform (data, length, options) { | ||
for (var i = 0; i < length; i += 4) { | ||
var r = data[i]; | ||
var g = data[i + 1]; | ||
var b = data[i + 2]; | ||
var v = (0.2126 * r + 0.7152 * g + 0.0722 * b >= options.threshold) ? 255 : 0; | ||
data[i] = data[i + 1] = data[i + 2] = v; | ||
} | ||
} | ||
``` |
109
src/index.js
require('es6-promise/auto'); | ||
var work = require('webworkify'); | ||
var worker = require('./worker'); | ||
/** | ||
* It returns a canvas with the given width and height | ||
* @name getCanvas | ||
* @param {Number} w - width | ||
* @param {Number} h - height | ||
* @returns {Object} | ||
*/ | ||
exports.getCanvas = function (w, h) { | ||
* It returns a canvas with the given width and height | ||
* @name getCanvas | ||
* @param {Number} w - width | ||
* @param {Number} h - height | ||
* @returns {Object} | ||
*/ | ||
function getCanvas(w, h) { | ||
var canvas = document.createElement('canvas'); | ||
@@ -17,11 +17,11 @@ canvas.width = w; | ||
return canvas; | ||
}; | ||
} | ||
/** | ||
* Given a ImageData it returns the dataURL | ||
* @name convertImageDataToCanvasURL | ||
* @param {ImageData} imageData | ||
* @returns {String} | ||
*/ | ||
exports.convertImageDataToCanvasURL = function (imageData) { | ||
* Given a ImageData it returns the dataURL | ||
* @name convertImageDataToCanvasURL | ||
* @param {ImageData} imageData | ||
* @returns {String} | ||
*/ | ||
function convertImageDataToCanvasURL(imageData) { | ||
var canvas = document.createElement('canvas'); | ||
@@ -34,19 +34,57 @@ var ctx = canvas.getContext('2d'); | ||
return canvas.toDataURL(); | ||
}; | ||
} | ||
/** | ||
* Transforms the body of a function into a string | ||
* This is used to require the worker function and create a new Blob | ||
* @method extractBodyFunction | ||
* @param {Function} fn | ||
* @returns {String} | ||
*/ | ||
function extractBodyFunction(fn) { | ||
return fn.toString().trim().match( | ||
/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/ | ||
)[1]; | ||
} | ||
/** | ||
* 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 | ||
* @name apply | ||
* @param {Object} worker | ||
* @param {Number} nWorkers | ||
* @param {Object} canvas | ||
* @param {Object} context | ||
* @param {Number} params | ||
* @returns {Promise} | ||
* Creates a Worker from the contents in ./worker.js | ||
* @method createWorker | ||
* @returns {Worker} | ||
*/ | ||
exports.apply = function (worker, nWorkers, canvas, context, params) { | ||
var w; | ||
function createWorker() { | ||
var functionBody = extractBodyFunction(worker); | ||
var blob = new Blob([functionBody], { type: 'text/javascript' }); | ||
return new Worker(window.URL.createObjectURL(blob)); | ||
} | ||
/** | ||
* Creats transformation ObjectURL so that this function | ||
* can be imported in the worker | ||
* @method createTransformation | ||
* @param {Function} transform | ||
* @returns {String} | ||
*/ | ||
function createTransformation(transform) { | ||
var blob = new Blob(['' + transform], { type: 'text/javascript' }); | ||
return window.URL.createObjectURL(blob); | ||
} | ||
/** | ||
* 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 | ||
* @name apply | ||
* @param {Function} worker | ||
* @param {Number} options | ||
* @returns {Promise} | ||
*/ | ||
function apply(data, transform, options, nWorkers) { | ||
var w = createWorker(); | ||
var transformationURL = createTransformation(transform); | ||
var canvas = getCanvas(data.width, data.height); | ||
var context = canvas.getContext('2d'); | ||
var finished = 0; | ||
@@ -57,2 +95,5 @@ var len = canvas.width * canvas.height * 4; | ||
// Drawing the source image into the target canvas | ||
context.putImageData(data, 0, 0); | ||
// Minimum number of workers = 1 | ||
@@ -68,3 +109,2 @@ if (!nWorkers) { | ||
for (var index = 0; index < nWorkers; index++) { | ||
w = work(worker); | ||
@@ -93,9 +133,16 @@ w.addEventListener('message', function (e) { | ||
w.postMessage({ | ||
data: canvasData, | ||
canvasData: canvasData, | ||
index: index, | ||
length: segmentLength, | ||
params: params | ||
options: options, | ||
transformationURL: transformationURL | ||
}); | ||
} | ||
}); | ||
} | ||
module.exports = { | ||
apply: apply, | ||
convertImageDataToCanvasURL: convertImageDataToCanvasURL, | ||
getCanvas: getCanvas | ||
}; |
const expect = require('chai').expect; | ||
const sinon = require('sinon'); | ||
const proxyquire = require('proxyquireify')(require); | ||
const imageFilterCore = require('../src/index'); | ||
describe('utils', function () { | ||
describe('index', function () { | ||
var sandbox; | ||
@@ -17,4 +17,3 @@ before(function () { | ||
it('should return a canvas of 100 x 100', function () { | ||
const utils = require('../src/index'); | ||
const element = utils.getCanvas(100, 100); | ||
const element = imageFilterCore.getCanvas(100, 100); | ||
@@ -29,3 +28,2 @@ expect(element.tagName).to.equal('CANVAS'); | ||
it('should create canvas and call toDataURL', function () { | ||
const utils = require('../src/index'); | ||
const expectedResult = 'TEST'; | ||
@@ -49,3 +47,3 @@ | ||
const result = utils.convertImageDataToCanvasURL(imageData); | ||
const result = imageFilterCore.convertImageDataToCanvasURL(imageData); | ||
@@ -65,7 +63,14 @@ expect(document.createElement.calledWith('canvas')).to.equal(true); | ||
var eventListenerCallback; | ||
const expectedResult = 'TEST'; | ||
const worker = { | ||
addEventListener: function addEventListener(evt, fn) { | ||
eventListenerCallback = fn; | ||
}, | ||
postMessage: sandbox.stub() | ||
}; | ||
const transform = sandbox.stub(); | ||
const ctx = { | ||
putImageData: sandbox.stub(), | ||
getImageData: sandbox.stub() | ||
getImageData: sandbox.stub(), | ||
putImageData: sandbox.stub() | ||
}; | ||
@@ -75,25 +80,18 @@ | ||
getContext: sandbox.stub().returns(ctx), | ||
toDataURL: sandbox.stub().returns(expectedResult) | ||
toDataURL: sandbox.stub().returns() | ||
}; | ||
const worker = { | ||
addEventListener: function addEventListener(evt, fn) { | ||
eventListenerCallback = fn; | ||
}, | ||
postMessage: sandbox.stub() | ||
}; | ||
const data = { width: 100, height: 200 }; | ||
const nWorkers = 4; | ||
const options = { test: 'DUMMY-OPTION' }; | ||
const utils = proxyquire('../src/index', { | ||
'webworkify': function () { return worker; } | ||
}); | ||
window.Worker = sandbox.stub().returns(worker); | ||
sandbox.stub(window.URL, 'createObjectURL'); | ||
sandbox.stub(document, 'createElement').returns(canvas); | ||
const nWorkers = 4; | ||
const result = imageFilterCore.apply(data, transform, options, nWorkers); | ||
const result = utils.apply( | ||
'DUMMY', | ||
nWorkers, | ||
canvas, | ||
ctx, | ||
{} | ||
); | ||
// Two object urls created, one for the worker one for the transform function | ||
expect(window.URL.createObjectURL.calledTwice).to.equal(true); | ||
expect(window.Worker.calledOnce).to.equal(true); | ||
@@ -110,4 +108,6 @@ const evt = { data: { result: 'DUMMY', index: 1 } }; | ||
// One for the intial render and One for each worker | ||
expect(ctx.putImageData.callCount).to.equal(nWorkers + 1); | ||
// One for each worker | ||
expect(ctx.putImageData.callCount).to.equal(nWorkers); | ||
expect(worker.postMessage.callCount).to.equal(nWorkers); | ||
@@ -122,7 +122,14 @@ done(); | ||
var eventListenerCallback; | ||
const expectedResult = 'TEST'; | ||
const worker = { | ||
addEventListener: function addEventListener(evt, fn) { | ||
eventListenerCallback = fn; | ||
}, | ||
postMessage: sandbox.stub() | ||
}; | ||
const transform = sandbox.stub(); | ||
const ctx = { | ||
putImageData: sandbox.stub(), | ||
getImageData: sandbox.stub() | ||
getImageData: sandbox.stub(), | ||
putImageData: sandbox.stub() | ||
}; | ||
@@ -132,25 +139,18 @@ | ||
getContext: sandbox.stub().returns(ctx), | ||
toDataURL: sandbox.stub().returns(expectedResult) | ||
toDataURL: sandbox.stub().returns() | ||
}; | ||
const worker = { | ||
addEventListener: function addEventListener(evt, fn) { | ||
eventListenerCallback = fn; | ||
}, | ||
postMessage: sandbox.stub() | ||
const options = { | ||
data: { width: 100, height: 200 } | ||
}; | ||
const utils = proxyquire('../src/index', { | ||
'webworkify': function () { return worker; } | ||
}); | ||
window.Worker = sandbox.stub().returns(worker); | ||
sandbox.stub(window.URL, 'createObjectURL'); | ||
sandbox.stub(document, 'createElement').returns(canvas); | ||
const nWorkers = 0; | ||
const result = imageFilterCore.apply(transform, options); | ||
const result = utils.apply( | ||
'DUMMY', | ||
nWorkers, | ||
canvas, | ||
ctx, | ||
{} | ||
); | ||
// Two object urls created, one for the worker one for the transform function | ||
expect(window.URL.createObjectURL.calledTwice).to.equal(true); | ||
expect(window.Worker.calledOnce).to.equal(true); | ||
@@ -164,4 +164,6 @@ const evt = { data: { result: 'DUMMY', index: 1 } }; | ||
// One for the intial render and One for each worker | ||
expect(ctx.putImageData.callCount).to.equal(2); | ||
// One for each worker | ||
expect(ctx.putImageData.callCount).to.equal(1); | ||
expect(worker.postMessage.callCount).to.equal(1); | ||
@@ -168,0 +170,0 @@ done(); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
20396
1
15
397
66
0
19
- Removedwebworkify@^1.2.1
- Removedwebworkify@1.5.0(transitive)