mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-07 00:40:00 +01:00
Compare commits
1 Commits
headless-o
...
rotate-def
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dccb514b69 |
11
.codecov.yml
11
.codecov.yml
@@ -1,11 +0,0 @@
|
||||
comment:
|
||||
layout: "reach, diff, flags, files"
|
||||
behavior: default
|
||||
require_changes: false # if true: only post the comment if coverage changes
|
||||
require_base: no # [yes :: must have a base report to post]
|
||||
require_head: yes # [yes :: must have a head report to post]
|
||||
branches: null # branch names that can post comment
|
||||
coverage:
|
||||
status:
|
||||
project: off
|
||||
patch: off
|
||||
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -10,7 +10,7 @@
|
||||
|
||||
### Please show us where to look
|
||||
|
||||
https://beta.sequencer.publiclab.org
|
||||
http://sequencer.publiclab.org...
|
||||
|
||||
|
||||
### What's your PublicLab.org username?
|
||||
|
||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,11 +1,11 @@
|
||||
Fixes #0000 (<=== Replace `0000` with the Issue Number)
|
||||
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 `npm test`
|
||||
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
||||
* [ ] PR is descriptively titled
|
||||
* [ ] ask `@publiclab/is-reviewers` for help, in a comment below
|
||||
* [ ] ask `@publiclab/reviewers` and `@publiclab/is-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!
|
||||
|
||||
|
||||
2
.github/config.yml
vendored
2
.github/config.yml
vendored
@@ -17,7 +17,7 @@ newPRWelcomeComment: |
|
||||
# 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 be published to https://beta.sequencer.publiclab.org in a day or two.
|
||||
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)
|
||||
|
||||
12
.github/first-timers.yml
vendored
12
.github/first-timers.yml
vendored
@@ -1,12 +0,0 @@
|
||||
# You can change the labels to suit your needs if "first-timers-only" is not what you are looking for.
|
||||
# These are some examples.
|
||||
labels:
|
||||
- first-timers-only
|
||||
- help wanted
|
||||
|
||||
#If you would like to add your own template for the issue, add an .md file to your .github folder
|
||||
template: .github/fto-template.md
|
||||
|
||||
# You can create the issue in a different repo than where the problem is. Just make sure you installed the bot on the configured repository.
|
||||
# The issue will link back to the original repository where the contribution will be made.
|
||||
#repository: repo-name
|
||||
51
.github/fto-template.md
vendored
51
.github/fto-template.md
vendored
@@ -1,51 +0,0 @@
|
||||
Hi, this is a [first-timers-only issue](https://code.publiclab.org/#r=all). This means we've worked to make it more legible to folks who either **haven't contributed to our codebase before, or even folks who haven't contributed to open source before**.
|
||||
|
||||
If that's you, we're interested in helping you take the first step and can answer questions and help you out as you do. Note that we're especially interested in contributions from people from groups underrepresented in free and open source software!
|
||||
|
||||
We know that the process of creating a pull request is the biggest barrier for new contributors. This issue is for you 💝
|
||||
|
||||
If you have contributed before, **consider leaving this one for someone new**, and looking through our general [help wanted](https://github.com/publiclab/image-sequencer/labels/help-wanted) issues. Thanks!
|
||||
|
||||
### 🤔 What you will need to know.
|
||||
|
||||
Nothing. This issue is meant to welcome you to Open Source :) We are happy to walk you through the process.
|
||||
|
||||
### 📋 Step by Step
|
||||
|
||||
- [ ] 🙋 **Claim this issue**: Comment below. If someone else has claimed it, ask if they've opened a pull request already and if they're stuck -- maybe you can help them solve a problem or move it along!
|
||||
|
||||
- [ ] 📝 **Update** the file [$FILENAME]($BRANCH_URL) in the `$REPO` repository (press the little pen Icon) and edit the line as shown below.
|
||||
|
||||
[See this page](https://code.publiclab.org/#r=all) for some help in taking your first steps!
|
||||
|
||||
Below is a "diff" showing in red (and a `-`) which lines to remove, and in green (and a `+`) which lines to add:
|
||||
|
||||
```diff
|
||||
|
||||
$DIFF
|
||||
|
||||
```
|
||||
- [ ] 💾 **Commit** your changes
|
||||
|
||||
- [ ] 🔀 **Start a Pull Request**. There are two ways how you can start a pull request:
|
||||
|
||||
1. If you are familiar with the terminal or would like to learn it, [here is a great tutorial](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github) on how to send a pull request using the terminal.
|
||||
|
||||
2. You can also [edit files directly in your browser](https://help.github.com/articles/editing-files-in-your-repository/) and open a pull request from there.
|
||||
|
||||
- [ ] 🏁 **Done** Ask in comments for a review :)
|
||||
|
||||
### Please keep us updated
|
||||
|
||||
💬⏰ - We encourage contributors to be respectful to the community and provide an update **within a week** of claiming a first-timers-only issue. We're happy to keep it assigned to you as long as you need if you update us with a request for more time or help, but if we don't see any activity a week after you claim it we may reassign it to give someone else a chance. Thank you in advance!
|
||||
|
||||
If this happens to you, don't sweat it! Grab another open issue.
|
||||
|
||||
### Is someone else already working on this?
|
||||
|
||||
🔗- We encourage contributors to link to the original issue in their pull request so all users can easily see if someone's already started on it.
|
||||
|
||||
👥- **If someone seems stuck, offer them some help!** Otherwise, [take a look at some other issues you can help with](https://code.publiclab.org/#r=all). Thanks!
|
||||
|
||||
### 🤔❓ Questions?
|
||||
Leave a comment below!
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -27,10 +27,6 @@ build/Release
|
||||
node_modules
|
||||
node_modules/*
|
||||
|
||||
# Dist Files
|
||||
dist/*
|
||||
dist
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
@@ -44,9 +40,5 @@ todo.txt
|
||||
test.js
|
||||
output.txt
|
||||
output/
|
||||
test/core/modules/test_outputs
|
||||
test/core/modules/test_outputs/*
|
||||
node_modules/
|
||||
node_modules/*
|
||||
test_outputs
|
||||
/test_outputs
|
||||
|
||||
@@ -37,8 +37,6 @@ test.js
|
||||
output.txt
|
||||
output/
|
||||
|
||||
|
||||
|
||||
examples/
|
||||
icons/
|
||||
|
||||
|
||||
@@ -7,16 +7,12 @@ env:
|
||||
- CXX=g++-4.8
|
||||
before_script:
|
||||
- npm install grunt-cli -g # for "grunt build"
|
||||
- npm install jasmine -g
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- ./cc-test-reporter before-build
|
||||
script:
|
||||
- npm test
|
||||
- npm run test-ui
|
||||
- grunt build
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
after_script:
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
addons:
|
||||
|
||||
@@ -43,8 +43,7 @@ __Moderators Group:__ The moderators group is responsible for addressing immedia
|
||||
|
||||
We begin interactions by acknowledging that we are part of a community with complementary goals. Different views are allowed to respectfully coexist in the same space. When something's happened and someone is uncomfortable, our first choice is to work through it. Endeavor to listen and appropriately adjust your behavior if someone approaches you privately with a request that you apologize or publicly requests that you stop an ongoing presentation. If someone questions your words, actions or motives, or "calls you out", hear their feedback and respond respectfully. It’s okay to not understand why something is hurtful or causes discomfort, as long as you approach it respectfully, with empathy. Repeating hurtful behavior after it has been addressed is disrespectful and is not allowed. Doing so will result in removal and subsequent banning from in-person events and being placed into moderation in online spaces.
|
||||
|
||||
### The first rule of engaging with others is consent
|
||||
|
||||
###The first rule of engaging with others is consent
|
||||
During in-person gatherings, consent is important to highlight because the negotiation of consent can be subtle, and it’s easy to miss each other’s non-verbal cues, resulting in miscommunication and/or offense. During online interactions, consent can be even harder to distinguish.
|
||||
|
||||
We make guesses or assessments of consent (willingness, welcome, invitation) all the time. Then we stay open to signs that the consent isn't there. Handshakes are a clear example of consent: someone offers a hand, and you take it if you want to shake it. A friendly smile might indicate consent to start a conversation. It might not. We learn that in the interaction. Sometimes we ask directly. We are open to making mistakes, and learning from them. The more we learn to be empathetic and see other people, the more we're able to talk about consent.
|
||||
@@ -111,4 +110,4 @@ Staff are bound by their Employment Handbook, you must reference it. Additionall
|
||||
* Direct problems that come up among community members to the Conduct Committee.
|
||||
* When organizing events, circulate access information regarding wheelchair-accessible ADA bathrooms, non-gendered bathrooms, the presence of stairs or curb ramps in the parking lot, et cetera.
|
||||
* During events that you are attending in person, solve accessibility issues by making sure attendees know where bathrooms are located and can access them by wheelchair without being obstructed by things like chairs, kites, contraptions, or cords.
|
||||
* Watch for people feeling left out and include them.
|
||||
* Watch for people feeling left out and include them.
|
||||
162
CONTRIBUTING.md
162
CONTRIBUTING.md
@@ -11,8 +11,6 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
|
||||
* [Contributing Modules](#contributing-modules)
|
||||
* [Info File](#info-file)
|
||||
* [Ideas](#Contribution-ideas)
|
||||
* [Grunt Tasks](#grunt-tasks)
|
||||
* [UI Helper Methods](#ui-helper-methods)
|
||||
|
||||
****
|
||||
|
||||
@@ -28,7 +26,7 @@ If you find a bug please list it here, and help us develop Image Sequencer by [o
|
||||
|
||||
## Contributing modules
|
||||
|
||||
Most contributions can happen in modules, rather than to core library code. Modules and their [corresponding info files](#info-file) are included into the library in this file: https://github.com/publiclab/image-sequencer/blob/main/src/Modules.js#L5-L7
|
||||
Most contributions can happen in modules, rather than to core library code. Modules and their [corresponding info files](#info-file) are included into the library in this file: https://github.com/publiclab/image-sequencer/blob/master/src/Modules.js#L5-L7
|
||||
|
||||
Module names, descriptions, and parameters are set in the `info.json` file -- [see below](#info-file).
|
||||
|
||||
@@ -64,8 +62,6 @@ Image Sequencer modules are designed to be run either in the browser or in a Nod
|
||||
|
||||
https://github.com/tech4gt/image-sequencer
|
||||
|
||||
### Browser/node compatibility
|
||||
|
||||
If you wish to offer a module without browser-compatibility, please indicate this in the returned `info` object as:
|
||||
|
||||
module.exports = [
|
||||
@@ -112,20 +108,7 @@ function ModuleName(options,UI) {
|
||||
// load a standard info.json file.
|
||||
];
|
||||
```
|
||||
### Running a browser-only module in node
|
||||
If your module has browser specific code or you are consuming a dependency which does the `gl-context` api. We designed this api especially for webl based modules but since it runs the module in a headless browser, ti supports all browser specific APIs.
|
||||
|
||||
The api must be used in the following format
|
||||
```js
|
||||
var step = this;
|
||||
|
||||
if (!options.inBrowser) {
|
||||
require('../_nomodule/gl-context')(input, callback, step, options);
|
||||
}
|
||||
else {
|
||||
/* Browser specific code */
|
||||
}
|
||||
```
|
||||
|
||||
### options
|
||||
|
||||
@@ -156,7 +139,7 @@ input = {
|
||||
pixelManipulation: "general purpose pixel manipulation API, see https://github.com/publiclab/image-sequencer/blob/master/src/modules/_nomodule/PixelManipulation.js"
|
||||
}
|
||||
```
|
||||
For example usage of pixelManipulation see https://github.com/publiclab/image-sequencer/blob/main/src/modules/Invert/Module.js
|
||||
For example usage for pixelManipulation see https://github.com/publiclab/image-sequencer/blob/master/src/modules/Invert/Module.js
|
||||
|
||||
**The module is included in the browser inside a script tag and since the code runs directly in the browser if any other module is required apart from the apis available on the input object, it should be either bundled with the module code and imported in es6 format or the module code must be browserified before distribution for browser**
|
||||
|
||||
@@ -278,9 +261,9 @@ The `progressObj` parameter of `draw()` is not consumed unless a custom progress
|
||||
|
||||
### Module example
|
||||
|
||||
See existing module `channel` for an example: https://github.com/publiclab/image-sequencer/blob/main/src/modules/Channel/Module.js
|
||||
See existing module `green-channel` for an example: https://github.com/publiclab/image-sequencer/tree/master/src/modules/GreenChannel/Module.js
|
||||
|
||||
The `channel` module is included into the core modules here: https://github.com/publiclab/image-sequencer/blob/main/src/Modules.js#L5-L7
|
||||
The `green-channel` module is included into the core modules here: https://github.com/publiclab/image-sequencer/blob/master/src/Modules.js#L5-L7
|
||||
|
||||
For help integrating, please open an issue.
|
||||
|
||||
@@ -289,20 +272,16 @@ For help integrating, please open an issue.
|
||||
IMAGE SEQUENCER supports "meta modules" -- modules made of other modules. The syntax and structure of these meta modules is very similar to standard modules. Sequencer can also genarate meta modules dynamically with the function `createMetaModule` which can be called in the following ways
|
||||
|
||||
```js
|
||||
// stepsString is a stringified sequence
|
||||
sequencer.createMetaModule(stepsString,info)
|
||||
|
||||
/* Mapping function is a function which gets the inputs of the module as argument
|
||||
* and returns an array with steps mapped to their options
|
||||
* See https://github.com/publiclab/image-sequencer/blob/main/src/modules/Colorbar/Module.js for example
|
||||
*/
|
||||
|
||||
/* Module options is an object with the following keys
|
||||
* infoJson: the info.json object for the module
|
||||
*/
|
||||
sequencer.createMetaModule(mappingFunction,moduleOptions)
|
||||
|
||||
/* createMetaModule returns an array of module function and info just like normal
|
||||
* modules. These can also be loaded into sequencer dynamically like other modules
|
||||
/* stepsArray is the array of objects in this format
|
||||
* [
|
||||
* {name: "moduleName",options: {}},
|
||||
* {name: "moduleName",options: {}}
|
||||
* ]
|
||||
*/
|
||||
sequencer.createMetaModule(stepsArray,info)
|
||||
```
|
||||
|
||||
A Meta module can also be contributed like a normal module with an info and a Module.js. A basic Meta module shall follow the following format
|
||||
@@ -310,17 +289,12 @@ A Meta module can also be contributed like a normal module with an info and a Mo
|
||||
|
||||
```js
|
||||
// Module.js
|
||||
module.exports = require('../../util/createMetaModule.js')(
|
||||
function mapFunction(options) {
|
||||
|
||||
return [
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
];
|
||||
}, {
|
||||
infoJson: require('./info.json')
|
||||
}
|
||||
)[0];
|
||||
module.exports = function metaModuleFun(){
|
||||
this.expandSteps([
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
{ 'name': 'module-name', options: {} }
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
@@ -328,8 +302,7 @@ A Meta module can also be contributed like a normal module with an info and a Mo
|
||||
{
|
||||
"name": "meta-moduleName",
|
||||
"description": "",
|
||||
"inputs": {
|
||||
}
|
||||
"length": //Integer representing number of steps in the metaModule
|
||||
}
|
||||
```
|
||||
|
||||
@@ -344,88 +317,19 @@ module.exports = [
|
||||
All of the above can also be combined together to form a single file module.
|
||||
|
||||
```js
|
||||
|
||||
// MetaModule.js
|
||||
module.exports =
|
||||
sequencer.createMetaModule(
|
||||
function mapFunction(options) {
|
||||
|
||||
return [
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
];
|
||||
}, {
|
||||
infoJson: {
|
||||
"name": "meta-moduleName",
|
||||
"description": "",
|
||||
"inputs": {
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Grunt Tasks
|
||||
This repository has different grunt tasks for different uses. The source code is in the [Gruntfile](https://github.com/publiclab/image-sequencer/blob/main/Gruntfile.js).
|
||||
|
||||
The following command is used for running the tasks: `grunt [task-name]`. Here `[task-name]` should be replaced by the name of the task to be run. To run the default task run `grunt` without any options.
|
||||
|
||||
#### Tasks
|
||||
1. **compile**: Compiles/Browserifies the dist files in `/dist/image-sequencer.js` and `/dist/image-sequencer-ui.js`.
|
||||
2. **build**: Compiles the files as in the **compile** task and minifies/uglifies dist files in `/dist/image-sequencer.min.js` and `/dist/image-sequencer-ui.min.js`.
|
||||
3. **watch**: Checks for any changes in the source code and runs the **compile** task if any changes are found.
|
||||
4. **serve**: Compiles the dist files as in the **compile** task and starts a local server on `localhost:3000` to host the demo site in `/examples/` directory. Also runs the **watch** task.
|
||||
5. **production**: Compiles and minifies dist files in `/dist/image-sequencer.js` and `/dist/image-sequencer-ui.js` without the `.min.js` extension to include minified files in the demo site. This script should only be used in production mode while deploying.
|
||||
6. **default**: Runs the **watch** task as default.
|
||||
|
||||
## UI Helper Methods
|
||||
|
||||
### scopeQuery
|
||||
|
||||
###### Path: `/examples/lib/scopeQuery.js`
|
||||
|
||||
The method returns a scoped `jQuery` object which only searches for elements inside a given scope (a DOM element).
|
||||
|
||||
To use the method,
|
||||
* import the `scopeSelector` and `scopeSelectorAll` methods from `lib/scopeQuery.js`
|
||||
* call the methods with scope as a parameter
|
||||
|
||||
```js
|
||||
var scopeQuery = require('./scopeQuery');
|
||||
|
||||
var $step = scopeQuery.scopeSelector(scope),
|
||||
$stepAll = scopeQuery.scopeSelectorAll(scope);
|
||||
```
|
||||
This will return an object with a constructor which returns a `jQuery` object (from inside the scope) but with new `elem` and `elemAll` methods.
|
||||
|
||||
#### Methods of the Returned Object
|
||||
* `elem()`: Selects an element inside the scope;
|
||||
* `elemAll()`: Selects all the instances of a given element inside the scope;
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
//The scope is a div element with id=“container“ and there are three divs in it
|
||||
//with ids „1“, „2“, and „3“, and all of them have a „child“ class attribute
|
||||
|
||||
var $step = require('./scopeQuery').scopeSelector(document.getElementById('container'));
|
||||
|
||||
$step('#1'); // returns the div element with id=“1“
|
||||
$step('#1').hide().elemAll('.child').fadeOut(); // abruptly hides the div element with id=“1“ and fades out all other div elements
|
||||
```
|
||||
|
||||
These two methods are chainable and will always return elements from inside the scope.
|
||||
|
||||
#### Usage
|
||||
|
||||
Instead of using
|
||||
|
||||
```js
|
||||
$(step.ui.querySelector('query')).show().hide();
|
||||
$(step.ui.querySelectorAll('q2')).show().hide();
|
||||
```
|
||||
The following code can be used
|
||||
|
||||
```js
|
||||
$step('query').show().hide();
|
||||
$stepAll('q2').show().hide();
|
||||
module.export = [
|
||||
function (){
|
||||
this.expandSteps([
|
||||
{ 'name': 'module-name', 'options': {} },
|
||||
{ 'name': 'module-name', options: {} }
|
||||
]);
|
||||
},
|
||||
{
|
||||
"name": "meta-moduleName",
|
||||
"description": "",
|
||||
"length": //Integer representing number of steps in the metaModule
|
||||
}
|
||||
]
|
||||
```
|
||||
The length is absolutely required for a meta-module, since sequencer is optimized to re-run minimum number of steps when a step is added in the UI which is 1 in the case of normal modules, if the added step is a meta-module the length of the sequence governs the number of steps to re-run.
|
||||
36
Gruntfile.js
36
Gruntfile.js
@@ -15,46 +15,30 @@ module.exports = function(grunt) {
|
||||
livereload: true
|
||||
},
|
||||
source: {
|
||||
files: ["src/**/*", "Gruntfile.js", "examples/lib/*", "examples/demo.js"],
|
||||
tasks: ["compile"]
|
||||
files: ["src/**/*", "Gruntfile.js"],
|
||||
tasks: ["build:js"]
|
||||
}
|
||||
},
|
||||
|
||||
browserify: {
|
||||
core: {
|
||||
dist: {
|
||||
src: ["src/ImageSequencer.js"],
|
||||
dest: "dist/image-sequencer.js"
|
||||
},
|
||||
ui: {
|
||||
},
|
||||
js: {
|
||||
src: ["examples/demo.js"],
|
||||
dest: "dist/image-sequencer-ui.js"
|
||||
},
|
||||
prodcore: {
|
||||
src: ["src/ImageSequencer.js"],
|
||||
dest: "dist/image-sequencer.brow.js"
|
||||
},
|
||||
produi: {
|
||||
src: ["examples/demo.js"],
|
||||
dest: "dist/image-sequencer-ui.brow.js"
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
core: {
|
||||
dist: {
|
||||
src: ["./dist/image-sequencer.js"],
|
||||
dest: "./dist/image-sequencer.min.js"
|
||||
},
|
||||
ui: {
|
||||
js: {
|
||||
src: ['dist/image-sequencer-ui.js'],
|
||||
dest: 'dist/image-sequencer-ui.min.js'
|
||||
},
|
||||
prodcore: {
|
||||
src: ["dist/image-sequencer.brow.js"],
|
||||
dest: "dist/image-sequencer.js"
|
||||
},
|
||||
produi: {
|
||||
src: ["dist/image-sequencer-ui.brow.js"],
|
||||
dest: "dist/image-sequencer-ui.js"
|
||||
}
|
||||
},
|
||||
browserSync: {
|
||||
@@ -69,8 +53,6 @@ module.exports = function(grunt) {
|
||||
|
||||
/* Default (development): Watch files and build on change. */
|
||||
grunt.registerTask("default", ["watch"]);
|
||||
grunt.registerTask("build", ["browserify:core", "browserify:ui", "uglify:core", "uglify:ui"]);
|
||||
grunt.registerTask("serve", ["browserify:core", "browserify:ui", "browserSync", "watch"]);
|
||||
grunt.registerTask("compile", ["browserify:core", "browserify:ui"]);
|
||||
grunt.registerTask("production", ["browserify:prodcore", "browserify:produi", "uglify:prodcore", "uglify:produi"]);
|
||||
grunt.registerTask("build", ["browserify:dist", "uglify:dist"]);
|
||||
grunt.registerTask("serve", ["browserify:dist","browserify:js","uglify:dist","uglify:js","browserSync", "watch"]);
|
||||
};
|
||||
|
||||
340
README.md
340
README.md
@@ -1,45 +1,34 @@
|
||||
Image Sequencer
|
||||
====
|
||||
|
||||
|
||||
[](https://travis-ci.org/publiclab/image-sequencer) [](https://codeclimate.com/github/publiclab/image-sequencer/maintainability) [](https://codecov.io/gh/publiclab/image-sequencer)
|
||||
|
||||
- **Latest Stable Demo**: https://sequencer.publiclab.org
|
||||
- **Latest Beta Demo**: https://beta.sequencer.publiclab.org
|
||||
- **Stable Branch**: https://github.com/publiclab/image-sequencer/tree/stable/
|
||||
[](https://travis-ci.org/publiclab/image-sequencer)
|
||||
|
||||
## Why
|
||||
|
||||
Image Sequencer is different from other image processing systems because it's _non-destructive_: instead of modifying the original image, it **creates a new image at each step in a sequence**. This is because it:
|
||||
Image Sequencer is different from other image processing systems in that it's _non-destructive_: instead of modifying the original image, it **creates a new image at each step in a sequence**. This is because it:
|
||||
|
||||
* 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 run through the same sequence of steps
|
||||
* allows many images to be run through the same sequence of steps
|
||||
* works identically in the browser, on Node.js, and on the command line
|
||||
|
||||
The following diagrams attempt to explain how the applications various components interconnect:
|
||||

|
||||
|
||||

|
||||
It is also for prototyping some other related ideas:
|
||||
|
||||

|
||||
|
||||
It also for prototypes other related ideas:
|
||||
|
||||
* filter-like image processing -- apply 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 other image processing tools, provable with example before/after images to compare with
|
||||
* logging each step -- to produce an evidentiary record of modifications to an original image
|
||||
* 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
|
||||
* "small modules" -- based extensibility: see [Contributing](https://github.com/publiclab/image-sequencer/blob/main/CONTRIBUTING.md)
|
||||
|
||||
* "small modules"-based extensibility: see [Contributing](https://github.com/publiclab/image-sequencer/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## Examples
|
||||
|
||||
* [Simple Demo](https://sequencer.publiclab.org)
|
||||
* [Latest Beta Demo](https://beta.sequencer.publiclab.org)
|
||||
* [Simple Demo](https://publiclab.github.io/image-sequencer/)
|
||||
|
||||
A diagram of this running 5 steps on a single sample image may help explain how it works:
|
||||
|
||||

|
||||

|
||||
|
||||
## Jump to:
|
||||
|
||||
@@ -50,21 +39,21 @@ A diagram of this running 5 steps on a single sample image may help explain how
|
||||
* [Method Chaining](#method-chaining)
|
||||
* [Multiple Images](#multiple-images)
|
||||
* [Creating a User Interface](#creating-a-user-interface)
|
||||
* [Contributing](https://github.com/publiclab/image-sequencer/blob/main/CONTRIBUTING.md)
|
||||
* [Submit a Module](https://github.com/publiclab/image-sequencer/blob/main/CONTRIBUTING.md#contributing-modules)
|
||||
* [Contributing](https://github.com/publiclab/image-sequencer/blob/master/CONTRIBUTING.md)
|
||||
* [Submit a Module](https://github.com/publiclab/image-sequencer/blob/master/CONTRIBUTING.md#contributing-modules)
|
||||
* [Get Demo Bookmarklet](https://publiclab.org/w/imagesequencerbookmarklet)
|
||||
|
||||
## Installation
|
||||
|
||||
This library conveniently works in the browser, in Node, and on the command line (CLI).
|
||||
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`.
|
||||
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 build; grunt serve
|
||||
npm i ; npm i -g grunt grunt-cli ; grunt serve
|
||||
```
|
||||
In case of a port conflict please run the following
|
||||
```powershell
|
||||
@@ -73,12 +62,12 @@ npm i -g http-server ; http-server -p 3000
|
||||
|
||||
### Browser
|
||||
|
||||
Just include [image-sequencer.min.js](https://github.com/publiclab/image-sequencer/blob/stable/dist/image-sequencer.min.js) in the Head section of your web page. See the [demo here](https://sequencer.publiclab.org)!
|
||||
Just include [image-sequencer.js](https://publiclab.github.io/image-sequencer/dist/image-sequencer.js) in the Head section of your web page. See the [demo here](https://publiclab.github.io/image-sequencer/)!
|
||||
|
||||
### Node (via NPM)
|
||||
|
||||
(You must have NPM for this)
|
||||
Add `image-sequencer` to your list of dependencies and run `npm install`
|
||||
Add `image-sequencer` to your list of dependencies and run `$ npm install`
|
||||
|
||||
### CLI
|
||||
|
||||
@@ -98,16 +87,8 @@ $ npm run debug invert
|
||||
|
||||
## Quick Usage
|
||||
|
||||
### Initializing the Sequencer
|
||||
|
||||
The Image Sequencer Library exports a function ImageSequencer which initializes a sequencer.
|
||||
|
||||
```js
|
||||
var sequencer = ImageSequencer();
|
||||
```
|
||||
|
||||
Image Sequencer can be used to run modules on an HTML Image Element using the
|
||||
`replaceImage` method, which accepts two parameters - `selector` and `steps`.
|
||||
`replaceImage` method. The method accepts two parameters - `selector` and `steps`.
|
||||
`selector` is a CSS selector. If it matches multiple images, all images will be
|
||||
modified. `steps` may be the name of a module or array of names of modules.
|
||||
|
||||
@@ -115,7 +96,7 @@ Note: Browser CORS Restrictions apply. Some browsers may not allow local images
|
||||
from other folders, and throw a Security Error instead.
|
||||
|
||||
```js
|
||||
sequencer.replaceImage(selector,steps,optional_options);
|
||||
sequencer.replaceImage(selector,steps,optional_options);
|
||||
```
|
||||
|
||||
`optional_options` allows passing additional arguments to the module itself.
|
||||
@@ -123,8 +104,8 @@ sequencer.replaceImage(selector,steps,optional_options);
|
||||
For example:
|
||||
|
||||
```js
|
||||
sequencer.replaceImage('#photo','invert');
|
||||
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
||||
sequencer.replaceImage('#photo','invert');
|
||||
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
||||
```
|
||||
|
||||
### Data URL usage
|
||||
@@ -150,7 +131,7 @@ Image Sequencer also provides a CLI for applying operations to local files. The
|
||||
The basic format for using the CLI is as follows:
|
||||
|
||||
```
|
||||
$ ./index.js -i [PATH] -s step-name
|
||||
$ ./index.js -i [PATH] -s step-name
|
||||
```
|
||||
|
||||
*NOTE:* On Windows you'll have to use `node index.js` instead of `./index.js`.
|
||||
@@ -158,7 +139,7 @@ $ ./index.js -i [PATH] -s step-name
|
||||
The CLI also can take multiple steps at once, like so:
|
||||
|
||||
```
|
||||
$ ./index.js -i [PATH] -s "step-name-1 step-name-2 ..."
|
||||
$ ./index.js -i [PATH] -s "step-name-1 step-name-2 ..."
|
||||
```
|
||||
|
||||
But for this, double quotes must wrap the space-separated steps.
|
||||
@@ -168,7 +149,7 @@ Options for the steps can be passed in one line as JSON in the details option li
|
||||
$ ./index.js -i [PATH] -s "brightness" -c '{"brightness":50}'
|
||||
|
||||
```
|
||||
Or the values can be given through the terminal prompt like
|
||||
Or the values can be given through terminal prompt like
|
||||
|
||||
<img width="1436" alt="screen shot 2018-02-14 at 5 18 50 pm" src="https://user-images.githubusercontent.com/25617855/36202790-3c6e8204-11ab-11e8-9e17-7f3387ab0158.png">
|
||||
|
||||
@@ -201,17 +182,15 @@ var sequencer = ImageSequencer();
|
||||
### Loading an Image into the Sequencer
|
||||
|
||||
The `loadImage` method is used to load an image into the sequencer. It accepts
|
||||
an image `src`, either a URL or a data-url. The method also accepts an optional callback.
|
||||
a name and an image. The method also accepts an optional callback.
|
||||
|
||||
```js
|
||||
sequencer.loadImage(image_src, optional_callback);
|
||||
sequencer.loadImage(image_src,optional_callback);
|
||||
```
|
||||
|
||||
On `Node.js` the `image_src` may be a DataURI or a local path or a URL.
|
||||
|
||||
On browsers, it may be a DatURI, a local image or a URL (Unless this violates
|
||||
CORS Restrictions). To sum up, these are accepted:
|
||||
|
||||
* Images in the same domain (or directory - for a local implementation)
|
||||
* CORS-Proof images in another domain.
|
||||
* DataURLs
|
||||
@@ -221,7 +200,7 @@ The callback is called within the scope of a sequencer. For example:
|
||||
(addSteps is defined later)
|
||||
|
||||
```js
|
||||
sequencer.loadImage('SRC', function(){
|
||||
sequencer.loadImage('SRC',function(){
|
||||
this.addSteps('module-name');
|
||||
});
|
||||
```
|
||||
@@ -239,43 +218,11 @@ sequencer.addSteps(modules, optional_options);
|
||||
```
|
||||
|
||||
If only one module is to be added, `modules` is simply the name of the module.
|
||||
If multiple images are to be added, `modules` is an array, which holds the names of modules
|
||||
to be added, in that particular order.
|
||||
If multiple images are to be added, `modules` is an array of the names of modules
|
||||
which are to be added, in that particular order.
|
||||
|
||||
optional_otions is just an optional parameter, in object form, which you might
|
||||
want to provide to the modules.
|
||||
|
||||
A variety of syntaxes are supported by Image Sequencer to add multiple steps and configurations quickly for module chaining. The project supports the string syntax, designed to be compact and URL friendly, and JSON, for handling more complex sequences. This can be achieved by passing strings to `sequencer.addStep()`:
|
||||
|
||||
|
||||
```js
|
||||
sequencer.addSteps('invert,channel');
|
||||
sequencer.addSteps(['invert','channel']);
|
||||
```
|
||||
|
||||
For passing default configurations ({} is optional):
|
||||
|
||||
```js
|
||||
sequencer.addSteps('brightness{}');
|
||||
```
|
||||
|
||||
For passing custom configurations:
|
||||
|
||||
```js
|
||||
sequencer.addSteps('brightness{brightness:80}');
|
||||
```
|
||||
|
||||
For passing multiple custom configurations:
|
||||
|
||||
```js
|
||||
sequencer.addSteps('crop{x:120|y:90}')
|
||||
```
|
||||
|
||||
For passing multiple custom configurable modules:
|
||||
|
||||
```js
|
||||
sequencer.addSteps('crop{x:130|y:80},brightness{brightness:80}')
|
||||
```
|
||||
optional_otions is just additional parameters, in object form, which you might
|
||||
want to provide to the modules. It's an optional parameter.
|
||||
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
@@ -326,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,
|
||||
@@ -353,7 +300,7 @@ role it played in `addSteps`.
|
||||
|
||||
Indexes can be negative. Negative sign with an index means that counting will be
|
||||
done in reverse order. If the index is out of bounds, the counting will wrap in
|
||||
the original direction of counting. So, an `index` of -1 means the module is
|
||||
the original direction of counting. So, an `index` of -1 means that the module is
|
||||
inserted at the end.
|
||||
|
||||
```js
|
||||
@@ -379,11 +326,12 @@ Methods can be chained on the Image Sequencer:
|
||||
* run() can not be in the middle of the chain.
|
||||
* If the chain starts with loadImage() or loadImages(), the following methods are
|
||||
applied only to the newly loaded images.
|
||||
|
||||
* If no name is provided to the image, a name will be generated for it. The name will
|
||||
be of the form "image<number>". For Ex: "image1", "image2", "image3", etc.
|
||||
|
||||
Valid Chains:
|
||||
```js
|
||||
sequencer.loadImage(function(){
|
||||
sequencer.loadImage('red',function(){
|
||||
this.addSteps('invert').run(function(out){
|
||||
//do something with ouptut.
|
||||
});
|
||||
@@ -398,20 +346,156 @@ sequencer.addSteps('invert').run().addSteps('ndvi-red');
|
||||
```
|
||||
|
||||
|
||||
## Multiple Images
|
||||
Image Sequencer is capable of handling multiple images at once.
|
||||
|
||||
## Fetching current steps
|
||||
|
||||
The `getSteps` method can be used to get the array of current steps in `this` instance of sequencer.For example
|
||||
|
||||
### Initializing a sequencer with multiple images.
|
||||
This is just like before.
|
||||
```js
|
||||
sequencer.getSteps()
|
||||
var sequencer = ImageSequencer();
|
||||
```
|
||||
|
||||
returns an array of steps associated with the current sequencer.
|
||||
### Loading Multiple Images into the Sequencer
|
||||
|
||||
Multiple images can be loaded by the method `loadImages`. Everything is the same,
|
||||
except that now, a unique identification called `image_name` has to be provided
|
||||
with each image. This is a string literal.
|
||||
|
||||
* 3/2 parameters :
|
||||
```js
|
||||
sequencer.loadImages(image_name,
|
||||
image_src,optional_callback);
|
||||
```
|
||||
* 1/2 parameters (JSON) :
|
||||
```js
|
||||
sequencer.loadImages({
|
||||
images: {
|
||||
image1_name: image_src,
|
||||
image2_name: image_src,
|
||||
...
|
||||
},
|
||||
callback: optional_callback
|
||||
});
|
||||
```
|
||||
|
||||
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,
|
||||
`module_name` in the following examples can be either strings or arrays of strings.
|
||||
|
||||
```js
|
||||
sequencer.addSteps(image_name,module_name,optional_options);
|
||||
```
|
||||
|
||||
If no Image Name is specified, the module is added to **all** images.
|
||||
|
||||
```js
|
||||
sequencer.addSteps(module_name,optional_options);
|
||||
```
|
||||
|
||||
All this can be passed in as JSON:
|
||||
|
||||
```js
|
||||
sequencer.addSteps({
|
||||
image1_name: {name: module_name, o: optional_options},
|
||||
image2_name: {name: module_name, o: optional_options},
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
|
||||
### Running a Sequencer with multiple images
|
||||
|
||||
The same `run` method can be used with a slight change in syntax.
|
||||
The `run` method accepts parameters `image` and `from`. `from` is the index from
|
||||
where the function starts generating output. By default, it will run across all
|
||||
the steps. (from = 1) If no image is specified, the sequencer will be run over **all
|
||||
the images**. `image_name` may be an array of image names.
|
||||
|
||||
```js
|
||||
sequencer.run(); //All images from first step
|
||||
```
|
||||
|
||||
```js
|
||||
sequencer.run(image_name,from); //Image 'image' from 'from'
|
||||
```
|
||||
|
||||
The `run` method also accepts an optional callback just like before:
|
||||
|
||||
```js
|
||||
sequencer.run(image_name,from,function(out){
|
||||
// This gets called back.
|
||||
// "out" is the DataURL of final image.
|
||||
});
|
||||
```
|
||||
|
||||
JSON input is also acceptable.
|
||||
|
||||
```js
|
||||
sequencer.run({
|
||||
image1_name: from,
|
||||
image2_name: from,
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
|
||||
### Removing Steps from an Image
|
||||
|
||||
Similarly, `removeSteps` can also accept an `image_name` parameter. Either, both,
|
||||
or none of `image_name` and `steps` them may be an array. JSON input is also acceptable.
|
||||
|
||||
```js
|
||||
sequencer.removeSteps("image_name",[steps]);
|
||||
```
|
||||
|
||||
```js
|
||||
sequencer.removeSteps("image_name",step);
|
||||
```
|
||||
|
||||
```js
|
||||
sequencer.removeSteps({
|
||||
image1_name: [steps],
|
||||
image2_name: [steps],
|
||||
...
|
||||
});
|
||||
```
|
||||
return value: **`sequencer`** (To allow method chaining)
|
||||
|
||||
|
||||
### Inserting steps on an image
|
||||
|
||||
The `insertSteps` method can also accept an `image_name` parameter. `image_name`
|
||||
may be an array. Everything else remains the same. JSON Input is acceptable too.
|
||||
|
||||
```js
|
||||
sequencer.insertSteps("image",index,"module_name",o);
|
||||
```
|
||||
```js
|
||||
sequencer.insertSteps([image],index,"module_name",o);
|
||||
```
|
||||
```js
|
||||
sequencer.insertSteps({
|
||||
image1: [
|
||||
{index:index1, name: module_name1, o:optional_options1},
|
||||
{index:index2, name: module_name2, o:optional_options2},
|
||||
...
|
||||
]
|
||||
});
|
||||
```
|
||||
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 of 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"
|
||||
@@ -432,7 +516,7 @@ Image sequencer supports stringifying a sequence which is appended to the url an
|
||||
channel{channel:green},invert{}
|
||||
```
|
||||
|
||||
The use of `()` in place of `{}` for backward compatibility with older links is now **deprecated**. (There is no longer support for the following syntax, and should be avoided)
|
||||
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()
|
||||
```
|
||||
@@ -451,29 +535,6 @@ Image Sequencer can also generate a string for usage in the CLI for the current
|
||||
sequencer.toCliString()
|
||||
```
|
||||
|
||||
|
||||
## Importing steps using JSON array
|
||||
|
||||
Image sequencer provides the following core API function to import the given sequence of JSON steps into sequencer.
|
||||
|
||||
```js
|
||||
sequencer.importJSON(obj)
|
||||
```
|
||||
It can be implemented the following way for example:
|
||||
|
||||
```js
|
||||
sequencer.importJSON([
|
||||
{ name: 'blur', options: {} }
|
||||
]);
|
||||
```
|
||||
where name is the name of step to be added, options object can be the one used to provide various params to the sequencer which can customise the default ones.
|
||||
|
||||
To see this in action, please refer to line # 51 of the following:
|
||||
|
||||
[test/core/modules/import-export.js](https://github.com/publiclab/image-sequencer/blob/main/test/core/modules/import-export.js)
|
||||
|
||||
|
||||
|
||||
## Creating a User Interface
|
||||
|
||||
Image Sequencer provides the following events which can be used to generate a UI:
|
||||
@@ -490,7 +551,7 @@ and remove the loading GIF generated above.
|
||||
for instance, to remove the DIV generated above.
|
||||
* `notify` : This event is triggered whenever we need to shoot a notification to the
|
||||
user-interface.For example when the step is not available, we can shoot a notification,
|
||||
by sending appropriate message.For HTML UI it adds a DOM node to the browser, for CLI
|
||||
by sending appropriate message.For HTML UI it adds a DOM node to the browser, for CLI
|
||||
and node , it logs the notification output to the respective console.
|
||||
|
||||
How to define these functions:
|
||||
@@ -544,37 +605,12 @@ sequencer.setUI({
|
||||
});
|
||||
```
|
||||
|
||||
## Using multiple images on same sequencer:
|
||||
Note: `identity.imageName` is the "name" of that particular image. This name can
|
||||
be specified while loading the image via `sequencer.loadImage("name","SRC")`. If
|
||||
not specified, the name of a loaded image defaults to a name like "image1",
|
||||
"image2", et cetra.
|
||||
|
||||
Image Sequencer object supports one imageURL at a time.
|
||||
|
||||
Adding a seccond image to same sequencer will result to adding same set of steps added to prior image and flushing out the previous one.
|
||||
|
||||
```js
|
||||
s1 = new ImageSequencer(...);
|
||||
s1.loadImage(url1);
|
||||
s1.addSteps('blur');
|
||||
s1.run();
|
||||
s1.addImage(url2);
|
||||
s1.run();
|
||||
```
|
||||
However if we want to use more than one image, we can either initialize a sequencer for each image like:
|
||||
|
||||
```js
|
||||
sequencer1 = new ImageSequencer(...);
|
||||
sequencer1.loadImage(...);
|
||||
sequencer1.addSteps(steps);
|
||||
sequencer1.run();
|
||||
|
||||
sequencer2 = new ImageSequencer(...);
|
||||
sequencer2.loadImage(...);
|
||||
sequencer2.addSteps(steps);
|
||||
sequencer2.run();
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Note**: Details of all modules can be sought using `sequencer.modulesInfo()`.
|
||||
Details of all modules can be sought using `sequencer.modulesInfo()`.
|
||||
This method returns an object which defines the name and inputs of the modules. If a module name (hyphenated) is passed in the method, then only the details of that module are returned.
|
||||
|
||||
The `notify` function takes two parameters `msg` and `id`, former being the message to be displayed on console (in case of CLI and node ) and a HTML component(in browser). The id is optional and is useful for HTML interface to give appropriate IDs.
|
||||
The `notify` function takes two parameters `msg` and `id`, former being the message to be displayed on console (in case of CLI and node ) and a HTML component(in browser). The id is optional and is useful for HTML interface to give appropriate IDs.
|
||||
895
dist/image-sequencer-ui.js
vendored
Normal file
895
dist/image-sequencer-ui.js
vendored
Normal file
@@ -0,0 +1,895 @@
|
||||
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||
setupCache = require('./lib/cache.js'),
|
||||
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||
urlHash = require('./lib/urlHash.js'),
|
||||
insertPreview = require('./lib/insertPreview.js');
|
||||
|
||||
window.onload = function() {
|
||||
sequencer = ImageSequencer();
|
||||
|
||||
function refreshOptions() {
|
||||
// Load information of all modules (Name, Inputs, Outputs)
|
||||
var modulesInfo = sequencer.modulesInfo();
|
||||
|
||||
var addStepSelect = $("#addStep select");
|
||||
addStepSelect.html("");
|
||||
|
||||
// Add modules to the addStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
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();
|
||||
|
||||
$(window).on('scroll', scrollFunction);
|
||||
|
||||
function scrollFunction() {
|
||||
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
||||
|
||||
$('#move-up').css({
|
||||
display: shouldDisplay ? 'block' : 'none'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function topFunction() {
|
||||
$('body').animate({scrollTop: 0});
|
||||
$(':root').animate({scrollTop: 0});
|
||||
}
|
||||
|
||||
$('#move-up').on("click",topFunction);
|
||||
|
||||
|
||||
// UI for each step:
|
||||
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||
|
||||
// UI for the overall demo:
|
||||
var ui = defaultHtmlSequencerUi(sequencer);
|
||||
|
||||
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
||||
} else {
|
||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||
}
|
||||
|
||||
var resetSequence = function(){
|
||||
var r=confirm("Do you want to reset the sequence?");
|
||||
if (r)
|
||||
window.location = "/";
|
||||
}
|
||||
|
||||
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||
$("#resetButton").on("click",resetSequence);
|
||||
|
||||
//Module button radio selection
|
||||
$('.radio-group .radio').on("click", function() {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
//$("#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;
|
||||
});
|
||||
|
||||
function displayMessageOnSaveSequence(){
|
||||
$(".savesequencemsg").fadeIn();
|
||||
setTimeout(function() {
|
||||
$(".savesequencemsg").fadeOut();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||
$('#save-seq').click(() => {
|
||||
var result = window.prompt("Please give a name to your sequence... (Saved sequence will only be available in this browser).");
|
||||
if(result){
|
||||
result = result + " (local)";
|
||||
sequencer.saveSequence(result, sequencer.toString());
|
||||
sequencer.loadModules();
|
||||
displayMessageOnSaveSequence();
|
||||
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];
|
||||
var util=IntermediateHtmlStepUi(sequencer);
|
||||
step.output.src = reader.result;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
insertPreview.updatePreviews(reader.result,'addStep');
|
||||
insertPreview.updatePreviews(sequencer.images.image1.steps[0].options.step.imgElement.src,'insertStep');
|
||||
},
|
||||
onTakePhoto: function (url) {
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
step.output.src = url;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = url;
|
||||
}
|
||||
});
|
||||
|
||||
setupCache();
|
||||
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'addStep');
|
||||
} else {
|
||||
insertPreview.updatePreviews("images/tulips.png",'addStep');
|
||||
}
|
||||
};
|
||||
},{"./lib/cache.js":2,"./lib/defaultHtmlSequencerUi.js":3,"./lib/defaultHtmlStepUi.js":4,"./lib/insertPreview.js":5,"./lib/urlHash.js":7}],2:[function(require,module,exports){
|
||||
var setupCache = function() {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupCache;
|
||||
},{}],3:[function(require,module,exports){
|
||||
var urlHash = require('./urlHash.js');
|
||||
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
var addStepSel = options.addStepSel = options.addStepSel || "#addStep";
|
||||
var removeStepSel = options.removeStepSel = options.removeStepSel || "button.remove";
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onLoad() {
|
||||
importStepsFromUrlHash();
|
||||
if (!$('#selectStep').val())
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
// look up needed steps from Url Hash:
|
||||
function importStepsFromUrlHash() {
|
||||
var hash = urlHash.getUrlHashParameter("steps");
|
||||
|
||||
if (hash) {
|
||||
_sequencer.importString(hash);
|
||||
_sequencer.run({ index: 0 });
|
||||
}
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
}
|
||||
|
||||
function selectNewStepUi() {
|
||||
var m = $(addStepSel + " select").val();
|
||||
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
|
||||
function removeStepUi() {
|
||||
var index = $(removeStepSel).index(this) + 1;
|
||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||
// remove from URL hash too
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
//disable save-sequence button if all steps are removed
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
function addStepUi() {
|
||||
if ($(addStepSel + " select").val() == "none") return;
|
||||
|
||||
var newStepName = $(addStepSel + " select").val();
|
||||
|
||||
/*
|
||||
* after adding the step we run the sequencer from defined step
|
||||
* and since loadImage is not a part of the drawarray the step lies at current
|
||||
* length - 2 of the drawarray
|
||||
*/
|
||||
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
|
||||
.addSteps(newStepName, options)
|
||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
||||
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||
|
||||
//enable save-sequence button if disabled initially
|
||||
handleSaveSequence();
|
||||
|
||||
// add to URL hash too
|
||||
urlHash.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,
|
||||
selectNewStepUi: selectNewStepUi,
|
||||
removeStepUi: removeStepUi,
|
||||
addStepUi: addStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlSequencerUi;
|
||||
|
||||
|
||||
},{"./urlHash.js":7}],4:[function(require,module,exports){
|
||||
// Set the UI in sequencer. This Will generate HTML based on
|
||||
// Image Sequencer events :
|
||||
// onSetup : Called every time a step is added
|
||||
// onDraw : Called every time a step starts draw
|
||||
// onComplete : Called every time a step finishes drawing
|
||||
// onRemove : Called everytime a step is removed
|
||||
// The variable 'step' stores useful data like input and
|
||||
// output values, step information.
|
||||
// See documetation for more details.
|
||||
|
||||
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||
var urlHash = require('./urlHash.js');
|
||||
|
||||
function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onSetup(step, stepOptions) {
|
||||
if (step.options && step.options.description)
|
||||
step.description = step.options.description;
|
||||
|
||||
step.ui =
|
||||
'\
|
||||
<div class="container">\
|
||||
<div class="row step">\
|
||||
<form class="input-form">\
|
||||
<div class="col-md-4 details">\
|
||||
<h3>\
|
||||
<span class = "toggle">' +step.name + ' <i class="fa fa-caret-up toggleIcon" aria-hidden="true"></i></span>' +
|
||||
'<span class="load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></span>' +
|
||||
'</h3><div class="cal"><p><i>"'+
|
||||
(step.description || "") +
|
||||
'</i></p></div>\
|
||||
</div>\
|
||||
</form>\
|
||||
<div class="col-md-8 cal">\
|
||||
<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 step-thumbnail"/></a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var tools =
|
||||
'<div class="cal"><div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
<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>\
|
||||
</div>';
|
||||
|
||||
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||
|
||||
var parser = new DOMParser();
|
||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||
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)) {
|
||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||
var merged = Object.assign(inputs, outputs); // combine outputs w inputs
|
||||
|
||||
for (var paramName in merged) {
|
||||
var isInput = inputs.hasOwnProperty(paramName);
|
||||
var html = "";
|
||||
var inputDesc = isInput ? inputs[paramName] : {};
|
||||
if (!isInput) {
|
||||
html += '<span class="output"></span>';
|
||||
} else if (inputDesc.type.toLowerCase() == "select") {
|
||||
html += '<select class="form-control target" name="' + paramName + '">';
|
||||
for (var option in inputDesc.values) {
|
||||
html += "<option>" + inputDesc.values[option] + "</option>";
|
||||
}
|
||||
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");
|
||||
div.className = "row";
|
||||
div.setAttribute("name", paramName);
|
||||
var description = inputs[paramName].desc || paramName;
|
||||
div.innerHTML =
|
||||
"<div class='det cal'>\
|
||||
<label for='" +
|
||||
paramName +
|
||||
"'>" +
|
||||
description +
|
||||
"</label>\
|
||||
" +
|
||||
html +
|
||||
"\
|
||||
</div>";
|
||||
step.ui.querySelector("div.details").appendChild(div);
|
||||
}
|
||||
|
||||
$(step.ui.querySelector("div.details")).append(
|
||||
'<div class="cal"><p><button type="submit" class="btn btn-default btn-save" disabled = "true" >Apply</button><span> Press apply to see changes</span></p></div>'
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (step.name != "load-image") {
|
||||
step.ui
|
||||
.querySelector("div.details")
|
||||
.appendChild(
|
||||
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||
);
|
||||
$(step.ui.querySelectorAll(".remove")).on('click', function() {notify('Step Removed','remove-notification')});
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
|
||||
// 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);
|
||||
}
|
||||
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||
$(step.ui.querySelector('.toggleIcon')).toggleClass('fa-caret-up').toggleClass('fa-caret-down');
|
||||
$(step.ui.querySelectorAll(".cal")).toggleClass("collapse");
|
||||
});
|
||||
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
if (optionsChanged){
|
||||
$(step.ui.querySelector("div.details"))
|
||||
.find("input,select")
|
||||
.each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false);
|
||||
step.options[$(input).attr("name")] = $(input).val();
|
||||
});
|
||||
_sequencer.run({ index: step.index - 1 });
|
||||
|
||||
// modify the url hash
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
// disable the save button
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||
optionsChanged = false;
|
||||
changedInputs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
||||
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
||||
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
||||
optionsChanged = changedInputs > 0;
|
||||
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', !optionsChanged);
|
||||
return inputChanged;
|
||||
}
|
||||
|
||||
var
|
||||
changedInputs = 0,
|
||||
optionsChanged = false;
|
||||
$(step.ui.querySelector('.input-form')).on('submit', saveOptions);
|
||||
$(step.ui.querySelectorAll('.target')).each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false)
|
||||
.on('input', function() {
|
||||
$(this)
|
||||
.focus()
|
||||
.data('hasChangedBefore',
|
||||
handleInputValueChange(
|
||||
$(this).val(),
|
||||
$(this).data('initValue'),
|
||||
$(this).data('hasChangedBefore')
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
$('input[type="range"]').on('input', function() {
|
||||
$(this).next().html($(this).val());
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function onDraw(step) {
|
||||
$(step.ui.querySelector(".load")).show();
|
||||
$(step.ui.querySelector("img")).hide();
|
||||
if( $(step.ui.querySelector(".toggleIcon")).hasClass("fa-caret-down") )
|
||||
{
|
||||
$(step.ui.querySelector(".load-spin")).show();
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete(step) {
|
||||
$(step.ui.querySelector(".load")).hide();
|
||||
$(step.ui.querySelector("img")).show();
|
||||
$(step.ui.querySelector(".load-spin")).hide();
|
||||
|
||||
step.imgElement.src = 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];
|
||||
}
|
||||
|
||||
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) {
|
||||
if (inputs[i].type.toLowerCase() === "input")
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
if (inputs[i].type.toLowerCase() === "select")
|
||||
$(step.ui.querySelector('div[name="' + i + '"] select'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
}
|
||||
}
|
||||
for (var i in outputs) {
|
||||
if (step[i] !== undefined)
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onRemove(step) {
|
||||
step.ui.remove();
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
$('div[class^=imgareaselect-]').remove();
|
||||
}
|
||||
|
||||
function getPreview() {
|
||||
return step.imgElement;
|
||||
}
|
||||
|
||||
function notify(msg,id){
|
||||
if ($('#'+id).length == 0) {
|
||||
var notification = document.createElement('span');
|
||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
||||
notification.id = id;
|
||||
notification.classList.add("notification");
|
||||
|
||||
$('body').append(notification);
|
||||
}
|
||||
|
||||
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
|
||||
return {
|
||||
getPreview: getPreview,
|
||||
onSetup: onSetup,
|
||||
onComplete: onComplete,
|
||||
onRemove: onRemove,
|
||||
onDraw: onDraw,
|
||||
notify: notify
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof window === "undefined"){
|
||||
module.exports={
|
||||
DefaultHtmlStepUi: DefaultHtmlStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlStepUi;
|
||||
|
||||
|
||||
},{"./intermediateHtmlStepUi.js":6,"./urlHash.js":7}],5:[function(require,module,exports){
|
||||
function generatePreview(previewStepName, customValues, path, selector) {
|
||||
|
||||
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 = $('#'+selector+' .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") {
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
else {
|
||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
||||
}
|
||||
}
|
||||
previewSequencer.loadImage(path, loadPreview);
|
||||
}
|
||||
|
||||
function updatePreviews(src, selector) {
|
||||
$('#'+selector+' 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, selector);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePreview : generatePreview,
|
||||
updatePreviews : updatePreviews
|
||||
}
|
||||
},{}],6:[function(require,module,exports){
|
||||
var urlHash = require('./urlHash.js');
|
||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
function stepUI() {
|
||||
return '<div class="row insertDiv">\
|
||||
<div class="col-md-6 col-md-offset-2" 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>\
|
||||
<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>\
|
||||
</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
|
||||
);
|
||||
updatePreviews(step.output,'insertStep');
|
||||
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
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
insertStep
|
||||
}
|
||||
}
|
||||
module.exports = IntermediateHtmlStepUi;
|
||||
|
||||
|
||||
},{"./urlHash.js":7}],7:[function(require,module,exports){
|
||||
function getUrlHashParameter(param) {
|
||||
|
||||
var params = getUrlHashParameters();
|
||||
return params[param];
|
||||
|
||||
}
|
||||
|
||||
function getUrlHashParameters() {
|
||||
|
||||
var sPageURL = window.location.hash;
|
||||
if (sPageURL) sPageURL = sPageURL.split('#')[1];
|
||||
var pairs = sPageURL.split('&');
|
||||
var object = {};
|
||||
pairs.forEach(function(pair, i) {
|
||||
pair = pair.split('=');
|
||||
if (pair[0] != '') object[pair[0]] = pair[1];
|
||||
});
|
||||
return object;
|
||||
}
|
||||
|
||||
// accepts an object like { paramName: value, paramName1: value }
|
||||
// and transforms to: url.com#paramName=value¶mName1=value
|
||||
function setUrlHashParameters(params) {
|
||||
|
||||
var keys = Object.keys(params);
|
||||
var values = Object.values(params);
|
||||
var pairs = [];
|
||||
keys.forEach(function(key, i) {
|
||||
if (key != '') pairs.push(keys[i] + '=' + values[i]);
|
||||
});
|
||||
var hash = pairs.join('&');
|
||||
window.location.hash = hash;
|
||||
|
||||
}
|
||||
|
||||
function setUrlHashParameter(param, value) {
|
||||
|
||||
var params = getUrlHashParameters();
|
||||
params[param] = value;
|
||||
setUrlHashParameters(params);
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUrlHashParameter: getUrlHashParameter,
|
||||
setUrlHashParameter: setUrlHashParameter,
|
||||
getUrlHashParameters: getUrlHashParameters,
|
||||
setUrlHashParameters: setUrlHashParameters
|
||||
}
|
||||
|
||||
},{}]},{},[1]);
|
||||
1
dist/image-sequencer-ui.min.js
vendored
Normal file
1
dist/image-sequencer-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
69480
dist/image-sequencer.js
vendored
Normal file
69480
dist/image-sequencer.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/image-sequencer.min.js
vendored
Normal file
1
dist/image-sequencer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
220
docs/MODULES.md
220
docs/MODULES.md
@@ -6,39 +6,30 @@ List of Module Documentations
|
||||
1. [Crop](#crop-module)
|
||||
2. [Segmented-Colormap](#segmented-colormap-module)
|
||||
3. [FisheyeGl](#fisheyeGl-module)
|
||||
4. [Add QR](#Add-QR-module)
|
||||
5. [Average](#average-module)
|
||||
6. [Blend](#blend-module)
|
||||
7. [Blur](#blur-module)
|
||||
8. [Brightness](#brightness-module)
|
||||
9. [Channel](#channel-module)
|
||||
10. [Colorbar](#colorbar-module)
|
||||
11. [Colormap](#colormap-module)
|
||||
12. [Contrast](#contrast-module)
|
||||
13. [Convolution](#convolution-module)
|
||||
14. [DecodeQr](#decodeQr-module)
|
||||
15. [Dither](#dither-module)
|
||||
16. [DrawRectangle](#draw-rectangle-module)
|
||||
17. [Dynamic](#dynamic-module)
|
||||
18. [Edge-Detect](#edge-detect-module)
|
||||
19. [FlipImage](#flipimage-module)
|
||||
20. [Gamma-Correction](#gamma-correction-module)
|
||||
21. [Gradient](#gradient-module)
|
||||
22. [Histogram](#histogram-module)
|
||||
23. [Import-image](#import-image-module)
|
||||
24. [Invert](#invert-module)
|
||||
25. [Ndvi](#ndvi-module)
|
||||
26. [Ndvi-Colormap](#ndvi-colormap-module)
|
||||
27. [Overlay](#overlay-module)
|
||||
28. [PaintBucket](#paint-bucket-module)
|
||||
29. [Resize](#resize-module)
|
||||
30. [ReplaceColor](#replacecolor-module)
|
||||
31. [Rotate](#rotate-module)
|
||||
32. [Saturation](#saturation-module)
|
||||
33. [Threshold](#threshold)
|
||||
34. [Tint](#tint)
|
||||
35. [ColorTemperature](#color-temperature)
|
||||
36. [Grid-Overlay](#grid-overlay)
|
||||
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
|
||||
@@ -109,23 +100,6 @@ where `options` is an object with the following properties:
|
||||
* x : Field of View x (0 to 2; default 1)
|
||||
* y : Field of View y (0 to 2; default 1)
|
||||
|
||||
## add-qr-module
|
||||
|
||||
This module Adds QR corresponding to the given string.
|
||||
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('add-qr',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* size : size of QR code in pixels (default 200)
|
||||
* qrCodeString : input string to generate QR code
|
||||
|
||||
|
||||
## average-module
|
||||
|
||||
This module is used for averaging all the pixels of the image.
|
||||
@@ -273,42 +247,6 @@ This module is used for decoding a QR in image (if present).
|
||||
.addSteps('decode-qr',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
## dither-module
|
||||
|
||||
This module approximates a color from a mixture of other colors when the required color is not available, creating illusions of the color that is not present actually.
|
||||
|
||||
[more info on wikipedia](https://en.wikipedia.org/wiki/Dither)
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('dither',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following property:
|
||||
* dither : Can select the name of the Dithering Algorithm(default none)
|
||||
|
||||
## draw-rectangle-module
|
||||
|
||||
This module helps to draw a rectangle on the image with a starting and ending corner with the specified thickness and color of the border.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('draw-rectangle',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following properties:
|
||||
* startingX : starting x position of the rectangle (default 0)
|
||||
* startingY : starting y position of the rectangle (default 0)
|
||||
* endX : last x position of the rectangle (default "width")
|
||||
* endY : last y position of the rectangle (default "height")
|
||||
* thickness : thickness of the border (default 1)
|
||||
* color : RGBA values separated by a space (default "0 0 0 255")
|
||||
|
||||
## dynamic-module
|
||||
|
||||
This module is used for producing each color channel based on the original image's color.
|
||||
@@ -343,22 +281,6 @@ where `options` is an object with the following properties:
|
||||
* highThresholdRatio : Upper Threshold Ratio ( default : 0.2)
|
||||
* lowThresholdratio : Lower Threshold Ratio ( default : 0.2)
|
||||
|
||||
## flipimage-module
|
||||
|
||||
This module is used for flipping the image on the selected axis.
|
||||
#### Usage
|
||||
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('flip-image',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following properties:
|
||||
* Axis : select the required axis (default : vertical)
|
||||
|
||||
|
||||
## gamma-correction-module
|
||||
|
||||
This module is used for applying gamma correction.
|
||||
@@ -464,24 +386,6 @@ where `options` is an object with the following properties:
|
||||
* 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)
|
||||
|
||||
## paint-bucket-module
|
||||
|
||||
This module fills any polygonal shape with the specified color in pixels.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('paint-bucket',options)
|
||||
.run()
|
||||
```
|
||||
|
||||
where `options` is an object with the following property:
|
||||
* startingX : it is the value of the starting x-cordinate (default 10)
|
||||
* startingY : it is the value of the starting y-cordinate (default 10)
|
||||
* fillColor : they are four spaced seperated numbers representing the RGBA values of fill-color (default "100 100 100 255")
|
||||
* tolerance : it is the % tolerance (default 10)
|
||||
|
||||
## resize-module
|
||||
|
||||
This module is used for resizing an image.
|
||||
@@ -496,22 +400,6 @@ This module is used for resizing an image.
|
||||
where `options` is an object with the following property:
|
||||
* resize : Percentage value of resize (default 125%)
|
||||
|
||||
## replacecolor-module
|
||||
|
||||
This module is used in replacing the color with grey or any desired color.
|
||||
#### Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('replace-color',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following properties:
|
||||
* replaceMethod : replaces with the desired color (default greyscale)
|
||||
* replaceColor : three space separated numbers representing the RGB values of color to be filled (default "0 0 255")
|
||||
* color : three space separated numbers representing the RGB values of color to be replaced (default "228 86 81")
|
||||
* tolerance : it is the % tolerance (default 50)
|
||||
|
||||
## rotate-module
|
||||
|
||||
This module is used for rotating an image.
|
||||
@@ -540,64 +428,4 @@ This module is used for changing the saturation of the image.
|
||||
where `options` is an object with the following property:
|
||||
* saturation : saturation for the new image (between 0 and 2; default 0)
|
||||
|
||||
## Threshold
|
||||
|
||||
Thresholding is used to create binary images.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('threshold',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following property:
|
||||
* threshold : it allows to select the types of thresholding (default "manual thresholding")
|
||||
* input : it allows to select the range of thresholding value (default 120)
|
||||
|
||||
|
||||
## Tint
|
||||
|
||||
It adds color tint to an image
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('tint',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following property:
|
||||
* color : RGB values seperated by a space (default "0 0 255")
|
||||
* factor : amount of tint (default 0.5)
|
||||
|
||||
|
||||
## Color Temperature
|
||||
|
||||
This changes the color temperature of the image.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('color-temperature',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following property:
|
||||
* temperature : temperature between 0 - 40,000 kelvin (default 6000)
|
||||
|
||||
## Grid Overlay
|
||||
|
||||
This adds the grid over an image.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
sequencer.loadImage('PATH')
|
||||
.addSteps('grid-overlay',options)
|
||||
.run()
|
||||
```
|
||||
where `options` is an object with the following property:
|
||||
* options.x : The value at which the grid line should start in x-axis.
|
||||
* options.y : The value at which the grid line should start in y-axis.
|
||||
* color : Color for the grid on the image.
|
||||
@@ -1,14 +1,14 @@
|
||||
/* https://github.com/theleagueof/league-spartan */
|
||||
@font-face {
|
||||
font-family: 'League Spartan';
|
||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
|
||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff2') format('woff2'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff') format('woff'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.ttf') format('truetype'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.svg#league_spartanbold') format('svg');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-family: 'League Spartan';
|
||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
|
||||
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot?#iefix') format('embedded-opentype'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff2') format('woff2'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff') format('woff'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.ttf') format('truetype'),
|
||||
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.svg#league_spartanbold') format('svg');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -18,19 +18,11 @@ body {
|
||||
background: #f8f8fa;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'League Spartan';
|
||||
color: #445;
|
||||
}
|
||||
|
||||
body > .container,
|
||||
body > .container-fluid {
|
||||
}
|
||||
|
||||
.center-align {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -79,6 +71,17 @@ body > .container-fluid {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.details {
|
||||
border-top: 3px solid #444;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.details h3 {
|
||||
font-family: monospace;
|
||||
margin-top: 12px;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.det {
|
||||
padding: 10px 16px;
|
||||
text-decoration: italic;
|
||||
@@ -97,6 +100,11 @@ body > .container-fluid {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.load-spin{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#addStep {
|
||||
max-width: 500px;
|
||||
margin: 20px auto;
|
||||
@@ -151,19 +159,19 @@ body > .container-fluid {
|
||||
}
|
||||
|
||||
#move-up {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 40px;
|
||||
z-index: 550;
|
||||
display: none;
|
||||
background:transparent;
|
||||
border:none;
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 40px;
|
||||
z-index: 550;
|
||||
display: none;
|
||||
background:transparent;
|
||||
border:none;
|
||||
}
|
||||
|
||||
#move-up i {
|
||||
font-size:60px;
|
||||
opacity:0.7;
|
||||
color:#BABABA;
|
||||
font-size:60px;
|
||||
opacity:0.7;
|
||||
color:#BABABA;
|
||||
}
|
||||
|
||||
.btn-circle{
|
||||
@@ -200,7 +208,7 @@ body > .container-fluid {
|
||||
.savesequencemsg{
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
background-color: #808b96;
|
||||
@@ -242,33 +250,3 @@ a.name-header{
|
||||
text-decoration: none;
|
||||
color: #445;
|
||||
}
|
||||
|
||||
.step-column{
|
||||
display:flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.trash-container button.btn-xs {
|
||||
margin-top: -5px !important;
|
||||
}
|
||||
|
||||
.toggleIcon {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.rotated {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#gif{
|
||||
margin-left:0px;
|
||||
margin-top:5px;
|
||||
width:100%;
|
||||
}
|
||||
.save-button{
|
||||
margin-top:20px;
|
||||
margin-bottom:0px;
|
||||
align:center;
|
||||
width:100%;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||
setupCache = require('./lib/cache.js'),
|
||||
intermediateHtmlStepUi = require('./lib/intermediateHtmlStepUi.js'),
|
||||
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||
urlHash = require('./lib/urlHash.js'),
|
||||
insertPreview = require('./lib/insertPreview.js');
|
||||
@@ -23,10 +22,7 @@ window.onload = function() {
|
||||
);
|
||||
}
|
||||
// Null option
|
||||
addStepSelect.append('<option value="" disabled selected>Select a Module</option>');
|
||||
addStepSelect.selectize({
|
||||
sortField: 'text'
|
||||
});
|
||||
addStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
}
|
||||
refreshOptions();
|
||||
|
||||
@@ -79,8 +75,8 @@ window.onload = function() {
|
||||
newStep = $(this).attr('data-value');
|
||||
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||
$("#addStep select").val(newStep);
|
||||
ui.selectNewStepUi(newStep);
|
||||
ui.addStepUi(newStep);
|
||||
ui.selectNewStepUi();
|
||||
ui.addStepUi();
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
|
||||
@@ -118,7 +114,7 @@ window.onload = function() {
|
||||
|
||||
var button = event.target;
|
||||
button.disabled = true;
|
||||
button.innerHTML='<i class="fa fa-circle-o-notch fa-spin"></i>'
|
||||
|
||||
|
||||
try {
|
||||
// Select all images from previous steps
|
||||
@@ -170,7 +166,6 @@ window.onload = function() {
|
||||
modal.modal();
|
||||
|
||||
button.disabled = false;
|
||||
button.innerHTML = 'View GIF';
|
||||
isWorkingOnGifGeneration = false;
|
||||
}
|
||||
});
|
||||
@@ -178,7 +173,6 @@ window.onload = function() {
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
button.disabled = false;
|
||||
button.innerHTML = 'View GIF';
|
||||
isWorkingOnGifGeneration = false;
|
||||
|
||||
}
|
||||
@@ -191,35 +185,27 @@ window.onload = function() {
|
||||
takePhotoSelector: "#take-photo",
|
||||
onLoad: function onFileReaderLoad(progress) {
|
||||
var reader = progress.target;
|
||||
var step = sequencer.steps[0];
|
||||
var util= intermediateHtmlStepUi(sequencer);
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
var util=IntermediateHtmlStepUi(sequencer);
|
||||
step.output.src = reader.result;
|
||||
sequencer.run({ index: 0 });
|
||||
if(typeof step.options !=="undefined")
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
else
|
||||
step.imgElement.src = reader.result;
|
||||
insertPreview.updatePreviews(reader.result,'#addStep');
|
||||
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'.insertDiv');
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
insertPreview.updatePreviews(reader.result,'addStep');
|
||||
insertPreview.updatePreviews(sequencer.images.image1.steps[0].options.step.imgElement.src,'insertStep');
|
||||
},
|
||||
onTakePhoto: function (url) {
|
||||
var step = sequencer.steps[0];
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
step.output.src = url;
|
||||
sequencer.run({ index: 0 });
|
||||
if(typeof step.options !=="undefined")
|
||||
step.options.step.imgElement.src = url;
|
||||
else
|
||||
step.imgElement.src = url;
|
||||
insertPreview.updatePreviews(url,'#addStep');
|
||||
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'.insertDiv');
|
||||
step.options.step.imgElement.src = url;
|
||||
}
|
||||
});
|
||||
|
||||
setupCache();
|
||||
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'#addStep');
|
||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'addStep');
|
||||
} else {
|
||||
insertPreview.updatePreviews("images/tulips.png",'#addStep');
|
||||
insertPreview.updatePreviews("images/tulips.png",'addStep');
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<html>
|
||||
|
||||
|
||||
<head>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -10,16 +11,6 @@
|
||||
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<!--Adding meta Tag for search engine optimisation-->
|
||||
<meta property="og:description"
|
||||
content="A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it creates a new image at each step in a sequence.">
|
||||
<meta property="og:site_name" content="sequencer.publiclab.org">
|
||||
<meta property="og:url" content="https://sequencer.publiclab.org">
|
||||
<meta property="og:title" content="Image Sequencer">
|
||||
<meta name="Description"
|
||||
content="Image Sequencer is an image editing tool that creates a new downloadble image at each step.It works in browser and supports both node and CLI.">
|
||||
<meta name="Keywords" content="image editing downloadable browser node CLI">
|
||||
|
||||
<title>Image Sequencer</title>
|
||||
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
@@ -32,23 +23,20 @@
|
||||
<script src="../node_modules/gifshot/dist/gifshot.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Download.js for large files -->
|
||||
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript" />
|
||||
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript"/>
|
||||
|
||||
<script src="lib/scrollToTop.js"></script>
|
||||
<script src="../node_modules/selectize/dist/js/standalone/selectize.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="../node_modules/selectize/dist/css/selectize.default.css" rel="stylesheet">
|
||||
<!-- for crop module: -->
|
||||
|
||||
<!-- for crop module: -->
|
||||
<link href="../node_modules/imgareaselect/distfiles/css/imgareaselect-default.css" rel="stylesheet">
|
||||
<link href="./selectize.default.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="demo.css">
|
||||
|
||||
<div class="container-fluid">
|
||||
@@ -56,8 +44,7 @@
|
||||
<header class="text-center">
|
||||
<h1><a href="/" target='_blank' class="name-header">Image Sequencer</a></h1>
|
||||
<p>
|
||||
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original
|
||||
image, it
|
||||
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it
|
||||
creates a new image at each step in a sequence.
|
||||
<a href="https://publiclab.org/image-sequencer">Learn more</a>
|
||||
</p>
|
||||
@@ -66,7 +53,7 @@
|
||||
<a href="https://github.com/publiclab/image-sequencer">
|
||||
<i class="fa fa-github"></i>
|
||||
</a>
|
||||
by <a href="https://publiclab.org" title="Publiclab Website"><i class="fa fa-globe"></i> Publiclab</a>
|
||||
by <a href= "https://publiclab.org" title = "Publiclab Website"><i class = "fa fa-globe"></i> Publiclab</a>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
@@ -76,8 +63,8 @@
|
||||
</p>
|
||||
<center>
|
||||
<input type="file" id="fileInput" value="" accept="image/*"><br />
|
||||
<button type="button" id="take-photo" class="btn btn-primary btn-block btn-lg ">Take a Photo</button>
|
||||
<video id="video" width="100%" height="100%" style="display:none"></video>
|
||||
<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>
|
||||
@@ -89,79 +76,70 @@
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
<p class="alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules.
|
||||
</p>
|
||||
<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="display:flex; justify-content:center;">
|
||||
<p class = "alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<section id="addStep" 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>
|
||||
<div class="radio" data-value="brightness">
|
||||
<i class="fa fa-sun-o fa-4x i-over"></i>
|
||||
</div>
|
||||
<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="resize">
|
||||
<i class="fa fa-arrows-alt fa-4x i-over"></i>
|
||||
</div>
|
||||
<p>Resize</p>
|
||||
</div>
|
||||
<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>
|
||||
<p>Brightness</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="radio" data-value="contrast">
|
||||
<i class="fa fa-adjust fa-4x i-over"></i>
|
||||
</div>
|
||||
<div class="row center-align">
|
||||
<div class="col-md-8">
|
||||
|
||||
<select 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>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button></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>
|
||||
<div class="row center-align">
|
||||
<button id="resetButton" class="btn btn-default btn-lg"
|
||||
style=" margin: 20px 35px 0px 35px; width:100%;">Clear All Steps</button>
|
||||
<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>
|
||||
</section>
|
||||
<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>
|
||||
|
||||
<section id="sequence-actions" class="panel">
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="row center-align">
|
||||
<button class="btn btn-primary btn-block btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
||||
<button class="btn btn-primary btn-block 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>
|
||||
<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">
|
||||
@@ -179,57 +157,34 @@
|
||||
</div>
|
||||
|
||||
</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;">
|
||||
<h2 style="margin-top:20px">Save</h2>
|
||||
<select class="form-control input-md" id="selectSaveOption" style="margin-top:20px">
|
||||
<option>Save as PNG</option>
|
||||
<option>Save as GIF (all steps)</option>
|
||||
<option>Save sequence</option>
|
||||
<option>Save sequence string</option>
|
||||
</select>
|
||||
<p><button id="saveButton" class="btn btn-primary btn-lg save-button">Save</button></p>
|
||||
<p><button class="btn btn-default btn-lg js-view-as-gif" id="gif">Preview GIF</button></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<hr style="margin:20px;">
|
||||
<center><button class="btn btn-default btn-sm" id="clear-cache">Clear offline cache</button></center>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h2>Need Help?</h2>
|
||||
<p>
|
||||
<a class="btn btn-default" href="https://github.com/publiclab/image-sequencer/issues">Ask a question</a>
|
||||
<a class="btn btn-default" href="https://publiclab.org/chat">Ask in our chatroom</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Improve this tool</h2>
|
||||
<p>
|
||||
This is an open source toolkit which you can help improve on Github
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn-default" href="https://github.com/publiclab/image-sequencer">View the code »</a>
|
||||
</p>
|
||||
<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>
|
||||
<button id="resetButton" class="btn btn-default btn-lg">Clear All Steps</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="move-up"><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||
<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;
|
||||
})
|
||||
</script>
|
||||
<button id="move-up"><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var sequencer;
|
||||
})
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
@@ -36,4 +36,4 @@ var setupCache = function() {
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupCache;
|
||||
module.exports = setupCache;
|
||||
@@ -8,8 +8,8 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
function onLoad() {
|
||||
importStepsFromUrlHash();
|
||||
if ($('#selectStep').val()==='none')
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||
if (!$('#selectStep').val())
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
function selectNewStepUi() {
|
||||
var m = $(addStepSel + " select").val();
|
||||
if(!m) m = arguments[0];
|
||||
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
@@ -42,12 +41,9 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
function addStepUi() {
|
||||
if ($(addStepSel + " select").val() == "none") return;
|
||||
var newStepName;
|
||||
if(typeof arguments[0] !== "string")
|
||||
newStepName = $(addStepSel + " select option").html().toLowerCase();
|
||||
else newStepName = arguments[0]
|
||||
|
||||
|
||||
var newStepName = $(addStepSel + " select").val();
|
||||
|
||||
/*
|
||||
* after adding the step we run the sequencer from defined step
|
||||
* and since loadImage is not a part of the drawarray the step lies at current
|
||||
@@ -61,19 +57,18 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
}
|
||||
_sequencer
|
||||
.addSteps(newStepName, options)
|
||||
.run({ index: _sequencer.steps.length - sequenceLength - 1 });
|
||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
||||
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||
$(addStepSel + " select").val("none");
|
||||
|
||||
//enable save-sequence button if disabled initially
|
||||
handleSaveSequence();
|
||||
|
||||
// add to URL hash too
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
}
|
||||
|
||||
function handleSaveSequence(){
|
||||
var stepCount=sequencer.steps.length;
|
||||
var stepCount=sequencer.images.image1.steps.length;
|
||||
if(stepCount<2)
|
||||
$(" #save-seq").prop("disabled", true);
|
||||
else
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||
var urlHash = require('./urlHash.js');
|
||||
var _ = require('lodash');
|
||||
var mapHtmlTypes = require('./mapHtmltypes');
|
||||
|
||||
function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
@@ -25,50 +23,44 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
step.ui =
|
||||
'\
|
||||
<div class="container-fluid step-container">\
|
||||
<div class="panel panel-default">\
|
||||
<div class="panel-heading">\
|
||||
<div class="trash-container pull-right"></div>\
|
||||
<h3 class="panel-title">' +
|
||||
'<span class="toggle">' +step.name + ' <span class="caret toggleIcon rotated"></span>\
|
||||
<span class="load-spin pull-right" style="display:none;padding:1px 8px;"><i class="fa fa-circle-o-notch fa-spin"></i></span>\
|
||||
</h3>\
|
||||
</div>\
|
||||
<form class="input-form">\
|
||||
<div class="panel-body cal collapse in">\
|
||||
<div class="row step">\
|
||||
<div class="col-md-4 details container-fluid">\
|
||||
<div class="cal collapse in"><p>' +
|
||||
'<i>' + (step.description || "") + '</i>' +
|
||||
'</p></div>\
|
||||
</div>\
|
||||
<div class="col-md-8 cal collapse in step-column">\
|
||||
<div class="load load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||
<div class="step-image">\
|
||||
<a class="cal collapse in"><img class="img-thumbnail step-thumbnail"/></a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="panel-footer cal collapse in"></div>\
|
||||
</form>\
|
||||
</div>\
|
||||
</div>';
|
||||
<div class="container">\
|
||||
<div class="row step">\
|
||||
<form class="input-form">\
|
||||
<div class="col-md-4 details">\
|
||||
<h3>\
|
||||
<span class = "toggle">' +step.name + ' <i class="fa fa-caret-up toggleIcon" aria-hidden="true"></i></span>' +
|
||||
'<span class="load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></span>' +
|
||||
'</h3><div class="cal"><p><i>"'+
|
||||
(step.description || "") +
|
||||
'</i></p></div>\
|
||||
</div>\
|
||||
</form>\
|
||||
<div class="col-md-8 cal">\
|
||||
<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 step-thumbnail"/></a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var tools =
|
||||
'<div class="trash">\
|
||||
<button confirm="Are you sure?" class="remove btn btn-default btn-xs">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
'<div class="cal"><div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
<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>\
|
||||
</div>';
|
||||
|
||||
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||
|
||||
var parser = new DOMParser();
|
||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||
step.ui = step.ui.querySelector("div.container-fluid");
|
||||
step.ui = step.ui.querySelector("div.container");
|
||||
step.linkElements = step.ui.querySelectorAll("a");
|
||||
step.imgElement = step.ui.querySelector("a img.img-thumbnail");
|
||||
step.imgElement = step.ui.querySelector("a img");
|
||||
|
||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||
@@ -78,7 +70,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
for (var paramName in merged) {
|
||||
var isInput = inputs.hasOwnProperty(paramName);
|
||||
var html = "";
|
||||
var inputDesc = isInput ? mapHtmlTypes(inputs[paramName]) : {};
|
||||
var inputDesc = isInput ? inputs[paramName] : {};
|
||||
if (!isInput) {
|
||||
html += '<span class="output"></span>';
|
||||
} else if (inputDesc.type.toLowerCase() == "select") {
|
||||
@@ -106,7 +98,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
'"max="' +
|
||||
inputDesc.max +
|
||||
'"step="' +
|
||||
(inputDesc.step ? inputDesc.step : 1)+ '">' + '<span>' + paramVal + '</span>';
|
||||
inputDesc.step + '">' + '<span>' + paramVal + '</span>';
|
||||
|
||||
}
|
||||
else html += '">';
|
||||
@@ -117,7 +109,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
div.setAttribute("name", paramName);
|
||||
var description = inputs[paramName].desc || paramName;
|
||||
div.innerHTML =
|
||||
"<div class='det cal collapse in'>\
|
||||
"<div class='det cal'>\
|
||||
<label for='" +
|
||||
paramName +
|
||||
"'>" +
|
||||
@@ -129,30 +121,29 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
</div>";
|
||||
step.ui.querySelector("div.details").appendChild(div);
|
||||
}
|
||||
$(step.ui.querySelector("div.panel-footer")).append(
|
||||
'<div class="cal collapse in"><button type="submit" class="btn btn-sm btn-default btn-save" disabled = "true" >Apply</button> <small style="padding-top:2px;">Press apply to see changes</small></div>'
|
||||
|
||||
$(step.ui.querySelector("div.details")).append(
|
||||
'<div class="cal"><p><button type="submit" class="btn btn-default btn-save" disabled = "true" >Apply</button><span> Press apply to see changes</span></p></div>'
|
||||
);
|
||||
$(step.ui.querySelector("div.panel-footer")).prepend(
|
||||
'<button class="pull-right btn btn-default btn-sm insert-step" >\
|
||||
<span class="insert-text"><i class="fa fa-plus"></i> Insert Step</span><span class="no-insert-text" style="display:none">Close</span>\
|
||||
</button>'
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (step.name != "load-image") {
|
||||
step.ui
|
||||
.querySelector("div.trash-container")
|
||||
.prepend(
|
||||
.querySelector("div.details")
|
||||
.appendChild(
|
||||
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||
);
|
||||
$(step.ui.querySelectorAll(".remove")).on('click', function() {notify('Step Removed','remove-notification')});
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
|
||||
// Insert the step's UI in the right place
|
||||
if (stepOptions.index == _sequencer.steps.length) {
|
||||
if (stepOptions.index == _sequencer.images.image1.steps.length) {
|
||||
stepsEl.appendChild(step.ui);
|
||||
$("#steps .step-container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
if($("#steps .step-container:nth-last-child(2)"))
|
||||
$("#steps .step-container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||
$("#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]);
|
||||
}
|
||||
@@ -161,11 +152,10 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
$("#load-image").append(step.ui);
|
||||
}
|
||||
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||
$(step.ui.querySelector('.toggleIcon')).toggleClass('rotated');
|
||||
$(step.ui.querySelectorAll(".cal")).collapse('toggle');
|
||||
$(step.ui.querySelector('.toggleIcon')).toggleClass('fa-caret-up').toggleClass('fa-caret-down');
|
||||
$(step.ui.querySelectorAll(".cal")).toggleClass("collapse");
|
||||
});
|
||||
|
||||
$(step.imgElement).on("mousemove", _.debounce(() => imageHover(step), 150));
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
@@ -181,7 +171,8 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
_sequencer.run({ index: step.index - 1 });
|
||||
|
||||
// modify the url hash
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
// disable the save button
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||
optionsChanged = false;
|
||||
@@ -206,7 +197,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false)
|
||||
.on('input change' , function() {
|
||||
.on('input', function() {
|
||||
$(this)
|
||||
.focus()
|
||||
.data('hasChangedBefore',
|
||||
@@ -230,19 +221,22 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
function onDraw(step) {
|
||||
$(step.ui.querySelector(".load")).show();
|
||||
$(step.ui.querySelector("img")).hide();
|
||||
$(step.ui.querySelectorAll(".load-spin")).show();
|
||||
if( $(step.ui.querySelector(".toggleIcon")).hasClass("fa-caret-down") )
|
||||
{
|
||||
$(step.ui.querySelector(".load-spin")).show();
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete(step) {
|
||||
$(step.ui.querySelector("img")).show();
|
||||
$(step.ui.querySelectorAll(".load-spin")).hide();
|
||||
$(step.ui.querySelector(".load")).hide();
|
||||
$(step.ui.querySelector("img")).show();
|
||||
$(step.ui.querySelector(".load-spin")).hide();
|
||||
|
||||
step.imgElement.src = (step.name == "load-image") ? step.output.src : step.output;
|
||||
step.imgElement.src = 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.imgElement.src;
|
||||
step.linkElements[index].href = step.output;
|
||||
}
|
||||
|
||||
// TODO: use a generalized version of this
|
||||
@@ -251,8 +245,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
}
|
||||
|
||||
for (let index = 0; index < step.linkElements.length; index++) {
|
||||
|
||||
step.linkElements[index].download = step.name + "." + fileExtension(step.imgElement.src);
|
||||
step.linkElements[index].download = step.name + "." + fileExtension(step.output);
|
||||
step.linkElements[index].target = "_blank";
|
||||
}
|
||||
|
||||
@@ -280,29 +273,10 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function imageHover(step){
|
||||
|
||||
var img = $(step.imgElement);
|
||||
|
||||
img.mousemove(function(e) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = img.width();
|
||||
canvas.height = img.height();
|
||||
var context = canvas.getContext('2d');
|
||||
context.drawImage(this,0,0);
|
||||
|
||||
var offset = $(this).offset();
|
||||
var xPos = e.pageX - offset.left;
|
||||
var yPos = e.pageY - offset.top;
|
||||
var myData = context.getImageData(xPos, yPos, 1, 1);
|
||||
img[0].title = "rgb: " +myData.data[0]+","+ myData.data[1]+","+myData.data[2];//+ rgbdata;
|
||||
});
|
||||
}
|
||||
|
||||
function onRemove(step) {
|
||||
step.ui.remove();
|
||||
$("#steps .step-container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
$('div[class*=imgareaselect-]').remove();
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
$('div[class^=imgareaselect-]').remove();
|
||||
}
|
||||
|
||||
function getPreview() {
|
||||
@@ -321,16 +295,14 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
getPreview: getPreview,
|
||||
onSetup: onSetup,
|
||||
onComplete: onComplete,
|
||||
onRemove: onRemove,
|
||||
onDraw: onDraw,
|
||||
notify: notify,
|
||||
imageHover: imageHover
|
||||
notify: notify
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ function generatePreview(previewStepName, customValues, path, selector) {
|
||||
img.src = src;
|
||||
$(img).css("max-width", "200%");
|
||||
$(img).css("transform", "translateX(-20%)");
|
||||
$(selector + ' .radio-group').find('div').each(function() {
|
||||
var stepDiv = $('#'+selector+' .row').find('div').each(function() {
|
||||
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||
$(this).find('div').append(img);
|
||||
}
|
||||
@@ -16,6 +16,7 @@ function generatePreview(previewStepName, customValues, path, selector) {
|
||||
}
|
||||
|
||||
function loadPreview() {
|
||||
previewSequencer = previewSequencer.addSteps('resize', { resize: "40%" });
|
||||
if (previewStepName === "crop") {
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
@@ -27,12 +28,11 @@ function generatePreview(previewStepName, customValues, path, selector) {
|
||||
}
|
||||
|
||||
function updatePreviews(src, selector) {
|
||||
$(selector+' img').remove();
|
||||
$('#'+selector+' img').remove();
|
||||
|
||||
var previewSequencerSteps = {
|
||||
"resize": "125%",
|
||||
"brightness": "175",
|
||||
"saturation": "0.5",
|
||||
"brightness": "20",
|
||||
"saturation": "5",
|
||||
"rotate": 90,
|
||||
"contrast": 90,
|
||||
"crop": {
|
||||
@@ -52,4 +52,4 @@ function generatePreview(previewStepName, customValues, path, selector) {
|
||||
module.exports = {
|
||||
generatePreview : generatePreview,
|
||||
updatePreviews : updatePreviews
|
||||
}
|
||||
}
|
||||
@@ -1,111 +1,75 @@
|
||||
var urlHash = require('./urlHash.js'),
|
||||
insertPreview = require('./insertPreview.js');
|
||||
|
||||
var urlHash = require('./urlHash.js');
|
||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
function stepUI() {
|
||||
return '<div class="row insertDiv collapse">\
|
||||
<section class="panel panel-primary .insert-step">\
|
||||
<button class="btn btn-default close-insert-box"><i class="fa fa-times" aria-hidden="true"></i> Close</button>\
|
||||
<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>\
|
||||
<div class="radio" data-value="resize">\
|
||||
<i class="fa fa-arrows-alt fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Resize</p>\
|
||||
</div>\
|
||||
<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>\
|
||||
return '<div class="row insertDiv">\
|
||||
<div class="col-md-6 col-md-offset-2" 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>\
|
||||
<div class="radio" data-value="brightness">\
|
||||
<i class="fa fa-sun-o fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Brightness</p>\
|
||||
</div>\
|
||||
<div class="row center-align">\
|
||||
<div class="col-md-8">\
|
||||
<select class="insert-step-select">\
|
||||
<!-- 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>\
|
||||
<div>\
|
||||
<div class="col-md-4">\
|
||||
<button class="btn btn-success btn-lg insert-save-btn add-step-btn" name="add">Add Step</button>\
|
||||
<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>\
|
||||
</div>\
|
||||
</section>\
|
||||
</div>\
|
||||
</section>\
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
||||
function selectNewStepUi() {
|
||||
var insertSelect = $(step.ui.querySelector('.insert-step-select'))
|
||||
var m = insertSelect.val();
|
||||
$(step.ui.querySelector('.insertDiv .info')).html(_sequencer.modulesInfo(m).description);
|
||||
$(step.ui.querySelector('.insertDiv .add-step-btn')).prop("disabled", false);
|
||||
var m = $("#insertStep select").val();
|
||||
$("#insertStep .info").html(_sequencer.modulesInfo(m).description);
|
||||
$("#insertStep #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
|
||||
|
||||
var toggleDiv = function(callback = function(){}){
|
||||
$(step.ui.querySelector('.insertDiv')).collapse('toggle');
|
||||
if ($(step.ui.querySelector('.insert-text')).css('display') != "none"){
|
||||
$(step.ui.querySelector('.insert-text')).fadeToggle(200, function(){$(step.ui.querySelector('.no-insert-text')).fadeToggle(200, callback)})
|
||||
}
|
||||
else {
|
||||
$(step.ui.querySelector('.no-insert-text')).fadeToggle(200, function(){$(step.ui.querySelector('.insert-text')).fadeToggle(200, callback)})
|
||||
}
|
||||
}
|
||||
|
||||
insertStep = function (id) {
|
||||
var modulesInfo = _sequencer.modulesInfo();
|
||||
var parser = new DOMParser();
|
||||
var addStepUI = stepUI();
|
||||
addStepUI = parser.parseFromString(addStepUI, "text/html").querySelector("div")
|
||||
|
||||
if ($(step.ui.querySelector('.insertDiv')).length > 0){
|
||||
toggleDiv();
|
||||
}
|
||||
else {
|
||||
step.ui
|
||||
step.ui
|
||||
.querySelector("div.step")
|
||||
.insertAdjacentElement('afterend',
|
||||
addStepUI
|
||||
);
|
||||
toggleDiv(function(){
|
||||
insertPreview.updatePreviews(step.output, '.insertDiv');
|
||||
});
|
||||
}
|
||||
|
||||
$(step.ui.querySelector('.insertDiv .close-insert-box')).off('click').on('click', function(){toggleDiv(function(){})});
|
||||
|
||||
var insertStepSelect = $(step.ui.querySelector('.insert-step-select'));
|
||||
updatePreviews(step.output,'insertStep');
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
insertStepSelect.html("");
|
||||
// Add modules to the insertStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
@@ -114,33 +78,31 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
}
|
||||
insertStepSelect.selectize({
|
||||
sortField: 'text'
|
||||
});
|
||||
$(step.ui.querySelector('.inserDiv .add-step-btn')).prop('disabled', true);
|
||||
|
||||
insertStepSelect.append('<option value="" disabled selected>Select a Module</option>');
|
||||
$(step.ui.querySelector('.insertDiv .radio-group .radio')).on("click", function () {
|
||||
|
||||
$('#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');
|
||||
$(step.ui.querySelector('.insert-step-select')).val(newStep);
|
||||
insertStepSelect.val(newStep);
|
||||
selectNewStepUi();
|
||||
insert(id);
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
insertStepSelect.on('change', selectNewStepUi);
|
||||
$(step.ui.querySelector('.insertDiv .add-step-btn')).on('click', function () { insert(id) });
|
||||
$(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 = $(step.ui.querySelector('.insert-step-select'));
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
if (insertStepSelect.val() == "none") return;
|
||||
|
||||
var newStepName = insertStepSelect.val()
|
||||
toggleDiv();
|
||||
$('div .insertDiv').remove();
|
||||
var sequenceLength = 1;
|
||||
if (sequencer.sequences[newStepName]) {
|
||||
sequenceLength = sequencer.sequences[newStepName].length;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
function mapHtmlTypes(inputInfo){
|
||||
var htmlType;
|
||||
switch(inputInfo.type.toLowerCase()){
|
||||
case 'integer':
|
||||
htmlType = inputInfo.min != undefined ? 'range' : 'number';
|
||||
break;
|
||||
case 'string':
|
||||
htmlType = 'text';
|
||||
break;
|
||||
case 'select':
|
||||
htmlType = 'select';
|
||||
break;
|
||||
case 'percentage':
|
||||
htmlType = 'number';
|
||||
break;
|
||||
case 'float':
|
||||
htmlType = inputInfo.min != undefined ? 'range' : 'text';
|
||||
break;
|
||||
default:
|
||||
htmlType = 'text';
|
||||
break;
|
||||
}
|
||||
var response = inputInfo;
|
||||
response.type = htmlType;
|
||||
return response;
|
||||
}
|
||||
|
||||
module.exports = mapHtmlTypes;
|
||||
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;
|
||||
});
|
||||
});
|
||||
});
|
||||
35
examples/lib/sw.js
Normal file
35
examples/lib/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;
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,403 +0,0 @@
|
||||
/**
|
||||
* selectize.default.css (v0.12.6) - Default Theme
|
||||
* Copyright (c) 2013–2015 Brian Reavis & contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||
* file except in compliance with the License. You may obtain a copy of the License at:
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under
|
||||
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||
* ANY KIND, either express or implied. See the License for the specific language
|
||||
* governing permissions and limitations under the License.
|
||||
*
|
||||
* @author Brian Reavis <brian@thirdroute.com>
|
||||
*/
|
||||
.selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder {
|
||||
visibility: visible !important;
|
||||
background: #f2f2f2 !important;
|
||||
background: rgba(0, 0, 0, 0.06) !important;
|
||||
border: 0 none !important;
|
||||
-webkit-box-shadow: inset 0 0 12px 4px #fff;
|
||||
box-shadow: inset 0 0 12px 4px #fff;
|
||||
}
|
||||
.selectize-control.plugin-drag_drop .ui-sortable-placeholder::after {
|
||||
content: '!';
|
||||
visibility: hidden;
|
||||
}
|
||||
.selectize-control.plugin-drag_drop .ui-sortable-helper {
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.selectize-dropdown-header {
|
||||
position: relative;
|
||||
padding: 5px 8px;
|
||||
border-bottom: 1px solid #d0d0d0;
|
||||
background: #f8f8f8;
|
||||
-webkit-border-radius: 3px 3px 0 0;
|
||||
-moz-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
.selectize-dropdown-header-close {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
color: #303030;
|
||||
opacity: 0.4;
|
||||
margin-top: -12px;
|
||||
line-height: 20px;
|
||||
font-size: 20px !important;
|
||||
}
|
||||
.selectize-dropdown-header-close:hover {
|
||||
color: #000000;
|
||||
}
|
||||
.selectize-dropdown.plugin-optgroup_columns .optgroup {
|
||||
border-right: 1px solid #f2f2f2;
|
||||
border-top: 0 none;
|
||||
float: left;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.selectize-dropdown.plugin-optgroup_columns .optgroup:last-child {
|
||||
border-right: 0 none;
|
||||
}
|
||||
.selectize-dropdown.plugin-optgroup_columns .optgroup:before {
|
||||
display: none;
|
||||
}
|
||||
.selectize-dropdown.plugin-optgroup_columns .optgroup-header {
|
||||
border-top: 0 none;
|
||||
}
|
||||
.selectize-control.plugin-remove_button [data-value] {
|
||||
position: relative;
|
||||
padding-right: 24px !important;
|
||||
}
|
||||
.selectize-control.plugin-remove_button [data-value] .remove {
|
||||
z-index: 1;
|
||||
/* fixes ie bug (see #392) */
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 17px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
padding: 2px 0 0 0;
|
||||
border-left: 1px solid #0073bb;
|
||||
-webkit-border-radius: 0 2px 2px 0;
|
||||
-moz-border-radius: 0 2px 2px 0;
|
||||
border-radius: 0 2px 2px 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.selectize-control.plugin-remove_button [data-value] .remove:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.selectize-control.plugin-remove_button [data-value].active .remove {
|
||||
border-left-color: #00578d;
|
||||
}
|
||||
.selectize-control.plugin-remove_button .disabled [data-value] .remove:hover {
|
||||
background: none;
|
||||
}
|
||||
.selectize-control.plugin-remove_button .disabled [data-value] .remove {
|
||||
border-left-color: #aaaaaa;
|
||||
}
|
||||
.selectize-control.plugin-remove_button .remove-single {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
font-size: 23px;
|
||||
}
|
||||
.selectize-control {
|
||||
position: relative;
|
||||
}
|
||||
.selectize-dropdown,
|
||||
.selectize-input,
|
||||
.selectize-input input {
|
||||
color: #303030;
|
||||
font-family: inherit;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
-webkit-font-smoothing: inherit;
|
||||
}
|
||||
.selectize-input,
|
||||
.selectize-control.single .selectize-input.input-active {
|
||||
background: #fff;
|
||||
cursor: text;
|
||||
display: inline-block;
|
||||
}
|
||||
.selectize-input {
|
||||
border: 1px solid #d0d0d0;
|
||||
padding: 10px 0px;
|
||||
display: inline-block;
|
||||
width: 24vw;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.has-items {
|
||||
padding: 5px 8px 2px;
|
||||
}
|
||||
.selectize-input.full {
|
||||
background-color: #fff;
|
||||
}
|
||||
.selectize-input.disabled,
|
||||
.selectize-input.disabled * {
|
||||
cursor: default !important;
|
||||
}
|
||||
.selectize-input.focus {
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
.selectize-input.dropdown-active {
|
||||
-webkit-border-radius: 3px 3px 0 0;
|
||||
-moz-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
.selectize-input > * {
|
||||
vertical-align: baseline;
|
||||
display: -moz-inline-stack;
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
*display: inline;
|
||||
}
|
||||
.selectize-control.multi .selectize-input > div {
|
||||
cursor: pointer;
|
||||
margin: 0 3px 3px 0;
|
||||
padding: 2px 6px;
|
||||
background: #1da7ee;
|
||||
color: #fff;
|
||||
border: 1px solid #0073bb;
|
||||
}
|
||||
.selectize-control.multi .selectize-input > div.active {
|
||||
background: #92c836;
|
||||
color: #fff;
|
||||
border: 1px solid #00578d;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.disabled > div,
|
||||
.selectize-control.multi .selectize-input.disabled > div.active {
|
||||
color: #ffffff;
|
||||
background: #d2d2d2;
|
||||
border: 1px solid #aaaaaa;
|
||||
}
|
||||
.selectize-input > input {
|
||||
display: inline-block !important;
|
||||
padding: 0 !important;
|
||||
min-height: 0 !important;
|
||||
max-height: none !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 1px !important;
|
||||
text-indent: 0 !important;
|
||||
border: 0 none !important;
|
||||
background: none !important;
|
||||
line-height: inherit !important;
|
||||
-webkit-user-select: auto !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.selectize-input > input::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
.selectize-input > input:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
.selectize-input::after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
clear: left;
|
||||
}
|
||||
.selectize-input.dropdown-active::before {
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
background: #f0f0f0;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.selectize-dropdown {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
border: 1px solid #d0d0d0;
|
||||
background: #fff;
|
||||
margin: -1px 0 0 0;
|
||||
border-top: 0 none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
-webkit-border-radius: 0 0 3px 3px;
|
||||
-moz-border-radius: 0 0 3px 3px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
.selectize-dropdown [data-selectable] {
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
.selectize-dropdown [data-selectable] .highlight {
|
||||
background: rgba(125, 168, 208, 0.2);
|
||||
-webkit-border-radius: 1px;
|
||||
-moz-border-radius: 1px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
.selectize-dropdown .option,
|
||||
.selectize-dropdown .optgroup-header {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
.selectize-dropdown .option,
|
||||
.selectize-dropdown [data-disabled],
|
||||
.selectize-dropdown [data-disabled] [data-selectable].option {
|
||||
cursor: inherit;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.selectize-dropdown [data-selectable].option {
|
||||
opacity: 1;
|
||||
}
|
||||
.selectize-dropdown .optgroup:first-child .optgroup-header {
|
||||
border-top: 0 none;
|
||||
}
|
||||
.selectize-dropdown .optgroup-header {
|
||||
color: #303030;
|
||||
background: #fff;
|
||||
cursor: default;
|
||||
}
|
||||
.selectize-dropdown .active {
|
||||
background-color: #f5fafd;
|
||||
color: #495c68;
|
||||
}
|
||||
.selectize-dropdown .active.create {
|
||||
color: #495c68;
|
||||
}
|
||||
.selectize-dropdown .create {
|
||||
color: rgba(48, 48, 48, 0.5);
|
||||
}
|
||||
.selectize-dropdown-content {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 200px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.selectize-control.single .selectize-input,
|
||||
.selectize-control.single .selectize-input input {
|
||||
cursor: pointer;
|
||||
}
|
||||
.selectize-control.single .selectize-input.input-active,
|
||||
.selectize-control.single .selectize-input.input-active input {
|
||||
cursor: text;
|
||||
}
|
||||
.selectize-control.single .selectize-input:after {
|
||||
content: ' ';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 15px;
|
||||
margin-top: -3px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-color: #808080 transparent transparent transparent;
|
||||
}
|
||||
.selectize-control.single .selectize-input.dropdown-active:after {
|
||||
margin-top: -4px;
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-color: transparent transparent #808080 transparent;
|
||||
}
|
||||
.selectize-control.rtl.single .selectize-input:after {
|
||||
left: 15px;
|
||||
right: auto;
|
||||
}
|
||||
.selectize-control.rtl .selectize-input > input {
|
||||
margin: 0 4px 0 -2px !important;
|
||||
}
|
||||
.selectize-control .selectize-input.disabled {
|
||||
opacity: 0.5;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.has-items {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.disabled [data-value] {
|
||||
color: #999;
|
||||
text-shadow: none;
|
||||
background: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.disabled [data-value],
|
||||
.selectize-control.multi .selectize-input.disabled [data-value] .remove {
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
.selectize-control.multi .selectize-input.disabled [data-value] .remove {
|
||||
background: none;
|
||||
}
|
||||
.selectize-control.multi .selectize-input [data-value] {
|
||||
text-shadow: 0 1px 0 rgba(0, 51, 83, 0.3);
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background-color: #1b9dec;
|
||||
background-image: -moz-linear-gradient(top, #1da7ee, #178ee9);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#1da7ee), to(#178ee9));
|
||||
background-image: -webkit-linear-gradient(top, #1da7ee, #178ee9);
|
||||
background-image: -o-linear-gradient(top, #1da7ee, #178ee9);
|
||||
background-image: linear-gradient(to bottom, #1da7ee, #178ee9);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1da7ee', endColorstr='#ff178ee9', GradientType=0);
|
||||
-webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
|
||||
}
|
||||
.selectize-control.multi .selectize-input [data-value].active {
|
||||
background-color: #0085d4;
|
||||
background-image: -moz-linear-gradient(top, #008fd8, #0075cf);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#008fd8), to(#0075cf));
|
||||
background-image: -webkit-linear-gradient(top, #008fd8, #0075cf);
|
||||
background-image: -o-linear-gradient(top, #008fd8, #0075cf);
|
||||
background-image: linear-gradient(to bottom, #008fd8, #0075cf);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff008fd8', endColorstr='#ff0075cf', GradientType=0);
|
||||
}
|
||||
.selectize-control.single .selectize-input {
|
||||
-webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||
background-color: #f9f9f9;
|
||||
background-image: -moz-linear-gradient(top, #fefefe, #f2f2f2);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fefefe), to(#f2f2f2));
|
||||
background-image: -webkit-linear-gradient(top, #fefefe, #f2f2f2);
|
||||
background-image: -o-linear-gradient(top, #fefefe, #f2f2f2);
|
||||
background-image: linear-gradient(to bottom, #fefefe, #f2f2f2);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffefefe', endColorstr='#fff2f2f2', GradientType=0);
|
||||
}
|
||||
/* .selectize-control.single .selectize-input,
|
||||
.selectize-dropdown.single {
|
||||
border-color: #b8b8b8;
|
||||
} */
|
||||
.selectize-dropdown .optgroup-header {
|
||||
padding-top: 7px;
|
||||
font-weight: bold;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.selectize-dropdown .optgroup {
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
.selectize-dropdown .optgroup:first-child {
|
||||
border-top: 0 none;
|
||||
}
|
||||
@@ -32,4 +32,4 @@ self.addEventListener('fetch', function(event) {
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
155
index.js
155
index.js
@@ -1,14 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('./src/ImageSequencer');
|
||||
require("./src/ImageSequencer");
|
||||
sequencer = ImageSequencer({ ui: false });
|
||||
var fs = require('fs')
|
||||
var program = require('commander');
|
||||
var utils = require('./src/CliUtils')
|
||||
var Spinner = require("ora");
|
||||
|
||||
var saveSequence = require('./src/cli/saveSequence.js')
|
||||
var installModule = require('./src/cli/installModule.js')
|
||||
var sequencerSteps = require('./src/cli/sequencerSteps.js')
|
||||
var program = require("commander");
|
||||
var readlineSync = require("readline-sync");
|
||||
|
||||
function exit(message) {
|
||||
console.error(message);
|
||||
@@ -26,11 +23,24 @@ program
|
||||
.option('--install-module [string]', "Module name space seaprated npm package name")
|
||||
.parse(process.argv);
|
||||
|
||||
if (program.saveSequence) saveSequence(program, sequencer)
|
||||
|
||||
else if (program.installModule) installModule(program, sequencer)
|
||||
|
||||
else {
|
||||
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");
|
||||
program.step = program.step.split(" ");
|
||||
@@ -39,12 +49,12 @@ else {
|
||||
if (!program.image) exit("Can't read file.");
|
||||
|
||||
// User must input an image.
|
||||
fs.access(program.image, function(err) {
|
||||
require("fs").access(program.image, function(err) {
|
||||
if (err) exit("Can't read file.");
|
||||
});
|
||||
|
||||
// User must input a step. If steps exist, check that every step is a valid step.
|
||||
if (!program.step || !(utils.validateSteps(program.step, sequencer)))
|
||||
if (!program.step || !validateSteps(program.step))
|
||||
exit("Please ensure all steps are valid.");
|
||||
|
||||
// If there's no user defined output directory, select a default directory.
|
||||
@@ -81,9 +91,124 @@ else {
|
||||
else {
|
||||
outputFilename = null;
|
||||
}
|
||||
require("./src/CliUtils").makedir(program.output, () => {
|
||||
console.log('Files will be exported to "' + program.output + '"');
|
||||
|
||||
sequencerSteps(program, sequencer, outputFilename)
|
||||
if (program.basic)
|
||||
console.log("Basic mode is enabled, outputting only final image");
|
||||
|
||||
// Iterate through the steps and retrieve their inputs.
|
||||
program.step.forEach(function(step) {
|
||||
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
||||
|
||||
// If inputs exists, print to console.
|
||||
if (Object.keys(options).length) {
|
||||
console.log("[" + step + "]: Inputs");
|
||||
}
|
||||
|
||||
// If inputs exists, print them out with descriptions.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
||||
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||
console.log(
|
||||
new Array(step.length + 5).join(" ") +
|
||||
input +
|
||||
": " +
|
||||
options[input].desc
|
||||
);
|
||||
});
|
||||
|
||||
if (program.config) {
|
||||
try {
|
||||
var config = JSON.parse(program.config);
|
||||
console.log(`The parsed options object: `, config);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options(Config) is not a not valid JSON Fallback activate`
|
||||
);
|
||||
program.config = false;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
if (program.config && validateConfig(config, options)) {
|
||||
console.log("Now using Options object");
|
||||
Object.keys(options).forEach(function(input) {
|
||||
options[input] = config[input];
|
||||
});
|
||||
} else {
|
||||
// If inputs exist, iterate through them and prompt for values.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
var value = readlineSync.question(
|
||||
"[" +
|
||||
step +
|
||||
"]: Enter a value for " +
|
||||
input +
|
||||
" (" +
|
||||
options[input].type +
|
||||
", default: " +
|
||||
options[input].default +
|
||||
"): "
|
||||
);
|
||||
options[input] = value;
|
||||
});
|
||||
}
|
||||
// Add the step and its inputs to the sequencer.
|
||||
sequencer.addSteps(step, options);
|
||||
});
|
||||
|
||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||
if (!process.env.TEST)
|
||||
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||
|
||||
// Run the sequencer.
|
||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||
// Export all images or final image as binary files.
|
||||
sequencer.exportBin(program.output, program.basic, outputFilename);
|
||||
|
||||
//check if spinner was not overriden stop it
|
||||
if (!spinnerObj.overrideFlag) {
|
||||
spinnerObj.succeed();
|
||||
console.log(`\nDone!!`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||
function validateSteps(steps) {
|
||||
// Assume all are valid in the beginning.
|
||||
var valid = true;
|
||||
steps.forEach(function(step) {
|
||||
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
||||
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
||||
return valid;
|
||||
}
|
||||
|
||||
//Takes config and options object and checks if all the keys exist in config
|
||||
function validateConfig(config_, options_) {
|
||||
options_ = Object.keys(options_);
|
||||
if (
|
||||
(function() {
|
||||
for (var input in options_) {
|
||||
if (!config_[options_[input]]) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options Object does not have the required details "${
|
||||
options_[input]
|
||||
}" not specified. Fallback case activated`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})() == false
|
||||
)
|
||||
return false;
|
||||
else return true;
|
||||
}
|
||||
}
|
||||
|
||||
1437
package-lock.json
generated
1437
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -1,13 +1,12 @@
|
||||
{
|
||||
"name": "image-sequencer",
|
||||
"version": "3.3.1",
|
||||
"version": "2.3.1",
|
||||
"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 istanbul cover tape test/core/*.js test/core/ui/user-interface.js test/core/modules/canvas-resize.js test/core/modules/QR.js test/core/modules/crop.js | tap-spec; browserify test/core/modules/image-sequencer.js test/core/modules/chain.js test/core/modules/meta-modules.js test/core/modules/replace.js test/core/modules/import-export.js test/core/modules/run.js test/core/modules/dynamic-imports.js test/core/util/parse-input.js test/core/modules/benchmark.js| tape-run --render=\"tap-spec\"",
|
||||
"test-ui": "jasmine test/spec/*.js",
|
||||
"setup": "npm i && npm i -g grunt grunt-cli && grunt build",
|
||||
"test": "TEST=true tape test/ui/*.js test/**/*.js test/*.js test/ui/user-interface.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 test/util/parse-input.js | tape-run --render=\"tap-spec\"",
|
||||
"setup": "npm i && npm i -g grunt grunt-cli",
|
||||
"start": "grunt serve"
|
||||
},
|
||||
"repository": {
|
||||
@@ -31,32 +30,23 @@
|
||||
"downloadjs": "^1.4.7",
|
||||
"fisheyegl": "^0.1.2",
|
||||
"font-awesome": "~4.7.0",
|
||||
"geotiff": "^1.0.0-beta.6",
|
||||
"get-pixels": "~3.3.0",
|
||||
"gifshot": "^0.4.5",
|
||||
"glfx": "0.0.4",
|
||||
"image-sequencer-invert": "^1.0.0",
|
||||
"imagejs": "0.0.9",
|
||||
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
||||
"istanbul": "^0.4.5",
|
||||
"jquery": "^3.3.1",
|
||||
"jsdom": "^15.0.0",
|
||||
"jsdom": "^13.1.0",
|
||||
"jsqr": "^1.1.1",
|
||||
"lodash": "^4.17.11",
|
||||
"ndarray": "^1.0.18",
|
||||
"lodash": "^4.17.5",
|
||||
"ndarray-gaussian-filter": "^1.0.0",
|
||||
"ora": "^3.0.0",
|
||||
"pace": "0.0.4",
|
||||
"puppeteer": "^1.14.0",
|
||||
"qrcode": "^1.3.3",
|
||||
"readline-sync": "^1.4.7",
|
||||
"save-pixels": "~2.3.4",
|
||||
"selectize": "^0.12.6",
|
||||
"urify": "^2.1.1",
|
||||
"webgl-distort": "0.0.2"
|
||||
"urify": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"base64-img": "^1.0.4",
|
||||
"browserify": "16.2.3",
|
||||
"grunt": "^1.0.3",
|
||||
"grunt-browser-sync": "^2.2.0",
|
||||
@@ -66,17 +56,14 @@
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"image-filter-core": "~2.0.2",
|
||||
"image-filter-threshold": "~2.0.1",
|
||||
"jasmine-core": "^3.3.0",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"jasmine-spec-reporter": "^4.2.1",
|
||||
"looks-same": "^7.0.0",
|
||||
"looks-same": "^6.0.0",
|
||||
"matchdep": "^2.0.0",
|
||||
"tap-spec": "^5.0.0",
|
||||
"tape": "^4.9.2",
|
||||
"tape-run": "^5.0.0",
|
||||
"uglify-es": "^3.3.7"
|
||||
},
|
||||
"homepage": "https://sequencer.publiclab.org",
|
||||
"homepage": "https://github.com/publiclab/image-sequencer",
|
||||
"bin": {
|
||||
"sequencer": "./index.js"
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
describe('Default sequencer HTML', function() {
|
||||
|
||||
var DefaultHtmlSequencerUi = require('../examples/lib/defaultHtmlSequencerUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var defaultHtmlSequencerUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlSequencerUi = new DefaultHtmlSequencerUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlSequencerUi,'onLoad')
|
||||
spyOn(defaultHtmlSequencerUi,'selectNewStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'removeStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'addStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'importStepsFromUrlHash')
|
||||
|
||||
defaultHtmlSequencerUi.onLoad()
|
||||
defaultHtmlSequencerUi.selectNewStepUi()
|
||||
defaultHtmlSequencerUi.addStepUi()
|
||||
defaultHtmlSequencerUi.removeStepUi()
|
||||
defaultHtmlSequencerUi.importStepsFromUrlHash()
|
||||
})
|
||||
|
||||
it('load default ui', function() {
|
||||
expect(defaultHtmlSequencerUi.onLoad).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('select step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.selectNewStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('add step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.addStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.removeStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('import options from url', function() {
|
||||
expect(defaultHtmlSequencerUi.importStepsFromUrlHash).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -1,61 +0,0 @@
|
||||
var { JSDOM } = require('jsdom');
|
||||
var DOM = new JSDOM(`<body></body>`);
|
||||
|
||||
global.document = DOM.window.document;
|
||||
|
||||
describe('Sequencer step HTML', function() {
|
||||
|
||||
var DefaultHtmlStepUi = require('../examples/lib/defaultHtmlStepUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var defaultHtmlStepUi;
|
||||
var step = 'brightness'
|
||||
var options = {
|
||||
name: "Brightness",
|
||||
description: "Change the brightness of the image by given percent value"
|
||||
}
|
||||
// options = JSON.parse(options)
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlStepUi = new DefaultHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlStepUi,'getPreview')
|
||||
spyOn(defaultHtmlStepUi,'onSetup')
|
||||
spyOn(defaultHtmlStepUi,'onComplete')
|
||||
spyOn(defaultHtmlStepUi,'onDraw')
|
||||
spyOn(defaultHtmlStepUi,'onRemove')
|
||||
spyOn(defaultHtmlStepUi,'notify')
|
||||
|
||||
defaultHtmlStepUi.getPreview()
|
||||
defaultHtmlStepUi.onSetup(step,options)
|
||||
defaultHtmlStepUi.onComplete(step)
|
||||
defaultHtmlStepUi.onDraw(step)
|
||||
defaultHtmlStepUi.onRemove(step)
|
||||
defaultHtmlStepUi.notify('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
|
||||
it('result preview ui', function() {
|
||||
expect(defaultHtmlStepUi.getPreview).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('load initial setup ui', function() {
|
||||
expect(defaultHtmlStepUi.onSetup).toHaveBeenCalledWith(step,options)
|
||||
})
|
||||
|
||||
it('load completion ui', function() {
|
||||
expect(defaultHtmlStepUi.onComplete).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('draw step ui', function() {
|
||||
expect(defaultHtmlStepUi.onDraw).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlStepUi.onRemove).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('notification ui', function() {
|
||||
expect(defaultHtmlStepUi.notify).toHaveBeenCalledWith('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
|
||||
jasmine.getEnv().clearReporters(); // remove default reporter logs
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter
|
||||
spec: {
|
||||
displayPending: true
|
||||
}
|
||||
}));
|
||||
@@ -1,26 +0,0 @@
|
||||
describe('Preview UI HTML', function() {
|
||||
|
||||
var InsertPreview = require('../examples/lib/insertPreview')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var insertPreview;
|
||||
var options = { brightness: 50 }
|
||||
|
||||
beforeEach(()=>{
|
||||
insertPreview = InsertPreview
|
||||
|
||||
spyOn(insertPreview,'generatePreview')
|
||||
spyOn(insertPreview,'updatePreviews')
|
||||
|
||||
insertPreview.generatePreview('brightness',options,'src','selector')
|
||||
insertPreview.updatePreviews('src','selector')
|
||||
})
|
||||
|
||||
it('generate preview ui', function() {
|
||||
expect(insertPreview.generatePreview).toHaveBeenCalledWith('brightness',options,'src','selector')
|
||||
})
|
||||
|
||||
it('update preview ui', function() {
|
||||
expect(insertPreview.updatePreviews).toHaveBeenCalledWith('src','selector')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
describe('Intermediate step HTML', function() {
|
||||
|
||||
var IntermediateHtmlStepUi = require('../examples/lib/intermediateHtmlStepUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var intermediateHtmlStepUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(intermediateHtmlStepUi,'insertStep')
|
||||
|
||||
intermediateHtmlStepUi.insertStep()
|
||||
})
|
||||
|
||||
it('insert step ui', function() {
|
||||
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.js"
|
||||
],
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
describe('URL manipulation methods', function() {
|
||||
|
||||
var UrlHash = require('../examples/lib/urlHash')
|
||||
var urlHash;
|
||||
var params = {
|
||||
module: 'brightness',
|
||||
brightness: 50
|
||||
}
|
||||
|
||||
beforeEach(()=>{
|
||||
urlHash = UrlHash
|
||||
|
||||
spyOn(urlHash,'getUrlHashParameters')
|
||||
spyOn(urlHash,'getUrlHashParameter')
|
||||
spyOn(urlHash,'setUrlHashParameters')
|
||||
spyOn(urlHash,'setUrlHashParameter')
|
||||
|
||||
urlHash.getUrlHashParameters()
|
||||
urlHash.getUrlHashParameter('module')
|
||||
urlHash.setUrlHashParameters(params)
|
||||
urlHash.setUrlHashParameter('module','brightness')
|
||||
})
|
||||
|
||||
it('gets url hash params from window hash', function() {
|
||||
expect(urlHash.getUrlHashParameters).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('gets url hash param from params object', function() {
|
||||
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module')
|
||||
})
|
||||
|
||||
it('accepts param object and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params)
|
||||
})
|
||||
|
||||
it('accepts param key-value pair and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module','brightness')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
// add steps to the sequencer
|
||||
function AddStep(_sequencer, name, o) {
|
||||
return require('./InsertStep')(_sequencer,-1,name,o);
|
||||
function AddStep(_sequencer, image, name, o) {
|
||||
return require('./InsertStep')(_sequencer,image,-1,name,o);
|
||||
}
|
||||
module.exports = AddStep;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
var fs = require('fs')
|
||||
const fs = require('fs')
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function checks if the directory exists, if not it creates one on the given path
|
||||
@@ -14,45 +16,6 @@ function makedir(path,callback){
|
||||
});
|
||||
};
|
||||
|
||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||
function validateSteps(steps, sequencer) {
|
||||
// Assume all are valid in the beginning.
|
||||
var valid = true;
|
||||
steps.forEach(function(step) {
|
||||
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
||||
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
||||
return valid;
|
||||
}
|
||||
|
||||
//Takes config and options object and checks if all the keys exist in config
|
||||
function validateConfig(config_, options_) {
|
||||
options_ = Object.keys(options_);
|
||||
if (
|
||||
(function() {
|
||||
for (var input in options_) {
|
||||
if (!config_[options_[input]]) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options Object does not have the required details "${
|
||||
options_[input]
|
||||
}" not specified. Fallback case activated`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})() == false
|
||||
)
|
||||
return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
module.exports = exports = {
|
||||
makedir: makedir,
|
||||
validateSteps: validateSteps,
|
||||
validateConfig: validateConfig
|
||||
makedir: makedir
|
||||
}
|
||||
@@ -32,11 +32,13 @@ module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
||||
if (err) console.error(err)
|
||||
});
|
||||
if (filename && basic) {
|
||||
var steps = ref.steps;
|
||||
var datauri = steps.slice(-1)[0].output.src;
|
||||
var ext = steps.slice(-1)[0].output.format;
|
||||
var buffer = require('data-uri-to-buffer')(datauri);
|
||||
fs.writeFile(dir + filename, buffer, function() { });
|
||||
for (var image in ref.images) {
|
||||
var steps = ref.images[image].steps;
|
||||
var datauri = steps.slice(-1)[0].output.src;
|
||||
var ext = steps.slice(-1)[0].output.format;
|
||||
var buffer = require('data-uri-to-buffer')(datauri);
|
||||
fs.writeFile(dir + filename, buffer, function() { });
|
||||
}
|
||||
}
|
||||
else {
|
||||
getDirectories(dir, function(dirs) {
|
||||
@@ -48,19 +50,21 @@ module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
||||
}
|
||||
fs.mkdir(dir + 'sequencer' + num, function() {
|
||||
var root = dir + 'sequencer' + num + '/';
|
||||
var steps = ref.steps;
|
||||
if (basic) {
|
||||
var datauri = steps.slice(-1)[0].output.src;
|
||||
var ext = steps.slice(-1)[0].output.format;
|
||||
var buffer = require('data-uri-to-buffer')(datauri);
|
||||
fs.writeFile(root + "image" + "_" + (steps.length - 1) + "." + ext, buffer, function() { });
|
||||
}
|
||||
else {
|
||||
for (var i in steps) {
|
||||
var datauri = steps[i].output.src;
|
||||
var ext = steps[i].output.format;
|
||||
for (var image in ref.images) {
|
||||
var steps = ref.images[image].steps;
|
||||
if (basic) {
|
||||
var datauri = steps.slice(-1)[0].output.src;
|
||||
var ext = steps.slice(-1)[0].output.format;
|
||||
var buffer = require('data-uri-to-buffer')(datauri);
|
||||
fs.writeFile(root + "image" + "_" + i + "." + ext, buffer, function() { });
|
||||
fs.writeFile(root + image + "_" + (steps.length - 1) + "." + ext, buffer, function() { });
|
||||
}
|
||||
else {
|
||||
for (var i in steps) {
|
||||
var datauri = steps[i].output.src;
|
||||
var ext = steps[i].output.format;
|
||||
var buffer = require('data-uri-to-buffer')(datauri);
|
||||
fs.writeFile(root + image + "_" + i + "." + ext, buffer, function() { });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -24,19 +24,42 @@ function copy(a) {
|
||||
}
|
||||
|
||||
function formatInput(args,format,images) {
|
||||
images = [];
|
||||
for (var image in this.images) {
|
||||
images.push(image);
|
||||
}
|
||||
var json_q = {};
|
||||
var format_i = format;
|
||||
if (format == "+")
|
||||
format = ['string_a', 'o_object'];
|
||||
format = ['o_string_a', 'string_a', 'o_object'];
|
||||
else if (format == "-")
|
||||
format = ['number_a'];
|
||||
format = ['o_string_a', 'number_a'];
|
||||
else if (format == "^")
|
||||
format = ['number', 'string', 'o_object'];
|
||||
format = ['o_string_a', 'number', 'string', 'o_object'];
|
||||
else if (format == "r")
|
||||
format = ['o_number'];
|
||||
format = ['o_string_a', 'o_number'];
|
||||
else if (format == "l")
|
||||
format = ['string','o_function'];
|
||||
|
||||
format = ['o_string','string','o_function'];
|
||||
|
||||
/*
|
||||
formats:
|
||||
addSteps :: o_image_a, name_a, o_o
|
||||
o_string_a, string_a, o_object => { image: [{name,o}] }
|
||||
removeSteps :: o_image_a, index_a
|
||||
o_string_a, number_a => { image: [index] }
|
||||
insertSteps :: o_image_a, index, name, o_o
|
||||
o_string_a, number, string, o_object => { image: [{index,name,o}] }
|
||||
run :: o_image_a, o_from
|
||||
o_string_a, o_number => { image: index }
|
||||
loadImages :: image, src, o_function
|
||||
string, string, o_function => { images: [{image:src}], callback }
|
||||
|
||||
optionals:
|
||||
image: o_string_a
|
||||
options: o_object
|
||||
from: o_number
|
||||
callback: o_function
|
||||
*/
|
||||
|
||||
if(format[format.length-1] == "o_object") {
|
||||
if(objTypeOf(args[args.length-1]) != "Object")
|
||||
@@ -51,56 +74,90 @@ function formatInput(args,format,images) {
|
||||
args.push(function(){});
|
||||
}
|
||||
|
||||
if(format[0] == "o_string_a") {
|
||||
if(args.length == format.length - 1) {
|
||||
var insert = false;
|
||||
for (var i in args) {
|
||||
if (format[parseInt(i)+1].includes( typeof(getPrimitive(args[i])) )){
|
||||
insert = true;
|
||||
}
|
||||
else {insert = false; break;}
|
||||
}
|
||||
if(insert)
|
||||
args.splice(0,0,copy(images));
|
||||
}
|
||||
}
|
||||
else if (format[0] == "o_string" && format_i == "l" && args.length == 2) {
|
||||
if (typeof(args[0]) == "string") {
|
||||
var identifier = "image";
|
||||
var number = 1;
|
||||
while (this.images.hasOwnProperty(identifier+number)) number++;
|
||||
args.splice(0,0,identifier+number);
|
||||
}
|
||||
}
|
||||
|
||||
if(args.length == format.length) {//making of arrays
|
||||
if(args.length == format.length) {
|
||||
for (var i in format) {
|
||||
if (format[i].substr(format[i].length-2,2)=="_a")
|
||||
args[i] = makeArray(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length == 1 ) {
|
||||
if(format_i == "r") json_q = {0:copy(args[0])};
|
||||
else if(format_i == "-") {
|
||||
json_q=[];
|
||||
json_q= copy(args[0]);
|
||||
if (args.length == 1) {
|
||||
json_q = copy(args[0]);
|
||||
if(!(format_i == "r" || format_i == "l")) {
|
||||
for (var img in json_q)
|
||||
json_q[img] = makeArray(json_q[img]);
|
||||
}
|
||||
}
|
||||
else if (format_i == "r" ) {
|
||||
for (var img in args[0]) json_q = {0:args[0]};
|
||||
else if (format_i == "r") {
|
||||
for (var img in args[0]) json_q[args[0][img]] = args[1];
|
||||
}
|
||||
else if (format_i == "l") {
|
||||
json_q = {
|
||||
image: args[0],
|
||||
callback: args[1]
|
||||
images: {},
|
||||
callback: args[2]
|
||||
}
|
||||
json_q.images[args[0]] = args[1];
|
||||
}
|
||||
else {
|
||||
json_q = [];
|
||||
for (var img in args[0]) {
|
||||
var image = args[0][img];
|
||||
json_q[image] = [];
|
||||
|
||||
if(format_i == "+") {
|
||||
for(var s in args[0]) {
|
||||
json_q.push({
|
||||
name: args[0][s],
|
||||
o: args[1]
|
||||
for(var s in args[1]) {
|
||||
json_q[image].push({
|
||||
name: args[1][s],
|
||||
o: args[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(format_i == "-") {
|
||||
json_q[image] = args[1];
|
||||
}
|
||||
|
||||
if(format_i == "^") {
|
||||
var size = this.steps.length;
|
||||
var index = args[0];
|
||||
var size = this.images[image].steps.length;
|
||||
var index = args[1];
|
||||
index = (index==size)?index:index%size;
|
||||
if (index<0) index += size+1;
|
||||
json_q.push({
|
||||
json_q[image].push({
|
||||
index: index,
|
||||
name: args[1],
|
||||
o: args[2]
|
||||
name: args[2],
|
||||
o: args[3]
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(format_i == "l") {
|
||||
json_q.loadedimages = [];
|
||||
for (var i in json_q.images) json_q.loadedimages.push(i);
|
||||
}
|
||||
|
||||
return json_q;
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
var sequencer = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
options = options || {};
|
||||
options.inBrowser = options.inBrowser === undefined ? isBrowser : options.inBrowser;
|
||||
options.inBrowser = options.inBrowser || isBrowser;
|
||||
options.sequencerCounter = 0;
|
||||
|
||||
function objTypeOf(object) {
|
||||
@@ -42,6 +42,7 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
modules = require('./Modules'),
|
||||
sequences = require('./SavedSequences.json'),
|
||||
formatInput = require('./FormatInput'),
|
||||
images = {},
|
||||
inputlog = [],
|
||||
events = require('./ui/UserInterface')(),
|
||||
fs = require('fs');
|
||||
@@ -65,78 +66,94 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
function addSteps() {
|
||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
var args = [];
|
||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
||||
var json_q = {};
|
||||
for (var arg in arguments) { args.push(copy(arguments[arg])); }
|
||||
json_q = formatInput.call(this_, args, "+");
|
||||
|
||||
inputlog.push({ method: "addSteps", json_q: copy(json_q) });
|
||||
for (var j in json_q)
|
||||
require("./AddStep")(this_, json_q[j].name, json_q[j].o);
|
||||
|
||||
for (var i in json_q)
|
||||
for (var j in json_q[i])
|
||||
require("./AddStep")(this_, i, json_q[i][j].name, json_q[i][j].o);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function removeStep(ref, index) {
|
||||
function removeStep(image, index) {
|
||||
//remove the step from images[image].steps and redraw remaining images
|
||||
if (index > 0) {
|
||||
//var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
thisStep = ref.steps[index];
|
||||
thisStep = images[image].steps[index];
|
||||
thisStep.UI.onRemove(thisStep.options.step);
|
||||
ref.steps.splice(index, 1);
|
||||
images[image].steps.splice(index, 1);
|
||||
}
|
||||
//tell the UI a step has been removed
|
||||
}
|
||||
|
||||
function removeSteps() {
|
||||
var indices;
|
||||
function removeSteps(image, index) {
|
||||
var run = {}, indices;
|
||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
var args = [];
|
||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
|
||||
var json_q = formatInput.call(this_, args, "-");
|
||||
inputlog.push({ method: "removeSteps", json_q: copy(json_q) });
|
||||
|
||||
indices = json_q.sort(function(a, b) { return b - a });
|
||||
for (var img in json_q) {
|
||||
indices = json_q[img].sort(function(a, b) { return b - a });
|
||||
run[img] = indices[indices.length - 1];
|
||||
for (var i in indices)
|
||||
removeStep(this_, indices[i]);
|
||||
removeStep(img, indices[i]);
|
||||
}
|
||||
// this.run(run); // This is creating problems
|
||||
return this;
|
||||
}
|
||||
|
||||
function insertSteps() {
|
||||
function insertSteps(image, index, name, o) {
|
||||
var run = {};
|
||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
var args = []
|
||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
||||
for (var arg in arguments) args.push(arguments[arg]);
|
||||
|
||||
var json_q = formatInput.call(this_, args, "^");
|
||||
inputlog.push({ method: "insertSteps", json_q: copy(json_q) });
|
||||
|
||||
var details = json_q;
|
||||
for (var img in json_q) {
|
||||
var details = json_q[img];
|
||||
details = details.sort(function(a, b) { return b.index - a.index });
|
||||
for (var i in details)
|
||||
require("./InsertStep")(this_, details[i].index, details[i].name, details[i].o);
|
||||
require("./InsertStep")(this_, img, details[i].index, details[i].name, details[i].o);
|
||||
run[img] = details[details.length - 1].index;
|
||||
}
|
||||
// this.run(run); // This is Creating issues
|
||||
return this;
|
||||
}
|
||||
|
||||
// Config is an object which contains the runtime configuration like progress bar
|
||||
// information and index from which the sequencer should run
|
||||
function run(config) {
|
||||
var progressObj, index = 0;
|
||||
function run(config, t_image, t_from) {
|
||||
let progressObj, index = 0;
|
||||
config = config || { mode: 'no-arg' };
|
||||
if (config.index) index = config.index;
|
||||
|
||||
if (config.mode != 'test') {
|
||||
if (config.mode != "no-arg" && typeof config != 'function') {
|
||||
if (config.progressObj) progressObj = config.progressObj;
|
||||
delete arguments['0'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
arguments['0'] = config.mode;
|
||||
}
|
||||
|
||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||
var args = [];
|
||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
|
||||
var callback = function() { };
|
||||
for (var arg in args)
|
||||
if (objTypeOf(args[arg]) == "Function")
|
||||
callback = args.splice(arg, 1)[0]; //callback is formed
|
||||
callback = args.splice(arg, 1)[0];
|
||||
|
||||
var json_q = formatInput.call(this_, args, "r");
|
||||
|
||||
@@ -147,17 +164,13 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
|
||||
function loadImages() {
|
||||
var args = [];
|
||||
var prevSteps = this.getSteps().slice(1).map(step=>step.options.name)
|
||||
var sequencer = this;
|
||||
sequencer.image = arguments[0];
|
||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||
var json_q = formatInput.call(this, args, "l");
|
||||
if(this.getSteps().length!=0){
|
||||
this.options.sequencerCounter = 0;
|
||||
inputlog = [];
|
||||
this.steps = [];
|
||||
}
|
||||
|
||||
inputlog.push({ method: "loadImages", json_q: copy(json_q) });
|
||||
var loadedimages = this.copy(json_q.loadedimages);
|
||||
|
||||
var ret = {
|
||||
name: "ImageSequencer Wrapper",
|
||||
sequencer: this,
|
||||
@@ -166,19 +179,22 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
insertSteps: this.insertSteps,
|
||||
run: this.run,
|
||||
UI: this.UI,
|
||||
setUI: this.setUI
|
||||
setUI: this.setUI,
|
||||
images: loadedimages
|
||||
};
|
||||
function loadPrevSteps(ref){
|
||||
if(prevSteps.length!=0){
|
||||
ref.addSteps(prevSteps)
|
||||
prevSteps=[];
|
||||
}
|
||||
}
|
||||
require('./ui/LoadImage')(sequencer, "image", json_q.image, function() {
|
||||
loadPrevSteps(sequencer);
|
||||
json_q.callback.call(ret);
|
||||
});
|
||||
|
||||
function load(i) {
|
||||
if (i == loadedimages.length) {
|
||||
json_q.callback.call(ret);
|
||||
return;
|
||||
}
|
||||
var img = loadedimages[i];
|
||||
require('./ui/LoadImage')(sequencer, img, json_q.images[img], function() {
|
||||
load(++i);
|
||||
});
|
||||
}
|
||||
|
||||
load(0);
|
||||
}
|
||||
|
||||
function replaceImage(selector, steps, options) {
|
||||
@@ -187,11 +203,6 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
return require('./ReplaceImage')(this, selector, steps, options);
|
||||
}
|
||||
|
||||
//returns the steps added
|
||||
function getSteps(){
|
||||
return this.steps;
|
||||
}
|
||||
|
||||
function setUI(UI) {
|
||||
this.events = require('./ui/UserInterface')(UI);
|
||||
}
|
||||
@@ -212,15 +223,129 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (modules[name]){
|
||||
modulesdata = modules[name][1];
|
||||
}
|
||||
if (modules[name])
|
||||
modulesdata = modules[name][1];
|
||||
else
|
||||
modulesdata = { 'inputs': sequences[name]['options'] };
|
||||
}
|
||||
return modulesdata;
|
||||
}
|
||||
|
||||
// Genates a CLI string for the current sequence
|
||||
function toCliString() {
|
||||
var cliStringSteps = `"`, cliOptions = {};
|
||||
for (var step in this.steps) {
|
||||
if (this.steps[step].options.name !== "load-image")
|
||||
cliStringSteps += `${this.steps[step].options.name} `;
|
||||
for (var inp in modulesInfo(this.steps[step].options.name).inputs) {
|
||||
cliOptions[inp] = this.steps[step].options[inp];
|
||||
}
|
||||
}
|
||||
cliStringSteps = cliStringSteps.substr(0, cliStringSteps.length - 1) + `"`;
|
||||
return `sequencer -i [PATH] -s ${cliStringSteps} -d '${JSON.stringify(cliOptions)}'`
|
||||
}
|
||||
|
||||
// Strigifies the current sequence
|
||||
function toString(step) {
|
||||
if (step) {
|
||||
return stepToString(step);
|
||||
} else {
|
||||
return copy(this.images.image1.steps).map(stepToString).slice(1).join(',');
|
||||
}
|
||||
}
|
||||
|
||||
// Stringifies one step of the sequence
|
||||
function stepToString(step) {
|
||||
let inputs = modulesInfo(step.options.name).inputs || {}, op = {};
|
||||
|
||||
for (let input in inputs) {
|
||||
|
||||
if (!!step.options[input] && step.options[input] != inputs[input].default) {
|
||||
op[input] = step.options[input];
|
||||
op[input] = encodeURIComponent(op[input]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var configurations = Object.keys(op).map(key => key + ':' + op[key]).join('|');
|
||||
return `${step.options.name}{${configurations}}`;
|
||||
}
|
||||
|
||||
// exports the current sequence as an array of JSON steps
|
||||
function toJSON() {
|
||||
return this.stringToJSON(this.toString());
|
||||
}
|
||||
|
||||
// Coverts stringified sequence into an array of JSON steps
|
||||
function stringToJSON(str) {
|
||||
let steps;
|
||||
if (str.includes(','))
|
||||
steps = str.split(',');
|
||||
else
|
||||
steps = [str];
|
||||
return steps.map(stringToJSONstep);
|
||||
}
|
||||
|
||||
// Converts one stringified step into JSON
|
||||
function stringToJSONstep(str) {
|
||||
var bracesStrings;
|
||||
if (str.includes('{'))
|
||||
if (str.includes('(') && str.indexOf('(') < str.indexOf('{'))
|
||||
bracesStrings = ['(', ')'];
|
||||
else
|
||||
bracesStrings = ['{', '}'];
|
||||
else
|
||||
bracesStrings = ['(', ')'];
|
||||
|
||||
if (str.indexOf(bracesStrings[0]) === -1) { // if there are no settings specified
|
||||
var moduleName = str.substr(0);
|
||||
stepSettings = "";
|
||||
} else {
|
||||
var moduleName = str.substr(0, str.indexOf(bracesStrings[0]));
|
||||
stepSettings = str.slice(str.indexOf(bracesStrings[0]) + 1, -1);
|
||||
}
|
||||
|
||||
stepSettings = stepSettings.split('|').reduce(function formatSettings(accumulator, current, i) {
|
||||
var settingName = current.substr(0, current.indexOf(':')),
|
||||
settingValue = current.substr(current.indexOf(':') + 1);
|
||||
settingValue = settingValue.replace(/^\(/, '').replace(/\)$/, ''); // strip () at start/end
|
||||
settingValue = settingValue.replace(/^\{/, '').replace(/\}$/, ''); // strip {} at start/end
|
||||
settingValue = decodeURIComponent(settingValue);
|
||||
current = [
|
||||
settingName,
|
||||
settingValue
|
||||
];
|
||||
if (!!settingName) accumulator[settingName] = settingValue;
|
||||
return accumulator;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
name: moduleName,
|
||||
options: stepSettings
|
||||
}
|
||||
}
|
||||
|
||||
// imports a string into the sequencer steps
|
||||
function importString(str) {
|
||||
let sequencer = this;
|
||||
if (this.name != "ImageSequencer")
|
||||
sequencer = this.sequencer;
|
||||
var stepsFromString = stringToJSON(str);
|
||||
stepsFromString.forEach(function eachStep(stepObj) {
|
||||
sequencer.addSteps(stepObj.name, stepObj.options);
|
||||
});
|
||||
}
|
||||
|
||||
// imports a array of JSON steps into the sequencer steps
|
||||
function importJSON(obj) {
|
||||
let sequencer = this;
|
||||
if (this.name != "ImageSequencer")
|
||||
sequencer = this.sequencer;
|
||||
obj.forEach(function eachStep(stepObj) {
|
||||
sequencer.addSteps(stepObj.name, stepObj.options);
|
||||
});
|
||||
}
|
||||
|
||||
function loadNewModule(name, options) {
|
||||
|
||||
if (!options) {
|
||||
@@ -257,6 +382,19 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
fs.writeFileSync('./src/Modules.js', mods);
|
||||
}
|
||||
|
||||
function createMetaModule(stepsCollection, info) {
|
||||
var stepsArr = stepsCollection;
|
||||
if (typeof stepsCollection === 'string')
|
||||
stepsArr = stringToJSON(stepsCollection);
|
||||
var metaMod = function() {
|
||||
this.expandSteps(stepsArr);
|
||||
return {
|
||||
isMeta: true
|
||||
}
|
||||
}
|
||||
return [metaMod, info];
|
||||
}
|
||||
|
||||
function saveSequence(name, sequenceString) {
|
||||
const sequence = stringToJSON(sequenceString);
|
||||
// Save the given sequence string as a module
|
||||
@@ -283,8 +421,6 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
this.sequences = require('./SavedSequences.json');
|
||||
}
|
||||
|
||||
var str = require('./Strings.js')(this.steps, modulesInfo, addSteps, copy)
|
||||
|
||||
return {
|
||||
//literals and objects
|
||||
name: "ImageSequencer",
|
||||
@@ -292,9 +428,8 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
inputlog: inputlog,
|
||||
modules: modules,
|
||||
sequences: sequences,
|
||||
images: images,
|
||||
events: events,
|
||||
steps: steps,
|
||||
image: image,
|
||||
|
||||
//user functions
|
||||
loadImages: loadImages,
|
||||
@@ -307,24 +442,20 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
setUI: setUI,
|
||||
exportBin: exportBin,
|
||||
modulesInfo: modulesInfo,
|
||||
toCliString: str.toCliString,
|
||||
detectStringSyntax: str.detectStringSyntax,
|
||||
parseStringSyntax: str.parseStringSyntax,
|
||||
stringToSteps: str.stringToSteps,
|
||||
toString: str.toString,
|
||||
stepToString: str.stepToString,
|
||||
toJSON: str.toJSON,
|
||||
stringToJSON: str.stringToJSON,
|
||||
stringToJSONstep: str.stringToJSONstep,
|
||||
importString: str.importString,
|
||||
importJSON: str.importJSON,
|
||||
toCliString: toCliString,
|
||||
toString: toString,
|
||||
stepToString: stepToString,
|
||||
toJSON: toJSON,
|
||||
stringToJSON: stringToJSON,
|
||||
stringToJSONstep: stringToJSONstep,
|
||||
importString: importString,
|
||||
importJSON: importJSON,
|
||||
loadNewModule: loadNewModule,
|
||||
saveNewModule: saveNewModule,
|
||||
createMetaModule: require('./util/createMetaModule'),
|
||||
createMetaModule: createMetaModule,
|
||||
saveSequence: saveSequence,
|
||||
loadModules: loadModules,
|
||||
getSteps:getSteps,
|
||||
|
||||
|
||||
//other functions
|
||||
log: log,
|
||||
objTypeOf: objTypeOf,
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
const getStepUtils = require('./util/getStep.js');
|
||||
|
||||
// insert one or more steps at a given index in the sequencer
|
||||
function InsertStep(ref, index, name, o) {
|
||||
function InsertStep(ref, image, index, name, o) {
|
||||
if (ref.sequences[name]) {
|
||||
return ref.importJSON(ref.sequences[name]);
|
||||
}
|
||||
|
||||
if (ref.detectStringSyntax(name)) {
|
||||
return ref.stringToSteps(name)
|
||||
}
|
||||
|
||||
function insertStep(index, name, o_) {
|
||||
function insertStep(image, index, name, o_) {
|
||||
if (ref.modules[name]) var moduleInfo = ref.modules[name][1];
|
||||
else {
|
||||
console.log('Module ' + name + ' not found.');
|
||||
}
|
||||
|
||||
var o = ref.copy(o_);
|
||||
|
||||
o.number = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
||||
o.name = o_.name || name || moduleInfo.name;
|
||||
o.description = o_.description || moduleInfo.description;
|
||||
o.selector = o_.selector || 'ismod-' + name;
|
||||
o.container = o_.container || ref.options.selector;
|
||||
o.image = image;
|
||||
o.inBrowser = ref.options.inBrowser;
|
||||
|
||||
if (index == -1) index = ref.steps.length;
|
||||
if (index == -1) index = ref.images[image].steps.length;
|
||||
|
||||
o.step = {
|
||||
name: o.name,
|
||||
description: o.description,
|
||||
ID: o.number,
|
||||
imageName: o.image,
|
||||
inBrowser: ref.options.inBrowser,
|
||||
ui: ref.options.ui,
|
||||
options: o
|
||||
@@ -41,7 +38,10 @@ function InsertStep(ref, index, name, o) {
|
||||
ref.modules[name].expandSteps = function expandSteps(stepsArray) {
|
||||
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']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ function InsertStep(ref, index, name, o) {
|
||||
|
||||
if (!ref.modules[name][1].length) {
|
||||
UI.onSetup(o.step, { index: index });
|
||||
ref.steps.splice(index, 0, ref.modules[name][0](o, UI));
|
||||
ref.images[image].steps.splice(index, 0, ref.modules[name][0](o, UI));
|
||||
} else {
|
||||
ref.modules[name][0](o, UI);
|
||||
}
|
||||
@@ -58,8 +58,8 @@ function InsertStep(ref, index, name, o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
insertStep(index, name, o);
|
||||
ref.steps = ref.steps;
|
||||
insertStep(image, index, name, o);
|
||||
ref.steps = ref.images[image].steps;
|
||||
|
||||
}
|
||||
module.exports = InsertStep;
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
* Core modules and their info files
|
||||
*/
|
||||
module.exports = {
|
||||
'add-qr': require('./modules/AddQR'),
|
||||
'average': require('./modules/Average'),
|
||||
'blend': require('./modules/Blend'),
|
||||
'blur': require('./modules/Blur'),
|
||||
'brightness': require('./modules/Brightness'),
|
||||
'canvas-resize': require('./modules/CanvasResize'),
|
||||
'channel': require('./modules/Channel'),
|
||||
'colorbar': require('./modules/Colorbar'),
|
||||
'color-temperature': require('./modules/ColorTemperature'),
|
||||
'colormap': require('./modules/Colormap'),
|
||||
'contrast': require('./modules/Contrast'),
|
||||
'convolution': require('./modules/Convolution'),
|
||||
@@ -20,26 +17,18 @@ module.exports = {
|
||||
'draw-rectangle': require('./modules/DrawRectangle'),
|
||||
'dynamic': require('./modules/Dynamic'),
|
||||
'edge-detect': require('./modules/EdgeDetect'),
|
||||
'exposure': require('./modules/Exposure'),
|
||||
'flip-image': require('./modules/FlipImage'),
|
||||
'fisheye-gl': require('./modules/FisheyeGl'),
|
||||
'histogram': require('./modules/Histogram'),
|
||||
'gamma-correction': require('./modules/GammaCorrection'),
|
||||
'gradient': require('./modules/Gradient'),
|
||||
'grid-overlay': require('./modules/GridOverlay'),
|
||||
'import-image': require('./modules/ImportImage'),
|
||||
'invert': require('image-sequencer-invert'),
|
||||
'ndvi': require('./modules/Ndvi'),
|
||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||
'paint-bucket': require('./modules/PaintBucket'),
|
||||
'overlay': require('./modules/Overlay'),
|
||||
'replace-color': require('./modules/ReplaceColor'),
|
||||
'resize': require('./modules/Resize'),
|
||||
'rotate': require('./modules/Rotate'),
|
||||
'saturation': require('./modules/Saturation'),
|
||||
'text-overlay': require('./modules/TextOverlay'),
|
||||
'threshold': require('./modules/Threshold'),
|
||||
'tint': require('./modules/Tint'),
|
||||
'webgl-distort': require('./modules/WebglDistort'),
|
||||
'white-balance': require('./modules/WhiteBalance')
|
||||
}
|
||||
|
||||
@@ -42,11 +42,7 @@ function ReplaceImage(ref,selector,steps,options) {
|
||||
|
||||
function make(url) {
|
||||
tempSequencer.loadImage(url, function(){
|
||||
// this.addSteps(steps).run({stop:function(){}},function(out){
|
||||
var sequence = this.addSteps(steps)
|
||||
if (ref.detectStringSyntax(steps))
|
||||
sequence = this.stringToSteps(steps)
|
||||
sequence.run({stop:function(){}},function(out){
|
||||
this.addSteps(steps).run({stop:function(){}},function(out){
|
||||
img.src = out;
|
||||
});
|
||||
});
|
||||
|
||||
60
src/Run.js
60
src/Run.js
@@ -5,8 +5,9 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
||||
|
||||
function drawStep(drawarray, pos) {
|
||||
if (pos == drawarray.length && drawarray[pos - 1] !== undefined) {
|
||||
if (ref.objTypeOf(callback) == "Function" && ref.steps.slice(-1)[0].output) {
|
||||
var steps = ref.steps;
|
||||
var image = drawarray[pos - 1].image;
|
||||
if (ref.objTypeOf(callback) == "Function" && ref.images[image].steps.slice(-1)[0].output) {
|
||||
var steps = ref.images[image].steps;
|
||||
var out = steps[steps.length - 1].output.src;
|
||||
callback(out);
|
||||
return true;
|
||||
@@ -15,39 +16,39 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
||||
|
||||
// so we don't run on the loadImage module:
|
||||
if (drawarray[pos] !== undefined) {
|
||||
var image = drawarray[pos].image;
|
||||
var i = drawarray[pos].i;
|
||||
var input = ref.steps[i - 1].output;
|
||||
var step = ref.steps[i];
|
||||
var input = ref.images[image].steps[i - 1].output;
|
||||
|
||||
step.getStep = function getStep(offset) {
|
||||
if (i + offset >= ref.steps.length) return { options: { name: undefined } };
|
||||
else return ref.steps.slice(i + offset)[0];
|
||||
ref.images[image].steps[i].getStep = function getStep(offset) {
|
||||
if (i + offset >= ref.images[image].steps.length) return { options: { name: undefined } };
|
||||
else return ref.images[image].steps.slice(i + offset)[0];
|
||||
};
|
||||
step.getIndex = function getIndex() {
|
||||
ref.images[image].steps[i].getIndex = function getIndex() {
|
||||
return i;
|
||||
}
|
||||
|
||||
for (var util in getStepUtils) {
|
||||
if (getStepUtils.hasOwnProperty(util)) {
|
||||
step[util] = getStepUtils[util];
|
||||
ref.images[image].steps[i][util] = getStepUtils[util];
|
||||
}
|
||||
}
|
||||
|
||||
// Tell UI that a step is being drawn.
|
||||
step.UI.onDraw(step.options.step);
|
||||
ref.images[image].steps[i].UI.onDraw(ref.images[image].steps[i].options.step);
|
||||
|
||||
// provides a set of standard tools for each step
|
||||
var inputForNextStep = require('./RunToolkit')(ref.copy(input));
|
||||
|
||||
step.draw(
|
||||
ref.images[image].steps[i].draw(
|
||||
inputForNextStep,
|
||||
function onEachStep() {
|
||||
|
||||
// This output is accessible by UI
|
||||
ref.steps[i].options.step.output = ref.steps[i].output.src;
|
||||
// This output is accessible by UI
|
||||
ref.images[image].steps[i].options.step.output = ref.images[image].steps[i].output.src;
|
||||
|
||||
// Tell UI that step has been drawn.
|
||||
ref.steps[i].UI.onComplete(ref.steps[i].options.step);
|
||||
ref.images[image].steps[i].UI.onComplete(ref.images[image].steps[i].options.step);
|
||||
|
||||
drawStep(drawarray, ++pos);
|
||||
},
|
||||
@@ -57,33 +58,36 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
||||
}
|
||||
|
||||
function drawSteps(json_q) {
|
||||
var drawarray = [],
|
||||
no_steps = ref.steps.length,
|
||||
init = json_q[0];
|
||||
var drawarray = [];
|
||||
for (var image in json_q) {
|
||||
var no_steps = ref.images[image].steps.length;
|
||||
var init = json_q[image];
|
||||
for (var i = 0; i < no_steps - init; i++) {
|
||||
drawarray.push({i: init + i });
|
||||
drawarray.push({ image: image, i: init + i });
|
||||
}
|
||||
}
|
||||
drawStep(drawarray, ind);
|
||||
}
|
||||
|
||||
function filter(json_q) {
|
||||
|
||||
if (json_q[0] == 0 && ref.steps.length == 1)
|
||||
delete json_q[0];
|
||||
else if (json_q[0] == 0) json_q[0]++;
|
||||
var prevstep = ref.steps[json_q[0] - 1];
|
||||
for (var image in json_q) {
|
||||
if (json_q[image] == 0 && ref.images[image].steps.length == 1)
|
||||
delete json_q[image];
|
||||
else if (json_q[image] == 0) json_q[image]++;
|
||||
}
|
||||
for (var image in json_q) {
|
||||
var prevstep = ref.images[image].steps[json_q[image] - 1];
|
||||
while (
|
||||
typeof prevstep == "undefined" ||
|
||||
typeof prevstep.output == "undefined"
|
||||
) {
|
||||
prevstep = ref.steps[--json_q[0] - 1];
|
||||
) {
|
||||
prevstep = ref.images[image].steps[--json_q[image] - 1];
|
||||
}
|
||||
|
||||
}
|
||||
return json_q;
|
||||
}
|
||||
|
||||
|
||||
var json_q = filter(json_q);
|
||||
|
||||
return drawSteps(json_q);
|
||||
}
|
||||
module.exports = Run;
|
||||
|
||||
159
src/Strings.js
159
src/Strings.js
@@ -1,159 +0,0 @@
|
||||
module.exports = function(steps, modulesInfo, addSteps, copy) {
|
||||
// Genates a CLI string for the current sequence
|
||||
function toCliString() {
|
||||
var cliStringSteps = `"`, cliOptions = {};
|
||||
for (var step in this.steps) {
|
||||
var name = (typeof this.steps[step].options !== "undefined")? this.steps[step].options.name : this.steps[step].name
|
||||
if (name !== "load-image"){
|
||||
cliStringSteps += `${name} `;
|
||||
}
|
||||
for (var inp in modulesInfo(name).inputs) {
|
||||
cliOptions[inp] = this.steps[step].options[inp];
|
||||
}
|
||||
}
|
||||
cliStringSteps = cliStringSteps.substr(0, cliStringSteps.length - 1) + `"`;
|
||||
return `sequencer -i [PATH] -s ${cliStringSteps} -d '${JSON.stringify(cliOptions)}'`
|
||||
}
|
||||
|
||||
// Checks if input is a string of comma separated module names
|
||||
function detectStringSyntax(str) {
|
||||
let result = (str.includes(',') || str.includes('{')) ? true : false
|
||||
return result
|
||||
}
|
||||
|
||||
// Parses input string and returns array of module names
|
||||
function parseStringSyntax(str) {
|
||||
let stringifiedNames = str.replace(/\s/g, '')
|
||||
let moduleNames = stringifiedNames.split(',')
|
||||
return moduleNames
|
||||
}
|
||||
|
||||
// imports string of comma separated module names to sequencer steps
|
||||
function stringToSteps(str) {
|
||||
let sequencer = this;
|
||||
let names = []
|
||||
if (this.name != "ImageSequencer")
|
||||
sequencer = this.sequencer;
|
||||
if (detectStringSyntax(str))
|
||||
names = stringToJSON(str)
|
||||
names.forEach(function eachStep(stepObj) {
|
||||
sequencer.addSteps(stepObj.name, stepObj.options)
|
||||
})
|
||||
}
|
||||
|
||||
// Strigifies the current sequence
|
||||
function toString(step) {
|
||||
if (step) {
|
||||
return stepToString(step);
|
||||
} else {
|
||||
return copy(this.steps.map(stepToString).slice(1).join(','));
|
||||
}
|
||||
}
|
||||
|
||||
// Stringifies one step of the sequence
|
||||
function stepToString(step) {
|
||||
var arg = (step.name)?step.name:step.options.name;
|
||||
let inputs = modulesInfo(arg).inputs || {}, op = {};
|
||||
|
||||
for (let input in inputs) {
|
||||
|
||||
if (!!step.options[input] && step.options[input] != inputs[input].default) {
|
||||
op[input] = step.options[input];
|
||||
op[input] = encodeURIComponent(op[input]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var configurations = Object.keys(op).map(key => key + ':' + op[key]).join('|');
|
||||
return `${arg}{${configurations}}`;
|
||||
}
|
||||
|
||||
// exports the current sequence as an array of JSON steps
|
||||
function toJSON() {
|
||||
return this.stringToJSON(this.toString());
|
||||
}
|
||||
|
||||
// Coverts stringified sequence into an array of JSON steps
|
||||
function stringToJSON(str) {
|
||||
let steps;
|
||||
if (detectStringSyntax(str))
|
||||
steps = parseStringSyntax(str);
|
||||
else
|
||||
steps = [str];
|
||||
return steps.map(stringToJSONstep);
|
||||
}
|
||||
|
||||
// Converts one stringified step into JSON
|
||||
function stringToJSONstep(str) {
|
||||
var bracesStrings;
|
||||
if (str.includes('{'))
|
||||
if (str.includes('(') && str.indexOf('(') < str.indexOf('{'))
|
||||
bracesStrings = ['(', ')'];
|
||||
else
|
||||
bracesStrings = ['{', '}'];
|
||||
else
|
||||
bracesStrings = ['(', ')'];
|
||||
|
||||
if (str.indexOf(bracesStrings[0]) === -1) { // if there are no settings specified
|
||||
var moduleName = str.substr(0);
|
||||
stepSettings = "";
|
||||
} else {
|
||||
var moduleName = str.substr(0, str.indexOf(bracesStrings[0]));
|
||||
stepSettings = str.slice(str.indexOf(bracesStrings[0]) + 1, -1);
|
||||
}
|
||||
|
||||
stepSettings = stepSettings.split('|').reduce(function formatSettings(accumulator, current, i) {
|
||||
var settingName = current.substr(0, current.indexOf(':')),
|
||||
settingValue = current.substr(current.indexOf(':') + 1);
|
||||
settingValue = settingValue.replace(/^\(/, ''); // strip () at start/end
|
||||
settingValue = settingValue.replace(/^\{/, '').replace(/\}$/, ''); // strip {} at start/end
|
||||
settingValue = decodeURIComponent(settingValue);
|
||||
current = [
|
||||
settingName,
|
||||
settingValue
|
||||
];
|
||||
if (!!settingName) accumulator[settingName] = settingValue;
|
||||
return accumulator;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
name: moduleName,
|
||||
options: stepSettings
|
||||
}
|
||||
}
|
||||
|
||||
// imports a string into the sequencer steps
|
||||
function importString(str) {
|
||||
let sequencer = this;
|
||||
if (this.name != "ImageSequencer")
|
||||
sequencer = this.sequencer;
|
||||
var stepsFromString = stringToJSON(str);
|
||||
stepsFromString.forEach(function eachStep(stepObj) {
|
||||
sequencer.addSteps(stepObj.name, stepObj.options);
|
||||
});
|
||||
}
|
||||
|
||||
// imports a array of JSON steps into the sequencer steps
|
||||
function importJSON(obj) {
|
||||
let sequencer = this;
|
||||
if (this.name != "ImageSequencer")
|
||||
sequencer = this.sequencer;
|
||||
obj.forEach(function eachStep(stepObj) {
|
||||
sequencer.addSteps(stepObj.name, stepObj.options);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
toCliString: toCliString,
|
||||
detectStringSyntax: detectStringSyntax,
|
||||
parseStringSyntax: parseStringSyntax,
|
||||
stringToSteps: stringToSteps,
|
||||
toString: toString,
|
||||
stepToString: stepToString,
|
||||
toJSON: toJSON,
|
||||
stringToJSON: stringToJSON,
|
||||
stringToJSONstep: stringToJSONstep,
|
||||
importString: importString,
|
||||
importJSON: importJSON
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
var childProcess = require('child_process')
|
||||
var Spinner = require('ora');
|
||||
|
||||
module.exports = function (program, sequencer) {
|
||||
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();
|
||||
childProcess.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!!");
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = function (program, sequencer) {
|
||||
|
||||
var params = program.saveSequence.split(' ');
|
||||
sequencer.saveSequence(params[0], params[1]);
|
||||
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
var Spinner = require('ora');
|
||||
var readlineSync = require('readline-sync');
|
||||
var utils = require('../CliUtils')
|
||||
|
||||
module.exports = function (program, sequencer, outputFilename) {
|
||||
utils.makedir(program.output, () => {
|
||||
console.log('Files will be exported to "' + program.output + '"');
|
||||
|
||||
if (program.basic)
|
||||
console.log("Basic mode is enabled, outputting only final image");
|
||||
|
||||
// Iterate through the steps and retrieve their inputs.
|
||||
program.step.forEach(function(step) {
|
||||
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
||||
|
||||
// If inputs exists, print to console.
|
||||
if (Object.keys(options).length) {
|
||||
console.log("[" + step + "]: Inputs");
|
||||
}
|
||||
|
||||
// If inputs exists, print them out with descriptions.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
||||
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||
console.log(
|
||||
new Array(step.length + 5).join(" ") +
|
||||
input +
|
||||
": " +
|
||||
options[input].desc
|
||||
);
|
||||
});
|
||||
|
||||
if (program.config) {
|
||||
try {
|
||||
var config = JSON.parse(program.config);
|
||||
console.log(`The parsed options object: `, config);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options(Config) is not a not valid JSON Fallback activate`
|
||||
);
|
||||
program.config = false;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
if (program.config && utils.validateConfig(config, options)) {
|
||||
console.log("Now using Options object");
|
||||
Object.keys(options).forEach(function(input) {
|
||||
options[input] = config[input];
|
||||
});
|
||||
} else {
|
||||
// If inputs exist, iterate through them and prompt for values.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
var value = readlineSync.question(
|
||||
"[" +
|
||||
step +
|
||||
"]: Enter a value for " +
|
||||
input +
|
||||
" (" +
|
||||
options[input].type +
|
||||
", default: " +
|
||||
options[input].default +
|
||||
"): "
|
||||
);
|
||||
options[input] = value;
|
||||
});
|
||||
}
|
||||
// Add the step and its inputs to the sequencer.
|
||||
sequencer.addSteps(step, options);
|
||||
});
|
||||
|
||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||
if (!process.env.TEST)
|
||||
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||
|
||||
// Run the sequencer.
|
||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||
// Export all images or final image as binary files.
|
||||
sequencer.exportBin(program.output, program.basic, outputFilename);
|
||||
|
||||
//check if spinner was not overriden stop it
|
||||
if (!spinnerObj.overrideFlag) {
|
||||
spinnerObj.succeed();
|
||||
console.log(`\nDone!!`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
module.exports = function AddQR(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
options.size = options.size || defaults.size;
|
||||
options.qrCodeString = options.qrCodeString || "https://github.com/publiclab/image-sequencer";
|
||||
var output;
|
||||
getPixels = require('get-pixels');
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
return getPixels(input.src, function (err, oldPixels) {
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a];
|
||||
}
|
||||
|
||||
function extraManipulation(pixels,generateOutput) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
require('./QR')(options, pixels, oldPixels, generateOutput);
|
||||
}
|
||||
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,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
module.exports = exports = function (options, pixels, oldPixels, callback) {
|
||||
var QRCode = require('qrcode')
|
||||
QRCode.toDataURL(options.qrCodeString, function (err, url) {
|
||||
var getPixels = require("get-pixels");
|
||||
getPixels(url, function (err, qrPixels) {
|
||||
if (err) {
|
||||
console.log("Bad image path", image);
|
||||
}
|
||||
|
||||
var imagejs = require('imagejs');
|
||||
var bitmap = new imagejs.Bitmap({ width: qrPixels.shape[0], height: qrPixels.shape[1] });
|
||||
bitmap._data.data = qrPixels.data;
|
||||
var resized = bitmap.resize({
|
||||
width: options.size, height: options.size,
|
||||
algorithm: "bicubicInterpolation"
|
||||
});
|
||||
|
||||
qrPixels.data = resized._data.data;
|
||||
qrPixels.shape = [options.size, options.size, 4];
|
||||
qrPixels.stride[1] = 4 * options.size;
|
||||
|
||||
var width = oldPixels.shape[0],
|
||||
height = oldPixels.shape[1];
|
||||
var xe = width - options.size,
|
||||
ye = height - options.size;
|
||||
for (var m = 0; m < width; m++) {
|
||||
for (var n = 0; n < height; n++) {
|
||||
if (m >= xe && n >= ye) {
|
||||
pixels.set(m, n, 0, qrPixels.get(m - xe, n - ye, 0))
|
||||
pixels.set(m, n, 1, qrPixels.get(m - xe, n - ye, 1))
|
||||
pixels.set(m, n, 2, qrPixels.get(m - xe, n - ye, 2))
|
||||
pixels.set(m, n, 3, qrPixels.get(m - xe, n - ye, 3))
|
||||
}
|
||||
|
||||
else {
|
||||
pixels.set(m, n, 0, oldPixels.get(m, n, 0))
|
||||
pixels.set(m, n, 1, oldPixels.get(m, n, 1))
|
||||
pixels.set(m, n, 2, oldPixels.get(m, n, 2))
|
||||
pixels.set(m, n, 3, oldPixels.get(m, n, 3))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
callback();
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "Add QR",
|
||||
"description": "Adds QR corresponding to the given string",
|
||||
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||
"inputs": {
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"desc": "size of QR code in pixels",
|
||||
"default": 200
|
||||
},
|
||||
"qrCodeString":{
|
||||
"type": "string",
|
||||
"desc": "input string to generate QR code",
|
||||
"default": "https://github.com/publiclab/image-sequencer"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#add-qr-module"
|
||||
}
|
||||
|
||||
@@ -1,63 +1,65 @@
|
||||
/*
|
||||
* Average all pixel colors
|
||||
*/
|
||||
module.exports = function Average(options, UI) {
|
||||
module.exports = function Average(options, UI){
|
||||
|
||||
options.blur = options.blur || 2
|
||||
var output;
|
||||
|
||||
options.step.metadata = options.step.metadata || {};
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
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]
|
||||
}
|
||||
|
||||
// do the averaging
|
||||
function extraManipulation(pixels) {
|
||||
var i = 0, sum = [0, 0, 0, 0];
|
||||
while (i < pixels.data.length) {
|
||||
sum[0] += pixels.data[i++];
|
||||
sum[1] += pixels.data[i++];
|
||||
sum[2] += pixels.data[i++];
|
||||
sum[3] += pixels.data[i++];
|
||||
function extraManipulation(pixels){
|
||||
var sum = [0,0,0,0];
|
||||
for (var i = 0; i < pixels.data.length; i += 4) {
|
||||
sum[0] += pixels.data[i + 0];
|
||||
sum[1] += pixels.data[i + 1];
|
||||
sum[2] += pixels.data[i + 2];
|
||||
sum[3] += pixels.data[i + 3];
|
||||
}
|
||||
|
||||
let divisor = pixels.data.length / 4;
|
||||
sum[0] = parseInt(sum[0] / (pixels.data.length / 4));
|
||||
sum[1] = parseInt(sum[1] / (pixels.data.length / 4));
|
||||
sum[2] = parseInt(sum[2] / (pixels.data.length / 4));
|
||||
sum[3] = parseInt(sum[3] / (pixels.data.length / 4));
|
||||
|
||||
sum[0] = Math.floor(sum[0] / divisor);
|
||||
sum[1] = Math.floor(sum[1] / divisor);
|
||||
sum[2] = Math.floor(sum[2] / divisor);
|
||||
sum[3] = Math.floor(sum[3] / divisor);
|
||||
|
||||
i = 0
|
||||
while (i < pixels.data.length) {
|
||||
pixels.data[i++] = sum[0];
|
||||
pixels.data[i++] = sum[1];
|
||||
pixels.data[i++] = sum[2];
|
||||
pixels.data[i++] = sum[3];
|
||||
for (var i = 0; i < pixels.data.length; i += 4) {
|
||||
pixels.data[i + 0] = sum[0];
|
||||
pixels.data[i + 1] = sum[1];
|
||||
pixels.data[i + 2] = sum[2];
|
||||
pixels.data[i + 3] = sum[3];
|
||||
}
|
||||
|
||||
// report back and store average in metadata:
|
||||
options.step.metadata.averages = sum;
|
||||
|
||||
console.log("average: ", sum);
|
||||
// TODO: refactor into a new "display()" method as per https://github.com/publiclab/image-sequencer/issues/242
|
||||
if (options.step.inBrowser && options.step.ui) $(options.step.ui).find('.details').append("<p><b>Averages</b> (r, g, b, a): " + sum.join(', ') + "</p>");
|
||||
return pixels;
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
function output(image, datauri, mimetype){
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = {
|
||||
src: datauri,
|
||||
format: mimetype
|
||||
src: datauri,
|
||||
format: mimetype
|
||||
};
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
@@ -67,7 +69,7 @@ module.exports = function Average(options, UI) {
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"description": "Average all pixel color",
|
||||
"inputs": {
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#average-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
module.exports = function Dynamic(options, UI, util) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
options.func = options.func || defaults.blend;
|
||||
options.offset = options.offset || defaults.offset;
|
||||
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;
|
||||
|
||||
@@ -21,14 +19,14 @@ module.exports = function Dynamic(options, UI, util) {
|
||||
var getPixels = require('get-pixels');
|
||||
|
||||
// convert offset as string to int
|
||||
if (typeof options.offset === "string") options.offset = parseInt(options.offset);
|
||||
if(typeof options.offset === "string") options.offset = parseInt(options.offset);
|
||||
|
||||
// save first image's pixels
|
||||
var priorStep = this.getStep(options.offset);
|
||||
|
||||
if (priorStep.output === undefined) {
|
||||
this.output = input;
|
||||
UI.notify('Offset Unavailable', 'offset-notification');
|
||||
UI.notify('Offset Unavailable','offset-notification');
|
||||
callback();
|
||||
}
|
||||
|
||||
@@ -37,7 +35,7 @@ module.exports = function Dynamic(options, UI, util) {
|
||||
|
||||
function changePixel(r2, g2, b2, a2, x, y) {
|
||||
// blend!
|
||||
let p = options.firstImagePixels;
|
||||
var p = options.firstImagePixels;
|
||||
return options.func(
|
||||
r2, g2, b2, a2,
|
||||
p.get(x, y, 0),
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
"default": -2
|
||||
},
|
||||
"blend": {
|
||||
"type": "string",
|
||||
"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#blend-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = exports = function(pixels, blur) {
|
||||
let kernel = kernelGenerator(blur, 1), oldpix = require('lodash').cloneDeep(pixels);
|
||||
let kernel = kernelGenerator(blur, 1), oldpix = pixels;
|
||||
kernel = flipKernel(kernel);
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
module.exports = function Blur(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
options.blur = options.blur || defaults.blur;
|
||||
options.blur = options.blur || 2
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
@@ -14,9 +13,13 @@ module.exports = function Blur(options, UI) {
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./Blur')(pixels, options.blur);
|
||||
return pixels;
|
||||
pixels = require('./Blur')(pixels, options.blur)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
@@ -28,6 +31,7 @@ module.exports = function Blur(options, UI) {
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
"description": "Applies a Gaussian blur given by the intensity value",
|
||||
"inputs": {
|
||||
"blur": {
|
||||
"type": "float",
|
||||
"type": "range",
|
||||
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"max": 5,
|
||||
"step": 0.25
|
||||
"default": "2",
|
||||
"min": "0",
|
||||
"max": "5",
|
||||
"step": "0.25"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blur-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
/*
|
||||
* Changes the Image Brightness
|
||||
*/
|
||||
module.exports = function Brightness(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
module.exports = function Brightness(options,UI){
|
||||
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.brightness = options.brightness || defaults.brightness;
|
||||
|
||||
options.brightness = parseInt(options.brightness) || 100;
|
||||
var val = (options.brightness)/100.0;
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
@@ -21,20 +20,20 @@ module.exports = function Brightness(options, UI) {
|
||||
For eg. progressObj = new SomeProgressModule()
|
||||
*/
|
||||
|
||||
var step = this, val = (options.brightness) / 100.0;;
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
function changePixel(r, g, b, a){
|
||||
|
||||
r = Math.min(val * r, 255);
|
||||
g = Math.min(val * g, 255);
|
||||
b = Math.min(val * b, 255);
|
||||
return [r, g, b, a];
|
||||
r = Math.min(val*r, 255)
|
||||
g = Math.min(val*g, 255)
|
||||
b = Math.min(val*b, 255)
|
||||
return [r, g, b, 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};
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +49,7 @@ module.exports = function Brightness(options, UI) {
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
"description": "Change the brightness of the image by given percent value",
|
||||
"inputs": {
|
||||
"brightness": {
|
||||
"type": "integer",
|
||||
"type": "range",
|
||||
"desc": "% brightness for the new image",
|
||||
"default": "175",
|
||||
"min": "0",
|
||||
"max": "200"
|
||||
"max": "200",
|
||||
"step": "1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#brightness-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Changes the Canvas Size
|
||||
*/
|
||||
module.exports = function canvasResize(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
var output;
|
||||
|
||||
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.width = options.width || defaults.width;
|
||||
options.height = options.height || defaults.height;
|
||||
options.x = options.x || defaults.x;
|
||||
options.y = options.y || defaults.y;
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
|
||||
let newPixels = require('ndarray')(new Uint8Array(4 * options.width * options.height).fill(255), [options.width, options.height, 4]);
|
||||
let iMax = options.width - options.x,
|
||||
jMax = options.height - options.y;
|
||||
for (let i = 0; i < iMax && i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < jMax && j < pixels.shape[1]; j++) {
|
||||
let x = i + options.x, y = j + options.y;
|
||||
newPixels.set(x, y, 0, pixels.get(i, j, 0));
|
||||
newPixels.set(x, y, 1, pixels.get(i, j, 1));
|
||||
newPixels.set(x, y, 2, pixels.get(i, j, 2));
|
||||
newPixels.set(x, y, 3, pixels.get(i, j, 3));
|
||||
}
|
||||
}
|
||||
return newPixels;
|
||||
}
|
||||
|
||||
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,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"name": "Resize Canvas",
|
||||
"description": "This module resizes the canvas and overlays the ouput of the previous step at given location",
|
||||
"inputs": {
|
||||
"width": {
|
||||
"type": "integer",
|
||||
"desc": "Final width of the canvas",
|
||||
"default": 1000
|
||||
},
|
||||
"height": {
|
||||
"type": "integer",
|
||||
"desc": "Final height of the canvas",
|
||||
"default": 1000
|
||||
},
|
||||
"x": {
|
||||
"type": "integer",
|
||||
"desc": "X-cord of the top left corner of the image on the canvas",
|
||||
"default": 500
|
||||
},
|
||||
"y": {
|
||||
"type": "float",
|
||||
"desc": "Y-cord of the top left corner of the image on the canvas",
|
||||
"default": 500
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@
|
||||
*/
|
||||
module.exports = function Channel(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
options.channel = options.channel || defaults.channel;
|
||||
options.channel = options.channel || "green";
|
||||
|
||||
var output;
|
||||
|
||||
@@ -17,9 +15,9 @@ module.exports = function Channel(options, UI) {
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
if (options.channel === "red") return [r, 0, 0, a];
|
||||
if (options.channel === "green") return [0, g, 0, a];
|
||||
if (options.channel === "blue") return [0, 0, b, a];
|
||||
if (options.channel == "red") return [r, 0, 0, a];
|
||||
if (options.channel == "green") return [0, g, 0, a];
|
||||
if (options.channel == "blue") return [0, 0, b, a];
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"values": ["red", "green", "blue"]
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#channel-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
module.exports = function ColorTemperature(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
options.temperature = (options.temperature > "40000") ? "40000" : options.temperature
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
|
||||
let temp = parseInt(options.temperature)
|
||||
temp /= 100
|
||||
|
||||
let r, g, b;
|
||||
|
||||
if (temp <= 66) {
|
||||
r = 255;
|
||||
g = Math.min(Math.max(99.4708025861 * Math.log(temp) - 161.1195681661, 0), 255);
|
||||
} else {
|
||||
r = Math.min(Math.max(329.698727446 * Math.pow(temp - 60, -0.1332047592), 0), 255);
|
||||
g = Math.min(Math.max(288.1221695283 * Math.pow(temp - 60, -0.0755148492), 0), 255);
|
||||
}
|
||||
|
||||
if (temp >= 66) {
|
||||
b = 255;
|
||||
} else if (temp <= 19) {
|
||||
b = 0;
|
||||
} else {
|
||||
b = temp - 10;
|
||||
b = Math.min(Math.max(138.5177312231 * Math.log(b) - 305.0447927307, 0), 255);
|
||||
}
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||
|
||||
r_data = pixels.get(i, j, 0)
|
||||
r_new_data = (255 / r) * r_data
|
||||
pixels.set(i, j, 0, r_new_data)
|
||||
|
||||
g_data = pixels.get(i, j, 1)
|
||||
g_new_data = (255 / g) * g_data
|
||||
pixels.set(i, j, 1, g_new_data)
|
||||
|
||||
b_data = pixels.get(i, j, 2)
|
||||
b_new_data = (255 / b) * b_data
|
||||
pixels.set(i, j, 2, b_new_data)
|
||||
}
|
||||
}
|
||||
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "Color Temperature",
|
||||
"description": "Changes the color temperature of the image.",
|
||||
"inputs": {
|
||||
"temperature": {
|
||||
"type": "integer",
|
||||
"desc": "Temperature between 0 - 40,000 Kelvin",
|
||||
"default": 6000
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#color-temperature"
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
module.exports = require('../../util/createMetaModule.js')(
|
||||
function mapFunction(options) {
|
||||
module.exports = function NdviColormapfunction(options, UI) {
|
||||
|
||||
// return steps with options:
|
||||
return [
|
||||
{ 'name': 'gradient', 'options': {} },
|
||||
{ 'name': 'colormap', 'options': { colormap: options.colormap } },
|
||||
{ 'name': 'crop', 'options': { 'y': 0, 'h': options.h } },
|
||||
{ 'name': 'overlay', 'options': { 'x': options.x, 'y': options.y, 'offset': -4 } }
|
||||
];
|
||||
}, {
|
||||
infoJson: require('./info.json')
|
||||
}
|
||||
)[0];
|
||||
options.x = options.x || 0;
|
||||
options.y = options.y || 0;
|
||||
options.colormap = options.colormap || "default";
|
||||
options.h = options.h || 10;
|
||||
this.expandSteps([
|
||||
{ 'name': 'gradient', 'options': {} },
|
||||
{ 'name': 'colormap', 'options': { colormap: options.colormap } },
|
||||
{ 'name': 'crop', 'options': { 'y': 0, 'h': options.h } },
|
||||
{ 'name': 'overlay', 'options': { 'x': options.x, 'y': options.y, 'offset': -4 } }
|
||||
]);
|
||||
return {
|
||||
isMeta: true
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,11 @@
|
||||
"default": 0
|
||||
},
|
||||
"h": {
|
||||
"type": "integer",
|
||||
"type": "iinteger",
|
||||
"desc": "height of the colorbar",
|
||||
"default": 10
|
||||
}
|
||||
},
|
||||
"docs-link": "https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#colorbar-module"
|
||||
}
|
||||
"length": 4,
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
module.exports = function Colormap(options, UI) {
|
||||
module.exports = function Colormap(options,UI) {
|
||||
|
||||
var output;
|
||||
|
||||
// This function is called on every draw.
|
||||
function draw(input, callback, progressObj) {
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
@@ -16,7 +16,7 @@ module.exports = function Colormap(options, UI) {
|
||||
return [res[0], res[1], res[2], 255];
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
function output(image,datauri,mimetype){
|
||||
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"values": ["default","greyscale","bluwhtgrngis","stretched","fastie","brntogrn","blutoredjet","colors16"]
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#colormap-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = exports = function(pixels, contrast) {
|
||||
let oldpix = _.cloneDeep(pixels);
|
||||
module.exports = exports = function(pixels , contrast){
|
||||
let oldpix = _.cloneDeep(pixels);
|
||||
contrast = Number(contrast)
|
||||
if (contrast < -100) contrast = -100;
|
||||
if (contrast < -100) contrast = -100;
|
||||
if (contrast > 100) contrast = 100;
|
||||
contrast = (100.0 + contrast) / 100.0;
|
||||
contrast *= contrast;
|
||||
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||
var r = oldpix.get(i, j, 0) / 255.0;
|
||||
r -= 0.5;
|
||||
|
||||
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 += 0.5;
|
||||
r *= 255;
|
||||
if (r < 0) r = 0;
|
||||
if (r > 255) r = 255;
|
||||
|
||||
|
||||
var g = oldpix.get(i, j, 1) / 255.0;
|
||||
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;
|
||||
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);
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
module.exports = function Contrast(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
options.contrast = options.contrast || defaults.contrast;
|
||||
options.contrast = options.contrast || 70
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
@@ -15,6 +14,10 @@ module.exports = function Contrast(options, UI) {
|
||||
|
||||
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
|
||||
@@ -29,6 +32,7 @@ module.exports = function Contrast(options, UI) {
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
"description": "Change the contrast of the image by given value",
|
||||
"inputs": {
|
||||
"contrast": {
|
||||
"type": "integer",
|
||||
"type": "range",
|
||||
"desc": "contrast for the new image, typically -100 to 100",
|
||||
"default": 70,
|
||||
"min": -100,
|
||||
"max": 100
|
||||
"default": "70",
|
||||
"min": "-100",
|
||||
"max": "100",
|
||||
"step": "1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#contrast-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
var _ = require('lodash');
|
||||
module.exports = exports = function(pixels, constantFactor, kernelValues) {
|
||||
let kernel = kernelGenerator(constantFactor, kernelValues), oldpix = _.cloneDeep(pixels);
|
||||
kernel = flipKernel(kernel);
|
||||
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 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];
|
||||
@@ -15,9 +15,9 @@ module.exports = exports = function(pixels, constantFactor, kernelValues) {
|
||||
acc[3] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 3) * kernel[a][b]);
|
||||
}
|
||||
}
|
||||
acc[0] = Math.min(acc[0], 255);
|
||||
acc[1] = Math.min(acc[1], 255);
|
||||
acc[2] = Math.min(acc[2], 255);
|
||||
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]);
|
||||
@@ -26,25 +26,25 @@ module.exports = exports = function(pixels, constantFactor, kernelValues) {
|
||||
return pixels;
|
||||
|
||||
|
||||
function kernelGenerator(constantFactor, kernelValues) {
|
||||
kernelValues = kernelValues.split(" ");
|
||||
for (i = 0; i < 9; i++) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
function getNeighbouringPixelPositions(pixelPosition) {
|
||||
let x = pixelPosition[0], y = pixelPosition[1], result = [];
|
||||
|
||||
for (let i = -1; i <= 1; i++) {
|
||||
@@ -57,7 +57,7 @@ module.exports = exports = function(pixels, constantFactor, kernelValues) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function flipKernel(kernel) {
|
||||
function flipKernel(kernel) {
|
||||
let result = [];
|
||||
for (let i = kernel.length - 1; i >= 0; i--) {
|
||||
let arr = [];
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
module.exports = function Convolution(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
options.kernelValues = options.kernelValues || defaults.kernelValues;
|
||||
options.constantFactor = options.constantFactor || defaults.constantFactor;
|
||||
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) {
|
||||
@@ -13,9 +11,13 @@ module.exports = function Convolution(options, UI) {
|
||||
|
||||
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;
|
||||
pixels = require('./Convolution')(pixels, options.constantFactor, options.kernelValues)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
@@ -26,6 +28,7 @@ module.exports = function Convolution(options, UI) {
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
"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",
|
||||
"type": "Float",
|
||||
"desc": "a constant factor, multiplies all the kernel values by that factor",
|
||||
"default": 0.1111,
|
||||
"placeholder": 0.1111
|
||||
},
|
||||
|
||||
"kernelValues": {
|
||||
"type": "string",
|
||||
"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#convolution-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
module.exports = function Crop(input,options,callback) {
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
var getPixels = require('get-pixels'),
|
||||
savePixels = require('save-pixels');
|
||||
|
||||
options.x = parseInt(options.x) || defaults.x;
|
||||
options.y = parseInt(options.y) || defaults.y;
|
||||
options.x = parseInt(options.x) || 0;
|
||||
options.y = parseInt(options.y) || 0;
|
||||
|
||||
getPixels(input.src,function(err,pixels){
|
||||
options.w = parseInt(options.w) || Math.floor(pixels.shape[0]);
|
||||
options.h = parseInt(options.h) || Math.floor(pixels.shape[1]);
|
||||
options.backgroundColor = options.backgroundColor || defaults.backgroundColor;
|
||||
options.backgroundColor = options.backgroundColor || '255 255 255 255';
|
||||
var ox = options.x;
|
||||
var oy = options.y;
|
||||
var w = options.w;
|
||||
@@ -21,21 +21,14 @@ module.exports = function Crop(input,options,callback) {
|
||||
for(var i = 0; i < w ; i++){
|
||||
backgroundArray = backgroundArray.concat([backgroundColor[0],backgroundColor[1],backgroundColor[2],backgroundColor[3]]);
|
||||
}
|
||||
// var newarray = new Uint8Array(4*w*h);
|
||||
var array = []
|
||||
var newarray = new Uint8Array(4*w*h);
|
||||
for (var n = oy; n < oy + h; n++) {
|
||||
var offsetValue = 4*w*n;
|
||||
if(n<ih){
|
||||
var start = n*4*iw + ox*4;
|
||||
var end = n*4*iw + ox*4 + 4*w;
|
||||
var pushArray = Array.from(pixels.data.slice(start, end ))
|
||||
array.push.apply(array,pushArray);
|
||||
newarray.set(pixels.data.slice(n*4*iw + ox, n*4*iw + ox + 4*w),4*w*(n-oy));
|
||||
} else {
|
||||
array.push.apply(array,backgroundArray);
|
||||
newarray.set(backgroundArray,4*w*(n-oy));
|
||||
}
|
||||
}
|
||||
|
||||
var newarray = Uint8Array.from(array);
|
||||
pixels.data = newarray;
|
||||
pixels.shape = [w,h,4];
|
||||
pixels.stride[1] = 4*w;
|
||||
|
||||
@@ -42,7 +42,6 @@ module.exports = function CropModuleUi(step, ui) {
|
||||
converted[2],
|
||||
converted[3]
|
||||
);
|
||||
$($(imgEl()).parents()[3]).find("input").trigger("change")
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -78,7 +77,7 @@ module.exports = function CropModuleUi(step, ui) {
|
||||
}
|
||||
|
||||
function setOptions(x1, y1, width, height) {
|
||||
let options = $($(imgEl()).parents()[3]).find("input");
|
||||
let options = $($(imgEl()).parents()[2]).find("input");
|
||||
options[0].value = x1;
|
||||
options[1].value = y1;
|
||||
options[2].value = width;
|
||||
|
||||
@@ -4,31 +4,31 @@
|
||||
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||
"inputs": {
|
||||
"x": {
|
||||
"type": "string",
|
||||
"type": "integer",
|
||||
"desc": "X-position (measured from left) from where cropping starts",
|
||||
"default": 0
|
||||
},
|
||||
"y": {
|
||||
"type": "string",
|
||||
"type": "integer",
|
||||
"desc": "Y-position (measured from top) from where cropping starts",
|
||||
"default": 0
|
||||
},
|
||||
"w": {
|
||||
"type": "string",
|
||||
"type": "integer",
|
||||
"desc": "Width of crop",
|
||||
"default": "(50%)"
|
||||
},
|
||||
"h": {
|
||||
"type": "string",
|
||||
"type": "integer",
|
||||
"desc": "Height of crop",
|
||||
"default": "(50%)"
|
||||
},
|
||||
"backgroundColor": {
|
||||
"type": "string",
|
||||
"type": "String",
|
||||
"desc": "Background Color (Four space separated RGBA values)",
|
||||
"default": "255 255 255 255",
|
||||
"placeholder": "255 255 255 255"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#crop-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ module.exports = function DoNothing(options,UI) {
|
||||
var getPixels = require('get-pixels');
|
||||
|
||||
// This function is called everytime a step has to be redrawn
|
||||
function draw(input,callback,progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
function draw(input,callback) {
|
||||
|
||||
var step = this;
|
||||
|
||||
@@ -21,25 +18,16 @@ module.exports = function DoNothing(options,UI) {
|
||||
|
||||
var w = pixels.shape[0];
|
||||
var h = pixels.shape[1];
|
||||
var decoded = jsQR(pixels.data,w,h);
|
||||
var decoded = jsQR.decodeQRFromImage(pixels.data,w,h);
|
||||
|
||||
// This output is accessible to Image Sequencer
|
||||
step.output = input;
|
||||
step.output.data = decoded;
|
||||
|
||||
// Tell Image Sequencer that this step is complete
|
||||
options.step.qrval = (decoded)?decoded.data:"undefined";
|
||||
});
|
||||
callback();
|
||||
options.step.qrval = decoded;
|
||||
|
||||
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,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
},
|
||||
"outputs": {
|
||||
"qrval": {
|
||||
"type": "string"
|
||||
"type": "text"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#decodeqr-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,76 +1,70 @@
|
||||
module.exports = function Dither(pixels, type) {
|
||||
type = type;
|
||||
let bayerThresholdMap = [
|
||||
[15, 135, 45, 165],
|
||||
[195, 75, 225, 105],
|
||||
[60, 180, 30, 150],
|
||||
[240, 120, 210, 90]
|
||||
];
|
||||
|
||||
let lumR = [];
|
||||
let lumG = [];
|
||||
let lumB = [];
|
||||
for (let i = 0; i < 256; i++) {
|
||||
lumR[i] = i * 0.299;
|
||||
lumG[i] = i * 0.587;
|
||||
lumB[i] = i * 0.114;
|
||||
type = type || "none";
|
||||
var bayerThresholdMap = [
|
||||
[ 15, 135, 45, 165 ],
|
||||
[ 195, 75, 225, 105 ],
|
||||
[ 60, 180, 30, 150 ],
|
||||
[ 240, 120, 210, 90 ]
|
||||
];
|
||||
|
||||
var lumR = [];
|
||||
var lumG = [];
|
||||
var lumB = [];
|
||||
for (var i=0; i<256; i++) {
|
||||
lumR[i] = i*0.299;
|
||||
lumG[i] = i*0.587;
|
||||
lumB[i] = i*0.114;
|
||||
}
|
||||
var threshold = 129;
|
||||
var imageDataLength = pixels.data.length; //imageData.data.length;
|
||||
|
||||
// Greyscale luminance (sets r pixels to luminance of rgb)
|
||||
for (var i = 0; i <= imageDataLength; i += 4) {
|
||||
pixels.data[i] = Math.floor(lumR[pixels.data[i]] + lumG[pixels.data[i+1]] + lumB[pixels.data[i+2]]);
|
||||
}
|
||||
|
||||
var w = pixels.shape[0];
|
||||
var newPixel, err;
|
||||
|
||||
for (var currentPixel = 0; currentPixel <= imageDataLength; currentPixel+=4) {
|
||||
|
||||
if (type === "none") {
|
||||
// No dithering
|
||||
pixels.data[currentPixel] = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
} else if (type === "bayer") {
|
||||
// 4x4 Bayer ordered dithering algorithm
|
||||
var x = currentPixel/4 % w;
|
||||
var y = Math.floor(currentPixel/4 / w);
|
||||
var map = Math.floor( (pixels.data[currentPixel] + bayerThresholdMap[x%4][y%4]) / 2 );
|
||||
pixels.data[currentPixel] = (map < threshold) ? 0 : 255;
|
||||
} else if (type === "floydsteinberg") {
|
||||
// Floyd–Steinberg dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < 129 ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 16);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4 ] += err*7;
|
||||
pixels.data[currentPixel + 4*w - 4 ] += err*3;
|
||||
pixels.data[currentPixel + 4*w ] += err*5;
|
||||
pixels.data[currentPixel + 4*w + 4 ] += err*1;
|
||||
} else {
|
||||
// Bill Atkinson's dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 8);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4 ] += err;
|
||||
pixels.data[currentPixel + 8 ] += err;
|
||||
pixels.data[currentPixel + 4*w - 4 ] += err;
|
||||
pixels.data[currentPixel + 4*w ] += err;
|
||||
pixels.data[currentPixel + 4*w + 4 ] += err;
|
||||
pixels.data[currentPixel + 8*w ] += err;
|
||||
}
|
||||
|
||||
// Set g and b pixels equal to r
|
||||
pixels.data[currentPixel + 1] = pixels.data[currentPixel + 2] = pixels.data[currentPixel];
|
||||
}
|
||||
return pixels;
|
||||
|
||||
}
|
||||
let threshold = 129;
|
||||
let imageDataLength = pixels.data.length; //imageData.data.length;
|
||||
|
||||
// Greyscale luminance (sets r pixels to luminance of rgb)
|
||||
for (let i = 0; i <= imageDataLength; i++) {
|
||||
pixels.data[i] = Math.floor(lumR[pixels.data[i++]] + lumG[pixels.data[i++]] + lumB[pixels.data[i++]]);
|
||||
}
|
||||
|
||||
let w = pixels.shape[0];
|
||||
let newPixel, err;
|
||||
|
||||
for (let currentPixel = 0; currentPixel <= imageDataLength; currentPixel += 4) {
|
||||
|
||||
if (type === "none") {
|
||||
// No dithering
|
||||
pixels.data[currentPixel] = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
|
||||
} else if (type === "bayer") {
|
||||
|
||||
// 4x4 Bayer ordered dithering algorithm
|
||||
let x = currentPixel / 4 % w;
|
||||
let y = Math.floor(currentPixel / 4 / w);
|
||||
let map = Math.floor((pixels.data[currentPixel] + bayerThresholdMap[x % 4][y % 4]) / 2);
|
||||
pixels.data[currentPixel] = (map < threshold) ? 0 : 255;
|
||||
|
||||
} else if (type === "floydsteinberg") {
|
||||
|
||||
// Floyd–Steinberg dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < 129 ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 16);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4] += err * 7;
|
||||
pixels.data[currentPixel + 4 * w - 4] += err * 3;
|
||||
pixels.data[currentPixel + 4 * w] += err * 5;
|
||||
pixels.data[currentPixel + 4 * w + 4] += err * 1;
|
||||
|
||||
} else {
|
||||
|
||||
// Bill Atkinson's dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 8);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4] += err;
|
||||
pixels.data[currentPixel + 8] += err;
|
||||
pixels.data[currentPixel + 4 * w - 4] += err;
|
||||
pixels.data[currentPixel + 4 * w] += err;
|
||||
pixels.data[currentPixel + 4 * w + 4] += err;
|
||||
pixels.data[currentPixel + 8 * w] += err;
|
||||
|
||||
}
|
||||
|
||||
// Set g and b pixels equal to r
|
||||
pixels.data[currentPixel + 1] = pixels.data[currentPixel + 2] = pixels.data[currentPixel];
|
||||
}
|
||||
return pixels;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = function Dither(options, UI){
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
@@ -8,7 +8,6 @@ module.exports = function Dither(options, UI){
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
options.dither = options.dither || defaults.dither;
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./Dither')(pixels, options.dither)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
"default": "none",
|
||||
"values": ["none","floydsteinberg","bayer","Atkinson"]
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#dither-module"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
module.exports = exports = function(pixels, options){
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
|
||||
options.startingX = options.startingX || defaults.startingX;
|
||||
options.startingY = options.startingY || defaults.startingY;
|
||||
options.startingX = options.startingX || 0;
|
||||
options.startingY = options.startingY || 0;
|
||||
var ox = Number(options.startingX),
|
||||
oy = Number(options.startingY),
|
||||
iw = pixels.shape[0],
|
||||
ih = pixels.shape[1],
|
||||
thickness = Number(options.thickness) || defaults.thickness,
|
||||
ex = options.endX = Number(options.endX) - thickness || iw - 1,
|
||||
ey = options.endY = Number(options.endY) -thickness || ih - 1,
|
||||
color = options.color || defaults.color;
|
||||
color = color.split(" ");
|
||||
ex = options.endX = Number(options.endX) || iw - 1,
|
||||
ey = options.endY = Number(options.endY) || ih - 1,
|
||||
thickness = Number(options.thickness) || 1,
|
||||
color = options.color || "0 0 0 255";
|
||||
|
||||
var drawSide = function(startX, startY, endX, endY){
|
||||
for (var n=startX; n <= endX+thickness; n++){
|
||||
for (var k=startY; k <= endY+thickness; k++){
|
||||
pixels.set(n, k, 0, color[0]);
|
||||
pixels.set(n, k, 1, color[1]);
|
||||
pixels.set(n, k, 2, color[2]);
|
||||
pixels.set(n, k, 3, color[3]);
|
||||
color = color.split(" ");
|
||||
|
||||
var drawSide = function(startY, startX, endY, endX, yIncrement, xIncrement, sign, incrementFactor = 1){
|
||||
for(var i = 0; i<thickness; i++){
|
||||
for(
|
||||
var n = (startY + i*yIncrement*sign)*4*iw + 4*(startX + i*xIncrement*sign);
|
||||
n <= (endY + i*yIncrement*sign)*4*iw + 4*(endX + i*xIncrement*sign);
|
||||
n = n+4*(incrementFactor)
|
||||
)
|
||||
{
|
||||
pixels.data[n] = color[0];
|
||||
pixels.data[n+1] = color[1];
|
||||
pixels.data[n+2] = color[2];
|
||||
pixels.data[n+3] = color[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawSide(ox, oy, ox, ey); // Left
|
||||
drawSide(ex, oy, ex, ey); // Right
|
||||
drawSide(ox, oy, ex, oy); // Top
|
||||
drawSide(ox, ey, ex, ey); // Bottom
|
||||
drawSide(oy, ox, oy, ex, 1, 0, 1); // Top
|
||||
drawSide(ey, ox, ey, ex, 1, 0, -1); // Bottom
|
||||
drawSide(oy, ox, ey, ox, 0, 1, 1, iw); // Left
|
||||
drawSide(oy, ex, ey, ex, 0, 1, -1, iw); // Right
|
||||
|
||||
return pixels;
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
"description": "It draws a rectangle on the image",
|
||||
"inputs": {
|
||||
"startingX":{
|
||||
"type": "integer",
|
||||
"type": "Number",
|
||||
"desc": "starting x position of the rectangle",
|
||||
"default": 0
|
||||
},
|
||||
|
||||
"startingY": {
|
||||
"type": "integer",
|
||||
"type": "Number",
|
||||
"desc": "starting y position of the rectangle",
|
||||
"default": 0
|
||||
},
|
||||
@@ -33,10 +33,9 @@
|
||||
},
|
||||
|
||||
"color":{
|
||||
"type": "string",
|
||||
"type": "String",
|
||||
"desc": "RGBA values separated by a space",
|
||||
"default": "0 0 0 255"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#draw-rectangle-module"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,25 +3,25 @@
|
||||
"description": "A module which accepts JavaScript math expressions to produce each color channel based on the original image's color. See <a href='https://publiclab.org/wiki/infragram-sandbox'>Infragrammar</a>.",
|
||||
"inputs": {
|
||||
"red": {
|
||||
"type": "string",
|
||||
"type": "input",
|
||||
"desc": "Expression to return for red channel with R, G, B, and A inputs",
|
||||
"default": "r"
|
||||
},
|
||||
"green": {
|
||||
"type": "string",
|
||||
"type": "input",
|
||||
"desc": "Expression to return for green channel with R, G, B, and A inputs",
|
||||
"default": "g"
|
||||
},
|
||||
"blue": {
|
||||
"type": "string",
|
||||
"type": "input",
|
||||
"desc": "Expression to return for blue channel with R, G, B, and A inputs",
|
||||
"default": "b"
|
||||
},
|
||||
"monochrome (fallback)": {
|
||||
"type": "string",
|
||||
"type": "input",
|
||||
"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#dynamic-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,201 +1,174 @@
|
||||
// Define kernels for the sobel filter
|
||||
const kernelx = [
|
||||
[-1, 0, 1],
|
||||
[-2, 0, 2],
|
||||
[-1, 0, 1]
|
||||
],
|
||||
kernely = [
|
||||
[-1,-2,-1],
|
||||
[ 0, 0, 0],
|
||||
[ 1, 2, 1]
|
||||
];
|
||||
const _ = require('lodash')
|
||||
|
||||
let pixelsToBeSupressed = [];
|
||||
//define kernels for the sobel filter
|
||||
const kernelx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
|
||||
kernely = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
|
||||
|
||||
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, hysteresis) {
|
||||
let angles = [], grads = [], strongEdgePixels = [], weakEdgePixels = [];
|
||||
for (var x = 0; x < pixels.shape[0]; x++) {
|
||||
grads.push([]);
|
||||
angles.push([]);
|
||||
for (var y = 0; y < pixels.shape[1]; y++) {
|
||||
var result = sobelFilter(
|
||||
pixels,
|
||||
x,
|
||||
y
|
||||
);
|
||||
let pixel = result.pixel;
|
||||
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, inBrowser) {
|
||||
let angles = [], mags = [], strongEdgePixels = [], weakEdgePixels = [], notInUI = !inBrowser;
|
||||
for (var x = 0; x < pixels.shape[0]; x++) {
|
||||
angles.push([]);
|
||||
mags.push([]);
|
||||
for (var y = 0; y < pixels.shape[1]; y++) {
|
||||
var result = changePixel(
|
||||
pixels,
|
||||
pixels.get(x, y, 0),
|
||||
pixels.get(x, y, 3),
|
||||
x,
|
||||
y
|
||||
);
|
||||
let pixel = result.pixel;
|
||||
|
||||
grads.slice(-1)[0].push(pixel[3]);
|
||||
angles.slice(-1)[0].push(result.angle);
|
||||
}
|
||||
}
|
||||
nonMaxSupress(pixels, grads, angles);
|
||||
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels);
|
||||
if(hysteresis.toLowerCase() == 'true') hysteresis(strongEdgePixels, weakEdgePixels);
|
||||
pixels.set(x, y, 0, pixel[0]);
|
||||
pixels.set(x, y, 1, pixel[1]);
|
||||
pixels.set(x, y, 2, pixel[2]);
|
||||
pixels.set(x, y, 3, pixel[3]);
|
||||
|
||||
strongEdgePixels.forEach(pixel => preserve(pixels, pixel));
|
||||
weakEdgePixels.forEach(pixel => supress(pixels, pixel));
|
||||
pixelsToBeSupressed.forEach(pixel => supress(pixels, pixel));
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
|
||||
function supress(pixels, pixel) {
|
||||
pixels.set(pixel[0], pixel[1], 0, 0);
|
||||
pixels.set(pixel[0], pixel[1], 1, 0);
|
||||
pixels.set(pixel[0], pixel[1], 2, 0);
|
||||
pixels.set(pixel[0], pixel[1], 3, 255);
|
||||
}
|
||||
|
||||
function preserve(pixels, pixel) {
|
||||
pixels.set(pixel[0], pixel[1], 0, 255);
|
||||
pixels.set(pixel[0], pixel[1], 1, 255);
|
||||
pixels.set(pixel[0], pixel[1], 2, 255);
|
||||
pixels.set(pixel[0], pixel[1], 3, 255);
|
||||
}
|
||||
|
||||
// sobelFilter function that convolves sobel kernel over every pixel
|
||||
function sobelFilter(pixels, x, y) {
|
||||
let val = pixels.get(x, y, 0),
|
||||
gradX = 0.0,
|
||||
gradY = 0.0;
|
||||
|
||||
for (let a = 0; a < 3; a++) {
|
||||
for (let b = 0; b < 3; b++) {
|
||||
|
||||
let xn = x + a - 1,
|
||||
yn = y + b - 1;
|
||||
|
||||
if (isOutOfBounds(pixels, xn, yn)) {
|
||||
gradX += pixels.get(xn+1, yn+1, 0) * kernelx[a][b];
|
||||
gradY += pixels.get(xn+1, yn+1, 0) * kernely[a][b];
|
||||
}
|
||||
else {
|
||||
gradX += pixels.get(xn, yn, 0) * kernelx[a][b];
|
||||
gradY += pixels.get(xn, yn, 0) * kernely[a][b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const grad = Math.sqrt(Math.pow(gradX, 2) + Math.pow(gradY, 2)),
|
||||
angle = Math.atan2(gradY, gradX);
|
||||
return {
|
||||
pixel: [val, val, val, grad],
|
||||
angle: angle
|
||||
};
|
||||
}
|
||||
|
||||
function categorizeAngle(angle){
|
||||
if ((angle >= -22.5 && angle <= 22.5) || (angle < -157.5 && angle >= -180)) return 1;
|
||||
else if ((angle >= 22.5 && angle <= 67.5) || (angle < -112.5 && angle >= -157.5)) return 2;
|
||||
else if ((angle >= 67.5 && angle <= 112.5) || (angle < -67.5 && angle >= -112.5)) return 3;
|
||||
else if ((angle >= 112.5 && angle <= 157.5) || (angle < -22.5 && angle >= -67.5)) return 4;
|
||||
|
||||
/* Category Map
|
||||
* 1 => E-W
|
||||
* 2 => NE-SW
|
||||
* 3 => N-S
|
||||
* 4 => NW-SE
|
||||
*/
|
||||
}
|
||||
|
||||
function isOutOfBounds(pixels, x, y){
|
||||
return ((x < 0) || (y < 0) || (x >= pixels.shape[0]) || (y >= pixels.shape[1]));
|
||||
}
|
||||
|
||||
const removeElem = (arr = [], elem) => {
|
||||
return arr = arr.filter((arrelem) => {
|
||||
return arrelem !== elem;
|
||||
})
|
||||
}
|
||||
|
||||
// Non Maximum Supression without interpolation
|
||||
function nonMaxSupress(pixels, grads, angles) {
|
||||
angles = angles.map((arr) => arr.map(convertToDegrees));
|
||||
|
||||
for (let x = 0; x < pixels.shape[0]; x++) {
|
||||
for (let y = 0; y < pixels.shape[1]; y++) {
|
||||
|
||||
let angleCategory = categorizeAngle(angles[x][y]);
|
||||
|
||||
if (!isOutOfBounds(pixels, x - 1, y - 1) && !isOutOfBounds(pixels, x+1, y+1)){
|
||||
switch (angleCategory){
|
||||
case 1:
|
||||
if (!((grads[x][y] >= grads[x][y + 1]) && (grads[x][y] >= grads[x][y - 1]))) {
|
||||
pixelsToBeSupressed.push([x, y]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!((grads[x][y] >= grads[x + 1][y + 1]) && (grads[x][y] >= grads[x - 1][y - 1]))){
|
||||
pixelsToBeSupressed.push([x, y]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (!((grads[x][y] >= grads[x + 1][y]) && (grads[x][y] >= grads[x - 1][y]))) {
|
||||
pixelsToBeSupressed.push([x, y]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!((grads[x][y] >= grads[x + 1][y - 1]) && (grads[x][y] >= grads[x - 1][y + 1]))) {
|
||||
pixelsToBeSupressed.push([x, y]);
|
||||
}
|
||||
break;
|
||||
mags.slice(-1)[0].push(pixel[3]);
|
||||
angles.slice(-1)[0].push(result.angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nonMaxSupress(pixels, mags, angles);
|
||||
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, mags, strongEdgePixels, weakEdgePixels);
|
||||
return pixels;
|
||||
}
|
||||
// Converts radians to degrees
|
||||
|
||||
//changepixel function that convolutes every pixel (sobel filter)
|
||||
function changePixel(pixels, val, a, x, y) {
|
||||
let magX = 0.0;
|
||||
for (let a = 0; a < 3; a++) {
|
||||
for (let b = 0; b < 3; b++) {
|
||||
|
||||
let xn = x + a - 1;
|
||||
let yn = y + b - 1;
|
||||
|
||||
magX += pixels.get(xn, yn, 0) * kernelx[a][b];
|
||||
}
|
||||
}
|
||||
let magY = 0.0;
|
||||
for (let a = 0; a < 3; a++) {
|
||||
for (let b = 0; b < 3; b++) {
|
||||
|
||||
let xn = x + a - 1;
|
||||
let yn = y + b - 1;
|
||||
|
||||
magY += pixels.get(xn, yn, 0) * kernely[a][b];
|
||||
}
|
||||
}
|
||||
let mag = Math.sqrt(Math.pow(magX, 2) + Math.pow(magY, 2));
|
||||
let angle = Math.atan2(magY, magX);
|
||||
return {
|
||||
pixel:
|
||||
[val, val, val, mag],
|
||||
angle: angle
|
||||
};
|
||||
}
|
||||
|
||||
//Non Maximum Supression without interpolation
|
||||
function nonMaxSupress(pixels, mags, angles) {
|
||||
|
||||
angles = angles.map((arr) => arr.map(convertToDegrees));
|
||||
|
||||
for (let i = 1; i < pixels.shape[0] - 1; i++) {
|
||||
for (let j = 1; j < pixels.shape[1] - 1; j++) {
|
||||
|
||||
let angle = angles[i][j];
|
||||
let pixel = pixels.get(i, j);
|
||||
|
||||
if ((angle >= -22.5 && angle <= 22.5) ||
|
||||
(angle < -157.5 && angle >= -180))
|
||||
|
||||
if ((mags[i][j] >= mags[i][j + 1]) &&
|
||||
(mags[i][j] >= mags[i][j - 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 22.5 && angle <= 67.5) ||
|
||||
(angle < -112.5 && angle >= -157.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i + 1][j + 1]) &&
|
||||
(mags[i][j] >= mags[i - 1][j - 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 67.5 && angle <= 112.5) ||
|
||||
(angle < -67.5 && angle >= -112.5))
|
||||
|
||||
if ((mags[i][i] >= mags[i + 1][j]) &&
|
||||
(mags[i][j] >= mags[i][j]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
else if ((angle >= 112.5 && angle <= 157.5) ||
|
||||
(angle < -22.5 && angle >= -67.5))
|
||||
|
||||
if ((mags[i][j] >= mags[i + 1][j - 1]) &&
|
||||
(mags[i][j] >= mags[i - 1][j + 1]))
|
||||
pixels.set(i, j, 3, mags[i][j]);
|
||||
else
|
||||
pixels.set(i, j, 3, 0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
//Converts radians to degrees
|
||||
var convertToDegrees = radians => (radians * 180) / Math.PI;
|
||||
|
||||
// Finds the max value in a 2d array like grads
|
||||
//Finds the max value in a 2d array like mags
|
||||
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, grads, strongEdgePixels, weakEdgePixels) {
|
||||
//Applies the double threshold to the image
|
||||
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, mags, strongEdgePixels, weakEdgePixels) {
|
||||
|
||||
const highThreshold = findMaxInMatrix(grads) * highThresholdRatio,
|
||||
lowThreshold = highThreshold * lowThresholdRatio;
|
||||
const highThreshold = findMaxInMatrix(mags) * highThresholdRatio;
|
||||
const lowThreshold = highThreshold * lowThresholdRatio;
|
||||
|
||||
for (let x = 0; x < pixels.shape[0]; x++) {
|
||||
for (let y = 0; y < pixels.shape[1]; y++) {
|
||||
let pixelPos = [x, y];
|
||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||
let pixelPos = [i, j];
|
||||
|
||||
if (grads[x][y] > lowThreshold){
|
||||
if (grads[x][y] > highThreshold) {
|
||||
strongEdgePixels.push(pixelPos);
|
||||
mags[i][j] > lowThreshold
|
||||
? mags[i][j] > highThreshold
|
||||
? strongEdgePixels.push(pixelPos)
|
||||
: weakEdgePixels.push(pixelPos)
|
||||
: pixels.set(i, j, 3, 0);
|
||||
}
|
||||
else {
|
||||
weakEdgePixels.push(pixelPos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
pixelsToBeSupressed.push(pixelPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 255));
|
||||
}
|
||||
|
||||
function hysteresis(strongEdgePixels, weakEdgePixels){
|
||||
strongEdgePixels.forEach(pixel => {
|
||||
let x = pixel[0],
|
||||
y = pixel[1];
|
||||
// hysteresis edge tracking algorithm -- not working as of now
|
||||
/* function hysteresis(pixels) {
|
||||
function getNeighbouringPixelPositions(pixelPosition) {
|
||||
let x = pixelPosition[0], y = pixelPosition[1]
|
||||
return [[x + 1, y + 1],
|
||||
[x + 1, y],
|
||||
[x + 1, y - 1],
|
||||
[x, y + 1],
|
||||
[x, y - 1],
|
||||
[x - 1, y + 1],
|
||||
[x - 1, y],
|
||||
[x - 1, y - 1]]
|
||||
}
|
||||
|
||||
//This can potentially be improved see https://en.wikipedia.org/wiki/Connected-component_labeling
|
||||
for (weakPixel in weakEdgePixels) {
|
||||
let neighbourPixels = getNeighbouringPixelPositions(weakEdgePixels[weakPixel])
|
||||
for (pixel in neighbourPixels) {
|
||||
if (strongEdgePixels.find(el => _.isEqual(el, neighbourPixels[pixel]))) {
|
||||
pixels.set(weakPixel[0], weakPixel[1], 3, 255)
|
||||
weakEdgePixels.splice(weakPixel, weakPixel)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
weakEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 0))
|
||||
return pixels
|
||||
} */
|
||||
|
||||
|
||||
|
||||
if (weakEdgePixels.includes([x+1, y])) {
|
||||
removeElem(weakEdgePixels, [x+1, y]);
|
||||
}
|
||||
else if (weakEdgePixels.includes([x-1, y])) {
|
||||
removeElem(weakEdgePixels, [x-1, y]);
|
||||
}
|
||||
else if (weakEdgePixels.includes([x, y+1])) {
|
||||
removeElem(weakEdgePixels, [x, y+1]);
|
||||
}
|
||||
else if(weakEdgePixels.includes([x, y-1])) {
|
||||
removeElem(weakEdgePixels, [x, y-1]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
*/
|
||||
module.exports = function edgeDetect(options, UI) {
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
options.blur = options.blur || defaults.blur;
|
||||
options.highThresholdRatio = options.highThresholdRatio || defaults.highThresholdRatio;
|
||||
options.lowThresholdRatio = options.lowThresholdRatio || defaults.lowThresholdRatio;
|
||||
options.hysteresis = options.hysteresis || defaults.hysteresis;
|
||||
options.blur = options.blur || 2;
|
||||
options.highThresholdRatio = options.highThresholdRatio || 0.2;
|
||||
options.lowThresholdRatio = options.lowThresholdRatio || 0.15;
|
||||
|
||||
var output;
|
||||
|
||||
@@ -20,19 +18,22 @@ module.exports = function edgeDetect(options, UI) {
|
||||
var step = this;
|
||||
|
||||
|
||||
// Extra Manipulation function used as an enveloper for applying gaussian blur and Convolution
|
||||
// Extra Manipulation function used as an enveloper for applying gaussian blur and Convolution
|
||||
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];
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('ndarray-gaussian-filter')(pixels, options.blur);
|
||||
pixels = require('./EdgeUtils')(pixels, options.highThresholdRatio, options.lowThresholdRatio, options.hysteresis);
|
||||
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, {
|
||||
@@ -44,6 +45,7 @@ module.exports = function edgeDetect(options, UI) {
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,35 +3,23 @@
|
||||
"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": "float",
|
||||
"type": "range",
|
||||
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": 2,
|
||||
"min": 0,
|
||||
"max": 5,
|
||||
"step": 0.25
|
||||
"default": "2",
|
||||
"min": "0",
|
||||
"max": "5",
|
||||
"step": "0.25"
|
||||
},
|
||||
"highThresholdRatio":{
|
||||
"type": "float",
|
||||
"desc": "The high threshold ratio for the image",
|
||||
"default": 0.2,
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.25
|
||||
"default": 0.2
|
||||
},
|
||||
"lowThresholdRatio": {
|
||||
"type": "float",
|
||||
"desc": "The low threshold value for the image",
|
||||
"default": 0.15,
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.05
|
||||
},
|
||||
"hysteresis": {
|
||||
"type": "select",
|
||||
"desc": "Toggle Hysteresis",
|
||||
"values": ["false", "true"],
|
||||
"default": "false"
|
||||
}
|
||||
"default": 0.15
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#edge-detect-module"
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Changes the Image Exposure
|
||||
*/
|
||||
|
||||
module.exports = function Exposure(options,UI){
|
||||
|
||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
options.exposure = options.exposure || defaults.exposure
|
||||
var exposure = Math.pow(2, options.exposure);
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a){
|
||||
|
||||
r = Math.min(255, r*exposure)
|
||||
g = Math.min(255, g*exposure)
|
||||
b = Math.min(255, b*exposure)
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
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,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user