mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-14 20:30:01 +01:00
Merge Commit
This commit is contained in:
37567
.source.1499879393800.0.5760841517536723.html
Normal file
37567
.source.1499879393800.0.5760841517536723.html
Normal file
File diff suppressed because one or more lines are too long
13
.travis.yml
13
.travis.yml
@@ -2,12 +2,23 @@ language: node_js
|
|||||||
node_js:
|
node_js:
|
||||||
- '4'
|
- '4'
|
||||||
- '5'
|
- '5'
|
||||||
|
- '6'
|
||||||
|
- '7' # Node.js 7 is most stable version
|
||||||
env:
|
env:
|
||||||
- CXX=g++-4.8
|
- CXX=g++-4.8
|
||||||
script: npm test
|
before_script:
|
||||||
|
- npm install grunt-cli -g # for "grunt build"
|
||||||
|
script:
|
||||||
|
- npm test
|
||||||
|
- grunt build
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- g++-4.8
|
- g++-4.8
|
||||||
|
- xvfb # for tape-run
|
||||||
|
install:
|
||||||
|
- export DISPLAY=':99.0' # for tape-run
|
||||||
|
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & # for tape-run
|
||||||
|
- npm install # for tape-run
|
||||||
|
|||||||
259
README.md
259
README.md
@@ -3,7 +3,7 @@ Image Sequencer
|
|||||||
|
|
||||||
aka "Consequencer"
|
aka "Consequencer"
|
||||||
|
|
||||||
[](https://travis-ci.org/jywarren/image-sequencer)
|
[](https://travis-ci.org/publiclab/image-sequencer)
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
@@ -26,8 +26,31 @@ It is also for prototyping some other related ideas:
|
|||||||
* [Basic example](https://jywarren.github.io/image-sequencer/)
|
* [Basic example](https://jywarren.github.io/image-sequencer/)
|
||||||
* [NDVI example](https://jywarren.github.io/image-sequencer/examples/ndvi/) - related to [Infragram.org](http://infragram.org)
|
* [NDVI example](https://jywarren.github.io/image-sequencer/examples/ndvi/) - related to [Infragram.org](http://infragram.org)
|
||||||
|
|
||||||
## Using the library:
|
## Quick Usage
|
||||||
|
|
||||||
|
Image Sequencer can be used to run modules on an HTML Image Element using the
|
||||||
|
`replaceImage` method. The method accepts two parameters - `selector` and `steps`.
|
||||||
|
`selector` is a CSS selector. If it matches multiple images, all images will be
|
||||||
|
modified. `steps` may be the name of a module or array of names of modules.
|
||||||
|
|
||||||
|
Note: Browser CORS Restrictions apply. Some browsers may not allow local images
|
||||||
|
form other folders, and throw a Security Error instead.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.replaceImage(selector,steps,optional_options);
|
||||||
|
```
|
||||||
|
|
||||||
|
`optional_options` allows to pass additional arguments to the module itself.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.replaceImage('#photo','invert');
|
||||||
|
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Classic Usage
|
||||||
|
|
||||||
### Initializing the Sequencer
|
### Initializing the Sequencer
|
||||||
|
|
||||||
@@ -37,11 +60,137 @@ The Image Sequencer Library exports a function ImageSequencer which initializes
|
|||||||
var sequencer = ImageSequencer();
|
var sequencer = ImageSequencer();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Loading Images into the Sequencer
|
### Loading an Image into the Sequencer
|
||||||
|
|
||||||
Image Sequencer has an array of images which gets stored in `sequencer.images` in this case.
|
The `loadImage` method is used to load an image into the sequencer. It accepts
|
||||||
Images can be loaded into this array by the method `loadImages`.
|
a name and an image. The method also accepts an optional callback.
|
||||||
loadImages accepts 1, 2, or 3 parameters.
|
|
||||||
|
```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)
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
### Adding steps to the image
|
||||||
|
|
||||||
|
The `addSteps` method is used to add steps on the image. One or more steps can
|
||||||
|
be added at a time. Each step is called a module.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.addSteps(modules, optional_options);
|
||||||
|
```
|
||||||
|
|
||||||
|
If only one module is to be added, `modules` is simply the name of the module.
|
||||||
|
If multiple images are to be added, `modules` is an array of the names of modules
|
||||||
|
which are to be added, in that particular order.
|
||||||
|
|
||||||
|
optional_otions is just additional parameters, in object form, which you might
|
||||||
|
want to provide to the modules. It's an optional parameter.
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
### Running the Sequencer
|
||||||
|
|
||||||
|
Once all steps are added, This method is used to generate the output of all these
|
||||||
|
modules.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.run();
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, an optional callback can be passed to this method.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.run(function(out){
|
||||||
|
// this gets called back.
|
||||||
|
// "out" is the DataURL of the final image.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
### Removing a step from the sequencer
|
||||||
|
|
||||||
|
The `removeSteps` method is used to remove unwanted steps from the sequencer.
|
||||||
|
It accepts the index of the step as an input, or an array of the unwanted indices
|
||||||
|
if there are more than one.
|
||||||
|
|
||||||
|
For example, if the modules ['ndvi-red','crop','invert'] were added in this order,
|
||||||
|
and I wanted to remove 'crop' and 'invert', I can either do this:
|
||||||
|
```js
|
||||||
|
sequencer.removeSteps(2);
|
||||||
|
sequencer.removeSteps(3);
|
||||||
|
```
|
||||||
|
or:
|
||||||
|
```js
|
||||||
|
sequencer.removeSteps([2,3]);
|
||||||
|
```
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
### Inserting a step in between the sequencer
|
||||||
|
|
||||||
|
The `insertSteps` method can be used to insert one or more steps at a given index
|
||||||
|
in the sequencer. It accepts the index where the module is to be inserted, name of
|
||||||
|
the module, and an optional options parameter. `index` is the index of the inserted
|
||||||
|
step. Only one step can be inserted at a time. `optional_options` plays the same
|
||||||
|
role it played in `addSteps`.
|
||||||
|
|
||||||
|
Indexes can be negative. Negative sign with an index means that counting will be
|
||||||
|
done in reverse order. If the index is out of bounds, the counting will wrap in
|
||||||
|
the original direction of counting. So, an `index` of -1 means that the module is
|
||||||
|
inserted at the end.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.insertSteps(index,module_name,optional_options);
|
||||||
|
```
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
## Method Chaining
|
||||||
|
Methods can be chained on the Image Sequencer:
|
||||||
|
* 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.
|
||||||
|
* If no name is provided to the image, a name will be generated for it. The name will
|
||||||
|
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.addSteps(['ndvi-red','invert']).run();
|
||||||
|
et cetra.
|
||||||
|
```
|
||||||
|
|
||||||
|
Invalid Chains:
|
||||||
|
```js
|
||||||
|
sequencer.addSteps('invert').run().addSteps('ndvi-red');
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Multiple Images
|
||||||
|
Image Sequencer is capable of handling multiple images at once.
|
||||||
|
|
||||||
|
### Initializing a sequencer with multiple images.
|
||||||
|
This is just like before.
|
||||||
|
```js
|
||||||
|
var sequencer = ImageSequencer();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loading Multiple Images into the Sequencer
|
||||||
|
|
||||||
|
Multiple images can be loaded by the method `loadImages`. Everything is the same,
|
||||||
|
except that now, a unique identification called `image_name` has to be provided
|
||||||
|
with each image. This is a string literal.
|
||||||
|
|
||||||
* 3/2 parameters :
|
* 3/2 parameters :
|
||||||
```js
|
```js
|
||||||
@@ -52,19 +201,22 @@ loadImages accepts 1, 2, or 3 parameters.
|
|||||||
```js
|
```js
|
||||||
sequencer.loadImages({
|
sequencer.loadImages({
|
||||||
images: {
|
images: {
|
||||||
image_name_1: image_src,
|
image1_name: image_src,
|
||||||
image_name_2: image_src,
|
image2_name: image_src,
|
||||||
...
|
...
|
||||||
},
|
},
|
||||||
callback: optional_callback
|
callback: optional_callback
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Adding Steps on Images
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
After loading the image, we can add modules to the image using the addSteps method.
|
|
||||||
The options argument (object) is an optional parameter to pass in arguments to the module.
|
### Adding Steps on Multiple Images
|
||||||
In all the following examples, `image_name` and `module_name` may be a string or an array of strings.
|
|
||||||
|
The same method `addSteps` is used for this. There's just a slight obvious change
|
||||||
|
in the syntax that the image name has to be supplied too. `image_name` as well as
|
||||||
|
`module_name` in the following examples can be either strings or arrays of strings.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.addSteps(image_name,module_name,optional_options);
|
sequencer.addSteps(image_name,module_name,optional_options);
|
||||||
@@ -80,53 +232,81 @@ All this can be passed in as JSON:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.addSteps({
|
sequencer.addSteps({
|
||||||
image_name: {name: module_name, o: optional_options},
|
image1_name: {name: module_name, o: optional_options},
|
||||||
image_name: {name: module_name, o: optional_options},
|
image2_name: {name: module_name, o: optional_options},
|
||||||
...
|
...
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running the Sequencer
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
After adding the steps, now we must generate output for each of the step via the `run` method.
|
|
||||||
The `run` method accepts parameters `image` and `from`.
|
### Running a Sequencer with multiple images
|
||||||
`from` is the index from where the function starts generating output. By default, it will run across all the steps. (from = 1) If no image is specified, the sequencer will be run over all the images.
|
|
||||||
|
The same `run` method can be used with a slight change in syntax.
|
||||||
|
The `run` method accepts parameters `image` and `from`. `from` is the index from
|
||||||
|
where the function starts generating output. By default, it will run across all
|
||||||
|
the steps. (from = 1) If no image is specified, the sequencer will be run over **all
|
||||||
|
the images**. `image_name` may be an array of image names.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.run(); //All images from first step
|
sequencer.run(); //All images from first step
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.run(image,from); //Image 'image' from 'from'
|
sequencer.run(image_name,from); //Image 'image' from 'from'
|
||||||
```
|
```
|
||||||
|
|
||||||
image may either be an array or a string.
|
The `run` method also accepts an optional callback just like before:
|
||||||
An optional callback may also be passed.
|
|
||||||
|
|
||||||
### Removing Steps from an Image
|
|
||||||
|
|
||||||
Steps can be removed using the `removeSteps` method. It accepts `image` and `index` as parameters.
|
|
||||||
Either, both, or none of them can be an array. JSON input is also accepted.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.removeSteps("image",[steps]);
|
sequencer.run(image_name,from,function(out){
|
||||||
|
// This gets called back.
|
||||||
|
// "out" is the DataURL of final image.
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
JSON Input is also acceptable.
|
||||||
sequencer.removeSteps("image",step);
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.removeSteps({
|
sequencer.run({
|
||||||
image: [steps],
|
image1_name: from,
|
||||||
image: [steps],
|
image2_name: from,
|
||||||
...
|
...
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
|
### Removing Steps from an Image
|
||||||
|
|
||||||
|
Similarly, `removeSteps` can also accept an `image_name` parameter. Either, both,
|
||||||
|
or none of `image_name` and `steps` them may be an array. JSON input is also acceptable.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.removeSteps("image_name",[steps]);
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.removeSteps("image_name",step);
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.removeSteps({
|
||||||
|
image1_name: [steps],
|
||||||
|
image2_name: [steps],
|
||||||
|
...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
### Inserting steps on an image
|
### Inserting steps on an image
|
||||||
|
|
||||||
Steps can be inserted using the `insertSteps` method. It accepts `image`, `index`, `module_name` and `optional_options` as parameters. `image` may be an array. `optional_options` is an object. The rest are literals. JSON Input is supported too. If no image is provided, Steps will be inserted on all images. Indexes can be negative. Negative sign with an index means that counting will be done in reverse order. If the index is out of bounds, the counting will wrap in the original direction of counting.
|
The `insertSteps` method can also accept an `image_name` parameter. `image_name`
|
||||||
|
may be an array. Everything else remains the same. JSON Inout is acceptable too.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.insertSteps("image",index,"module_name",o);
|
sequencer.insertSteps("image",index,"module_name",o);
|
||||||
```
|
```
|
||||||
@@ -142,6 +322,7 @@ sequencer.insertSteps({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
@@ -214,16 +395,16 @@ Notes on development next steps:
|
|||||||
### Modularization
|
### Modularization
|
||||||
|
|
||||||
* [ ] remotely includable modules, not compiled in -- see plugin structures in other libs
|
* [ ] remotely includable modules, not compiled in -- see plugin structures in other libs
|
||||||
* [ ] ability to start running at any point -- already works?
|
* [x] ability to start running at any point -- already works?
|
||||||
* [ ] commandline runnability?
|
* [x] commandline runnability?
|
||||||
* [ ] Make available as browserified OR `require()` includable...
|
* [x] Make available as browserified OR `require()` includable...
|
||||||
* [ ] standardize panel addition with submodule that offers Panel.display(image)
|
* [ ] standardize panel addition with submodule that offers Panel.display(image)
|
||||||
* [ ] allow passing data as data-uri or Image object, or stream, or ndarray or ImageData array, if both of neighboring pair has ability?
|
* [ ] allow passing data as data-uri or Image object, or stream, or ndarray or ImageData array, if both of neighboring pair has ability?
|
||||||
* see https://github.com/jywarren/image-sequencer/issues/1
|
* see https://github.com/jywarren/image-sequencer/issues/1
|
||||||
* [ ] ...could we directly include package.json for module descriptions? At least as a fallback.
|
* [ ] ...could we directly include package.json for module descriptions? At least as a fallback.
|
||||||
* [ ] (for node-and-line style UIs) non-linear sequences with Y-splitters
|
* [ ] (for node-and-line style UIs) non-linear sequences with Y-splitters
|
||||||
* [ ] `sequencer.addModule('path/to/module.js')` style module addition -- also to avoid browserifying all of Plotly :-P
|
* [ ] `sequencer.addModule('path/to/module.js')` style module addition -- also to avoid browserifying all of Plotly :-P
|
||||||
* [ ] remove step
|
* [x] remove step
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
@@ -237,7 +418,7 @@ Notes on development next steps:
|
|||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
|
|
||||||
* [ ] BUG: this doesn't work for defaults: imageboard.loadImage('examples/grid.png', function() {
|
* [x] BUG: this doesn't work for defaults: imageboard.loadImage('examples/grid.png', function() {});
|
||||||
* we should make defaults a config of the first module
|
* we should make defaults a config of the first module
|
||||||
|
|
||||||
****
|
****
|
||||||
|
|||||||
4
dist/image-sequencer.css
vendored
4
dist/image-sequencer.css
vendored
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
/* https://github.com/theleagueof/league-spartan */
|
/* https://github.com/theleagueof/league-spartan */
|
||||||
@font-face {
|
/*@font-face {
|
||||||
font-family: 'League Spartan';
|
font-family: 'League Spartan';
|
||||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
|
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
|
||||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot?#iefix') format('embedded-opentype'),
|
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot?#iefix') format('embedded-opentype'),
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.svg#league_spartanbold') format('svg');
|
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.svg#league_spartanbold') format('svg');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|||||||
1267
dist/image-sequencer.js
vendored
1267
dist/image-sequencer.js
vendored
File diff suppressed because one or more lines are too long
BIN
examples/cyan.jpg
Normal file
BIN
examples/cyan.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 621 B |
63
examples/replace.html
Normal file
63
examples/replace.html
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<title>Replace Image Demo | Image Sequencer</title>
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
||||||
|
|
||||||
|
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
<link href="../dist/image-sequencer.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||||
|
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||||
|
<script src="../dist/image-sequencer.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
|
||||||
|
<h1>Image Sequencer</h1>
|
||||||
|
<h3>
|
||||||
|
<a href="https://github.com/publiclab/image-sequencer"><i class="fa fa-github"></i></a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="display:none;" class="spinner"><i class="fa fa-spinner fa-spin"></i></p>
|
||||||
|
|
||||||
|
<div class="panels">
|
||||||
|
|
||||||
|
<div class="panel ismod-image-select" style="display:flex;justify-content:center">
|
||||||
|
<img src="replace.jpg" id="pencils" style="cursor:pointer">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mod-new-panel" style="display:flex;justify-content:center">
|
||||||
|
<p class="lead" style="text-align:center">
|
||||||
|
Click on the image above to invert it.<br>
|
||||||
|
(This may take a few seconds)<br>
|
||||||
|
Syntax:</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="log">
|
||||||
|
<h4>var sequencer = new ImageSequencer();</h4><br>
|
||||||
|
<h4>sequencer.replaceImage('#pencils','invert');</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var sequencer = ImageSequencer();
|
||||||
|
document.querySelector('#pencils').onclick = function() {
|
||||||
|
sequencer.replaceImage('#pencils','invert');
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
examples/replace.jpg
Normal file
BIN
examples/replace.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
@@ -4,7 +4,7 @@
|
|||||||
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
||||||
"main": "dist/image-sequencer.js",
|
"main": "dist/image-sequencer.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "tape test/*.js"
|
"test": "tape test/*.js | tap-spec; browserify test/image-sequencer.js test/chain.js | tape-run --render=\"tap-spec\""
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -39,7 +39,9 @@
|
|||||||
"matchdep": "^0.3.0",
|
"matchdep": "^0.3.0",
|
||||||
"plotly.js": "~1.21.2",
|
"plotly.js": "~1.21.2",
|
||||||
"save-pixels": "~2.3.4",
|
"save-pixels": "~2.3.4",
|
||||||
"tape": "^3.5.0"
|
"tap-spec": "^4.1.1",
|
||||||
|
"tape": ">=4.7.0",
|
||||||
|
"tape-run": "^3.0.0"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/publiclab/image-sequencer"
|
"homepage": "https://github.com/publiclab/image-sequencer"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
function AddStep(ref, image, name, o) {
|
function AddStep(ref, image, name, o) {
|
||||||
|
|
||||||
function addStep(image, name, o_) {
|
function addStep(image, name, o_) {
|
||||||
ref.clog('\x1b[36m%s\x1b[0m','adding step \"' + name + '\" to \"' + image + '\".');
|
ref.log('\x1b[36m%s\x1b[0m','adding step \"' + name + '\" to \"' + image + '\".');
|
||||||
|
|
||||||
o = {};
|
o = ref.copy(o_);
|
||||||
o.id = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
o.id = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
||||||
o.name = o_.name || name;
|
o.name = o_.name || name;
|
||||||
o.selector = o_.selector || 'ismod-' + name;
|
o.selector = o_.selector || 'ismod-' + name;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function copy(a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatInput(args,format,images) {
|
function formatInput(args,format,images) {
|
||||||
images = images || [];
|
images = [];
|
||||||
for (image in this.images) {
|
for (image in this.images) {
|
||||||
images.push(image);
|
images.push(image);
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ function formatInput(args,format,images) {
|
|||||||
else if (format == "r")
|
else if (format == "r")
|
||||||
format = ['o_string_a', 'o_number'];
|
format = ['o_string_a', 'o_number'];
|
||||||
else if (format == "l")
|
else if (format == "l")
|
||||||
format = ['string','string','o_function'];
|
format = ['o_string','string','o_function'];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
formats:
|
formats:
|
||||||
@@ -87,6 +87,14 @@ function formatInput(args,format,images) {
|
|||||||
args.splice(0,0,copy(images));
|
args.splice(0,0,copy(images));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (format[0] == "o_string" && format_i == "l" && args.length == 2) {
|
||||||
|
if (typeof(args[0]) == "string") {
|
||||||
|
identifier = "image";
|
||||||
|
number = 1;
|
||||||
|
while (this.images.hasOwnProperty(identifier+number)) number++;
|
||||||
|
args.splice(0,0,identifier+number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(args.length == format.length) {
|
if(args.length == format.length) {
|
||||||
for (i in format) {
|
for (i in format) {
|
||||||
@@ -145,6 +153,11 @@ function formatInput(args,format,images) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(format_i == "l") {
|
||||||
|
json_q.loadedimages = [];
|
||||||
|
for (i in json_q.images) json_q.loadedimages.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
return json_q;
|
return json_q;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
if (typeof window !== 'undefined') {window.$ = window.jQuery = require('jquery'); isBrowser = true}
|
if (typeof window !== 'undefined') {window.$ = window.jQuery = require('jquery'); isBrowser = true}
|
||||||
else {window = global; var isBrowser = false}
|
else {var isBrowser = false}
|
||||||
|
|
||||||
ImageSequencer = function ImageSequencer(options) {
|
ImageSequencer = function ImageSequencer(options) {
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
return Object.prototype.toString.call(object).split(" ")[1].slice(0,-1)
|
return Object.prototype.toString.call(object).split(" ")[1].slice(0,-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function clog(color,msg) {
|
function log(color,msg) {
|
||||||
if(options.ui!="none") {
|
if(options.ui!="none") {
|
||||||
if(arguments.length==1) console.log(arguments[0]);
|
if(arguments.length==1) console.log(arguments[0]);
|
||||||
else if(arguments.length==2) console.log(color,msg);
|
else if(arguments.length==2) console.log(color,msg);
|
||||||
@@ -42,27 +42,32 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
steps = [],
|
steps = [],
|
||||||
modules = require('./Modules'),
|
modules = require('./Modules'),
|
||||||
images = {},
|
images = {},
|
||||||
log = [];
|
inputlog = [];
|
||||||
|
|
||||||
// if in browser, prompt for an image
|
// if in browser, prompt for an image
|
||||||
// if (options.imageSelect || options.inBrowser) addStep('image-select');
|
// if (options.imageSelect || options.inBrowser) addStep('image-select');
|
||||||
// else if (options.imageUrl) loadImage(imageUrl);
|
// else if (options.imageUrl) loadImage(imageUrl);
|
||||||
|
|
||||||
function addSteps(){
|
function addSteps(){
|
||||||
args = [];
|
const this_ = (this.name == "ImageSequencer")?this:this.sequencer;
|
||||||
|
args = (this.name == "ImageSequencer")?[]:[this.images];
|
||||||
json_q = {};
|
json_q = {};
|
||||||
for(arg in arguments){args.push(copy(arguments[arg]));}
|
for(arg in arguments){args.push(copy(arguments[arg]));}
|
||||||
json_q = formatInput.call(this,args,"+");
|
json_q = formatInput.call(this_,args,"+");
|
||||||
log.push({method:"addSteps", json_q:copy(json_q)});
|
|
||||||
|
inputlog.push({method:"addSteps", json_q:copy(json_q)});
|
||||||
|
|
||||||
for (i in json_q)
|
for (i in json_q)
|
||||||
for (j in json_q[i])
|
for (j in json_q[i])
|
||||||
require("./AddStep")(this,i,json_q[i][j].name,json_q[i][j].o);
|
require("./AddStep")(this_,i,json_q[i][j].name,json_q[i][j].o);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStep(image,index) {
|
function removeStep(image,index) {
|
||||||
//remove the step from images[image].steps and redraw remaining images
|
//remove the step from images[image].steps and redraw remaining images
|
||||||
if(index>0) {
|
if(index>0) {
|
||||||
clog('\x1b[31m%s\x1b[0m',"Removing "+index+" from "+image);
|
log('\x1b[31m%s\x1b[0m',"Removing "+index+" from "+image);
|
||||||
images[image].steps.splice(index,1);
|
images[image].steps.splice(index,1);
|
||||||
}
|
}
|
||||||
//tell the UI a step has been removed
|
//tell the UI a step has been removed
|
||||||
@@ -70,10 +75,12 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
|
|
||||||
function removeSteps(image,index) {
|
function removeSteps(image,index) {
|
||||||
run = {};
|
run = {};
|
||||||
args = [];
|
const this_ = (this.name == "ImageSequencer")?this:this.sequencer;
|
||||||
|
args = (this.name == "ImageSequencer")?[]:[this.images];
|
||||||
for(arg in arguments) args.push(copy(arguments[arg]));
|
for(arg in arguments) args.push(copy(arguments[arg]));
|
||||||
json_q = formatInput.call(this,args,"-");
|
|
||||||
log.push({method:"removeSteps", json_q:copy(json_q)});
|
json_q = formatInput.call(this_,args,"-");
|
||||||
|
inputlog.push({method:"removeSteps", json_q:copy(json_q)});
|
||||||
|
|
||||||
for (img in json_q) {
|
for (img in json_q) {
|
||||||
indices = json_q[img].sort(function(a,b){return b-a});
|
indices = json_q[img].sort(function(a,b){return b-a});
|
||||||
@@ -82,77 +89,92 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
removeStep(img,indices[i]);
|
removeStep(img,indices[i]);
|
||||||
}
|
}
|
||||||
// this.run(run); // This is creating problems
|
// this.run(run); // This is creating problems
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertSteps(image, index, name, o) {
|
function insertSteps(image, index, name, o) {
|
||||||
run = {};
|
run = {};
|
||||||
this_ = this;
|
const this_ = (this.name == "ImageSequencer")?this:this.sequencer;
|
||||||
args = [];
|
args = (this.name == "ImageSequencer")?[]:[this.images];
|
||||||
for (arg in arguments) args.push(arguments[arg]);
|
for (arg in arguments) args.push(arguments[arg]);
|
||||||
|
|
||||||
json_q = formatInput.call(this,args,"^");
|
json_q = formatInput.call(this_,args,"^");
|
||||||
log.push({method:"insertSteps", json_q:copy(json_q)});
|
inputlog.push({method:"insertSteps", json_q:copy(json_q)});
|
||||||
|
|
||||||
for (img in json_q) {
|
for (img in json_q) {
|
||||||
var details = json_q[img];
|
var details = json_q[img];
|
||||||
details = details.sort(function(a,b){return b.index-a.index});
|
details = details.sort(function(a,b){return b.index-a.index});
|
||||||
for (i in details)
|
for (i in details)
|
||||||
require("./InsertStep")(this,img,details[i].index,details[i].name,details[i].o);
|
require("./InsertStep")(this_,img,details[i].index,details[i].name,details[i].o);
|
||||||
// run[img] = details[details.length-1].index;
|
run[img] = details[details.length-1].index;
|
||||||
}
|
}
|
||||||
// this.run(run); // This is Creating issues
|
// this.run(run); // This is Creating issues
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function run(t_image,t_from) {
|
function run(t_image,t_from) {
|
||||||
clog('\x1b[32m%s\x1b[0m',"Running the Sequencer!");
|
log('\x1b[32m%s\x1b[0m',"Running the Sequencer!");
|
||||||
this_ = this;
|
const this_ = (this.name == "ImageSequencer")?this:this.sequencer;
|
||||||
args = [];
|
args = (this.name == "ImageSequencer")?[]:[this.images];
|
||||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||||
|
|
||||||
callback = function() {};
|
callback = function() {};
|
||||||
for (var arg in args)
|
for (var arg in args)
|
||||||
if(objTypeOf(args[arg]) == "Function")
|
if(objTypeOf(args[arg]) == "Function")
|
||||||
callback = args.splice(arg,1)[0];
|
callback = args.splice(arg,1)[0];
|
||||||
|
|
||||||
json_q = formatInput.call(this,args,"r");
|
json_q = formatInput.call(this_,args,"r");
|
||||||
|
|
||||||
require('./Run')(this, json_q, callback);
|
require('./Run')(this_, json_q, callback);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadImages() {
|
function loadImages() {
|
||||||
args = [];
|
args = [];
|
||||||
for (arg in arguments) args.push(copy(arguments[arg]));
|
for (arg in arguments) args.push(copy(arguments[arg]));
|
||||||
json_q = formatInput.call(this,args,"l");
|
json_q = formatInput.call(this,args,"l");
|
||||||
json_q_push = copy(json_q);
|
|
||||||
delete json_q_push.callback;
|
inputlog.push({method:"loadImages", json_q:copy(json_q)});
|
||||||
log.push({method:"loadImages", json_q:json_q_push});
|
loadedimages = this.copy(json_q.loadedimages);
|
||||||
|
|
||||||
for (i in json_q.images)
|
for (i in json_q.images)
|
||||||
require('./LoadImage')(this,i,json_q.images[i])
|
require('./LoadImage')(this,i,json_q.images[i])
|
||||||
|
|
||||||
if (json_q.callback) json_q.callback();
|
json_q.callback();
|
||||||
|
return {
|
||||||
|
name: "ImageSequencer Wrapper",
|
||||||
|
sequencer: this,
|
||||||
|
addSteps: this.addSteps,
|
||||||
|
removeSteps: this.removeSteps,
|
||||||
|
insertSteps: this.insertSteps,
|
||||||
|
run: this.run,
|
||||||
|
images: loadedimages
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function runLog() {
|
function replaceImage(selector,steps,options) {
|
||||||
for(i in sequencer.log)
|
options = options || {};
|
||||||
eval("sequencer."+sequencer.log[i].method).call(sequencer,sequencer.log[i].json_q);
|
return require('./ReplaceImage')(this,selector,steps);
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
name: "ImageSequencer",
|
||||||
options: options,
|
options: options,
|
||||||
loadImages: loadImages,
|
loadImages: loadImages,
|
||||||
|
loadImage: loadImages,
|
||||||
addSteps: addSteps,
|
addSteps: addSteps,
|
||||||
removeSteps: removeSteps,
|
removeSteps: removeSteps,
|
||||||
insertSteps: insertSteps,
|
insertSteps: insertSteps,
|
||||||
|
replaceImage: replaceImage,
|
||||||
run: run,
|
run: run,
|
||||||
log: log,
|
inputlog: inputlog,
|
||||||
modules: modules,
|
modules: modules,
|
||||||
images: images,
|
images: images,
|
||||||
ui: options.ui,
|
ui: options.ui,
|
||||||
clog: clog,
|
log: log,
|
||||||
objTypeOf: objTypeOf,
|
objTypeOf: objTypeOf,
|
||||||
copy: copy,
|
copy: copy
|
||||||
runLog: runLog
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
function InsertStep(ref, image, index, name, o) {
|
function InsertStep(ref, image, index, name, o) {
|
||||||
|
|
||||||
function insertStep(image, index, name, o) {
|
function insertStep(image, index, name, o_) {
|
||||||
ref.clog('\x1b[36m%s\x1b[0m','inserting step \"' + name + '\" to \"' + image + '\" at \"'+index+'\".');
|
ref.log('\x1b[36m%s\x1b[0m','inserting step \"' + name + '\" to \"' + image + '\" at \"'+index+'\".');
|
||||||
|
|
||||||
o = o || {};
|
o = ref.copy(o_);
|
||||||
o.id = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
o.id = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
||||||
o.name = o.name || name;
|
o.name = o.name || name;
|
||||||
o.selector = o.selector || 'ismod-' + name;
|
o.selector = o.selector || 'ismod-' + name;
|
||||||
|
|||||||
@@ -19,7 +19,12 @@ function LoadImage(ref, name, src) {
|
|||||||
},
|
},
|
||||||
draw: function() {
|
draw: function() {
|
||||||
if(arguments.length==1){
|
if(arguments.length==1){
|
||||||
this.outputData = CImage(arguments[0]);
|
this.output = CImage(arguments[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(arguments.length==2) {
|
||||||
|
this.output = CImage(arguments[0]);
|
||||||
|
arguments[1]();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ module.exports = {
|
|||||||
'green-channel': require('./modules/GreenChannel'),
|
'green-channel': require('./modules/GreenChannel'),
|
||||||
'ndvi-red': require('./modules/NdviRed'),
|
'ndvi-red': require('./modules/NdviRed'),
|
||||||
'do-nothing-pix': require('./modules/DoNothingPix'),
|
'do-nothing-pix': require('./modules/DoNothingPix'),
|
||||||
'invert': require('./modules/Invert')
|
'invert': require('./modules/Invert'),
|
||||||
|
'crop': require('./modules/Crop')
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/ReplaceImage.js
Normal file
35
src/ReplaceImage.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
function ReplaceImage(ref,selector,steps,options) {
|
||||||
|
if(!ref.options.inBrowser) return false; // This isn't for Node.js
|
||||||
|
this_ = ref;
|
||||||
|
var input = document.querySelectorAll(selector);
|
||||||
|
var images = [];
|
||||||
|
for (i = 0; i < input.length; i++)
|
||||||
|
if (input[i] instanceof HTMLImageElement) images.push(input[i]);
|
||||||
|
for (i in images) {
|
||||||
|
the_image = images[i];
|
||||||
|
var url = images[i].src;
|
||||||
|
var ext = url.split('.').pop();
|
||||||
|
|
||||||
|
var xmlHTTP = new XMLHttpRequest();
|
||||||
|
xmlHTTP.open('GET', url, true);
|
||||||
|
xmlHTTP.responseType = 'arraybuffer';
|
||||||
|
xmlHTTP.onload = function(e) {
|
||||||
|
var arr = new Uint8Array(this.response);
|
||||||
|
var raw = String.fromCharCode.apply(null,arr);
|
||||||
|
var base64 = btoa(raw);
|
||||||
|
var dataURL="data:image/"+ext+";base64," + base64;
|
||||||
|
make(dataURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
if(url.substr(0,11).toLowerCase()!="data:image/") xmlHTTP.send();
|
||||||
|
else make(url);
|
||||||
|
|
||||||
|
function make(url) {
|
||||||
|
this_.loadImage('default',url).addSteps('default',steps).run(function(out){
|
||||||
|
the_image.src = out;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ReplaceImage;
|
||||||
16
src/Run.js
16
src/Run.js
@@ -1,8 +1,14 @@
|
|||||||
function Run(ref, json_q, callback) {
|
function Run(ref, json_q, callback) {
|
||||||
|
|
||||||
function drawStep(drawarray,pos) {
|
function drawStep(drawarray,pos) {
|
||||||
if(pos==drawarray.length) if(ref.objTypeOf(callback)=='Function') callback();
|
if(pos==drawarray.length) {
|
||||||
if(pos>=drawarray.length) return true;
|
image = drawarray[pos-1].image;
|
||||||
|
if(ref.objTypeOf(callback)=='Function'){
|
||||||
|
steps = ref.images[image].steps;
|
||||||
|
out = steps[steps.length-1].output.src;
|
||||||
|
callback(out);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
image = drawarray[pos].image;
|
image = drawarray[pos].image;
|
||||||
i = drawarray[pos].i;
|
i = drawarray[pos].i;
|
||||||
input = ref.images[image].steps[i-1].output;
|
input = ref.images[image].steps[i-1].output;
|
||||||
@@ -25,7 +31,7 @@ function Run(ref, json_q, callback) {
|
|||||||
for (image in json_q) {
|
for (image in json_q) {
|
||||||
if (json_q[image]==0 && ref.images[image].steps.length==1)
|
if (json_q[image]==0 && ref.images[image].steps.length==1)
|
||||||
delete json_q[image];
|
delete json_q[image];
|
||||||
else json_q[image]++;
|
else if (json_q[image]==0) json_q[image]++;
|
||||||
}
|
}
|
||||||
for (image in json_q) {
|
for (image in json_q) {
|
||||||
prevstep = ref.images[image].steps[json_q[image]-1];
|
prevstep = ref.images[image].steps[json_q[image]-1];
|
||||||
@@ -36,6 +42,6 @@ function Run(ref, json_q, callback) {
|
|||||||
return json_q;
|
return json_q;
|
||||||
}
|
}
|
||||||
json_q = filter(json_q);
|
json_q = filter(json_q);
|
||||||
drawSteps(json_q);
|
return drawSteps(json_q);
|
||||||
}
|
}
|
||||||
module.exports = Run;
|
module.exports = Run;
|
||||||
|
|||||||
@@ -14,17 +14,19 @@
|
|||||||
* y = options.y + options.h
|
* y = options.y + options.h
|
||||||
*/
|
*/
|
||||||
module.exports = function Crop(options) {
|
module.exports = function Crop(options) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.title = "Crop Image";
|
options.title = "Do Nothing";
|
||||||
options.format = options.format || "png";
|
this_ = this;
|
||||||
|
var output
|
||||||
function draw(image) {
|
|
||||||
var getPixels = require("get-pixels"),
|
var getPixels = require("get-pixels"),
|
||||||
savePixels = require("save-pixels"),
|
savePixels = require("save-pixels"),
|
||||||
base64 = require('base64-stream');
|
base64 = require('base64-stream');
|
||||||
|
|
||||||
getPixels(image.src,function(err,pixels){
|
function draw(input,callback) {
|
||||||
|
|
||||||
|
const this_ = this;
|
||||||
|
|
||||||
|
getPixels(input.src,function(err,pixels){
|
||||||
var newdata = [];
|
var newdata = [];
|
||||||
var ox = options.x || 0;
|
var ox = options.x || 0;
|
||||||
var oy = options.y || 0;
|
var oy = options.y || 0;
|
||||||
@@ -39,23 +41,23 @@
|
|||||||
pixels.shape = [w,h,4];
|
pixels.shape = [w,h,4];
|
||||||
pixels.stride[1] = 4*w;
|
pixels.stride[1] = 4*w;
|
||||||
|
|
||||||
var buffer = base64.encode();
|
options.format = "jpeg";
|
||||||
savePixels(pixels, options.format)
|
|
||||||
.on('end', function() {
|
|
||||||
|
|
||||||
var img = new Image();
|
|
||||||
|
|
||||||
img.src = 'data:image/' + options.format + ';base64,' + buffer.read().toString();
|
|
||||||
|
|
||||||
if (options.output) options.output(img);
|
|
||||||
|
|
||||||
}).pipe(buffer);
|
|
||||||
|
|
||||||
|
w = base64.encode();
|
||||||
|
var r = savePixels(pixels, options.format);
|
||||||
|
r.pipe(w).on('finish',function(){
|
||||||
|
data = w.read().toString();
|
||||||
|
datauri = 'data:image/' + options.format + ';base64,' + data;
|
||||||
|
this_.output = {src:datauri,format:options.format};
|
||||||
|
callback();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options: options,
|
options: options,
|
||||||
draw: draw
|
draw: draw,
|
||||||
|
output: output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,14 +9,12 @@ module.exports = function ImageThreshold(options) {
|
|||||||
var image;
|
var image;
|
||||||
|
|
||||||
function draw(inputImage) {
|
function draw(inputImage) {
|
||||||
$(inputImage).load(function(){
|
|
||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
canvas.width = inputImage.naturalWidth;
|
canvas.width = inputImage.naturalWidth;
|
||||||
canvas.height = inputImage.naturalHeight;
|
canvas.height = inputImage.naturalHeight;
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
context.drawImage(inputImage, 0, 0 );
|
context.drawImage(inputImage, 0, 0 );
|
||||||
|
var imageData = context.getImageData(0, 0, inputImage.naturalWidth, inputImage.naturalHeight);
|
||||||
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
||||||
|
|
||||||
var imageThreshold = require('image-filter-threshold');
|
var imageThreshold = require('image-filter-threshold');
|
||||||
var imageFilterCore = require('image-filter-core');
|
var imageFilterCore = require('image-filter-core');
|
||||||
@@ -31,7 +29,6 @@ module.exports = function ImageThreshold(options) {
|
|||||||
}
|
}
|
||||||
image.src = imageFilterCore.convertImageDataToCanvasURL(imageData);
|
image.src = imageFilterCore.convertImageDataToCanvasURL(imageData);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get() {
|
function get() {
|
||||||
|
|||||||
76
test/chain.js
Normal file
76
test/chain.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var test = require('tape');
|
||||||
|
|
||||||
|
// We should only test headless code here.
|
||||||
|
// http://stackoverflow.com/questions/21358015/error-jquery-requires-a-window-with-a-document#25622933
|
||||||
|
|
||||||
|
require('../src/ImageSequencer.js');
|
||||||
|
|
||||||
|
var sequencer = ImageSequencer({ ui: "none" });
|
||||||
|
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||||
|
|
||||||
|
test('loadImages/loadImage has a name generator.', function (t){
|
||||||
|
sequencer.loadImage(red);
|
||||||
|
t.equal(sequencer.images.image1.steps.length, 1, "Initial Step Created");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('loadImages/loadImage returns a wrapper.', function (t){
|
||||||
|
var returnval = sequencer.loadImage(red);
|
||||||
|
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');
|
||||||
|
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");
|
||||||
|
t.equal(sequencer.images.image3.steps[1].options.name,"invert","Correct Step Added");
|
||||||
|
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){
|
||||||
|
var returnval = sequencer.addSteps("image3","ndvi-red");
|
||||||
|
t.equal(returnval.name,"ImageSequencer","Sequencer is returned");
|
||||||
|
t.equal(sequencer.images.image3.steps.length,3,"Step length increased");
|
||||||
|
t.equal(sequencer.images.image3.steps[2].options.name,"ndvi-red","Correct Step Added");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('removeSteps is two-way chainable.', function (t){
|
||||||
|
var returnval = sequencer.loadImage(red).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){
|
||||||
|
var returnval = sequencer.removeSteps("image3",1);
|
||||||
|
t.equal(returnval.name,"ImageSequencer","Sequencer is returned");
|
||||||
|
t.equal(sequencer.images.image3.steps.length,2);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('insertSteps is two-way chainable.', function (t){
|
||||||
|
var returnval = sequencer.loadImage(red).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){
|
||||||
|
var returnval = sequencer.insertSteps("image5",1,"ndvi-red");
|
||||||
|
t.equal(returnval.name,"ImageSequencer","Sequencer is returned");
|
||||||
|
t.equal(sequencer.images.image5.steps.length,3);
|
||||||
|
t.equal(sequencer.images.image5.steps[1].options.name,"ndvi-red","Correct Step Inserrted");
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
@@ -9,20 +9,17 @@ require('../src/ImageSequencer.js');
|
|||||||
|
|
||||||
var sequencer = ImageSequencer({ ui: "none" });
|
var sequencer = ImageSequencer({ ui: "none" });
|
||||||
var image = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
var image = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||||
sequencer.loadImages({images:{
|
sequencer.loadImages(image);
|
||||||
test1: image,
|
|
||||||
test2: image
|
|
||||||
}, callback:function(){}});
|
|
||||||
|
|
||||||
sequencer.addSteps("test1", ['do-nothing-pix','invert','invert']);
|
sequencer.addSteps(['do-nothing-pix','invert','invert']);
|
||||||
sequencer.run();
|
sequencer.run();
|
||||||
|
|
||||||
test("Inverted image isn't identical", function (t) {
|
test("Inverted image isn't identical", function (t) {
|
||||||
t.notEqual(sequencer.images.test1.steps[1].output.src, sequencer.images.test1.steps[2].output.src);
|
t.notEqual(sequencer.images.image1.steps[1].output.src, sequencer.images.image1.steps[2].output.src);
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Twice inverted image is identical to original image", function (t) {
|
test("Twice inverted image is identical to original image", function (t) {
|
||||||
t.equal(sequencer.images.test1.steps[1].output.src, sequencer.images.test1.steps[3].output.src);
|
t.equal(sequencer.images.image1.steps[1].output.src, sequencer.images.image1.steps[3].output.src);
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,102 +9,132 @@ var test = require('tape');
|
|||||||
require('../src/ImageSequencer.js');
|
require('../src/ImageSequencer.js');
|
||||||
|
|
||||||
var sequencer = ImageSequencer({ ui: "none" });
|
var sequencer = ImageSequencer({ ui: "none" });
|
||||||
|
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||||
|
|
||||||
test('Image Sequencer has tests', function (t) {
|
test('Image Sequencer has tests', function (t) {
|
||||||
t.equal(true, true);
|
t.equal(true, true, "Initial Test");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('loadImages loads an image and creates a step.', function (t){
|
test('loadImages loads a DataURL image and creates a step.', function (t){
|
||||||
sequencer.loadImages('test','examples/red.jpg');
|
sequencer.loadImages('test',red);
|
||||||
t.equal(sequencer.images.test.steps.length, 1, "It Does!");
|
t.equal(sequencer.images.test.steps.length, 1, "Initial Step Created");
|
||||||
|
t.equal(typeof(sequencer.images.test.steps[0].output.src), "string", "Initial output exists");
|
||||||
|
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");
|
||||||
|
t.end();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sequencer.loadImages(red);
|
||||||
|
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);
|
||||||
|
t.equal(sequencer.images.test2.steps.length, 1, "Initial Step Created");
|
||||||
|
t.equal(typeof(sequencer.images.test2.steps[0].output.src), "string", "Initial output exists");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('addSteps("image","name") adds a step', function (t) {
|
test('addSteps("image","name") adds a step', function (t) {
|
||||||
sequencer.addSteps('test','do-nothing');
|
sequencer.addSteps('test','do-nothing');
|
||||||
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 2, "Length of steps increased")
|
||||||
t.equal(sequencer.images.test.steps.length, 2, "It Does!")
|
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing", "Correct Step Added");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('addSteps("name") adds a step', function (t) {
|
test('addSteps("name") adds a step', function (t) {
|
||||||
sequencer.addSteps('do-nothing');
|
sequencer.addSteps('do-nothing');
|
||||||
t.equal(sequencer.images.test.steps[2].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 3, "Length of steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 3, "It Does!")
|
t.equal(sequencer.images.test.steps[2].options.name, "do-nothing", "Correct Step Added");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('addSteps(["name"]) adds a step', function (t) {
|
test('addSteps(["name"]) adds a step', function (t) {
|
||||||
sequencer.addSteps(['do-nothing','do-nothing-pix']);
|
sequencer.addSteps(['do-nothing','do-nothing-pix']);
|
||||||
t.equal(sequencer.images.test.steps[3].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 5, "Length of steps increased by two")
|
||||||
t.equal(sequencer.images.test.steps[4].options.name, "do-nothing-pix");
|
t.equal(sequencer.images.test.steps[3].options.name, "do-nothing", "Correct Step Added");
|
||||||
t.equal(sequencer.images.test.steps.length, 5, "It Does!")
|
t.equal(sequencer.images.test.steps[4].options.name, "do-nothing-pix", "Correct Step Added");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('addSteps("name",o) adds a step', function (t) {
|
test('addSteps("name",o) adds a step', function (t) {
|
||||||
sequencer.addSteps('do-nothing',{});
|
sequencer.addSteps('do-nothing',{});
|
||||||
t.equal(sequencer.images.test.steps[5].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 6, "Length of steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 6, "It Does!")
|
t.equal(sequencer.images.test.steps[5].options.name, "do-nothing", "Correct Step Added");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('addSteps("image","name",o) adds a step', function (t) {
|
test('addSteps("image","name",o) adds a step', function (t) {
|
||||||
sequencer.addSteps('test','do-nothing',{});
|
sequencer.addSteps('test','do-nothing',{});
|
||||||
t.equal(sequencer.images.test.steps[6].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 7, "Length of steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 7, "It Does!")
|
t.equal(sequencer.images.test.steps[6].options.name, "do-nothing", "Correct Step Added");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('removeSteps("image",position) removes a step', function (t) {
|
test('removeSteps("image",position) removes a step', function (t) {
|
||||||
sequencer.removeSteps('test',1);
|
sequencer.removeSteps('test',1);
|
||||||
t.equal(sequencer.images.test.steps.length, 6, "It Does!");
|
t.equal(sequencer.images.test.steps.length, 6, "Length of steps reduced");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('removeSteps({image: [positions]}) removes steps', function (t) {
|
test('removeSteps({image: [positions]}) removes steps', function (t) {
|
||||||
sequencer.removeSteps('test',[1,2]);
|
sequencer.removeSteps('test',[1,2]);
|
||||||
t.equal(sequencer.images.test.steps.length, 4, "It Does!");
|
t.equal(sequencer.images.test.steps.length, 4, "Length of steps reduced");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('removeSteps(position) removes steps', function (t) {
|
test('removeSteps(position) removes steps', function (t) {
|
||||||
sequencer.removeSteps([1,2]);
|
sequencer.removeSteps([1,2]);
|
||||||
t.equal(sequencer.images.test.steps.length, 2, "It Does!");
|
t.equal(sequencer.images.test.steps.length, 2, "Length of steps reduced");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insertSteps("image",position,"module",options) inserts a step', function (t) {
|
test('insertSteps("image",position,"module",options) inserts a step', function (t) {
|
||||||
sequencer.insertSteps('test',1,'do-nothing',{});
|
sequencer.insertSteps('test',1,'do-nothing',{});
|
||||||
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 3, "Length of Steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 3, "It Does!");
|
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing", "Correct Step Inserted");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insertSteps("image",position,"module") inserts a step', function (t) {
|
test('insertSteps("image",position,"module") inserts a step', function (t) {
|
||||||
sequencer.insertSteps('test',1,'do-nothing');
|
sequencer.insertSteps('test',1,'do-nothing');
|
||||||
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 4, "Length of Steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 4, "It Does!");
|
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing", "Correct Step Inserted");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insertSteps(position,"module") inserts a step', function (t) {
|
test('insertSteps(position,"module") inserts a step', function (t) {
|
||||||
sequencer.insertSteps(1,'do-nothing');
|
sequencer.insertSteps(1,'do-nothing');
|
||||||
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 5, "Length of Steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 5, "It Does!");
|
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing", "Correct Step Inserted");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insertSteps({image: {index: index, name: "module", o: options} }) inserts a step', function (t) {
|
test('insertSteps({image: {index: index, name: "module", o: options} }) inserts a step', function (t) {
|
||||||
sequencer.insertSteps({test: {index:1, name:'do-nothing', o:{} } });
|
sequencer.insertSteps({test: {index:1, name:'do-nothing', o:{} } });
|
||||||
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing");
|
t.equal(sequencer.images.test.steps.length, 6, "Length of Steps increased");
|
||||||
t.equal(sequencer.images.test.steps.length, 6, "It Does!");
|
t.equal(sequencer.images.test.steps[1].options.name, "do-nothing", "Correct Step Inserted");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('run() runs the sequencer', function (t) {
|
test('run() runs the sequencer and returns output to callback', function (t) {
|
||||||
sequencer.run();
|
sequencer.run('test',function(out){
|
||||||
t.equal(typeof(sequencer.images.test.steps[sequencer.images.test.steps.length - 1].output), "object", "It Does!");
|
t.equal(typeof(sequencer.images.test.steps[sequencer.images.test.steps.length - 1].output), "object", "Output is Generated");
|
||||||
|
t.equal(out,sequencer.images.test.steps[sequencer.images.test.steps.length - 1].output.src, "Output callback works");
|
||||||
|
});
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('replaceImage returns false in NodeJS', function (t) {
|
||||||
|
var returnvalue = (sequencer.options.inBrowser)?false:sequencer.replaceImage("#selector","test");
|
||||||
|
t.equal(returnvalue,false,"It does.");
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user