mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-10 10:20:00 +01:00
Compare commits
118 Commits
v2.2.2
...
MargaretAN
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb023a5305 | ||
|
|
611016b022 | ||
|
|
f77cface7b | ||
|
|
f3291e201f | ||
|
|
901cf6a96c | ||
|
|
7f4f9a0950 | ||
|
|
3a39d2b4bb | ||
|
|
3ab02125cb | ||
|
|
d5aac98a29 | ||
|
|
8ff09e26cc | ||
|
|
d7b175eceb | ||
|
|
ee5a3a5e4f | ||
|
|
35b95a68b1 | ||
|
|
5288973a48 | ||
|
|
d49acd504e | ||
|
|
ac9086e4ef | ||
|
|
94e4dfe1b9 | ||
|
|
056e57af8b | ||
|
|
9fedf4b9c7 | ||
|
|
300d972718 | ||
|
|
e2f1fb9729 | ||
|
|
3e5cec32e4 | ||
|
|
8a96bd8cac | ||
|
|
7cd89c4481 | ||
|
|
980966ecfa | ||
|
|
eebf149532 | ||
|
|
59898d72fe | ||
|
|
23f4851bb5 | ||
|
|
6bab70ad09 | ||
|
|
327b421284 | ||
|
|
98e4eca24f | ||
|
|
a93440093b | ||
|
|
0c2d2a47d8 | ||
|
|
16debae154 | ||
|
|
3e30c0f7ed | ||
|
|
fd78285ac7 | ||
|
|
4eb386eb47 | ||
|
|
f27b09793c | ||
|
|
a56e8a3b16 | ||
|
|
b666ad510b | ||
|
|
809fb0b37a | ||
|
|
a4818d70d8 | ||
|
|
537cc41b36 | ||
|
|
95f8dad901 | ||
|
|
ceca433806 | ||
|
|
1e719936c4 | ||
|
|
1ae20b536a | ||
|
|
753e73f355 | ||
|
|
a26a441b20 | ||
|
|
7ae8a2ddf7 | ||
|
|
c81f5c6caf | ||
|
|
6d381c0df8 | ||
|
|
6a2f106b4c | ||
|
|
65a6b77b78 | ||
|
|
c688817ffc | ||
|
|
ca67bf1ece | ||
|
|
88a31e564e | ||
|
|
2161d58e50 | ||
|
|
108e87996a | ||
|
|
f152a78e70 | ||
|
|
5af30d9046 | ||
|
|
ddf4bd0dae | ||
|
|
3712f0c1cf | ||
|
|
f672dc814a | ||
|
|
98c71b18a8 | ||
|
|
3ca4081042 | ||
|
|
cd6f61d71a | ||
|
|
20cf3277ea | ||
|
|
bf13d5807a | ||
|
|
ef10fb77f1 | ||
|
|
19110c4677 | ||
|
|
d209cd46b1 | ||
|
|
4bdc5b6583 | ||
|
|
4576e497db | ||
|
|
1311119787 | ||
|
|
9e1a12c58d | ||
|
|
948f67fb60 | ||
|
|
8685dcb66c | ||
|
|
2243a4b8f7 | ||
|
|
7fe16735b3 | ||
|
|
a17d1a6ccd | ||
|
|
5f57123503 | ||
|
|
d2ff6f2d6c | ||
|
|
361be0074c | ||
|
|
f9376808fd | ||
|
|
85c92626e4 | ||
|
|
b30b539dab | ||
|
|
e5e372d89d | ||
|
|
11b65604cd | ||
|
|
c762f1ad5d | ||
|
|
965399a2b4 | ||
|
|
3df5ca3802 | ||
|
|
7e594c4168 | ||
|
|
5e28f901eb | ||
|
|
48eafe806f | ||
|
|
6638e9bdb4 | ||
|
|
bf80c2b2b6 | ||
|
|
e512e98921 | ||
|
|
9168c15cf9 | ||
|
|
276a637ac3 | ||
|
|
1d085c7f20 | ||
|
|
802b281096 | ||
|
|
67408ca338 | ||
|
|
a67fe91d0d | ||
|
|
09669fe858 | ||
|
|
768117a078 | ||
|
|
2e7e042baa | ||
|
|
b300dc2d1f | ||
|
|
fef021911b | ||
|
|
70654a5aac | ||
|
|
338e610fe7 | ||
|
|
06d2aaf1e2 | ||
|
|
5a362f5c9a | ||
|
|
76826d431d | ||
|
|
88364decf6 | ||
|
|
bb17e9452f | ||
|
|
cce65141d2 | ||
|
|
b707592588 |
35
.github/ISSUE_TEMPLATE.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
### Please describe the problem (or idea)
|
||||
|
||||
> What happened just before the problem occurred? Or what problem could this idea solve?
|
||||
|
||||
|
||||
|
||||
> What did you expect to see that you didn't?
|
||||
|
||||
|
||||
|
||||
### Please show us where to look
|
||||
|
||||
http://sequencer.publiclab.org...
|
||||
|
||||
|
||||
### What's your PublicLab.org username?
|
||||
|
||||
> This can help us diagnose the issue:
|
||||
|
||||
|
||||
|
||||
### Browser, version, and operating system
|
||||
|
||||
> Many bugs are related to these -- please help us track it down and reproduce what you're seeing!
|
||||
|
||||
|
||||
****
|
||||
|
||||
## Thank you!
|
||||
|
||||
Your help makes Public Lab better! We *deeply* appreciate your helping refine and improve this site.
|
||||
|
||||
To learn how to write really great issues, which increases the chances they'll be resolved, see:
|
||||
|
||||
https://publiclab.org/wiki/developers#Contributing+for+non-coders
|
||||
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
Fixes #[Add issue number here.]
|
||||
|
||||
Make sure these boxes are checked before your pull request (PR) is ready to be reviewed and merged. Thanks!
|
||||
|
||||
* [ ] tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with `rake test`
|
||||
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
||||
* [ ] PR is descriptively titled
|
||||
* [ ] ask `@publiclab/reviewers` for help, in a comment below
|
||||
|
||||
> We're happy to help you get this ready -- don't be afraid to ask for help, and **don't be discouraged** if your tests fail at first!
|
||||
|
||||
If tests do fail, click on the red `X` to learn why by reading the logs.
|
||||
|
||||
Please be sure you've reviewed our contribution guidelines at https://publiclab.org/contributing-to-public-lab-software
|
||||
|
||||
Thanks!
|
||||
25
.github/config.yml
vendored
Normal file
25
.github/config.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Configuration for welcome - https://github.com/behaviorbot/welcome
|
||||
|
||||
# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
|
||||
|
||||
# Comment to be posted to on first time issues
|
||||
newIssueWelcomeComment: |
|
||||
Thanks for opening your first issue here! Please follow the issue template to help us help you 👍🎉😄
|
||||
If you have screenshots to share demonstrating the issue, that's really helpful! 📸 You can [make a gif](https://www.cockos.com/licecap/) too!
|
||||
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
|
||||
|
||||
# Comment to be posted to on PRs from first time contributors in your repository
|
||||
newPRWelcomeComment: |
|
||||
Thanks for opening this pull request! `Dangerbot` will test out your code and reply in a bit with some pointers and requests.
|
||||
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
|
||||
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||
|
||||
# Comment to be posted to on pull requests merged by a first time user
|
||||
firstPRMergeComment: |
|
||||
Congrats on merging your first pull request! 🙌🎉⚡️
|
||||
Your code will likely be published to https://sequencer.publiclab.org in the next few days.
|
||||
In the meantime, can you tell us your Twitter handle so we can thank you properly?
|
||||
Now that you've completed this, you can help someone else take their first step!
|
||||
See: [Public Lab's coding community!](https://code.publiclab.org)
|
||||
|
||||
# It is recommended to include as many gifs and emojis as possible
|
||||
45
.npmignore
Normal file
45
.npmignore
Normal file
@@ -0,0 +1,45 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
.DS_Store
|
||||
|
||||
*.swp
|
||||
todo.txt
|
||||
test.js
|
||||
output.txt
|
||||
output/
|
||||
|
||||
examples/
|
||||
icons/
|
||||
|
||||
.travis.yml
|
||||
Gruntfile.js
|
||||
yarn.lock
|
||||
@@ -10,13 +10,13 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
|
||||
* [README.md](https://github.com/publiclab/image-sequencer)
|
||||
* [Contributing Modules](#contributing-modules)
|
||||
* [Info File](#info-file)
|
||||
* [Ideas](#ideas)
|
||||
* [Ideas](#Contribution-ideas)
|
||||
|
||||
****
|
||||
|
||||
## Contribution ideas
|
||||
## Contribution-ideas
|
||||
|
||||
See [this issue](https://github.com/publiclab/image-sequencer/issues/118) for a range of ideas for new contributions, and links to possibly helpful libraries. Also see the [new features issues list](https://github.com/publiclab/image-sequencer/labels/new-feature).
|
||||
See [this issue](https://github.com/publiclab/image-sequencer/issues/118) for a range of ideas for new contributions and links to possibly helpful libraries, or you can solve an [existing issue](https://github.com/publiclab/image-sequencer/labels/module). Also see the [new features issues list](https://github.com/publiclab/image-sequencer/labels/new-feature).
|
||||
|
||||
### Bugs
|
||||
|
||||
|
||||
63
README.md
63
README.md
@@ -10,13 +10,13 @@ Image Sequencer is different from other image processing systems in that it's _n
|
||||
* produces a legible trail of operations, to "show your work" for evidential, educational, or reproducibility reasons
|
||||
* makes the creation of new tools or "modules" simpler -- each must accept an input image, and produce an output image
|
||||
* allows many images to be run through the same sequence of steps
|
||||
* works identically in the browser, on Node.js, and on the commandline
|
||||
* works identically in the browser, on Node.js, and on the command line
|
||||
|
||||

|
||||
|
||||
It is also for prototyping some other related ideas:
|
||||
|
||||
* filter-like image processing -- applying a transform to any image from a given source, like a proxy. I.e. every image tile of a satellite imagery web map
|
||||
* filter-like image processing -- applying a transform to an image from a given source, like a proxy. I.e. [every image tile of a satellite imagery web map](https://publiclab.org/notes/warren/05-10-2018/prototype-filter-map-tiles-in-real-time-in-a-browser-with-imagesequencer-ndvi-landsat)
|
||||
* test-based image processing -- the ability to create a sequence of steps that do the same task as some other image processing tool, provable with example before/after images to compare with
|
||||
* logging of each step to produce an evidentiary record of modifications to an original image
|
||||
* cascading changes -- change an earlier step's settings, and see those changes affect later steps
|
||||
@@ -45,7 +45,20 @@ A diagram of this running 5 steps on a single sample image may help explain how
|
||||
|
||||
## Installation
|
||||
|
||||
This library works in the browser, in Node, and on the commandline (CLI), which we think is great. You can start a local environement to test the UI with `npm start`
|
||||
This library works in the browser, in Node, and on the command line (CLI), which we think is great.
|
||||
|
||||
### Unix based platforms
|
||||
You can set up a local environment to test the UI with `sudo npm run setup` followed by `npm start`
|
||||
|
||||
### Windows
|
||||
Our npm scripts do not support windows shells, please run the following snippet in PowerShell.
|
||||
```powershell
|
||||
npm i ; npm i -g grunt grunt-cli ; grunt serve
|
||||
```
|
||||
In case of a port conflict please run the following
|
||||
```powershell
|
||||
npm i -g http-server ; http-server -p 3000
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
||||
@@ -54,7 +67,7 @@ Just include [image-sequencer.js](https://publiclab.github.io/image-sequencer/di
|
||||
### Node (via NPM)
|
||||
|
||||
(You must have NPM for this)
|
||||
Add `image-sequencer` to your list of dependancies and run `$ npm install`
|
||||
Add `image-sequencer` to your list of dependencies and run `$ npm install`
|
||||
|
||||
### CLI
|
||||
|
||||
@@ -80,13 +93,13 @@ Image Sequencer can be used to run modules on an HTML Image Element using the
|
||||
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.
|
||||
from 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.
|
||||
`optional_options` allows passing additional arguments to the module itself.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -95,6 +108,14 @@ For example:
|
||||
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
||||
```
|
||||
|
||||
### Data URL usage
|
||||
|
||||
Since Image Sequencer uses data-urls, you can initiate a new sequence by providing an image in the [data URL format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs), which will import into the demo and run:
|
||||
|
||||
[Try this example link with a very small Data URL](http://sequencer.publiclab.org/examples/#src=data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z&steps=invert{})
|
||||
|
||||
To produce a data URL from an HTML image, see [this nice blog post with example code](https://davidwalsh.name/convert-image-data-uri-javascript).
|
||||
|
||||
## CLI Usage
|
||||
|
||||
Image Sequencer also provides a CLI for applying operations to local files. The CLI takes the following arguments:
|
||||
@@ -123,7 +144,7 @@ The CLI also can take multiple steps at once, like so:
|
||||
|
||||
But for this, double quotes must wrap the space-separated steps.
|
||||
|
||||
Options for the steps can be passed in one line as json in the details option like
|
||||
Options for the steps can be passed in one line as JSON in the details option like
|
||||
```
|
||||
$ ./index.js -i [PATH] -s "brightness" -c '{"brightness":50}'
|
||||
|
||||
@@ -137,7 +158,7 @@ Or the values can be given through terminal prompt like
|
||||
sequencer --save-sequence "invert-colormap invert(),colormap()"
|
||||
```
|
||||
|
||||
`install-module` option can be used to install new modules from npm. You can register this module in your sequencer with a custom name space sepated with the npm package name. Below is an example for the `image-sequencer-invert` module.
|
||||
`install-module` option can be used to install new modules from npm. You can register this module in your sequencer with a custom namespace separated with the npm package name. Below is an example of the `image-sequencer-invert` module.
|
||||
```shell
|
||||
sequencer --install-module "invert image-sequencer-invert"
|
||||
```
|
||||
@@ -175,7 +196,7 @@ CORS Restrictions). To sum up, these are accepted:
|
||||
* 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:
|
||||
The callback is called within the scope of a sequencer. For example:
|
||||
(addSteps is defined later)
|
||||
|
||||
```js
|
||||
@@ -189,7 +210,7 @@ In this case, only `'SRC'`.
|
||||
|
||||
### Adding steps to the image
|
||||
|
||||
The `addSteps` method is used to add steps on the image. One or more steps can
|
||||
The `addSteps` method is used to add steps to the image. One or more steps can
|
||||
be added at a time. Each step is called a module.
|
||||
|
||||
```js
|
||||
@@ -218,7 +239,7 @@ sequencer.run();
|
||||
Sequencer can be run with a custom config object
|
||||
|
||||
```js
|
||||
// The config object enables custom progress bars in node environment and
|
||||
// The config object enables custom progress bars in a node environment and
|
||||
// ability to run the sequencer from a particular index(of the steps array)
|
||||
|
||||
sequencer.run(config);
|
||||
@@ -242,7 +263,7 @@ sequencer.run(function callback(out){
|
||||
// "out" is the DataURL of the final image.
|
||||
});
|
||||
sequencer.run(config,function callback(out){
|
||||
// the callback is supported with all types of invocations
|
||||
// the callback is supported by all types of invocations
|
||||
});
|
||||
```
|
||||
|
||||
@@ -252,7 +273,7 @@ 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
|
||||
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,
|
||||
@@ -272,7 +293,7 @@ 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
|
||||
in the sequencer. It accepts the index where the module is to be inserted, the 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`.
|
||||
@@ -290,7 +311,7 @@ return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
### Importing an independent module
|
||||
|
||||
The `loadNewModule` method can be used to import a new module inside sequencer. Modules can be downloaded via npm, yarn or cdn and are imported with a custom name. If you wish to load a new module at runtime, it will need to avoid using `require()` -- unless it is compiled with a system like browserify or webpack.
|
||||
The `loadNewModule` method can be used to import a new module inside the sequencer. Modules can be downloaded via npm, yarn or CDN and are imported with a custom name. If you wish to load a new module at runtime, it will need to avoid using `require()` -- unless it is compiled with a system like browserify or webpack.
|
||||
|
||||
```js
|
||||
const module = require('sequencer-moduleName')
|
||||
@@ -306,7 +327,7 @@ Methods can be chained on the Image Sequencer:
|
||||
* 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.
|
||||
be of the form "image<number>". For Ex: "image1", "image2", "image3", etc.
|
||||
|
||||
Valid Chains:
|
||||
```js
|
||||
@@ -363,7 +384,7 @@ return value: **none**
|
||||
### Adding Steps on Multiple Images
|
||||
|
||||
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
|
||||
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
|
||||
@@ -414,7 +435,7 @@ The `run` method also accepts an optional callback just like before:
|
||||
});
|
||||
```
|
||||
|
||||
JSON Input is also acceptable.
|
||||
JSON input is also acceptable.
|
||||
|
||||
```js
|
||||
sequencer.run({
|
||||
@@ -453,7 +474,7 @@ return value: **`sequencer`** (To allow method chaining)
|
||||
### Inserting steps on an image
|
||||
|
||||
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.
|
||||
may be an array. Everything else remains the same. JSON Input is acceptable too.
|
||||
|
||||
```js
|
||||
sequencer.insertSteps("image",index,"module_name",o);
|
||||
@@ -474,7 +495,7 @@ return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
## Saving Sequences
|
||||
|
||||
IMAGE SEQUENCER supports saving a sequence of modules and their associated settings in a simple string syntax. These sequences can be saved in the local storage inside the browser and inside a json file in node.js. sequences can be saved in node context using the CLI option
|
||||
IMAGE SEQUENCER supports saving a sequence of modules and their associated settings in a simple string syntax. These sequences can be saved in the local storage inside the browser and inside a JSON file in node.js. sequences can be saved in node context using the CLI option
|
||||
|
||||
```shell
|
||||
--save-sequence "name stringified-sequence"
|
||||
@@ -495,7 +516,7 @@ Image sequencer supports stringifying a sequence which is appended to the url an
|
||||
channel{channel:green},invert{}
|
||||
```
|
||||
|
||||
Sequencer also supports use of `()` in place of `{}` for backwards compatibility with older links.(This syntax is deprecated and should be avoided as far as possible)
|
||||
Sequencer also supports the use of `()` in place of `{}` for backward compatibility with older links. (This syntax is deprecated and should be avoided as far as possible)
|
||||
```
|
||||
channel(channel:green),invert()
|
||||
```
|
||||
|
||||
46249
dist/image-sequencer.js
vendored
46249
dist/image-sequencer.js
vendored
File diff suppressed because one or more lines are too long
2
dist/image-sequencer.min.js
vendored
2
dist/image-sequencer.min.js
vendored
File diff suppressed because one or more lines are too long
367
docs/MODULES.md
367
docs/MODULES.md
@@ -1,7 +1,38 @@
|
||||
Documentation of various Modules
|
||||
===
|
||||
|
||||
## Crop Module (crop)
|
||||
List of Module Documentations
|
||||
|
||||
1. [Crop](#crop-module)
|
||||
2. [Segmented-Colormap](#segmented-colormap-module)
|
||||
3. [FisheyeGl](#fisheyeGl-module)
|
||||
4. [Average](#average-module)
|
||||
5. [Blend](#blend-module)
|
||||
6. [Blur](#blur-module)
|
||||
7. [Brightness](#brightness-module)
|
||||
8. [Channel](#channel-module)
|
||||
9. [Colorbar](#colorbar-module)
|
||||
10. [Colormap](#colormap-module)
|
||||
11. [Contrast](#contrast-module)
|
||||
12. [Convolution](#convolutioon-module)
|
||||
13. [DecodeQr](#decodeQr-module)
|
||||
14. [Dynamic](#dynamic-module)
|
||||
15. [Edge-Detect](#edge-detect-module)
|
||||
16. [Gamma-Correction](#gamma-correction-module)
|
||||
17. [Gradient](#gradient-module)
|
||||
18. [Histogram](#histogram-module)
|
||||
19. [Import-image](#import-image-module)
|
||||
20. [Invert](#invert-module)
|
||||
21. [Ndvi](#ndvi-module)
|
||||
22. [Ndvi-Colormap](#ndvi-colormap-module)
|
||||
23. [Overlay](#overlay-module)
|
||||
24. [Resize](#resize-module)
|
||||
25. [Rotate](#rotate-module)
|
||||
26. [Saturation](#saturation-module)
|
||||
|
||||
|
||||
|
||||
## crop-module
|
||||
|
||||
This module is used to crop an image.
|
||||
|
||||
@@ -24,7 +55,7 @@ Where `options` is an object having the properties `x`, `y`, `w`, `h`. This diag
|
||||
* `options.h` : half of image height
|
||||
|
||||
|
||||
## Segmented Colormap Module (segmented-colormap)
|
||||
## segmented-colormap-module
|
||||
|
||||
This module is used to map the pixels of the image to a segmented colormap.
|
||||
|
||||
@@ -48,7 +79,7 @@ where `options` is an object with the property `colormap`. `options.colormap` ca
|
||||
|
||||
* A custom array.
|
||||
|
||||
## FisheyeGl (fisheye-gl)
|
||||
## fisheyeGl-module
|
||||
|
||||
This module is used for correcting Fisheye or Lens Distortion
|
||||
|
||||
@@ -68,3 +99,333 @@ where `options` is an object with the following properties:
|
||||
* scale : The ratio to which the original image is to be scaled (0 to 20; default 1.5)
|
||||
* x : Field of View x (0 to 2; default 1)
|
||||
* y : Field of View y (0 to 2; default 1)
|
||||
|
||||
## average-module
|
||||
|
||||
This module is used for averaging all the pixels of the image.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('average',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
## blend-module
|
||||
|
||||
This module is used for blending two images .
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('blend',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
|
||||
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })
|
||||
|
||||
## blur-module
|
||||
|
||||
This module is used for applying a Gaussian blur effect.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('blur',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
||||
|
||||
## brightness-module
|
||||
|
||||
This module is used for changing the brightness of the image.
|
||||
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('brightness',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* brightness : brightness of the image in percentage (0 to 100; default 100)
|
||||
|
||||
## channel-module
|
||||
|
||||
This module is used for forming a grayscale image by applying one of the three primary colors.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('channel',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* channel : color of the channel (red, green, blue; default green)
|
||||
|
||||
## colorbar-module
|
||||
|
||||
This module is used for displaying an image with a colorbar.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('colorbar',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* colormap : Name of the Colormap(default, greyscale, stretched, fastie, brntogrn, blutoredjet, colors16; default: default)
|
||||
* x : X-position of the image on which the new image is overlayed (default 0)
|
||||
* y : Y-position of the image on which the new image is overlayed (default 0)
|
||||
* h : height of resulting cropped image (default : 50% of input image width )
|
||||
|
||||
## colormap-module
|
||||
|
||||
This module is used for mapping brightness values (average of red, green & blue) to a given color lookup table, made up of a set of one more color gradients.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('colormap',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* colormap : Name of the Colormap ( greyscale, stretched, fastie, brntogrn, blutoredjet, colors16)
|
||||
|
||||
## contrast-module
|
||||
|
||||
This module is used for changing the contrast of the image.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('contrast',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* contrast : contrast for the given image (-100 to 100; default : 70)
|
||||
|
||||
## convolution-module
|
||||
|
||||
This module is used for performing image-convolution.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('convolution',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* constantFactor : a constant factor, multiplies all the kernel values by that factor (default : 1/9)
|
||||
* kernelValues : nine space separated numbers representing the kernel values in left to right and top to bottom format(default : 1 1 1 1 1 1 1 1 1)
|
||||
|
||||
## decodeQr-module
|
||||
|
||||
This module is used for decoding a QR in image (if present).
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('decode-qr',options)
|
||||
.run()
|
||||
```
|
||||
## dynamic-module
|
||||
|
||||
This module is used for producing each color channel based on the original image's color.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('dynamic',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* red : expression for red channel (R, G, B and A as inputs; default r)
|
||||
* green : expression for green channel (R, G, B and A as inputs; default g)
|
||||
* blue : expression for blue channel (R, G, B and A as inputs; default b)
|
||||
* monochrome: fallback for other channels if none provided (default : r+g+b/3)
|
||||
|
||||
## edge-detect-module
|
||||
|
||||
This module is used for detecting images.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('edge-detect',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
||||
* highThresholdRatio : Upper Threshold Ratio ( default : 0.2)
|
||||
* lowThresholdratio : Lower Threshold Ratio ( default : 0.2)
|
||||
|
||||
## gamma-correction-module
|
||||
|
||||
This module is used for applying gamma correction.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('gamma-correction',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* adjustment : Inverse of actual gamma factor (default 0.2)
|
||||
|
||||
## gradient-module
|
||||
|
||||
This module is used for finding gradient of the image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('gradient',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
## histogram-module
|
||||
|
||||
This module is used for calculating histogram of the image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('histogram',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* gradient : boolean value used to toggle gradient along x-axis (true or false; default true)
|
||||
|
||||
## import-image-module
|
||||
|
||||
This module is used for importing a new image and replacing the original with it.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('import-image',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* url : url of the new image (local image url or data url;default : "./images/monarch.png")
|
||||
|
||||
## invert-module
|
||||
|
||||
This module is used for inverting the image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('invert',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
## ndvi-module
|
||||
|
||||
This module is used for applying ndvi technique to the image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('ndvi',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* filter : filter for NDVI (blue or red; default red)
|
||||
|
||||
## ndvi-colormap-module
|
||||
|
||||
This module is used for demonstrating ndvi and colormap properties consecutively.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('ndvi-colormap',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
## overlay-module
|
||||
|
||||
This module is used for overlaying an Image over another .
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('overlay',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* x : X-position of the image on which the new image is overlayed (default 0)
|
||||
* y : Y-position of the image on which the new image is overlayed (default 0)
|
||||
* offset : offset to the step on which the output of the last step is overlayed (default -2)
|
||||
|
||||
## resize-module
|
||||
|
||||
This module is used for resizing an image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('resize',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* resize : Percentage value of resize (default 125%)
|
||||
|
||||
## rotate-module
|
||||
|
||||
This module is used for rotating an image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('rotate',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* rotate : angular value for rotation in degrees (between 0 and 360; default 0)
|
||||
|
||||
## saturation-module
|
||||
|
||||
This module is used for changing the saturation of the image.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('saturation',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* saturation : saturation for the new image (between 0 and 2; default 0)
|
||||
|
||||
|
||||
|
||||
@@ -23,14 +23,29 @@ h1 {
|
||||
color: #445;
|
||||
}
|
||||
|
||||
.center-align {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.nomargin {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
#dropzone {
|
||||
padding: 30px;
|
||||
margin: 0 20% 30px;
|
||||
@@ -90,6 +105,10 @@ h1 {
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
#add-step-btn{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#addStep .labels {
|
||||
text-align: right;
|
||||
padding: 6px;
|
||||
@@ -110,4 +129,104 @@ h1 {
|
||||
#save-seq {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
min-width: 250px;
|
||||
}
|
||||
.info {
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
#gif {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
min-width: 250px;
|
||||
}
|
||||
#dwnld {
|
||||
max-width: 500px;
|
||||
margin: 20px auto;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#gif_element {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.move-up {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 40px;
|
||||
z-index: 3;
|
||||
display: none;
|
||||
z-index:1000;
|
||||
}
|
||||
.move-up button {
|
||||
background:transparent;
|
||||
border:none;
|
||||
}
|
||||
.move-up button:active:hover {
|
||||
padding-right:4px !important;
|
||||
margin-right:2px;
|
||||
}
|
||||
.move-up i {
|
||||
font-size:60px;
|
||||
opacity:0.5;
|
||||
color:#BABABA;
|
||||
}
|
||||
|
||||
.btn-circle{
|
||||
min-width: 80px;
|
||||
min-height: 80px;
|
||||
text-align: center;
|
||||
display: flex !important;
|
||||
flex-direction: column;
|
||||
padding: 6px 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.42;
|
||||
border-radius: 10px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.radio{
|
||||
cursor:pointer;
|
||||
overflow: hidden;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#stepRemovedNotification {
|
||||
background-color: #808b96;
|
||||
padding:4px;
|
||||
color:white;
|
||||
border-radius:3px;
|
||||
font-size:2rem;
|
||||
position:fixed;
|
||||
bottom:8px;
|
||||
left:45%;
|
||||
min-width:14rem;
|
||||
text-align:center;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.i-over {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
z-index: 2;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.i-small {
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
215
examples/demo.js
215
examples/demo.js
@@ -1,19 +1,54 @@
|
||||
window.onload = function() {
|
||||
function generatePreview(previewStepName, customValues, path) {
|
||||
var previewSequencer = ImageSequencer();
|
||||
|
||||
function insertPreview(src) {
|
||||
var img = document.createElement('img');
|
||||
img.classList.add('img-thumbnail')
|
||||
img.classList.add('no-border');
|
||||
img.src = src;
|
||||
$(img).css("max-width", "200%");
|
||||
$(img).css("transform", "translateX(-20%)");
|
||||
var stepDiv = $('#addStep .row').find('div').each(function() {
|
||||
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||
$(this).find('div').append(img);
|
||||
}
|
||||
});
|
||||
}
|
||||
function loadPreview() {
|
||||
previewSequencer = previewSequencer.addSteps('resize', { resize: "40%" });
|
||||
|
||||
if (previewStepName === "crop") {
|
||||
console.log(customValues);
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
else {
|
||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
||||
}
|
||||
}
|
||||
previewSequencer.loadImage(path, loadPreview);
|
||||
}
|
||||
|
||||
|
||||
sequencer = ImageSequencer();
|
||||
|
||||
function refreshOptions() {
|
||||
// Load information of all modules (Name, Inputs, Outputs)
|
||||
var modulesInfo = sequencer.modulesInfo();
|
||||
console.log(modulesInfo)
|
||||
|
||||
var addStepSelect = $("#addStep select");
|
||||
addStepSelect.html("");
|
||||
|
||||
// Add modules to the addStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
addStepSelect.append(
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
if (modulesInfo[m] && modulesInfo[m].name)
|
||||
addStepSelect.append(
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
}
|
||||
// Null option
|
||||
addStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
}
|
||||
refreshOptions();
|
||||
|
||||
@@ -23,10 +58,34 @@ window.onload = function() {
|
||||
// UI for the overall demo:
|
||||
var ui = DefaultHtmlSequencerUi(sequencer);
|
||||
|
||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||
if (getUrlHashParameter('src')) {
|
||||
sequencer.loadImage(getUrlHashParameter('src'), ui.onLoad);
|
||||
} else {
|
||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||
}
|
||||
|
||||
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||
$("#addStep button").on("click", ui.addStepUi);
|
||||
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||
|
||||
//Module button radio selection
|
||||
$('.radio-group .radio').on("click", function() {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
console.log(newStep);
|
||||
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||
$("#addStep select").val(newStep);
|
||||
ui.selectNewStepUi();
|
||||
ui.addStepUi();
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
|
||||
$('#download-btn').click(function() {
|
||||
$('.step-thumbnail:last()').trigger("click");
|
||||
return false;
|
||||
});
|
||||
|
||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||
$('#save-seq').click(() => {
|
||||
sequencer.saveSequence(window.prompt("Please give a name to your sequence..."), sequencer.toString());
|
||||
@@ -34,16 +93,162 @@ window.onload = function() {
|
||||
refreshOptions();
|
||||
});
|
||||
|
||||
var isWorkingOnGifGeneration = false;
|
||||
|
||||
$('.js-view-as-gif').on('click', function(event) {
|
||||
// Prevent user from triggering generation multiple times
|
||||
if (isWorkingOnGifGeneration) return;
|
||||
|
||||
isWorkingOnGifGeneration = true;
|
||||
|
||||
var button = event.target;
|
||||
button.disabled = true;
|
||||
|
||||
|
||||
try {
|
||||
// Select all images from previous steps
|
||||
var imgs = document.getElementsByClassName("step-thumbnail");
|
||||
|
||||
var imgSrcs = [];
|
||||
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
imgSrcs.push(imgs[i].src);
|
||||
}
|
||||
|
||||
var options = {
|
||||
'gifWidth': imgs[0].width,
|
||||
'gifHeight': imgs[0].height,
|
||||
'images': imgSrcs,
|
||||
'frameDuration': 7,
|
||||
}
|
||||
|
||||
gifshot.createGIF(options, function(obj) {
|
||||
if (!obj.error) {
|
||||
// Final gif encoded with base64 format
|
||||
var image = obj.image;
|
||||
var animatedImage = document.createElement('img');
|
||||
|
||||
animatedImage.id = "gif_element";
|
||||
animatedImage.src = image;
|
||||
|
||||
|
||||
var modal = $('#js-download-gif-modal');
|
||||
|
||||
$("#js-download-as-gif-button").one("click", function() {
|
||||
// Trigger download
|
||||
download(image, "index.gif", "image/gif");
|
||||
|
||||
// Close modal
|
||||
modal.modal('hide');
|
||||
})
|
||||
|
||||
var gifContainer = document.getElementById("js-download-modal-gif-container");
|
||||
|
||||
// Clear previous results
|
||||
gifContainer.innerHTML = '';
|
||||
|
||||
// Insert image
|
||||
gifContainer.appendChild(animatedImage);
|
||||
|
||||
|
||||
// Open modal
|
||||
modal.modal();
|
||||
|
||||
button.disabled = false;
|
||||
isWorkingOnGifGeneration = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
button.disabled = false;
|
||||
isWorkingOnGifGeneration = false;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
||||
sequencer.setInputStep({
|
||||
dropZoneSelector: "#dropzone",
|
||||
fileInputSelector: "#fileInput",
|
||||
takePhotoSelector: "#take-photo",
|
||||
onLoad: function onFileReaderLoad(progress) {
|
||||
var reader = progress.target;
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
step.output.src = reader.result;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
updatePreviews(reader.result);
|
||||
},
|
||||
onTakePhoto: function (url) {
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
step.output.src = url;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = url;
|
||||
}
|
||||
});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||
.then(function(registration) {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
console.log(installingWorker)
|
||||
if (installingWorker.state === 'installed') {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
console.log('Registration successful, scope is:', registration.scope);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log('Service worker registration failed, error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
$("#clear-cache").append(" " + cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$("#clear-cache").click(function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
|
||||
function updatePreviews(src) {
|
||||
$('#addStep img').remove();
|
||||
|
||||
var previewSequencerSteps = {
|
||||
"brightness": "20",
|
||||
"saturation": "5",
|
||||
"rotate": 90,
|
||||
"contrast": 90,
|
||||
"crop": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": "(50%)",
|
||||
"h": "(50%)",
|
||||
"noUI": true
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(previewSequencerSteps).forEach(function(step, index) {
|
||||
generatePreview(step, Object.values(previewSequencerSteps)[index], src);
|
||||
});
|
||||
}
|
||||
|
||||
if (getUrlHashParameter('src')) {
|
||||
updatePreviews(getUrlHashParameter('src'));
|
||||
} else {
|
||||
updatePreviews("images/tulips.png");
|
||||
}
|
||||
};
|
||||
|
||||
2839
examples/gifshot.js
Normal file
2839
examples/gifshot.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,9 @@
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
||||
<meta name="theme-color" content="#428bca">
|
||||
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
||||
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<title>Image Sequencer</title>
|
||||
|
||||
@@ -19,9 +20,16 @@
|
||||
<script src="lib/urlHash.js" charset="utf-8"></script>
|
||||
<script src="lib/defaultHtmlStepUi.js" charset="utf-8"></script>
|
||||
<script src="lib/defaultHtmlSequencerUi.js" charset="utf-8"></script>
|
||||
<script src="lib/intermediateHtmlStepUi.js" charset="utf-8"></script>
|
||||
<script src="demo.js" charset="utf-8"></script>
|
||||
<!-- for crop module: -->
|
||||
<script src="../node_modules/imgareaselect/jquery.imgareaselect.dev.js"></script>
|
||||
<script src="gifshot.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Download.js for large files -->
|
||||
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript"/>
|
||||
|
||||
<script src="lib/scrollToTop.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -30,8 +38,7 @@
|
||||
|
||||
<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="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
|
||||
<!-- for crop module: -->
|
||||
<link href="../node_modules/imgareaselect/distfiles/css/imgareaselect-default.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
@@ -49,8 +56,8 @@
|
||||
Open Source
|
||||
<a href="https://github.com/publiclab/image-sequencer">
|
||||
<i class="fa fa-github"></i>
|
||||
</a> by
|
||||
<a href="https://publiclab.org">Public Lab</a>
|
||||
</a>
|
||||
by <a href= "https://publiclab.org" title = "Publiclab Website"><i class = "fa fa-globe"></i> Publiclab</a>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
@@ -59,32 +66,124 @@
|
||||
<i>Select or drag in an image to start!</i>
|
||||
</p>
|
||||
<center>
|
||||
<input type="file" id="fileInput" value="">
|
||||
<input type="file" id="fileInput" value="" accept="image/*"><br />
|
||||
<button type="button" id="take-photo">Take a Photo</button>
|
||||
<video id="video" width="400" height="300" style="display:none"></video>
|
||||
<a href="#" id="capture" style="display:none" class="btn btn-primary btn-md">Click Picture</a>
|
||||
<a href="#" id="close" style="display:none" class="btn btn-default btn-md">Close</a>
|
||||
<canvas id="canvas" width="400" height="300" style="display:none"></canvas>
|
||||
</center>
|
||||
</div>
|
||||
|
||||
<section id="steps" class="row"></section>
|
||||
<section id="steps" class="row">
|
||||
<div id="load-image"></div>
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<section id="addStep" class="panel panel-primary">
|
||||
<div class="form-inline">
|
||||
<div class="panel-body">
|
||||
<div style="text-align:center;">
|
||||
<select class="form-control input-lg" id="selectStep">
|
||||
<option value="none" disabled selected>Select a new step...</option>
|
||||
</select>
|
||||
<button class="btn btn-success btn-lg" name="add">Add Step</button>
|
||||
<p class="info">Select a new module to add to your sequence.</p>
|
||||
<div class="row center-align radio-group">
|
||||
<div>
|
||||
<div class="radio" data-value="brightness">
|
||||
<i class="fa fa-sun-o fa-4x i-over"></i>
|
||||
</div>
|
||||
<p>Brightness</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="radio" data-value="contrast">
|
||||
<i class="fa fa-adjust fa-4x i-over"></i>
|
||||
</div>
|
||||
<p>Contrast</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="radio" data-value="saturation">
|
||||
<i class="fa fa-tint fa-4x i-over i-small"></i>
|
||||
</div>
|
||||
<p>Saturation</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="radio" data-value="rotate">
|
||||
<i class="fa fa-rotate-right fa-4x i-over"></i>
|
||||
</div>
|
||||
<p>Rotate</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="radio" data-value="crop">
|
||||
<i class="fa fa-crop fa-4x i-over"></i>
|
||||
</div>
|
||||
<p>Crop</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center-align">
|
||||
<select class="form-control input-lg" id="selectStep">
|
||||
<!-- The default null selection has been appended manually in demo.js
|
||||
This is because the options in select are overritten when options are appended.-->
|
||||
</select>
|
||||
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button>
|
||||
</div>
|
||||
<br />
|
||||
<p class="info" style="padding:8px;">Select a new module to add to your sequence.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<button class="btn btn-primary btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
||||
|
||||
<section id="sequence-actions" class="panel">
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="row center-align">
|
||||
<button class="btn btn-primary btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
||||
<button class="btn btn-primary btn-lg js-view-as-gif" id="gif">View GIF</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="js-download-gif-modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">Your gif is ready</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="js-download-modal-gif-container">
|
||||
<!-- Gif should appear here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>
|
||||
|
||||
<button id="js-download-as-gif-button" class="btn btn-primary">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<section id="dwnld" class="panel panel-primary">
|
||||
<div class="form-inline">
|
||||
<div class="panel-body">
|
||||
<div style="text-align:center;">
|
||||
<button class="btn btn-success btn-lg" id="download-btn" name="download">Download PNG</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="move-up" action="#up">
|
||||
<button><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||
</form>
|
||||
|
||||
<footer>
|
||||
<hr style="margin:20px;"><center><a class="color:grey;" id="clear-cache">Clear offline cache</a></center>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var sequencer;
|
||||
@@ -93,4 +192,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -8,7 +8,8 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
function onLoad() {
|
||||
importStepsFromUrlHash();
|
||||
if (!$('#selectStep').val())
|
||||
$(addStepSel + " button").prop("disabled", true);
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
// look up needed steps from Url Hash:
|
||||
@@ -25,7 +26,7 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
function selectNewStepUi() {
|
||||
var m = $(addStepSel + " select").val();
|
||||
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||
$(addStepSel + " button").prop("disabled", false);
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
|
||||
function removeStepUi() {
|
||||
@@ -33,6 +34,8 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||
// remove from URL hash too
|
||||
setUrlHashParameter("steps", sequencer.toString());
|
||||
//disable save-sequence button if all steps are removed
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
function addStepUi() {
|
||||
@@ -55,10 +58,21 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
.addSteps(newStepName, options)
|
||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
||||
|
||||
//enable save-sequence button if disabled initially
|
||||
handleSaveSequence();
|
||||
|
||||
// add to URL hash too
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
}
|
||||
|
||||
function handleSaveSequence(){
|
||||
var stepCount=sequencer.images.image1.steps.length;
|
||||
if(stepCount<2)
|
||||
$(" #save-seq").prop("disabled", true);
|
||||
else
|
||||
$(" #save-seq").prop("disabled", false);
|
||||
}
|
||||
|
||||
return {
|
||||
onLoad: onLoad,
|
||||
importStepsFromUrlHash: importStepsFromUrlHash,
|
||||
|
||||
@@ -7,18 +7,29 @@
|
||||
// The variable 'step' stores useful data like input and
|
||||
// output values, step information.
|
||||
// See documetation for more details.
|
||||
function stepRemovedNotify() {
|
||||
if ($('#stepRemovedNotification').length == 0) {
|
||||
var notification = document.createElement('span');
|
||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> Step Removed ';
|
||||
notification.id = 'stepRemovedNotification';
|
||||
|
||||
$('body').append(notification);
|
||||
}
|
||||
|
||||
$('#stepRemovedNotification').fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onSetup(step) {
|
||||
function onSetup(step, stepOptions) {
|
||||
if (step.options && step.options.description)
|
||||
step.description = step.options.description;
|
||||
|
||||
step.ui =
|
||||
'\
|
||||
<div class="container">\
|
||||
<div class="row step">\
|
||||
<div class="col-md-4 details">\
|
||||
<h3>' +
|
||||
@@ -30,22 +41,28 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
</div>\
|
||||
<div class="col-md-8">\
|
||||
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||
<a><img alt="" style="max-width=100%" class="img-thumbnail" /></a>\
|
||||
<a><img alt="" style="max-width=100%" class="img-thumbnail step-thumbnail"/></a>\
|
||||
</div>\
|
||||
</div>\
|
||||
';
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var tools =
|
||||
'<div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||
<button confirm="Are you sure?" onclick="stepRemovedNotify()" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
</div>';
|
||||
<button class="btn insert-step" style="margin-left:10px;border-radius:6px;background-color:#fff;border:solid #bababa 1.1px;" >\
|
||||
<i class="fa fa-plus"></i> Add\
|
||||
</button>\
|
||||
</div>';
|
||||
|
||||
var util = IntermediateHtmlStepUi(_sequencer, step);
|
||||
|
||||
var parser = new DOMParser();
|
||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||
step.ui = step.ui.querySelector("div.row");
|
||||
step.linkElement = step.ui.querySelector("a");
|
||||
step.ui = step.ui.querySelector("div.container");
|
||||
step.linkElements = step.ui.querySelectorAll("a");
|
||||
step.imgElement = step.ui.querySelector("a img");
|
||||
|
||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||
@@ -66,12 +83,28 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
}
|
||||
html += "</select>";
|
||||
} else {
|
||||
let paramVal = step.options[paramName] || inputDesc.default;
|
||||
html =
|
||||
'<input class="form-control target" type="' +
|
||||
inputDesc.type +
|
||||
'" name="' +
|
||||
paramName +
|
||||
'">';
|
||||
'" value="' +
|
||||
paramVal +
|
||||
'" placeholder ="' +
|
||||
(inputDesc.placeholder || "");
|
||||
|
||||
if (inputDesc.type.toLowerCase() == "range") {
|
||||
html +=
|
||||
'"min="' +
|
||||
inputDesc.min +
|
||||
'"max="' +
|
||||
inputDesc.max +
|
||||
'"step="' +
|
||||
inputDesc.step + '">' + '<span>' + paramVal + '</span>';
|
||||
|
||||
}
|
||||
else html += '">';
|
||||
}
|
||||
|
||||
var div = document.createElement("div");
|
||||
@@ -80,6 +113,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
var description = inputs[paramName].desc || paramName;
|
||||
div.innerHTML =
|
||||
"<div class='det'>\
|
||||
<form class='input-form'>\
|
||||
<label for='" +
|
||||
paramName +
|
||||
"'>" +
|
||||
@@ -88,21 +122,28 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
" +
|
||||
html +
|
||||
"\
|
||||
</form>\
|
||||
</div>";
|
||||
step.ui.querySelector("div.details").appendChild(div);
|
||||
}
|
||||
|
||||
function toggleSaveButton(){
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled",false);
|
||||
function toggleSaveButton() {
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled", false);
|
||||
focusInput();
|
||||
}
|
||||
|
||||
$(step.ui.querySelector(".target")).change(toggleSaveButton);
|
||||
$(step.ui.querySelectorAll(".target")).on('change', toggleSaveButton);
|
||||
|
||||
$(step.ui.querySelector("div.details")).append(
|
||||
"<p><button class='btn btn-default btn-save' disabled = 'true' >Save</button></p>"
|
||||
"<p><button class='btn btn-default btn-save' disabled = 'true' >Apply</button><span> Press apply to see changes</span></p>"
|
||||
);
|
||||
|
||||
function saveOptions() {
|
||||
function focusInput() {
|
||||
$(step.ui.querySelector("div.details .target")).focus();
|
||||
}
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
$(step.ui.querySelector("div.details"))
|
||||
.find("input,select")
|
||||
.each(function(i, input) {
|
||||
@@ -113,23 +154,43 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
// modify the url hash
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
// disable the save button
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled",true);
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled", true);
|
||||
}
|
||||
|
||||
// on clicking Save in the details pane of the step
|
||||
$(step.ui.querySelector("div.details .btn-save")).click(saveOptions);
|
||||
$(step.ui.querySelector("div.details .input-form")).on('submit', saveOptions);
|
||||
}
|
||||
|
||||
if (step.name != "load-image")
|
||||
if (step.name != "load-image") {
|
||||
step.ui
|
||||
.querySelector("div.details")
|
||||
.appendChild(
|
||||
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||
);
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
|
||||
stepsEl.appendChild(step.ui);
|
||||
// Insert the step's UI in the right place
|
||||
if (stepOptions.index == _sequencer.images.image1.steps.length) {
|
||||
stepsEl.appendChild(step.ui);
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
if($("#steps .container:nth-last-child(2)"))
|
||||
$("#steps .container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||
} else {
|
||||
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("#load-image").append(step.ui);
|
||||
}
|
||||
}
|
||||
|
||||
var inputs = document.querySelectorAll('input[type="range"]')
|
||||
for (i in inputs)
|
||||
inputs[i].oninput = function(e) {
|
||||
e.target.nextSibling.innerHTML = e.target.value;
|
||||
}
|
||||
|
||||
function onDraw(step) {
|
||||
$(step.ui.querySelector(".load")).show();
|
||||
$(step.ui.querySelector("img")).hide();
|
||||
@@ -140,33 +201,35 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
$(step.ui.querySelector("img")).show();
|
||||
|
||||
step.imgElement.src = step.output;
|
||||
step.linkElement.href = step.output;
|
||||
var imgthumbnail = step.ui.querySelector(".img-thumbnail");
|
||||
for (let index = 0; index < step.linkElements.length; index++) {
|
||||
if (step.linkElements[index].contains(imgthumbnail))
|
||||
step.linkElements[index].href = step.output;
|
||||
}
|
||||
|
||||
// TODO: use a generalized version of this
|
||||
function fileExtension(output) {
|
||||
return output.split("/")[1].split(";")[0];
|
||||
}
|
||||
|
||||
step.linkElement.download = step.name + "." + fileExtension(step.output);
|
||||
step.linkElement.target = "_blank";
|
||||
for (let index = 0; index < step.linkElements.length; index++) {
|
||||
step.linkElements[index].download = step.name + "." + fileExtension(step.output);
|
||||
step.linkElements[index].target = "_blank";
|
||||
}
|
||||
|
||||
// fill inputs with stored step options
|
||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||
for (var i in inputs) {
|
||||
if (
|
||||
step.options[i] !== undefined &&
|
||||
inputs[i].type.toLowerCase() === "input"
|
||||
)
|
||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||
step.options[i];
|
||||
if (
|
||||
step.options[i] !== undefined &&
|
||||
inputs[i].type.toLowerCase() === "select"
|
||||
)
|
||||
step.ui.querySelector('div[name="' + i + '"] select').value =
|
||||
step.options[i];
|
||||
if (step.options[i] !== undefined) {
|
||||
if (inputs[i].type.toLowerCase() === "input")
|
||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||
step.options[i];
|
||||
if (inputs[i].type.toLowerCase() === "select")
|
||||
step.ui.querySelector('div[name="' + i + '"] select').value =
|
||||
step.options[i];
|
||||
}
|
||||
}
|
||||
for (var i in outputs) {
|
||||
if (step[i] !== undefined)
|
||||
@@ -178,6 +241,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
function onRemove(step) {
|
||||
step.ui.remove();
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
}
|
||||
|
||||
function getPreview() {
|
||||
@@ -191,4 +255,4 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
onRemove: onRemove,
|
||||
onDraw: onDraw
|
||||
}
|
||||
}
|
||||
}
|
||||
118
examples/lib/intermediateHtmlStepUi.js
Normal file
118
examples/lib/intermediateHtmlStepUi.js
Normal file
@@ -0,0 +1,118 @@
|
||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
function stepUI() {
|
||||
return '<div class="row insertDiv">\
|
||||
<div class="col-md-6" style="margin-top:5%">\
|
||||
<section id="insertStep" class="panel panel-primary">\
|
||||
<div class="form-inline">\
|
||||
<div class="panel-body">\
|
||||
<p class="info">Select a new module to add to your sequence.</p>\
|
||||
<div class="row center-align radio-group">\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="brightness">\
|
||||
<i class="fa fa-sun-o fa-4x"></i>\
|
||||
</button>\
|
||||
<p>Brightness</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="contrast">\
|
||||
<i class="fa fa-adjust fa-4x"></i>\
|
||||
</button>\
|
||||
<p>Contrast</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="saturation">\
|
||||
<i class="fa fa-tint fa-4x"></i>\
|
||||
</button>\
|
||||
<p>Saturation</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="rotate">\
|
||||
<i class="fa fa-rotate-right fa-4x"></i>\
|
||||
</button>\
|
||||
<p>Rotate</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="crop">\
|
||||
<i class="fa fa-crop fa-4x"></i>\
|
||||
</button>\
|
||||
<p>Crop</p>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="center-align">\
|
||||
<select class="form-control input-lg" id="selectStep">\
|
||||
<!-- The default null selection has been appended manually in demo.js\
|
||||
This is because the options in select are overritten when options are appended.-->\
|
||||
</select>\
|
||||
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</section>\
|
||||
</div>';
|
||||
}
|
||||
function selectNewStepUi() {
|
||||
var m = $("#insertStep select").val();
|
||||
$("#insertStep .info").html(_sequencer.modulesInfo(m).description);
|
||||
$("#insertStep #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
insertStep = function(id) {
|
||||
var modulesInfo = _sequencer.modulesInfo();
|
||||
var parser = new DOMParser();
|
||||
var addStepUI = stepUI();
|
||||
addStepUI = parser.parseFromString(addStepUI, "text/html").querySelector("div")
|
||||
step.ui
|
||||
.querySelector("div.step")
|
||||
.insertAdjacentElement('afterend',
|
||||
addStepUI
|
||||
);
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
insertStepSelect.html("");
|
||||
// Add modules to the insertStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
if (modulesInfo[m] !== undefined)
|
||||
insertStepSelect.append(
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
}
|
||||
|
||||
$('#insertStep #add-step-btn').prop('disabled', true);
|
||||
|
||||
insertStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
$('#insertStep .radio-group .radio').on("click", function() {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
insertStepSelect.val(newStep);
|
||||
selectNewStepUi();
|
||||
insert(id);
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
$(step.ui.querySelector("#insertStep select")).on('change', selectNewStepUi);
|
||||
$(step.ui.querySelector("#insertStep #add-step-btn")).on('click', function() { insert(id) });
|
||||
}
|
||||
|
||||
function insert(id) {
|
||||
|
||||
options = options || {};
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
if (insertStepSelect.val() == "none") return;
|
||||
|
||||
var newStepName = insertStepSelect.val()
|
||||
$('div .insertDiv').remove();
|
||||
var sequenceLength = 1;
|
||||
if (sequencer.sequences[newStepName]) {
|
||||
sequenceLength = sequencer.sequences[newStepName].length;
|
||||
} else if (sequencer.modules[newStepName][1]["length"]) {
|
||||
sequenceLength = sequencer.modules[newStepName][1]["length"];
|
||||
}
|
||||
_sequencer
|
||||
.insertSteps(id + 1, newStepName).run({ index: id });
|
||||
|
||||
// add to URL hash too
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
}
|
||||
return {
|
||||
insertStep
|
||||
}
|
||||
}
|
||||
17
examples/lib/scrollToTop.js
Normal file
17
examples/lib/scrollToTop.js
Normal file
@@ -0,0 +1,17 @@
|
||||
$(document).ready(function($){
|
||||
$(function(){
|
||||
$(window).scroll(function(){
|
||||
if ($(this).scrollTop() > 100){
|
||||
$('.move-up').fadeIn();
|
||||
} else {
|
||||
$('.move-up').fadeOut();
|
||||
}
|
||||
});
|
||||
$('.move-up button').click(function(){
|
||||
$('body,html').animate({
|
||||
scrollTop: 0
|
||||
}, 800);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
21
examples/manifest.json
Normal file
21
examples/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"short_name": "IS",
|
||||
"name": "Image Sequencer",
|
||||
"icons": [
|
||||
{
|
||||
"src": "../icons/ic_192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "../icons/ic_512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": "/examples/#steps=",
|
||||
"background_color": "#428bca",
|
||||
"display": "standalone",
|
||||
"scope": "/examples/",
|
||||
"theme_color": "#428bca"
|
||||
}
|
||||
35
examples/sw.js
Normal file
35
examples/sw.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const staticCacheName = 'image-sequencer-static-v3';
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
console.log('Attempting to install service worker');
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function(e) {
|
||||
console.log('[ServiceWorker] Activate');
|
||||
e.waitUntil(
|
||||
caches.keys().then(function(cacheNames) {
|
||||
return Promise.all(
|
||||
cacheNames.filter(function(cacheName){
|
||||
return cacheName.startsWith('image-sequencer-') &&
|
||||
cacheName != staticCacheName;
|
||||
}).map(function(cacheName){
|
||||
return caches.delete(cacheName);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(event) {
|
||||
event.respondWith(
|
||||
caches.open(staticCacheName).then(function(cache) {
|
||||
return cache.match(event.request).then(function (response) {
|
||||
return response || fetch(event.request).then(function(response) {
|
||||
if(event.request.method == "GET")
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
BIN
icons/ic_512.png
Normal file
BIN
icons/ic_512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
8
index.js
8
index.js
@@ -26,13 +26,20 @@ program
|
||||
if (program.saveSequence) {
|
||||
var params = program.saveSequence.split(' ');
|
||||
sequencer.saveSequence(params[0], params[1]);
|
||||
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||
} else if (program.installModule) {
|
||||
console.log(
|
||||
"\x1b[33m%s\x1b[0m",
|
||||
"Please wait while your Module is being Installed...\nThis may take a while!"
|
||||
);
|
||||
|
||||
var params = program.installModule.split(' ');
|
||||
var spinner = Spinner("Now Installing...").start();
|
||||
require('child_process').execSync(`npm i ${params[1]}`)
|
||||
sequencer.saveNewModule(params[0], params[1]);
|
||||
sequencer.loadNewModule(params[0], require(params[1]));
|
||||
spinner.stop();
|
||||
console.log("\x1b[32m%s\x1b[0m", "Your module was installed successfully!!");
|
||||
} else {
|
||||
// Parse step into an array to allow for multiple steps.
|
||||
if (!program.step) exit("No steps passed");
|
||||
@@ -202,4 +209,3 @@ if (program.saveSequence) {
|
||||
else return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
6162
package-lock.json
generated
6162
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "image-sequencer",
|
||||
"version": "2.2.2",
|
||||
"version": "2.2.3",
|
||||
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
||||
"main": "src/ImageSequencer.js",
|
||||
"scripts": {
|
||||
"debug": "TEST=true node ./index.js -i ./examples/images/monarch.png -s invert",
|
||||
"test": "TEST=true tape test/**/*.js test/*.js | tap-spec; browserify test/modules/image-sequencer.js test/modules/chain.js test/modules/meta-modules.js test/modules/replace.js test/modules/import-export.js test/modules/run.js test/modules/dynamic-imports.js | tape-run --render=\"tap-spec\"",
|
||||
"setup": "npm i && npm i -g grunt grunt-cli",
|
||||
"start": "grunt serve"
|
||||
},
|
||||
"repository": {
|
||||
@@ -22,40 +23,42 @@
|
||||
"url": "https://github.com/publiclab/image-sequencer/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "~3.2.0",
|
||||
"buffer": "~5.0.2",
|
||||
"bootstrap": "~3.4.0",
|
||||
"buffer": "~5.2.1",
|
||||
"commander": "^2.11.0",
|
||||
"data-uri-to-buffer": "^2.0.0",
|
||||
"downloadjs": "^1.4.7",
|
||||
"fisheyegl": "^0.1.2",
|
||||
"font-awesome": "~4.5.0",
|
||||
"font-awesome": "~4.7.0",
|
||||
"get-pixels": "~3.3.0",
|
||||
"image-sequencer-invert": "^1.0.0",
|
||||
"imagejs": "0.0.9",
|
||||
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
||||
"jquery": "~2",
|
||||
"jquery": "^3.3.1",
|
||||
"jsqr": "^0.2.2",
|
||||
"lodash": "^4.17.5",
|
||||
"ndarray-gaussian-filter": "^1.0.0",
|
||||
"ora": "^2.0.0",
|
||||
"ora": "^3.0.0",
|
||||
"pace": "0.0.4",
|
||||
"readline-sync": "^1.4.7",
|
||||
"save-pixels": "~2.3.4",
|
||||
"urify": "^2.1.0"
|
||||
"urify": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "13.0.0",
|
||||
"grunt": "^0.4.5",
|
||||
"browserify": "16.2.3",
|
||||
"grunt": "^1.0.3",
|
||||
"grunt-browser-sync": "^2.2.0",
|
||||
"grunt-browserify": "^5.0.0",
|
||||
"grunt-contrib-concat": "^0.5.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"grunt-contrib-uglify-es": "^3.3.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"image-filter-core": "~1.0.0",
|
||||
"image-filter-threshold": "~1.0.0",
|
||||
"looks-same": "^3.2.1",
|
||||
"matchdep": "^0.3.0",
|
||||
"tap-spec": "^4.1.1",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"image-filter-core": "~2.0.2",
|
||||
"image-filter-threshold": "~2.0.1",
|
||||
"looks-same": "^4.1.0",
|
||||
"matchdep": "^2.0.0",
|
||||
"tap-spec": "^5.0.0",
|
||||
"tape": ">=4.7.0",
|
||||
"tape-run": "^3.0.0",
|
||||
"tape-run": "^5.0.0",
|
||||
"uglify-es": "^3.3.7"
|
||||
},
|
||||
"homepage": "https://github.com/publiclab/image-sequencer",
|
||||
|
||||
@@ -219,7 +219,7 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
modulesdata[modulename] = modules[modulename][1];
|
||||
}
|
||||
for (var sequencename in this.sequences) {
|
||||
modulesdata[sequencename] = { name: sequencename, steps: sequences[sequencename] };
|
||||
modulesdata[sequencename] = { name: sequencename, steps: this.sequences[sequencename] };
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -256,15 +256,18 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
// Stringifies one step of the sequence
|
||||
function stepToString(step) {
|
||||
let inputs = copy(modulesInfo(step.options.name).inputs);
|
||||
inputs = inputs || {};
|
||||
let inputs = modulesInfo(step.options.name).inputs || {}, op = {};
|
||||
|
||||
for (let input in inputs) {
|
||||
inputs[input] = step.options[input] || inputs[input].default;
|
||||
inputs[input] = encodeURIComponent(inputs[input]);
|
||||
|
||||
if (!!step.options[input] && step.options[input] != inputs[input].default) {
|
||||
op[input] = step.options[input];
|
||||
op[input] = encodeURIComponent(op[input]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var configurations = Object.keys(inputs).map(key => key + ':' + inputs[key]).join('|');
|
||||
var configurations = Object.keys(op).map(key => key + ':' + op[key]).join('|');
|
||||
return `${step.options.name}{${configurations}}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,17 +34,25 @@ function InsertStep(ref, image, index, name, o) {
|
||||
};
|
||||
var UI = ref.events;
|
||||
|
||||
// Tell UI that a step has been set up.
|
||||
o = o || {};
|
||||
// define the expandSteps function for sequencer
|
||||
ref.modules[name].expandSteps = function expandSteps(stepsArray) {
|
||||
for (var step of stepsArray) {
|
||||
ref.addSteps(step['name'], step['options']);
|
||||
for (var i in stepsArray) {
|
||||
let step = stepsArray[i];
|
||||
console.log(step['name'])
|
||||
console.log(step['options'])
|
||||
ref.insertSteps(index + Number.parseInt(i), step['name'], step['options']);
|
||||
// ref.addSteps(step['name'], step['options']);
|
||||
}
|
||||
}
|
||||
var mod = ref.modules[name][0](o, UI);
|
||||
if (!mod.isMeta) {
|
||||
UI.onSetup(o.step);
|
||||
ref.images[image].steps.splice(index, 0, mod);
|
||||
|
||||
// Tell UI that a step has been set up.
|
||||
o = o || {};
|
||||
|
||||
if (!ref.modules[name][1].length) {
|
||||
UI.onSetup(o.step, { index: index });
|
||||
ref.images[image].steps.splice(index, 0, ref.modules[name][0](o, UI));
|
||||
} else {
|
||||
ref.modules[name][0](o, UI);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -2,23 +2,29 @@
|
||||
* Core modules and their info files
|
||||
*/
|
||||
module.exports = {
|
||||
'channel': require('./modules/Channel'),
|
||||
'brightness': require('./modules/Brightness'),
|
||||
'edge-detect': require('./modules/EdgeDetect'),
|
||||
'ndvi': require('./modules/Ndvi'),
|
||||
'crop': require('./modules/Crop'),
|
||||
'colormap': require('./modules/Colormap'),
|
||||
'decode-qr': require('./modules/DecodeQr'),
|
||||
'fisheye-gl': require('./modules/FisheyeGl'),
|
||||
'dynamic': require('./modules/Dynamic'),
|
||||
'blur': require('./modules/Blur'),
|
||||
'saturation': require('./modules/Saturation'),
|
||||
'average': require('./modules/Average'),
|
||||
'blend': require('./modules/Blend'),
|
||||
'import-image': require('./modules/ImportImage'),
|
||||
'overlay': require('./modules/Overlay'),
|
||||
'gradient': require('./modules/Gradient'),
|
||||
'invert': require('image-sequencer-invert'),
|
||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||
'blur': require('./modules/Blur'),
|
||||
'brightness': require('./modules/Brightness'),
|
||||
'channel': require('./modules/Channel'),
|
||||
'colorbar': require('./modules/Colorbar'),
|
||||
}
|
||||
'colormap': require('./modules/Colormap'),
|
||||
'contrast': require('./modules/Contrast'),
|
||||
'convolution': require('./modules/Convolution'),
|
||||
'crop': require('./modules/Crop'),
|
||||
'decode-qr': require('./modules/DecodeQr'),
|
||||
'dynamic': require('./modules/Dynamic'),
|
||||
'edge-detect': require('./modules/EdgeDetect'),
|
||||
'fisheye-gl': require('./modules/FisheyeGl'),
|
||||
'histogram': require('./modules/Histogram'),
|
||||
'gamma-correction': require('./modules/GammaCorrection'),
|
||||
'gradient': require('./modules/Gradient'),
|
||||
'import-image': require('./modules/ImportImage'),
|
||||
'invert': require('image-sequencer-invert'),
|
||||
'ndvi': require('./modules/Ndvi'),
|
||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||
'overlay': require('./modules/Overlay'),
|
||||
'resize': require('./modules/Resize'),
|
||||
'rotate': require('./modules/Rotate'),
|
||||
'saturation': require('./modules/Saturation')
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"name": "Average",
|
||||
"description": "Average all pixel color",
|
||||
"inputs": {
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,63 +1,67 @@
|
||||
module.exports = function Dynamic(options, UI, util) {
|
||||
|
||||
options.func = options.func || "function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] }";
|
||||
options.func = options.func || "function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] }";
|
||||
options.offset = options.offset || -2;
|
||||
|
||||
var output;
|
||||
var output;
|
||||
|
||||
// This function is called on every draw.
|
||||
function draw(input, callback, progressObj) {
|
||||
// This function is called on every draw.
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
var step = this;
|
||||
|
||||
// convert to runnable code:
|
||||
if (typeof options.func === "string") eval('options.func = ' + options.func);
|
||||
// convert to runnable code:
|
||||
if (typeof options.func === "string") eval('options.func = ' + options.func);
|
||||
|
||||
var getPixels = require('get-pixels');
|
||||
var getPixels = require('get-pixels');
|
||||
|
||||
// save first image's pixels
|
||||
var priorStep = this.getStep(-2);
|
||||
// convert offset as string to int
|
||||
if(typeof options.offset === "string") options.offset = parseInt(options.offset);
|
||||
|
||||
getPixels(priorStep.output.src, function(err, pixels) {
|
||||
options.firstImagePixels = pixels;
|
||||
// save first image's pixels
|
||||
var priorStep = this.getStep(options.offset);
|
||||
|
||||
function changePixel(r2, g2, b2, a2, x, y) {
|
||||
// blend!
|
||||
var p = options.firstImagePixels;
|
||||
return options.func(
|
||||
r2, g2, b2, a2,
|
||||
p.get(x, y, 0),
|
||||
p.get(x, y, 1),
|
||||
p.get(x, y, 2),
|
||||
p.get(x, y, 3)
|
||||
)
|
||||
}
|
||||
getPixels(priorStep.output.src, function(err, pixels) {
|
||||
options.firstImagePixels = pixels;
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
function changePixel(r2, g2, b2, a2, x, y) {
|
||||
// blend!
|
||||
var p = options.firstImagePixels;
|
||||
return options.func(
|
||||
r2, g2, b2, a2,
|
||||
p.get(x, y, 0),
|
||||
p.get(x, y, 1),
|
||||
p.get(x, y, 2),
|
||||
p.get(x, y, 3)
|
||||
)
|
||||
}
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
}
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
// run PixelManipulatin on second image's pixels
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
}
|
||||
|
||||
// run PixelManipulatin on second image's pixels
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
{
|
||||
"name": "Blend",
|
||||
"description": "Blend the past two image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
|
||||
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
|
||||
"inputs": {
|
||||
"offset": {
|
||||
"type": "integer",
|
||||
"desc": "Choose which image to blend the current image with. Two steps back is -2, three steps back is -3 etc.",
|
||||
"default": -2
|
||||
},
|
||||
"blend": {
|
||||
"type": "input",
|
||||
"desc": "Function to use to blend the two images.",
|
||||
"default": "function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] }"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
{
|
||||
"name": "Blur",
|
||||
"description": "Gaussian blur an image by a given value, typically 0-5",
|
||||
"description": "Applies a Gaussian blur given by the intensity value",
|
||||
"inputs": {
|
||||
"blur": {
|
||||
"type": "integer",
|
||||
"desc": "amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": 2
|
||||
"type": "range",
|
||||
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": "2",
|
||||
"min": "0",
|
||||
"max": "5",
|
||||
"step": "0.25"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -20,12 +20,14 @@ module.exports = function Brightness(options,UI){
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a){
|
||||
options.brightness =
|
||||
options.brightness || 100
|
||||
var val = (options.brightness)/100.0
|
||||
|
||||
r = val*r<255?val*r:255
|
||||
g = val*g<255?val*g:255
|
||||
b = val*b<255?val*b:255
|
||||
return [r , g, b, a]
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function output(image,datauri,mimetype){
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
{
|
||||
"name": "Brightness",
|
||||
"description": "Change the brightness of the image by given percent value",
|
||||
"inputs": {
|
||||
"brightness": {
|
||||
"type": "integer",
|
||||
"desc": "% brightness for the new image",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
"name": "Brightness",
|
||||
"description": "Change the brightness of the image by given percent value",
|
||||
"inputs": {
|
||||
"brightness": {
|
||||
"type": "range",
|
||||
"desc": "% brightness for the new image",
|
||||
"default": "100",
|
||||
"min": "0",
|
||||
"max": "200",
|
||||
"step": "1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
"default": "green",
|
||||
"values": ["red", "green", "blue"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
"default": 10
|
||||
}
|
||||
},
|
||||
"length": 4
|
||||
"length": 4,
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -53,35 +53,145 @@ function colormap(segments) {
|
||||
|
||||
var colormaps = {
|
||||
greyscale: colormap([
|
||||
[0, [0, 0, 0], [255, 255, 255] ],
|
||||
[0, [0, 0, 0], [220, 20, 60] ],
|
||||
[1, [255, 255, 255], [255, 255, 255] ]
|
||||
]),
|
||||
default: colormap([
|
||||
[0, [0, 0, 255], [0, 255, 0] ],
|
||||
[0.25, [0, 255, 0], [255, 255, 0] ],
|
||||
[0.50, [0, 255, 255], [255, 255, 0] ],
|
||||
[0.75, [255, 255, 0], [255, 0, 0] ]
|
||||
|
||||
bluwhtgrngis: colormap([
|
||||
[0, [6,23,86], [6,25, 84] ],
|
||||
[0.0625, [6,25,84], [6,25, 84] ],//1
|
||||
[0.125, [6,25,84], [6,25, 84] ],//2
|
||||
[0.1875, [6,25,84], [6,25, 84] ],
|
||||
[0.25, [6,25,84], [6,25,84] ],
|
||||
[0.3125, [6,25,84], [9,24, 84] ],//5
|
||||
[0.3438, [9,24, 84], [119,120,162] ],//5
|
||||
[0.375, [119,129,162],[249,250,251] ], //6
|
||||
[0.406, [249,250,251],[255,255,255] ], //6.5
|
||||
[0.4375, [255,255,255],[255,255,255] ], //7 white
|
||||
[0.50, [255,255,255],[214,205,191] ],//8
|
||||
[0.52, [214,205,191],[178,175,96] ],//8.2
|
||||
[0.5625, [178,175,96], [151,176,53] ],//9
|
||||
[0.593, [151,176,53], [146,188,12] ],//9.5
|
||||
[0.625, [146,188,12], [96,161,1] ], //10
|
||||
[0.6875, [96,161,1], [30,127,3] ],//11
|
||||
[0.75, [30,127,3], [0,99,1] ],//12
|
||||
[0.8125, [0,99,1], [0,74,1] ],//13
|
||||
[0.875, [0,74,1], [0,52, 0] ],//14
|
||||
[0.9375, [0,52, 0], [0,34,0] ], //15
|
||||
[0.968, [0,34,0], [68,70,67] ] //16
|
||||
]),
|
||||
|
||||
|
||||
brntogrn: colormap([
|
||||
[0, [110,12,3], [118,6,1] ],
|
||||
[0.0625, [118,6,1], [141,19,6] ],
|
||||
[0.125, [141,19,6], [165,35,13] ],
|
||||
[0.1875, [165,35,13], [177,59,25] ],
|
||||
[0.2188, [177,59,25], [192,91,36] ],
|
||||
[0.25, [192,91,36], [214, 145, 76] ],
|
||||
[0.3125, [214,145,76], [230,183,134] ],
|
||||
[0.375, [230,183,134],[243, 224, 194]],
|
||||
[0.4375, [243,224,194],[250,252,229] ],
|
||||
[0.50, [250,252,229],[217,235,185] ],
|
||||
[0.5625, [217,235,185],[184,218,143] ],
|
||||
[0.625, [184,218,143],[141,202,89] ],
|
||||
[0.6875, [141,202,89], [80,176,61] ],
|
||||
[0.75, [80,176,61], [0, 147, 32] ],
|
||||
[0.8125, [0,147,32], [1, 122, 22] ],
|
||||
[0.875, [1,122,22], [0, 114, 19] ],
|
||||
[0.90, [0,114,19], [0,105,18] ],
|
||||
[0.9375, [0,105,18], [7,70,14] ]
|
||||
|
||||
]),
|
||||
ndvi: colormap([
|
||||
[0, [0, 0, 255], [38, 195, 195] ],
|
||||
[0.5, [0, 150, 0], [255, 255, 0] ],
|
||||
[0.75, [255, 255, 0], [255, 50, 50] ]
|
||||
|
||||
|
||||
blutoredjet: colormap([
|
||||
[0, [0,0,140], [1,1,186] ],
|
||||
[0.0625, [1,1,186], [0,1,248] ],
|
||||
[0.125, [0,1,248], [0,70,254] ],
|
||||
[0.1875, [0,70,254], [0,130,255] ],
|
||||
[0.25, [0,130,255], [2,160,255] ],
|
||||
[0.2813, [2,160,255], [0,187,255] ], //inset
|
||||
[0.3125, [0,187,255], [6,250,255] ],
|
||||
// [0.348, [0,218,255], [8,252,251] ],//inset
|
||||
[0.375, [8,252,251], [27,254,228] ],
|
||||
[0.406, [27,254,228], [70,255,187] ], //insert
|
||||
[0.4375, [70,255,187], [104,254,151]],
|
||||
[0.47, [104,254,151],[132,255,19] ],//insert
|
||||
[0.50, [132,255,19], [195,255,60] ],
|
||||
[0.5625, [195,255,60], [231,254,25] ],
|
||||
[0.5976, [231,254,25], [253,246,1] ],//insert
|
||||
[0.625, [253,246,1], [252,210,1] ], //yellow
|
||||
[0.657, [252,210,1], [255,183,0] ],//insert
|
||||
[0.6875, [255,183,0], [255,125,2] ],
|
||||
[0.75, [255,125,2], [255,65, 1] ],
|
||||
[0.8125, [255,65, 1], [247, 1, 1] ],
|
||||
[0.875, [247,1,1], [200, 1, 3] ],
|
||||
[0.9375, [200,1,3], [122, 3, 2] ]
|
||||
|
||||
]),
|
||||
|
||||
|
||||
colors16: colormap([
|
||||
[0, [0,0,0], [0,0,0] ],
|
||||
[0.0625, [3,1,172], [3,1,172] ],
|
||||
[0.125, [3,1,222], [3,1, 222] ],
|
||||
[0.1875, [0,111,255], [0,111,255] ],
|
||||
[0.25, [3,172,255], [3,172,255] ],
|
||||
[0.3125, [1,226,255], [1,226,255] ],
|
||||
[0.375, [2,255,0], [2,255,0] ],
|
||||
[0.4375, [198,254,0], [190,254,0] ],
|
||||
[0.50, [252,255,0], [252,255,0] ],
|
||||
[0.5625, [255,223,3], [255,223,3] ],
|
||||
[0.625, [255,143,3], [255,143,3] ],
|
||||
[0.6875, [255,95,3], [255,95,3] ],
|
||||
[0.75, [242,0,1], [242,0,1] ],
|
||||
[0.8125, [245,0,170], [245,0,170] ],
|
||||
[0.875, [223,180,225], [223,180,225] ],
|
||||
[0.9375, [255,255,255], [255,255, 255]]
|
||||
|
||||
]),
|
||||
|
||||
default: colormap([
|
||||
[0, [45,1,121], [25,1,137] ],
|
||||
[0.125, [25,1,137], [0,6,156] ],
|
||||
[0.1875, [0,6,156], [7,41,172] ],
|
||||
[0.25, [7,41,172], [22,84,187] ],
|
||||
[0.3125, [22,84,187], [25,125,194] ],
|
||||
[0.375, [25,125,194], [26,177,197] ],
|
||||
[0.4375, [26,177,197], [23,199,193] ],
|
||||
[0.47, [23,199,193], [25, 200,170] ],
|
||||
[0.50, [25, 200,170], [21,209,27] ],
|
||||
[0.5625, [21,209,27], [108,215,18] ],
|
||||
[0.625, [108,215,18], [166,218,19] ],
|
||||
[0.6875, [166,218,19], [206,221,20] ],
|
||||
[0.75, [206,221,20], [222,213,19 ] ],
|
||||
[0.7813, [222,213,19], [222, 191, 19]],
|
||||
[0.8125, [222, 191, 19], [227,133,17] ],
|
||||
[0.875, [227,133,17], [231,83,16] ],
|
||||
[0.9375, [231,83,16], [220,61,48] ]
|
||||
|
||||
]),
|
||||
|
||||
|
||||
fastie: colormap([
|
||||
[0, [255, 255, 255], [0, 0, 0] ],
|
||||
[0.167, [0, 0, 0], [255, 255, 255] ],
|
||||
[0.33, [2, 0, 226], [2, 0, 226] ],
|
||||
[0.5, [0, 0, 0], [140, 140, 255] ],
|
||||
[0.55, [140, 140, 255], [0, 255, 0] ],
|
||||
[0.63, [0, 255, 0], [255, 255, 0] ],
|
||||
[0.75, [255, 255, 0], [255, 0, 0] ],
|
||||
[0.95, [255, 0, 0], [255, 0, 255] ]
|
||||
]),
|
||||
|
||||
|
||||
stretched: colormap([
|
||||
[0, [0, 0, 255], [0, 0, 255] ],
|
||||
[0.1, [0, 0, 255], [38, 195, 195] ],
|
||||
[0.5, [0, 150, 0], [255, 255, 0] ],
|
||||
[0.7, [255, 255, 0], [255, 50, 50] ],
|
||||
[0.9, [255, 50, 50], [255, 50, 50] ]
|
||||
]),
|
||||
fastie: colormap([
|
||||
[0, [255, 255, 255], [0, 0, 0] ],
|
||||
[0.167, [0, 0, 0], [255, 255, 255] ],
|
||||
[0.33, [255, 255, 255], [0, 0, 0] ],
|
||||
[0.5, [0, 0, 0], [140, 140, 255] ],
|
||||
[0.55, [140, 140, 255], [0, 255, 0] ],
|
||||
[0.63, [0, 255, 0], [255, 255, 0] ],
|
||||
[0.75, [255, 255, 0], [255, 0, 0] ],
|
||||
[0.95, [255, 0, 0], [255, 0, 255] ]
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,8 @@
|
||||
"type": "select",
|
||||
"desc": "Name of the Colormap",
|
||||
"default": "default",
|
||||
"values": ["default","greyscale","stretched","fastie"]
|
||||
"values": ["default","greyscale","bluwhtgrngis","stretched","fastie","brntogrn","blutoredjet","colors16"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
47
src/modules/Contrast/Contrast.js
Normal file
47
src/modules/Contrast/Contrast.js
Normal file
@@ -0,0 +1,47 @@
|
||||
var _ = require('lodash');
|
||||
module.exports = exports = function(pixels , contrast){
|
||||
let oldpix = _.cloneDeep(pixels);
|
||||
contrast = Number(contrast)
|
||||
if (contrast < -100) contrast = -100;
|
||||
if (contrast > 100) contrast = 100;
|
||||
contrast = (100.0 + contrast) / 100.0;
|
||||
contrast *= contrast;
|
||||
|
||||
for (let i = 0; i < oldpix.shape[0]; i++) {
|
||||
for (let j = 0; j < oldpix.shape[1]; j++) {
|
||||
var r = oldpix.get(i,j,0)/255.0;
|
||||
r -= 0.5;
|
||||
r *= contrast;
|
||||
r += 0.5;
|
||||
r *= 255;
|
||||
if (r < 0) r = 0;
|
||||
if (r > 255) r = 255;
|
||||
|
||||
|
||||
var g = oldpix.get(i,j,1)/255.0;
|
||||
g -= 0.5;
|
||||
g *= contrast;
|
||||
g += 0.5;
|
||||
g *= 255;
|
||||
if (g < 0) g = 0;
|
||||
if (g > 255) g = 255;
|
||||
|
||||
|
||||
|
||||
var b = oldpix.get(i,j,2)/255.0;
|
||||
b -= 0.5;
|
||||
b *= contrast;
|
||||
b += 0.5;
|
||||
b *= 255;
|
||||
if (b < 0) b = 0;
|
||||
if (b > 255) b = 255;
|
||||
|
||||
|
||||
pixels.set(i, j, 0, r);
|
||||
pixels.set(i, j, 1, g);
|
||||
pixels.set(i, j, 2, b);
|
||||
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
49
src/modules/Contrast/Module.js
Normal file
49
src/modules/Contrast/Module.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// /*
|
||||
// * Changes the Image Contrast
|
||||
// */
|
||||
|
||||
module.exports = function Contrast(options, UI) {
|
||||
|
||||
options.contrast = options.contrast || 70
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./Contrast')(pixels, options.contrast)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Contrast/index.js
Normal file
4
src/modules/Contrast/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
12
src/modules/Contrast/info.json
Normal file
12
src/modules/Contrast/info.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Contrast",
|
||||
"description": "Change the contrast of the image by given value",
|
||||
"inputs": {
|
||||
"contrast": {
|
||||
"type": "Number",
|
||||
"desc": "contrast for the new image, typically -100 to 100",
|
||||
"default": 70
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
71
src/modules/Convolution/Convolution.js
Normal file
71
src/modules/Convolution/Convolution.js
Normal file
@@ -0,0 +1,71 @@
|
||||
var _ = require('lodash');
|
||||
module.exports = exports = function(pixels, constantFactor, kernelValues){
|
||||
let kernel = kernelGenerator(constantFactor, kernelValues), oldpix = _.cloneDeep(pixels);
|
||||
kernel = flipKernel(kernel);
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||
let neighboutPos = getNeighbouringPixelPositions([i, j]);
|
||||
let acc = [0.0, 0.0, 0.0, 0.0];
|
||||
for (let a = 0; a < kernel.length; a++) {
|
||||
for (let b = 0; b < kernel.length; b++) {
|
||||
acc[0] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 0) * kernel[a][b]);
|
||||
acc[1] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 1) * kernel[a][b]);
|
||||
acc[2] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 2) * kernel[a][b]);
|
||||
acc[3] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 3) * kernel[a][b]);
|
||||
}
|
||||
}
|
||||
acc[0] = acc[0]%255;
|
||||
acc[1] = acc[1]%255;
|
||||
acc[2] = acc[2]%255;
|
||||
pixels.set(i, j, 0, acc[0]);
|
||||
pixels.set(i, j, 1, acc[1]);
|
||||
pixels.set(i, j, 2, acc[2]);
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
|
||||
|
||||
function kernelGenerator(constantFactor, kernelValues){
|
||||
kernelValues = kernelValues.split(" ");
|
||||
for(i = 0 ; i < 9; i++){
|
||||
kernelValues[i] = Number(kernelValues[i]) * constantFactor;
|
||||
}
|
||||
let k = 0;
|
||||
let arr = [];
|
||||
for(i = 0; i < 3; i++){
|
||||
let columns = [];
|
||||
for(j = 0; j < 3; j++){
|
||||
columns.push(kernelValues[k]);
|
||||
k += 1;
|
||||
}
|
||||
arr.push(columns);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getNeighbouringPixelPositions(pixelPosition) {
|
||||
let x = pixelPosition[0], y = pixelPosition[1], result = [];
|
||||
|
||||
for (let i = -1; i <= 1; i++) {
|
||||
let arr = [];
|
||||
for (let j = -1; j <= 1; j++)
|
||||
arr.push([x + i, y + j]);
|
||||
|
||||
result.push(arr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function flipKernel(kernel) {
|
||||
let result = [];
|
||||
for (let i = kernel.length - 1; i >= 0; i--) {
|
||||
let arr = [];
|
||||
for (let j = kernel[i].length - 1; j >= 0; j--) {
|
||||
arr.push(kernel[i][j]);
|
||||
}
|
||||
result.push(arr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
45
src/modules/Convolution/Module.js
Normal file
45
src/modules/Convolution/Module.js
Normal file
@@ -0,0 +1,45 @@
|
||||
module.exports = function Convolution(options, UI) {
|
||||
|
||||
options.kernelValues = options.kernelValues || '1 1 1 1 1 1 1 1 1';
|
||||
options.constantFactor = options.constantFactor || 1/9;
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./Convolution')(pixels, options.constantFactor, options.kernelValues)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Convolution/index.js
Normal file
4
src/modules/Convolution/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
20
src/modules/Convolution/info.json
Normal file
20
src/modules/Convolution/info.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Convolution",
|
||||
"description": "Image Convolution using a given 3x3 kernel matrix <a href='https://en.wikipedia.org/wiki/Kernel_(image_processing)'>Read more</a>",
|
||||
"inputs": {
|
||||
"constantFactor":{
|
||||
"type": "Float",
|
||||
"desc": "a constant factor, multiplies all the kernel values by that factor",
|
||||
"default": 0.1111,
|
||||
"placeholder": 0.1111
|
||||
},
|
||||
|
||||
"kernelValues": {
|
||||
"type": "String",
|
||||
"desc": "nine space separated numbers representing the kernel values in left to right and top to bottom format.",
|
||||
"default": "1 1 1 1 1 1 1 1 1",
|
||||
"placeholder": "1 1 1 1 1 1 1 1 1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -17,7 +17,7 @@ module.exports = function CropModule(options, UI) {
|
||||
|
||||
// we should get UI to return the image thumbnail so we can attach our own UI extensions
|
||||
// add our custom in-module html ui:
|
||||
if (options.step.inBrowser) var ui = require('./Ui.js')(options.step, UI);
|
||||
if (options.step.inBrowser && !options.noUI) var ui = require('./Ui.js')(options.step, UI);
|
||||
var output,
|
||||
setupComplete = false;
|
||||
|
||||
@@ -49,7 +49,7 @@ module.exports = function CropModule(options, UI) {
|
||||
|
||||
// start custom UI setup (draggable UI)
|
||||
// only once we have an input image
|
||||
if (setupComplete === false && options.step.inBrowser) {
|
||||
if (setupComplete === false && options.step.inBrowser && !options.noUI) {
|
||||
setupComplete = true;
|
||||
ui.setup();
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
"desc": "Height of crop",
|
||||
"default": "(100%)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -7,5 +7,6 @@
|
||||
"qrval": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -54,6 +54,22 @@ module.exports = function Dynamic(options,UI) {
|
||||
]
|
||||
}
|
||||
|
||||
// via P5js: https://github.com/processing/p5.js/blob/2920492842aae9a8bf1a779916893ac19d65cd38/src/math/calculation.js#L461-L472
|
||||
function map(n, start1, stop1, start2, stop2, withinBounds) {
|
||||
var newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
|
||||
if (!withinBounds) {
|
||||
return newval;
|
||||
}
|
||||
// also via P5js: https://github.com/processing/p5.js/blob/2920492842aae9a8bf1a779916893ac19d65cd38/src/math/calculation.js#L116-L119
|
||||
function constrain(n, low, high) {
|
||||
return Math.max(Math.min(n, high), low);
|
||||
};
|
||||
if (start2 < stop2) {
|
||||
return constrain(newval, start2, stop2);
|
||||
} else {
|
||||
return constrain(newval, stop2, start2);
|
||||
}
|
||||
};
|
||||
|
||||
function output(image,datauri,mimetype){
|
||||
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
"desc": "Expression to return with R, G, B, and A inputs; fallback for other channels if none provided",
|
||||
"default": "r + g + b"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@ const _ = require('lodash')
|
||||
const kernelx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
|
||||
kernely = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
|
||||
|
||||
let angles = [], mags = [], strongEdgePixels = [], weakEdgePixels = [], notInUI;
|
||||
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, inBrowser) {
|
||||
notInUI = !inBrowser;
|
||||
let angles = [], mags = [], strongEdgePixels = [], weakEdgePixels = [], notInUI = !inBrowser;
|
||||
for (var x = 0; x < pixels.shape[0]; x++) {
|
||||
angles.push([]);
|
||||
mags.push([]);
|
||||
@@ -29,8 +28,9 @@ module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, inBrows
|
||||
angles.slice(-1)[0].push(result.angle);
|
||||
}
|
||||
}
|
||||
|
||||
return doubleThreshold(nonMaxSupress(pixels), highThresholdRatio, lowThresholdRatio);
|
||||
nonMaxSupress(pixels, mags, angles);
|
||||
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, mags, strongEdgePixels, weakEdgePixels);
|
||||
return pixels;
|
||||
}
|
||||
|
||||
//changepixel function that convolutes every pixel (sobel filter)
|
||||
@@ -65,7 +65,7 @@ function changePixel(pixels, val, a, x, y) {
|
||||
}
|
||||
|
||||
//Non Maximum Supression without interpolation
|
||||
function nonMaxSupress(pixels) {
|
||||
function nonMaxSupress(pixels, mags, angles) {
|
||||
|
||||
angles = angles.map((arr) => arr.map(convertToDegrees));
|
||||
|
||||
@@ -113,7 +113,6 @@ function nonMaxSupress(pixels) {
|
||||
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
//Converts radians to degrees
|
||||
var convertToDegrees = radians => (radians * 180) / Math.PI;
|
||||
@@ -122,9 +121,9 @@ var convertToDegrees = radians => (radians * 180) / Math.PI;
|
||||
var findMaxInMatrix = arr => Math.max(...arr.map(el => el.map(val => !!val ? val : 0)).map(el => Math.max(...el)));
|
||||
|
||||
//Applies the double threshold to the image
|
||||
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio) {
|
||||
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, mags, strongEdgePixels, weakEdgePixels) {
|
||||
|
||||
const highThreshold = findMaxInMatrix(mags) * 0.2;
|
||||
const highThreshold = findMaxInMatrix(mags) * highThresholdRatio;
|
||||
const lowThreshold = highThreshold * lowThresholdRatio;
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
@@ -140,8 +139,6 @@ function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio) {
|
||||
}
|
||||
|
||||
strongEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 255));
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
// hysteresis edge tracking algorithm -- not working as of now
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* Detect Edges in an Image
|
||||
*/
|
||||
module.exports = function edgeDetect(options,UI) {
|
||||
module.exports = function edgeDetect(options, UI) {
|
||||
|
||||
options.blur = options.blur || 2;
|
||||
options.highThresholdRatio = options.highThresholdRatio||0.2;
|
||||
options.lowThresholdRatio = options.lowThresholdRatio||0.15;
|
||||
options.highThresholdRatio = options.highThresholdRatio || 0.2;
|
||||
options.lowThresholdRatio = options.lowThresholdRatio || 0.15;
|
||||
|
||||
var output;
|
||||
|
||||
// The function which is called on every draw.
|
||||
function draw(input,callback,progressObj) {
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
@@ -19,19 +19,20 @@ module.exports = function edgeDetect(options,UI) {
|
||||
|
||||
|
||||
// Extra Manipulation function used as an enveloper for applying gaussian blur and Convolution
|
||||
function extraManipulation(pixels){
|
||||
pixels = require('ndarray-gaussian-filter')(pixels,options.blur);
|
||||
return require('./EdgeUtils')(pixels,options.highThresholdRatio,options.lowThresholdRatio,options.inBrowser);
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('ndarray-gaussian-filter')(pixels, options.blur);
|
||||
pixels = require('./EdgeUtils')(pixels, options.highThresholdRatio, options.lowThresholdRatio, options.inBrowser);
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [(r+g+b)/3, (r+g+b)/3, (r+g+b)/3, a];
|
||||
return [(r + g + b) / 3, (r + g + b) / 3, (r + g + b) / 3, a];
|
||||
}
|
||||
|
||||
function output(image,datauri,mimetype){
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = {src:datauri,format:mimetype};
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ module.exports = function edgeDetect(options,UI) {
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Detect Edges",
|
||||
"description": "this module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge. Read more at: https://en.wikipedia.org/wiki/Canny_edge_detector",
|
||||
"description": "this module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge.<a href='https://en.wikipedia.org/wiki/Canny_edge_detector'> Read more. </a>",
|
||||
"inputs": {
|
||||
"blur": {
|
||||
"type": "integer",
|
||||
@@ -17,5 +17,6 @@
|
||||
"desc": "The low threshold value for the image",
|
||||
"default": 0.15
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -54,13 +54,14 @@
|
||||
},
|
||||
"fragmentSrc": {
|
||||
"type": "PATH",
|
||||
"desc": "Patht to a WebGL fragment shader file",
|
||||
"desc": "Path to a WebGL fragment shader file",
|
||||
"default": "(inbuilt)"
|
||||
},
|
||||
"vertexSrc": {
|
||||
"type": "PATH",
|
||||
"desc": "Patht to a WebGL vertex shader file",
|
||||
"desc": "Path to a WebGL vertex shader file",
|
||||
"default": "(inbuilt)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
44
src/modules/GammaCorrection/Module.js
Normal file
44
src/modules/GammaCorrection/Module.js
Normal file
@@ -0,0 +1,44 @@
|
||||
module.exports = function Gamma(options,UI){
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a){
|
||||
var val = options.adjustment || 0.2;
|
||||
|
||||
r = Math.pow(r / 255, val) * 255;
|
||||
g = Math.pow(g / 255, val) * 255;
|
||||
b = Math.pow(b / 255, val) * 255;
|
||||
|
||||
return [r , g, b, a];
|
||||
}
|
||||
|
||||
function output(image,datauri,mimetype){
|
||||
|
||||
step.output = {src:datauri,format:mimetype};
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/GammaCorrection/index.js
Normal file
4
src/modules/GammaCorrection/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
12
src/modules/GammaCorrection/info.json
Normal file
12
src/modules/GammaCorrection/info.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Gamma Correction",
|
||||
"description": "Apply gamma correction on the image <a href='https://en.wikipedia.org/wiki/Gamma_correction'>Read more</a>",
|
||||
"inputs": {
|
||||
"adjustment": {
|
||||
"type": "float",
|
||||
"desc": "gamma correction (inverse of actual gamma factor) for the new image",
|
||||
"default": 0.2
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "Gradient",
|
||||
"description": "Gives a gradient of the image",
|
||||
"inputs": {}
|
||||
"inputs": {},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
93
src/modules/Histogram/Module.js
Normal file
93
src/modules/Histogram/Module.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Calculates the histogram of the image
|
||||
*/
|
||||
module.exports = function Channel(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.gradient = options.gradient || "true";
|
||||
options.gradient = JSON.parse(options.gradient);
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this, hist = new Array(256).fill(0);
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
let pixVal = Math.round((r + g + b) / 3);
|
||||
hist[pixVal]++;
|
||||
return [r, g, b, a];
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
// if (!options.inBrowser)
|
||||
// require('fs').writeFileSync('./output/histo.txt', hist.reduce((tot, cur, idx) => `${tot}\n${idx} : ${cur}`, ``));
|
||||
var newarray = new Uint8Array(4 * 256 * 256);
|
||||
pixels.data = newarray;
|
||||
pixels.shape = [256, 256, 4];
|
||||
pixels.stride[1] = 4 * 256;
|
||||
|
||||
for (let x = 0; x < 256; x++) {
|
||||
for (let y = 0; y < 256; y++) {
|
||||
pixels.set(x, y, 0, 255);
|
||||
pixels.set(x, y, 1, 255);
|
||||
pixels.set(x, y, 2, 255);
|
||||
pixels.set(x, y, 3, 255);
|
||||
}
|
||||
}
|
||||
|
||||
let startY = options.gradient ? 10 : 0;
|
||||
if (options.gradient) {
|
||||
for (let x = 0; x < 256; x++) {
|
||||
for (let y = 0; y < 10; y++) {
|
||||
pixels.set(x, 255 - y, 0, x);
|
||||
pixels.set(x, 255 - y, 1, x);
|
||||
pixels.set(x, 255 - y, 2, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let convfactor = (256 - startY) / Math.max(...hist);
|
||||
|
||||
for (let x = 0; x < 256; x++) {
|
||||
let pixCount = Math.round(convfactor * hist[x]);
|
||||
|
||||
for (let y = startY; y < pixCount; y++) {
|
||||
pixels.set(x, 255 - y, 0, 204);
|
||||
pixels.set(x, 255 - y, 1, 255);
|
||||
pixels.set(x, 255 - y, 2, 153);
|
||||
}
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
// This output is accesible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
//setup: setup, // optional
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Histogram/index.js
Normal file
4
src/modules/Histogram/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module.js'),
|
||||
require('./info.json')
|
||||
]
|
||||
16
src/modules/Histogram/info.json
Normal file
16
src/modules/Histogram/info.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Histogram",
|
||||
"description": "Calculates the histogram for the image",
|
||||
"inputs": {
|
||||
"gradient": {
|
||||
"type": "select",
|
||||
"desc": "Toggle the gradient along x-axis",
|
||||
"default": "true",
|
||||
"values": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -8,5 +8,6 @@
|
||||
"desc": "URL of image to import",
|
||||
"default": "./images/monarch.png"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -2,5 +2,6 @@
|
||||
"name": "Invert",
|
||||
"description": "Inverts the image.",
|
||||
"inputs": {
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ module.exports = function CropModuleUi(step, ui) {
|
||||
var offset = $(this).offset();
|
||||
var xPos = e.pageX - offset.left;
|
||||
var yPos = e.pageY - offset.top;
|
||||
ndviImage[0].title = "NDVI: " + canvas.getContext('2d').getImageData(xPos, yPos, 1, 1).data[0];
|
||||
var ndvi = canvas.getContext('2d').getImageData(xPos, yPos, 1, 1).data[0];
|
||||
ndvi = ndvi/127.5 - 1 ;
|
||||
ndvi = ndvi.toFixed(2);
|
||||
ndviImage[0].title = "NDVI: " + ndvi;
|
||||
});
|
||||
}
|
||||
// step.imgSelector is not defined, imgElement is:
|
||||
|
||||
@@ -8,5 +8,6 @@
|
||||
"default": "red",
|
||||
"values": ["red", "blue"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"name": "NDVI-Colormap",
|
||||
"description": "Sequentially Applies NDVI and Colormap steps",
|
||||
"inputs": {},
|
||||
"length": 2
|
||||
"length": 2,
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -17,5 +17,6 @@
|
||||
"desc": "offset to the output of the step on which the output of the last step is overlayed",
|
||||
"default": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
71
src/modules/Resize/Module.js
Normal file
71
src/modules/Resize/Module.js
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Resize the image by given percentage value
|
||||
*/
|
||||
module.exports = function Resize(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.resize = options.resize || "125%";
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
var imagejs = require('imagejs');
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
// value above 100% scales up, and below 100% scales down
|
||||
var resize_value = parseInt(options.resize.slice(0, -1));
|
||||
|
||||
var new_width,
|
||||
new_height;
|
||||
|
||||
new_width = Math.round(pixels.shape[0] * (resize_value / 100));
|
||||
new_height = Math.round(pixels.shape[1] * (resize_value / 100));
|
||||
|
||||
var bitmap = new imagejs.Bitmap({width: pixels.shape[0], height: pixels.shape[1]});
|
||||
bitmap._data.data = pixels.data;
|
||||
|
||||
|
||||
var resized = bitmap.resize({
|
||||
width: new_width, height: new_height,
|
||||
algorithm: "bicubicInterpolation"
|
||||
});
|
||||
|
||||
pixels.data = resized._data.data;
|
||||
pixels.shape = [new_width,new_height,4];
|
||||
pixels.stride[1] = 4 * new_width;
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
// This output is accesible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Resize/index.js
Normal file
4
src/modules/Resize/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
12
src/modules/Resize/info.json
Normal file
12
src/modules/Resize/info.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Resize",
|
||||
"description": "Resize image by given percentage value",
|
||||
"inputs": {
|
||||
"resize": {
|
||||
"type": "string",
|
||||
"desc": "Percentage value of the resize",
|
||||
"default": "125%"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
62
src/modules/Rotate/Module.js
Normal file
62
src/modules/Rotate/Module.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Rotates image
|
||||
*/
|
||||
module.exports = function Rotate(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.rotate = parseInt(options.rotate) || 0;
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
var imagejs = require('imagejs');
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
var rotate_value = (options.rotate)%360;
|
||||
|
||||
if(rotate_value%360 == 0)
|
||||
return pixels;
|
||||
|
||||
var bitmap = new imagejs.Bitmap({width: pixels.shape[0], height: pixels.shape[1]});
|
||||
bitmap._data.data = pixels.data;
|
||||
|
||||
var rotated = bitmap.rotate({
|
||||
degrees: rotate_value,
|
||||
});
|
||||
pixels.data = rotated._data.data;
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
// This output is accesible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Rotate/index.js
Normal file
4
src/modules/Rotate/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
12
src/modules/Rotate/info.json
Normal file
12
src/modules/Rotate/info.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Rotate",
|
||||
"description": "Rotates image by specified degrees",
|
||||
"inputs": {
|
||||
"rotate": {
|
||||
"type": "integer",
|
||||
"desc": "Angular value for rotation in degrees",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -7,5 +7,6 @@
|
||||
"desc": "saturation for the new image between 0 and 2, 0 being black and white and 2 being highly saturated",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ function setInputStepInit() {
|
||||
|
||||
var dropzone = $(options.dropZoneSelector);
|
||||
var fileInput = $(options.fileInputSelector);
|
||||
var takePhoto = $(options.takePhotoSelector);
|
||||
|
||||
var onLoad = options.onLoad;
|
||||
|
||||
var onTakePhoto = options.onTakePhoto;
|
||||
|
||||
var reader = new FileReader();
|
||||
|
||||
function handleFile(e) {
|
||||
@@ -25,8 +27,53 @@ function setInputStepInit() {
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function runVideo(){
|
||||
/* event handler for Take-Photo */
|
||||
document.getElementById('video').style.display='inline';
|
||||
document.getElementById('capture').style.display='inline';
|
||||
document.getElementById('close').style.display='inline';
|
||||
|
||||
var video = document.getElementById('video');
|
||||
canvas = document.getElementById('canvas'),
|
||||
context = canvas.getContext('2d'),
|
||||
vendorUrl = window.URL || window.webkitURL;
|
||||
|
||||
navigator.getMedia = navigator.getUserMedia || navigator.wekitGetUserMedia ||
|
||||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
|
||||
navigator.getMedia({
|
||||
video: true,
|
||||
audio: false
|
||||
}, function(stream){ // success callback
|
||||
video.srcObject = stream;
|
||||
video.onloadedmetadata = function(e) {
|
||||
video.play();
|
||||
};
|
||||
document.getElementById('close').addEventListener('click', function () {
|
||||
stopStream(stream);
|
||||
});
|
||||
}, function(error){ // error
|
||||
console.log("error");
|
||||
});
|
||||
|
||||
document.getElementById('capture').addEventListener('click', function(stream){
|
||||
context.drawImage(video, 0, 0, 400, 300);
|
||||
options.onTakePhoto(canvas.toDataURL());
|
||||
});
|
||||
|
||||
function stopStream(stream) {
|
||||
stream.getVideoTracks().forEach(function (track) {
|
||||
track.stop();
|
||||
});
|
||||
document.getElementById('video').style.display='none';
|
||||
document.getElementById('capture').style.display='none';
|
||||
document.getElementById('close').style.display='none';
|
||||
}
|
||||
}
|
||||
|
||||
fileInput.on('change', handleFile);
|
||||
takePhoto.on('click', runVideo);
|
||||
|
||||
dropzone[0].addEventListener('drop', handleFile, false);
|
||||
|
||||
|
||||
@@ -184,10 +184,22 @@ test('getStep(offset) returns the step at offset distance relative to current st
|
||||
});
|
||||
|
||||
test('toCliString() returns the CLI command for the sequence', function(t) {
|
||||
t.deepEqual(sequencer.toCliString(), `sequencer -i [PATH] -s "channel channel channel channel channel invert blend" -d '{"channel":"green"}'`, "works correctly");
|
||||
t.deepEqual(sequencer.toCliString(), `sequencer -i [PATH] -s "channel channel channel channel channel invert blend" -d '{"channel":"green","offset":-2}'`, "works correctly");
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('blend returns different output depending on the set offset', function(t) {
|
||||
sequencer.addSteps('test', 'invert', {});
|
||||
sequencer.addSteps('test', 'invert', {});
|
||||
sequencer.addSteps('test', 'blend', {});
|
||||
// because we've added blend before, so instead of -3 we set it to -4
|
||||
sequencer.addSteps('test', 'blend', {'offset': -4});
|
||||
sequencer.run({ mode: 'test' }, function(out) {
|
||||
t.notStrictEqual(out, sequencer.images.test.steps[sequencer.images.test.steps.length - 2].output.src, 'different offsets give different output');
|
||||
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.");
|
||||
|
||||
@@ -8,8 +8,8 @@ test('toString() and stepToString() return the step/steps in string format', fun
|
||||
sequencer.loadImages('image1', red);
|
||||
sequencer.addSteps('channel');
|
||||
sequencer.addSteps('invert');
|
||||
t.equal(sequencer.toString(), "channel{channel:green},invert{}", "toString works");
|
||||
t.equal(sequencer.stepToString(sequencer.steps[1]), "channel{channel:green}", "stepToString works");
|
||||
t.equal(sequencer.toString(), "channel{},invert{}", "toString works");
|
||||
t.equal(sequencer.stepToString(sequencer.steps[1]), "channel{}", "stepToString works");
|
||||
t.end();
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ test('stringToJSON() and stringToJSONstep() return the step/steps from a string
|
||||
|
||||
test('toJSON() returns the right sequence of steps', function(t) {
|
||||
t.deepEqual(sequencer.toJSON(), [
|
||||
{ name: 'channel', options: { channel: 'green' } },
|
||||
{ name: 'channel', options: {} },
|
||||
{ name: 'invert', options: {} }
|
||||
]);
|
||||
t.end();
|
||||
@@ -44,7 +44,7 @@ test('toJSON() returns the right sequence of steps', function(t) {
|
||||
|
||||
test('importString() imports a string of steps into the sequencer', function(t) {
|
||||
sequencer.importString('brightness{brightness:50},invert');
|
||||
t.equal(sequencer.toString(), "channel{channel:green},invert{},brightness{brightness:50},invert{}");
|
||||
t.equal(sequencer.toString(), "channel{},invert{},brightness{brightness:50},invert{}");
|
||||
t.end();
|
||||
});
|
||||
|
||||
@@ -52,7 +52,7 @@ test('importJSON() imports a JSON array of steps into the sequencer', function(t
|
||||
sequencer.importJSON([
|
||||
{ name: 'blur', options: {} }
|
||||
]);
|
||||
t.equal(sequencer.toString(), "channel{channel:green},invert{},brightness{brightness:50},invert{},blur{blur:2}")
|
||||
t.equal(sequencer.toString(), "channel{},invert{},brightness{brightness:50},invert{},blur{}")
|
||||
t.end();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user