mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-14 20:30:01 +01:00
Merge publiclab/master after #81
This commit is contained in:
32
README.md
32
README.md
@@ -76,11 +76,26 @@ a name and an image. The method also accepts an optional callback.
|
||||
```js
|
||||
sequencer.loadImage(image_src,optional_callback);
|
||||
```
|
||||
On `Node.js` the `image_src` may be a DataURI or a local path. On browsers, it
|
||||
must be a DatURI (or 'selector to image' -- Work in Progress)
|
||||
On `Node.js` the `image_src` may be a DataURI or a local path or a URL.
|
||||
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
On browsers, it may be a DatURI, a local image or a URL (Unless this violates
|
||||
CORS Restrictions). To sum up, these are accepted:
|
||||
* Images in the same domain (or directory - for a local implementation)
|
||||
* CORS-Proof images in another domain.
|
||||
* DataURLs
|
||||
|
||||
return value: **none** (A callback should be used to ensure the image gets loaded)
|
||||
The callback is called within the scope of a the sequencer. For example:
|
||||
(addSteps is defined later)
|
||||
|
||||
```js
|
||||
sequencer.loadImage('SRC',function(){
|
||||
this.addSteps('module-name');
|
||||
});
|
||||
```
|
||||
|
||||
The `this` refers to all the images added in the parent `loadImages` function only.
|
||||
In this case, only `'SRC'`.
|
||||
|
||||
### Adding steps to the image
|
||||
|
||||
@@ -164,6 +179,7 @@ return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
## Method Chaining
|
||||
Methods can be chained on the Image Sequencer:
|
||||
* loadImage()/loadImages() can only terminate a chain.
|
||||
* run() can not be in the middle of the chain.
|
||||
* If the chain starts with loadImage() or loadImages(), the following methods are
|
||||
applied only to the newly loaded images.
|
||||
@@ -172,9 +188,11 @@ be of the form "image<number>". For ex: "image1", "image2", "image3", etc.
|
||||
|
||||
Valid Chains:
|
||||
```js
|
||||
sequencer.loadImage('red').addSteps('invert').run(function(out){
|
||||
//do something with otuput.
|
||||
});
|
||||
sequencer.loadImage('red',function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
//do something with ouptut.
|
||||
});
|
||||
})
|
||||
sequencer.addSteps(['ndvi-red','invert']).run();
|
||||
et cetra.
|
||||
```
|
||||
@@ -217,7 +235,7 @@ with each image. This is a string literal.
|
||||
});
|
||||
```
|
||||
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
return value: **none**
|
||||
|
||||
|
||||
### Adding Steps on Multiple Images
|
||||
|
||||
74
dist/image-sequencer.js
vendored
74
dist/image-sequencer.js
vendored
@@ -34711,17 +34711,15 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
function loadImages() {
|
||||
var args = [];
|
||||
var sequencer = this;
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
var json_q = formatInput.call(this,args,"l");
|
||||
|
||||
inputlog.push({method:"loadImages", json_q:copy(json_q)});
|
||||
var loadedimages = this.copy(json_q.loadedimages);
|
||||
// require('./LoadImage')(this,i,json_q.images[i]);
|
||||
|
||||
for (var i in json_q.images)
|
||||
require('./LoadImage')(this,i,json_q.images[i])
|
||||
|
||||
json_q.callback();
|
||||
return {
|
||||
var ret = {
|
||||
name: "ImageSequencer Wrapper",
|
||||
sequencer: this,
|
||||
addSteps: this.addSteps,
|
||||
@@ -34732,6 +34730,19 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
setUI: this.setUI,
|
||||
images: loadedimages
|
||||
};
|
||||
|
||||
function load(i) {
|
||||
if(i==loadedimages.length) {
|
||||
json_q.callback.call(ret);
|
||||
return;
|
||||
}
|
||||
var img = loadedimages[i];
|
||||
require('./LoadImage')(sequencer,img,json_q.images[img],function(){
|
||||
load(++i);
|
||||
});
|
||||
}
|
||||
|
||||
load(0);
|
||||
}
|
||||
|
||||
function replaceImage(selector,steps,options) {
|
||||
@@ -34803,15 +34814,50 @@ function InsertStep(ref, image, index, name, o) {
|
||||
module.exports = InsertStep;
|
||||
|
||||
},{}],115:[function(require,module,exports){
|
||||
function LoadImage(ref, name, src) {
|
||||
function CImage(src) {
|
||||
var datauri = (ref.options.inBrowser || src.substring(0,11) == "data:image/")?(src):require('urify')(src);
|
||||
function LoadImage(ref, name, src, main_callback) {
|
||||
function makeImage(datauri) {
|
||||
var image = {
|
||||
src: datauri,
|
||||
format: datauri.split(':')[1].split(';')[0].split('/')[1]
|
||||
}
|
||||
return image;
|
||||
}
|
||||
function CImage(src, callback) {
|
||||
var datauri;
|
||||
if (!!src.match(/^data:/i)) {
|
||||
datauri = src;
|
||||
callback(datauri);
|
||||
}
|
||||
else if (!ref.options.inBrowser && !!src.match(/^https?:\/\//i)) {
|
||||
require( src.match(/^(https?):\/\//i)[1] ).get(src,function(res){
|
||||
var data = '';
|
||||
var contentType = res.headers['content-type'];
|
||||
res.setEncoding('base64');
|
||||
res.on('data',function(chunk) {data += chunk;});
|
||||
res.on('end',function() {
|
||||
callback("data:"+contentType+";base64,"+data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (ref.options.inBrowser) {
|
||||
var ext = src.split('.').pop();
|
||||
var image = document.createElement('img');
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
image.onload = function() {
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
context.drawImage(image,0,0);
|
||||
datauri = canvas.toDataURL(ext);
|
||||
callback(datauri);
|
||||
}
|
||||
image.src = src;
|
||||
}
|
||||
else {
|
||||
datauri = require('urify')(src);
|
||||
callback(datauri);
|
||||
}
|
||||
}
|
||||
|
||||
function loadImage(name, src) {
|
||||
var step = {
|
||||
@@ -34849,15 +34895,21 @@ function LoadImage(ref, name, src) {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
output: CImage(src)
|
||||
}]
|
||||
};
|
||||
CImage(src, function(datauri) {
|
||||
var output = makeImage(datauri);
|
||||
ref.images[name] = image;
|
||||
loadImageStep = ref.images[name].steps[0];
|
||||
var loadImageStep = ref.images[name].steps[0];
|
||||
loadImageStep.output = output;
|
||||
loadImageStep.options.step.output = loadImageStep.output.src;
|
||||
loadImageStep.UI.onSetup(loadImageStep.options.step);
|
||||
loadImageStep.UI.onDraw(loadImageStep.options.step);
|
||||
loadImageStep.UI.onComplete(loadImageStep.options.step);
|
||||
|
||||
main_callback();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return loadImage(name,src);
|
||||
@@ -35431,7 +35483,7 @@ module.exports = function PixelManipulation(image, options) {
|
||||
// but node modules and their documentation are essentially arcane on this point
|
||||
var chunks = [];
|
||||
var totalLength = 0;
|
||||
var r = savePixels(pixels, options.format);
|
||||
var r = savePixels(pixels, options.format, {quality: 100});
|
||||
|
||||
r.on('data', function(chunk){
|
||||
totalLength += chunk.length;
|
||||
|
||||
BIN
examples/red.png
Normal file
BIN
examples/red.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 277 B |
@@ -133,17 +133,15 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
function loadImages() {
|
||||
var args = [];
|
||||
var sequencer = this;
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
var json_q = formatInput.call(this,args,"l");
|
||||
|
||||
inputlog.push({method:"loadImages", json_q:copy(json_q)});
|
||||
var loadedimages = this.copy(json_q.loadedimages);
|
||||
// require('./LoadImage')(this,i,json_q.images[i]);
|
||||
|
||||
for (var i in json_q.images)
|
||||
require('./LoadImage')(this,i,json_q.images[i])
|
||||
|
||||
json_q.callback();
|
||||
return {
|
||||
var ret = {
|
||||
name: "ImageSequencer Wrapper",
|
||||
sequencer: this,
|
||||
addSteps: this.addSteps,
|
||||
@@ -154,6 +152,19 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
setUI: this.setUI,
|
||||
images: loadedimages
|
||||
};
|
||||
|
||||
function load(i) {
|
||||
if(i==loadedimages.length) {
|
||||
json_q.callback.call(ret);
|
||||
return;
|
||||
}
|
||||
var img = loadedimages[i];
|
||||
require('./LoadImage')(sequencer,img,json_q.images[img],function(){
|
||||
load(++i);
|
||||
});
|
||||
}
|
||||
|
||||
load(0);
|
||||
}
|
||||
|
||||
function replaceImage(selector,steps,options) {
|
||||
|
||||
@@ -1,12 +1,47 @@
|
||||
function LoadImage(ref, name, src) {
|
||||
function CImage(src) {
|
||||
var datauri = (ref.options.inBrowser || src.substring(0,11) == "data:image/")?(src):require('urify')(src);
|
||||
function LoadImage(ref, name, src, main_callback) {
|
||||
function makeImage(datauri) {
|
||||
var image = {
|
||||
src: datauri,
|
||||
format: datauri.split(':')[1].split(';')[0].split('/')[1]
|
||||
}
|
||||
return image;
|
||||
}
|
||||
function CImage(src, callback) {
|
||||
var datauri;
|
||||
if (!!src.match(/^data:/i)) {
|
||||
datauri = src;
|
||||
callback(datauri);
|
||||
}
|
||||
else if (!ref.options.inBrowser && !!src.match(/^https?:\/\//i)) {
|
||||
require( src.match(/^(https?):\/\//i)[1] ).get(src,function(res){
|
||||
var data = '';
|
||||
var contentType = res.headers['content-type'];
|
||||
res.setEncoding('base64');
|
||||
res.on('data',function(chunk) {data += chunk;});
|
||||
res.on('end',function() {
|
||||
callback("data:"+contentType+";base64,"+data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else if (ref.options.inBrowser) {
|
||||
var ext = src.split('.').pop();
|
||||
var image = document.createElement('img');
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
image.onload = function() {
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
context.drawImage(image,0,0);
|
||||
datauri = canvas.toDataURL(ext);
|
||||
callback(datauri);
|
||||
}
|
||||
image.src = src;
|
||||
}
|
||||
else {
|
||||
datauri = require('urify')(src);
|
||||
callback(datauri);
|
||||
}
|
||||
}
|
||||
|
||||
function loadImage(name, src) {
|
||||
var step = {
|
||||
@@ -44,15 +79,21 @@ function LoadImage(ref, name, src) {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
output: CImage(src)
|
||||
}]
|
||||
};
|
||||
CImage(src, function(datauri) {
|
||||
var output = makeImage(datauri);
|
||||
ref.images[name] = image;
|
||||
loadImageStep = ref.images[name].steps[0];
|
||||
var loadImageStep = ref.images[name].steps[0];
|
||||
loadImageStep.output = output;
|
||||
loadImageStep.options.step.output = loadImageStep.output.src;
|
||||
loadImageStep.UI.onSetup(loadImageStep.options.step);
|
||||
loadImageStep.UI.onDraw(loadImageStep.options.step);
|
||||
loadImageStep.UI.onComplete(loadImageStep.options.step);
|
||||
|
||||
main_callback();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return loadImage(name,src);
|
||||
|
||||
@@ -43,7 +43,7 @@ module.exports = function PixelManipulation(image, options) {
|
||||
// but node modules and their documentation are essentially arcane on this point
|
||||
var chunks = [];
|
||||
var totalLength = 0;
|
||||
var r = savePixels(pixels, options.format);
|
||||
var r = savePixels(pixels, options.format, {quality: 100});
|
||||
|
||||
r.on('data', function(chunk){
|
||||
totalLength += chunk.length;
|
||||
|
||||
4
test.js
4
test.js
@@ -1,4 +0,0 @@
|
||||
require('./src/ImageSequencer');
|
||||
sequencer = ImageSequencer();
|
||||
sequencer.loadImages('examples/red.jpg');
|
||||
sequencer.addSteps('do-nothing');
|
||||
@@ -17,15 +17,19 @@ test('loadImages/loadImage has a name generator.', function (t){
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('loadImages/loadImage returns a wrapper.', function (t){
|
||||
var returnval = sequencer.loadImage(red);
|
||||
test('loadImages/loadImage returns a wrapper in the callback.', function (t){
|
||||
sequencer.loadImage(red, function() {
|
||||
var returnval = this;
|
||||
t.equal(returnval.name,"ImageSequencer Wrapper", "Wrapper is returned");
|
||||
t.equal(returnval.images[0],"image2","Image scope is defined");
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('addSteps is two-way chainable.', function (t){
|
||||
var returnval = sequencer.loadImage(red).addSteps('invert');
|
||||
sequencer.loadImage(red, function(){
|
||||
var returnval = this;
|
||||
this.addSteps('invert');
|
||||
t.equal(returnval.name,"ImageSequencer Wrapper", "Wrapper is returned");
|
||||
t.equal(returnval.images[0],"image3","Image scope is defined");
|
||||
t.equal(sequencer.images.image3.steps.length,2,"Loaded image is affected");
|
||||
@@ -33,6 +37,7 @@ test('addSteps is two-way chainable.', function (t){
|
||||
t.equal(sequencer.images.image2.steps.length,1,"Other images are not affected");
|
||||
t.equal(sequencer.images.image1.steps.length,1,"Other images are not affected");
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('addSteps is two-way chainable without loadImages.', function (t){
|
||||
@@ -44,11 +49,14 @@ test('addSteps is two-way chainable without loadImages.', function (t){
|
||||
});
|
||||
|
||||
test('removeSteps is two-way chainable.', function (t){
|
||||
var returnval = sequencer.loadImage(red).addSteps('invert').removeSteps(1);
|
||||
sequencer.loadImage(red,function(){
|
||||
var returnval = this;
|
||||
this.addSteps('invert').removeSteps(1);
|
||||
t.equal(returnval.name,"ImageSequencer Wrapper", "Wrapper is returned");
|
||||
t.equal(returnval.images[0],"image4","Image scope is defined");
|
||||
t.equal(sequencer.images.image4.steps.length,1);
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('removeSteps is two-way chainable without loadImages.', function (t){
|
||||
@@ -59,12 +67,15 @@ test('removeSteps is two-way chainable without loadImages.', function (t){
|
||||
});
|
||||
|
||||
test('insertSteps is two-way chainable.', function (t){
|
||||
var returnval = sequencer.loadImage(red).insertSteps(1,'invert');
|
||||
sequencer.loadImage(red,function() {
|
||||
var returnval = this;
|
||||
this.insertSteps(1,'invert');
|
||||
t.equal(returnval.name,"ImageSequencer Wrapper","Wrapper is returned");
|
||||
t.equal(returnval.images[0],"image5","Image scope is defined");
|
||||
t.equal(sequencer.images.image5.steps.length,2);
|
||||
t.equal(sequencer.images.image5.steps[1].options.name,"invert","Correct Step Inserrted");
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('insertSteps is two-way chainable without loadImages.', function (t){
|
||||
|
||||
@@ -10,13 +10,17 @@ require('../src/ImageSequencer.js');
|
||||
//require image files as DataURLs so they can be tested alike on browser and Node.
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
|
||||
var image = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
var test_png = require('../examples/test.png.js');
|
||||
var test_gif = require('../examples/test.gif.js');
|
||||
|
||||
sequencer.loadImages(image);
|
||||
sequencer.loadImages(test_png);
|
||||
sequencer.addSteps(['do-nothing-pix','invert','invert']);
|
||||
sequencer.run();
|
||||
|
||||
test("Preload", function(t) {
|
||||
sequencer.run(function(){
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("Inverted image isn't identical", function (t) {
|
||||
t.notEqual(sequencer.images.image1.steps[1].output.src, sequencer.images.image1.steps[2].output.src);
|
||||
@@ -29,15 +33,19 @@ test("Twice inverted image is identical to original image", function (t) {
|
||||
});
|
||||
|
||||
test("PixelManipulation works for PNG images", function (t) {
|
||||
sequencer.loadImages(test_png).addSteps('invert').run(function(out){
|
||||
sequencer.loadImages(test_png,function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
t.equal(1,1)
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("PixelManipulation works for GIF images", function (t) {
|
||||
sequencer.loadImages(test_gif).addSteps('invert').run(function(out){
|
||||
sequencer.loadImages(test_gif,function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
t.equal(1,1)
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,18 +40,22 @@ test('loadImages loads a DataURL image and creates a step.', function (t){
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('loadImages loads a PATH image and creates a step. (NodeJS)', function (t){
|
||||
if(sequencer.options.inBrowser){
|
||||
t.equal("not applicable","not applicable","Not applicable for Browser");
|
||||
if(!sequencer.options.inBrowser)
|
||||
test('loadImage loads an image from URL and creates a step. (NodeJS)', function (t){
|
||||
sequencer.loadImage('URL','https://ccpandhare.github.io/image-sequencer/examples/red.jpg', function(){
|
||||
t.equal(sequencer.images.URL.steps.length, 1, "Initial Step Created");
|
||||
t.equal(typeof(sequencer.images.URL.steps[0].output.src), "string", "Initial output exists");
|
||||
t.end();
|
||||
}
|
||||
else {
|
||||
sequencer.loadImages(red);
|
||||
});
|
||||
});
|
||||
|
||||
if(!sequencer.options.inBrowser)
|
||||
test('loadImages loads an image from PATH and creates a step. (NodeJS)', function (t){
|
||||
sequencer.loadImages('examples/red.jpg');
|
||||
t.equal(sequencer.images.image1.steps.length, 1, "Initial Step Created");
|
||||
t.equal(typeof(sequencer.images.image1.steps[0].output.src), "string", "Initial output exists");
|
||||
t.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('loadImage works too.', function (t){
|
||||
sequencer.loadImage('test2',red);
|
||||
|
||||
Reference in New Issue
Block a user