mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-13 20:00:05 +01:00
Compare commits
1 Commits
dependabot
...
Coverage-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57c3679feb |
10
.codecov.yml
10
.codecov.yml
@@ -1,11 +1,5 @@
|
|||||||
comment:
|
comment: off
|
||||||
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:
|
coverage:
|
||||||
status:
|
status:
|
||||||
project: off
|
project: off
|
||||||
patch: off
|
patch: off
|
||||||
@@ -1 +0,0 @@
|
|||||||
dist/*
|
|
||||||
36
.eslintrc.js
36
.eslintrc.js
@@ -1,36 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
'env': {
|
|
||||||
'browser': true,
|
|
||||||
'commonjs': true,
|
|
||||||
'es6': true,
|
|
||||||
'node': true
|
|
||||||
},
|
|
||||||
'extends': 'eslint:recommended',
|
|
||||||
'globals': {
|
|
||||||
'Atomics': 'readonly',
|
|
||||||
'SharedArrayBuffer': 'readonly'
|
|
||||||
},
|
|
||||||
'parserOptions': {
|
|
||||||
'ecmaVersion': 2018
|
|
||||||
},
|
|
||||||
'rules': {
|
|
||||||
'indent': ['error',2],
|
|
||||||
'linebreak-style': ['error','unix'],
|
|
||||||
'quotes': ['error','single'],
|
|
||||||
'semi': ['error','always'], //
|
|
||||||
'no-undef': 0,
|
|
||||||
'no-console': 'off',
|
|
||||||
'no-unused-vars': 'off',
|
|
||||||
'no-redeclare': 'off',
|
|
||||||
'no-inner-declarations':'off',
|
|
||||||
'no-empty':'off',
|
|
||||||
'no-mixed-spaces-and-tabs':'off',
|
|
||||||
'no-self-assign':'off',
|
|
||||||
'no-constant-condition':'off',
|
|
||||||
'no-dupe-keys':'off',
|
|
||||||
'space-infix-ops': ['error', {'int32Hint': false}], // Enforce spaces around operators
|
|
||||||
'comma-spacing': ['error', { "before": false, "after": true }], // require spacing after a comma
|
|
||||||
'comma-style': ['error', 'last'], // requires comma after and on the same line
|
|
||||||
'no-trailing-spaces': ['error', { 'skipBlankLines': true }], // Disallows trailing whitespace on end of lines and empty lines
|
|
||||||
}
|
|
||||||
};
|
|
||||||
75
.github/CODEOWNERS
vendored
75
.github/CODEOWNERS
vendored
@@ -1,75 +0,0 @@
|
|||||||
# <-- DOCS FOR THIS FILE -->
|
|
||||||
# This is a comment.
|
|
||||||
# Each line is a file pattern followed by one or more owners.
|
|
||||||
|
|
||||||
# These owners will be the default owners for everything in
|
|
||||||
# the repo. Unless a later match takes precedence,
|
|
||||||
# @global-owner1 and @global-owner2 will be requested for
|
|
||||||
# review when someone opens a pull request.
|
|
||||||
# * @global-owner1 @global-owner2
|
|
||||||
|
|
||||||
# Order is important; the last matching pattern takes the most
|
|
||||||
# precedence. When someone opens a pull request that only
|
|
||||||
# modifies JS files, only @js-owner and not the global
|
|
||||||
# owner(s) will be requested for a review.
|
|
||||||
# *.js @js-owner
|
|
||||||
|
|
||||||
# You can also use email addresses if you prefer. They'll be
|
|
||||||
# used to look up users just like we do for commit author
|
|
||||||
# emails.
|
|
||||||
# *.go docs@example.com
|
|
||||||
|
|
||||||
# In this example, @doctocat owns any files in the build/logs
|
|
||||||
# directory at the root of the repository and any of its
|
|
||||||
# subdirectories.
|
|
||||||
# /build/logs/ @doctocat
|
|
||||||
|
|
||||||
# The `docs/*` pattern will match files like
|
|
||||||
# `docs/getting-started.md` but not further nested files like
|
|
||||||
# `docs/build-app/troubleshooting.md`.
|
|
||||||
# docs/* docs@example.com
|
|
||||||
|
|
||||||
# In this example, @octocat owns any file in an apps directory
|
|
||||||
# anywhere in your repository.
|
|
||||||
# apps/ @octocat
|
|
||||||
|
|
||||||
# In this example, @doctocat owns any file in the `/docs`
|
|
||||||
# directory in the root of your repository.
|
|
||||||
# /docs/ @doctocat
|
|
||||||
# <-- /DOCS FOR THIS FILE -->
|
|
||||||
|
|
||||||
# <-- COMMON TO ALL MAINTAINERS -->
|
|
||||||
/*.json @publiclab/is-maintainers
|
|
||||||
/*.md @publiclab/is-maintainers
|
|
||||||
/*.lock @ubliclab/is-maintainers
|
|
||||||
/Gruntfile.js @publiclab/is-maintainers
|
|
||||||
/.github/ @publiclab/is-maintainers
|
|
||||||
/scripts/ @publiclab/is-maintainers
|
|
||||||
# <-- /COMMON TO ALL MAINTAINERS -->
|
|
||||||
|
|
||||||
# <-- SPECIFIC MAINTAINERS -->
|
|
||||||
/index.js @publiclab/is-cli-maintainers
|
|
||||||
/src/cli/ @publiclab/is-cli-maintainers
|
|
||||||
/src/CliUtils.js @publiclab/is-cli-maintainers
|
|
||||||
|
|
||||||
/src/*.js @publiclab/is-core-maintainers
|
|
||||||
/src/*.json @publiclab/is-core-maintainers
|
|
||||||
/src/util/ @publiclab/is-core-maintainers
|
|
||||||
/test/core/* @publiclab/is-core-maintainers
|
|
||||||
|
|
||||||
/src/modules/ @publiclab/is-module-maintainers
|
|
||||||
/docs/ @publiclab/is-module-maintainers
|
|
||||||
|
|
||||||
/test/ @publiclab/is-tests-maintainers
|
|
||||||
/jest* @publiclab/is-tests-maintainers
|
|
||||||
/eslint* @publiclab/is-tests-maintainers
|
|
||||||
/travis* @publiclab/is-tests-maintainers
|
|
||||||
.travis.yml @publiclab/is-tests-maintainers
|
|
||||||
.gitpod* @publiclab/is-tests-maintainers
|
|
||||||
/gitpod* @publiclab/is-tests-maintainers
|
|
||||||
|
|
||||||
/examples/ @publiclab/is-ui-maintainers
|
|
||||||
/icons/ @publiclab/is-ui-maintainers
|
|
||||||
/test/ui-2/test/* @publiclab/is-ui-maintainers
|
|
||||||
/test/ui/spec/* @publiclab/is-ui-maintainers
|
|
||||||
# <-- /SPECIFIC MAINTAINERS -->
|
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
---
|
|
||||||
name: Bug report 🐞
|
|
||||||
about: Help us identify and fix a bug!
|
|
||||||
title: ''
|
|
||||||
labels: bug
|
|
||||||
---
|
|
||||||
|
|
||||||
### Please describe the problem (or idea)
|
### Please describe the problem (or idea)
|
||||||
|
|
||||||
> What happened just before the problem occurred? Or what problem could this idea solve?
|
> What happened just before the problem occurred? Or what problem could this idea solve?
|
||||||
@@ -17,13 +10,13 @@ labels: bug
|
|||||||
|
|
||||||
### Please show us where to look
|
### Please show us where to look
|
||||||
|
|
||||||
Paste in a full URL, starting with:
|
https://beta.sequencer.publiclab.org
|
||||||
|
|
||||||
> https://beta.sequencer.publiclab.org/
|
|
||||||
|
|
||||||
If you can share a screenshot or a GIF that is EXTRA helpful! 💖
|
### What's your PublicLab.org username?
|
||||||
|
|
||||||
|
> This can help us diagnose the issue:
|
||||||
|
|
||||||
If you can see a version number in the upper right, please note that!
|
|
||||||
|
|
||||||
|
|
||||||
### Browser, version, and operating system
|
### Browser, version, and operating system
|
||||||
25
.github/ISSUE_TEMPLATE/enhancement template.md
vendored
25
.github/ISSUE_TEMPLATE/enhancement template.md
vendored
@@ -1,25 +0,0 @@
|
|||||||
# New Enhancement Request
|
|
||||||
|
|
||||||
Describe your enhancement
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
What does your enhancement do?
|
|
||||||
|
|
||||||
Upload Screenshot of your enhancement
|
|
||||||
|
|
||||||
### Please show us where to look
|
|
||||||
Paste in a full URL, starting with:
|
|
||||||
### Problem it can solve
|
|
||||||
|
|
||||||
what problem could this enhancement solve?
|
|
||||||
|
|
||||||
Your help makes Public Lab better! We *deeply* appreciate your helping refine and improve this site.
|
|
||||||
|
|
||||||
To learn how to write really great issues, which increases the chances they'll be resolved, see:
|
|
||||||
|
|
||||||
https://publiclab.org/wiki/developers#Contributing+for+non-coders
|
|
||||||
### Thank you :)
|
|
||||||
22
.github/ISSUE_TEMPLATE/feature request.md
vendored
22
.github/ISSUE_TEMPLATE/feature request.md
vendored
@@ -1,22 +0,0 @@
|
|||||||
# New Feature Request
|
|
||||||
|
|
||||||
Describe your feature
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
What does your feature do?
|
|
||||||
|
|
||||||
Upload Screenshot of your implementation/feature
|
|
||||||
|
|
||||||
### Please show us where to look
|
|
||||||
Paste in a full URL, starting with:
|
|
||||||
### Problem it can solve
|
|
||||||
Your help makes Public Lab better! We *deeply* appreciate your helping refine and improve this site.
|
|
||||||
|
|
||||||
To learn how to write really great issues, which increases the chances they'll be resolved, see:
|
|
||||||
|
|
||||||
https://publiclab.org/wiki/developers#Contributing+for+non-coders
|
|
||||||
### Thank you :)
|
|
||||||
52
.github/ISSUE_TEMPLATE/release_workflow.md
vendored
52
.github/ISSUE_TEMPLATE/release_workflow.md
vendored
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
name: New release checklist ✅
|
|
||||||
about: Coordinate steps to publish a new release
|
|
||||||
title: 'Checklist and coordination for v0.0.0 major/minor/patch release'
|
|
||||||
labels: release
|
|
||||||
assignees: '@publiclab/is-maintainers'
|
|
||||||
---
|
|
||||||
|
|
||||||
This template guides us through the steps of creating a new release, based on conversation and testing in [#1692](https://github.com/publiclab/image-sequencer/issues/1692).
|
|
||||||
|
|
||||||
Discuss with @publiclab/is-maintainers if anything is ambiguous!
|
|
||||||
|
|
||||||
<!-- NOTE: Change v0.0.0 to the appropriate release version -->
|
|
||||||
|
|
||||||
* [x] open an issue using the "release" template with this checklist with title `Checklist and coordination for v0.0.0 major/minor/patch release` (see [semantic versioning](https://docs.npmjs.com/about-semantic-versioning/))
|
|
||||||
* [ ] create a release draft in https://github.com/publiclab/image-sequencer/releases
|
|
||||||
* [ ] auto-compile release notes and copy below from corresponding release draft
|
|
||||||
* [ ] open a pull request with updated version numbers
|
|
||||||
* [ ] update version number in `package.json` (ex #1695)
|
|
||||||
* [ ] update version number in `examples/sw.js` (ex #1734)
|
|
||||||
* [ ] run `npm install` to update `package-lock.json` (from recent node version - 16 at time of writing, in GitPod should work)
|
|
||||||
* [ ] check in `package-lock.json`
|
|
||||||
* [ ] finalize and merge to `main` branch (freeze merges to `main` branch until next step)
|
|
||||||
|
|
||||||
Now, move to `stable` branch:
|
|
||||||
|
|
||||||
* [ ] force push from `main` to `stable`
|
|
||||||
* [ ] then in `stable` branch, compile `dist/` files with `grunt build`
|
|
||||||
* [ ] add `dist/` files with `git add -f dist/*` and commit them to `stable` branch
|
|
||||||
* [ ] publish `stable` branch to `npm` with `npm publish` (logging in first as necessary)
|
|
||||||
* [ ] push local `stable` branch up to origin github.com/publiclab/image-sequencer.git with `git push`
|
|
||||||
|
|
||||||
Draft a release:
|
|
||||||
|
|
||||||
* [ ] [create a release on GitHub](https://github.com/publiclab/image-sequencer/releases) and reconcile with features description + release notes from below
|
|
||||||
* [ ] tag version number branch (i.e. `v0.0.0`) based on `stable` or choose `stable`
|
|
||||||
* [ ] publish to live Github pages [demo](https://sequencer.publiclab.org) (with [bash script](https://github.com/publiclab/image-sequencer/pull/1703) from `/scripts/update-demo`) (from within GitPod works well)
|
|
||||||
* [ ] move anything necessary to next release project, i.e. <!-- Update this link -->https://github.com/publiclab/image-sequencer/projects/[insert project number]
|
|
||||||
* [ ] close this issue!
|
|
||||||
|
|
||||||
Noting we're now in this process in https://github.com/publiclab/image-sequencer/issues/1751 for `v3.7.0`.
|
|
||||||
|
|
||||||
****
|
|
||||||
|
|
||||||
### Release notes
|
|
||||||
Compile and edit release notes below, to be copied into the release description.
|
|
||||||
|
|
||||||
#### Added
|
|
||||||
|
|
||||||
#### Fixed
|
|
||||||
|
|
||||||
#### Changed
|
|
||||||
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
23
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,19 +1,16 @@
|
|||||||
<!--- (Replace `0000` with the Issue Number below) --->
|
Fixes #[Add issue number here.]
|
||||||
Fixes #0000
|
|
||||||
|
|
||||||
|
Make sure these boxes are checked before your pull request (PR) is ready to be reviewed and merged. Thanks!
|
||||||
|
|
||||||
<!---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`
|
||||||
|
|
||||||
* [ ] tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with `npm run test-all`
|
|
||||||
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
||||||
* [ ] PR is descriptively titled
|
* [ ] PR is descriptively titled
|
||||||
* [ ] ask `@publiclab/is-reviewers` for help, in a comment below
|
* [ ] ask `@publiclab/is-reviewers` for help, in a comment below
|
||||||
* [ ] at least 2 reviews required for getting pull request merged
|
|
||||||
* [ ] Insert-step functionality is working correct as expected.
|
|
||||||
<!--- We're happy to help you get this ready -- don't be afraid to ask for help, and **don't be discouraged** if your tests fail at first!--->
|
|
||||||
|
|
||||||
<!---If tests do fail, click on the red `X` to learn why by reading the logs.--->
|
> 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!
|
||||||
|
|
||||||
<!---Please be sure you've reviewed our contribution guidelines at https://publiclab.org/contributing-to-public-lab-software--->
|
If tests do fail, click on the red `X` to learn why by reading the logs.
|
||||||
<!---Please make sure to get at least two reviews before asking for merging the PR as that would make the PR more reliable on our part
|
|
||||||
Thanks!--->
|
Please be sure you've reviewed our contribution guidelines at https://publiclab.org/contributing-to-public-lab-software
|
||||||
|
|
||||||
|
Thanks!
|
||||||
|
|||||||
17
.github/config.yml
vendored
17
.github/config.yml
vendored
@@ -4,27 +4,22 @@
|
|||||||
|
|
||||||
# Comment to be posted to on first time issues
|
# Comment to be posted to on first time issues
|
||||||
newIssueWelcomeComment: |
|
newIssueWelcomeComment: |
|
||||||
Thanks for opening your first issue here! This space is [protected by our Code of Conduct](https://publiclab.org/conduct) - and we're here to help.
|
Thanks for opening your first issue here! Please follow the issue template to help us help you 👍🎉😄
|
||||||
Please follow the issue template to help us help you 👍🎉😄
|
If you have screenshots to share demonstrating the issue, that's really helpful! 📸 You can [make a gif](https://www.cockos.com/licecap/) too!
|
||||||
If you have screenshots to share demonstrating the issue, that's really helpful! 📸 You can [make a gif](https://www.cockos.com/licecap/) too!
|
|
||||||
Don't forget to join our [PublicLab Gitter channel](https://gitter.im/publiclab/publiclab) and our [ImageSequencer Gitter Channel](https://gitter.im/publiclab/image-sequencer) for some brainstorming discussions.
|
|
||||||
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
|
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
|
||||||
|
|
||||||
# Comment to be posted to on PRs from first time contributors in your repository
|
# Comment to be posted to on PRs from first time contributors in your repository
|
||||||
newPRWelcomeComment: |
|
newPRWelcomeComment: |
|
||||||
Thanks for opening this pull request! This space is [protected by our Code of Conduct](https://publiclab.org/conduct).
|
Thanks for opening this pull request!
|
||||||
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
|
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
|
||||||
Also please refer (https://github.com/publiclab/image-sequencer/blob/main/README.md) for installation help.
|
|
||||||
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||||
|
|
||||||
# Comment to be posted to on pull requests merged by a first time user
|
# Comment to be posted to on pull requests merged by a first time user
|
||||||
firstPRMergeComment: |
|
firstPRMergeComment: |
|
||||||
Congrats on merging your first pull request! 🙌🎉⚡️
|
Congrats on merging your first pull request! 🙌🎉⚡️
|
||||||
Your code will be published to https://beta.sequencer.publiclab.org in a day or two. Please test out your work on this testing server and report back with a comment that all has gone well!
|
Your code will be published to https://beta.sequencer.publiclab.org in a day or two.
|
||||||
In the meantime, can you tell us your Twitter handle so we can thank you properly also do join our weekly check-in to share your this week goal and the awesome work you did 😃.
|
In the meantime, can you tell us your Twitter handle so we can thank you properly?
|
||||||
Please find the link **pinned in the issue section**
|
Now that you've completed this, you can help someone else take their first step!
|
||||||
Now that you've completed this, you can help someone else take their first step! Try looking at this list of `first-timers-only` issues, and see if someone else is waiting for feedback, or even stuck! 😕
|
|
||||||
People often get stuck at the same steps, so you might be able to help someone get unstuck, or help lead them to some documentation that'd help. Reach out and be encouraging and friendly! 😄 🎉
|
|
||||||
See: [Public Lab's coding community!](https://code.publiclab.org)
|
See: [Public Lab's coding community!](https://code.publiclab.org)
|
||||||
|
|
||||||
# It is recommended to include as many gifs and emojis as possible
|
# It is recommended to include as many gifs and emojis as possible
|
||||||
|
|||||||
25
.github/dependabot.yml
vendored
25
.github/dependabot.yml
vendored
@@ -1,25 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: npm
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
open-pull-requests-limit: 10
|
|
||||||
ignore:
|
|
||||||
- dependency-name: jest-puppeteer
|
|
||||||
versions:
|
|
||||||
- 5.0.1
|
|
||||||
- 5.0.2
|
|
||||||
- dependency-name: geotiff
|
|
||||||
versions:
|
|
||||||
- 1.0.2
|
|
||||||
- dependency-name: "@babel/core"
|
|
||||||
versions:
|
|
||||||
- 7.13.13
|
|
||||||
- dependency-name: puppeteer
|
|
||||||
versions:
|
|
||||||
- 5.2.1
|
|
||||||
- 7.1.0
|
|
||||||
- dependency-name: tape
|
|
||||||
versions:
|
|
||||||
- 5.1.1
|
|
||||||
21
.github/workflows/rebase.yml
vendored
21
.github/workflows/rebase.yml
vendored
@@ -1,21 +0,0 @@
|
|||||||
name: Automatic Rebase
|
|
||||||
# https://github.com/marketplace/actions/automatic-rebase
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
jobs:
|
|
||||||
rebase:
|
|
||||||
name: Rebase
|
|
||||||
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout the latest code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
|
|
||||||
- name: Automatic Rebase
|
|
||||||
uses: cirrus-actions/rebase@1.4
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
209
.github/workflows/tests.yml
vendored
209
.github/workflows/tests.yml
vendored
@@ -1,209 +0,0 @@
|
|||||||
name: tests
|
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
base-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "Base istanbul/tape node tests"
|
|
||||||
run: npm test
|
|
||||||
|
|
||||||
benchmark-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "Benchmark tests"
|
|
||||||
run: npm run benchmark
|
|
||||||
|
|
||||||
gif-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "Gif tests"
|
|
||||||
run: npm run gif-test
|
|
||||||
|
|
||||||
browserify-core-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- run: sudo apt-get install xvfb
|
|
||||||
- name: "Browserify core tests and run"
|
|
||||||
run: grunt tests && xvfb-run --auto-servernum npm run core-tests
|
|
||||||
|
|
||||||
jsmine-ui-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "Jasmine UI tests (mocked browser env)"
|
|
||||||
run: npm run test-ui
|
|
||||||
|
|
||||||
jest-ui-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "jest-puppeteer UI tests (full browser env)"
|
|
||||||
run: npm run test-ui-2
|
|
||||||
|
|
||||||
cli-tests:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "CLI tests"
|
|
||||||
run: npm run test-cli
|
|
||||||
|
|
||||||
grunt-build-test:
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
check-latest: true
|
|
||||||
- name: Cache node modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
path: ~/.npm
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install
|
|
||||||
- name: "Grunt build test of dev environment"
|
|
||||||
run: grunt build
|
|
||||||
|
|
||||||
## Cache NPM folder
|
|
||||||
# cache:
|
|
||||||
# directories:
|
|
||||||
# - ~/.npm
|
|
||||||
# - ~/.cache
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
FROM gitpod/workspace-full
|
|
||||||
|
|
||||||
USER root
|
|
||||||
RUN sudo apt-get update && apt-get install -y apt-transport-https \
|
|
||||||
&& sudo apt-get install -y \
|
|
||||||
xserver-xorg-dev \
|
|
||||||
libxext-dev \
|
|
||||||
build-essential \
|
|
||||||
libxi-dev \
|
|
||||||
libglew-dev \
|
|
||||||
pkg-config \
|
|
||||||
libglu1-mesa-dev \
|
|
||||||
freeglut3-dev \
|
|
||||||
mesa-common-dev \
|
|
||||||
x11-apps \
|
|
||||||
libice6 \
|
|
||||||
libsm6 \
|
|
||||||
libxaw7 \
|
|
||||||
libxft2 \
|
|
||||||
libxmu6 \
|
|
||||||
libxpm4 \
|
|
||||||
libxt6 \
|
|
||||||
x11-apps \
|
|
||||||
xbitmaps \
|
|
||||||
ca-certificates \
|
|
||||||
fonts-liberation \
|
|
||||||
libappindicator3-1 \
|
|
||||||
libasound2 \
|
|
||||||
libatk-bridge2.0-0 \
|
|
||||||
libatk1.0-0 \
|
|
||||||
libc6 \
|
|
||||||
libcairo2 \
|
|
||||||
libcairo2-dev \
|
|
||||||
libcups2 \
|
|
||||||
libdbus-1-3 \
|
|
||||||
libexpat1 \
|
|
||||||
libfontconfig1 \
|
|
||||||
libgbm1 \
|
|
||||||
libgcc1 \
|
|
||||||
libgif-dev \
|
|
||||||
libglib2.0-0 \
|
|
||||||
libgtk-3-0 \
|
|
||||||
libjpeg-dev \
|
|
||||||
libnspr4 \
|
|
||||||
libnss3 \
|
|
||||||
libpango-1.0-0 \
|
|
||||||
libpango1.0-dev \
|
|
||||||
libpangocairo-1.0-0 \
|
|
||||||
libstdc++6 \
|
|
||||||
librsvg2-dev \
|
|
||||||
libx11-6 \
|
|
||||||
libx11-xcb1 \
|
|
||||||
libxcb1 \
|
|
||||||
libxcomposite1 \
|
|
||||||
libxcursor1 \
|
|
||||||
libxdamage1 \
|
|
||||||
libxext6 \
|
|
||||||
libxfixes3 \
|
|
||||||
libxi6 \
|
|
||||||
libxrandr2 \
|
|
||||||
libxrender1 \
|
|
||||||
libxss1 \
|
|
||||||
libxtst6 \
|
|
||||||
lsb-release \
|
|
||||||
wget \
|
|
||||||
xdg-utils \
|
|
||||||
xvfb \
|
|
||||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*
|
|
||||||
18
.gitpod.yml
18
.gitpod.yml
@@ -1,18 +0,0 @@
|
|||||||
image:
|
|
||||||
file: .gitpod.dockerfile
|
|
||||||
tasks:
|
|
||||||
- init: npm run setup
|
|
||||||
command: npm start
|
|
||||||
ports:
|
|
||||||
- port: 3000
|
|
||||||
onOpen: open-preview
|
|
||||||
|
|
||||||
github:
|
|
||||||
prebuilds:
|
|
||||||
branches: true
|
|
||||||
pullRequests: true
|
|
||||||
pullRequestsFromForks: true
|
|
||||||
addCheck: true
|
|
||||||
addComment: true
|
|
||||||
addBadge: false
|
|
||||||
addLabel: false
|
|
||||||
31
.travis.yml
31
.travis.yml
@@ -1,33 +1,20 @@
|
|||||||
sudo: required
|
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
|
- '6'
|
||||||
|
- '8'
|
||||||
- '10'
|
- '10'
|
||||||
- '12'
|
|
||||||
env:
|
env:
|
||||||
- CXX=g++-4.8
|
- CXX=g++-4.8
|
||||||
before_script:
|
before_script:
|
||||||
- npm install grunt-cli -g # for "grunt build"
|
- 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
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||||
- chmod +x ./cc-test-reporter
|
- chmod +x ./cc-test-reporter
|
||||||
- ./cc-test-reporter before-build
|
- ./cc-test-reporter before-build
|
||||||
jobs:
|
script:
|
||||||
include:
|
- npm test
|
||||||
- name: "Base istanbul/tape node tests"
|
- npm run test-ui
|
||||||
script: npm test
|
- grunt build
|
||||||
- name: "Benchmark tests"
|
|
||||||
script: npm run benchmark
|
|
||||||
- name: "Gif tests"
|
|
||||||
script: npm run gif-test
|
|
||||||
- name: "Browserify core tests and run"
|
|
||||||
script: grunt tests && npm run core-tests
|
|
||||||
- name: "Jasmine UI tests (mocked browser env)"
|
|
||||||
script: npm run test-ui
|
|
||||||
- name: "jest-puppeteer UI tests (full browser env)"
|
|
||||||
script: npm run test-ui-2
|
|
||||||
- name: "CLI tests"
|
|
||||||
script: npm run test-cli
|
|
||||||
- name: "Grunt build test of dev environment"
|
|
||||||
script: grunt build
|
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
after_script:
|
after_script:
|
||||||
@@ -39,10 +26,6 @@ addons:
|
|||||||
packages:
|
packages:
|
||||||
- g++-4.8
|
- g++-4.8
|
||||||
- xvfb # for tape-run
|
- xvfb # for tape-run
|
||||||
before_install:
|
|
||||||
- sudo apt-get update
|
|
||||||
- sudo apt-get install xserver-xorg-dev libxext-dev libxi-dev
|
|
||||||
- sudo apt-get install -y build-essential libxi-dev libglu1-mesa-dev libglew-dev pkg-config libglu1-mesa-dev freeglut3-dev mesa-common-dev
|
|
||||||
install:
|
install:
|
||||||
- export DISPLAY=':99.0' # for tape-run
|
- export DISPLAY=':99.0' # for tape-run
|
||||||
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & # for tape-run
|
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & # for tape-run
|
||||||
|
|||||||
@@ -1,11 +1,114 @@
|
|||||||
|
This document was copied from its home at https://publiclab.org/conduct on October 12, 2017. See that page if you would like to submit your concerns in a safe, completely anonymous way, and to learn more about this document.
|
||||||
|
|
||||||
|
****
|
||||||
|
|
||||||
# Public Lab Code of Conduct
|
# Public Lab Code of Conduct
|
||||||
|
|
||||||
_Public Lab, 55 Cromwell Street, 1C, Providence, RI 02907_
|
_Public Lab, PO Box 426113, Cambridge, MA 02142_
|
||||||
|
|
||||||
We are coming together with an intent to care for ourselves and one another as we produce knowledge in pursuit of environmental justice. For this to work for everybody, individual decisions will not be allowed to run counter to the welfare of other people. We—visitors, community members, community moderators, staff, organizers, sponsors, and all others—hold ourselves accountable to the same values regardless of position or experience. This community aspires to be a respectful place both during online and in-person interactions so that all people are able to fully participate with their dignity intact. This document is a piece of the culture we're creating.
|
We are coming together with an intent to care for ourselves and one another. We want to nurture a compassionate democratic culture where responsibility is shared. We -- visitors, community members, community moderators, staff, organizers, sponsors, and all others -- hold ourselves accountable to the same values regardless of position or experience. For this to work for everybody, individual decisions will not be allowed to run counter to the welfare of other people. This community aspires to be a respectful place both during online and in-person interactions so that all people are able to fully participate with their dignity intact. This document is a piece of the culture we're creating.
|
||||||
|
|
||||||
This code of conduct applies to all spaces managed by the Public Lab community and non-profit, both online and in person. It provides a clear set of practical guidelines for events led by organizers and community members, multi-day events such as Barnraisings, and online venues such as the website, comment threads on software platforms, chatrooms, our mailing lists, the issue tracker, and any other forums created by Public Lab which the community uses for communication. For interactions with additional groups, see our Partnership Guidelines at https://publiclab.org/partners.
|
|
||||||
|
|
||||||
To read the full Code of Conduct and learn how to contact the Conduct Committee or the Moderators group, see:
|
This code of conduct applies to all spaces managed by the Public Lab community and non-profit, both online and in person. It was written by the Conduct Committee (formed in 2015 during Public Lab’s annual conference “The Barnraising”) and facilitated by staff to provide a clear set of practical guidelines for multi-day events such as Barnraisings, events led by organizers and community members, and online venues such as the website, comment threads on software platforms, chatrooms, our mailing lists, the issue tracker, and any other forums created by Public Lab which the community uses for communication.
|
||||||
|
|
||||||
https://publiclab.org/conduct
|
|
||||||
|
## We come from all kinds of backgrounds
|
||||||
|
|
||||||
|
Our community is best when we fully invite and include participants from a wide range of backgrounds. We specifically design spaces to be welcoming and accessible to newcomers and folks from underrepresented groups. Public Lab is dedicated to providing a harassment-free, safe, and inclusive experience for everyone, regardless of personal and professional background, gender, gender identity and expression, style of clothing, sexual orientation, dis-/ability, physical appearance, body size, race, class, age, or religion. Public Lab resists and rejects: racism, sexism, ableism, ageism, homophobia, transphobia, body shaming, religion shaming, “geekier-than-thou” shaming, education bias, the shaming of people nursing children, and the dismissal or bullying of children or adults.
|
||||||
|
|
||||||
|
## We do not tolerate harassment or shaming
|
||||||
|
|
||||||
|
While we operate under the assumption that all people involved with Public Lab subscribe to the basic understanding laid out above, we take these issues very seriously and think they should, in general, be taken seriously. Therefore, individuals who violate this Code both in and outside of Public Lab spaces may affect their ability to participate in Public Lab ranging from temporarily being placed into online moderation to, as a last resort, expulsion from the community. If you have any questions about our commitment to this framework and/or if you are unsure about aspects of it, email conduct@publiclab.org and we will do our best to provide clarification.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
Sometimes things go wrong. When a situation is uncomfortable, hurtful, exclusionary, or upsetting, there is a problem that should be addressed. This code of conduct is an effort to maintain a safe space for everyone, and to talk about what might happen if that space is compromised. Please see additional guidelines below for community behavior on how we expect people to interact with one another.
|
||||||
|
|
||||||
|
### Two helpful groups
|
||||||
|
|
||||||
|
__Conduct Committee (ConductCom)__: If at any time you experience something that you are not comfortable with, you may contact the Conduct Committee. As established during the 2015 Annual Barnraising, the following individuals are on the Conduct Committee: Klie Kliebert, Carla Green, Nick Shapiro, and Shannon Dosemagen, the executive director of the Public Lab nonprofit.
|
||||||
|
|
||||||
|
|
||||||
|
If you would like to have a confidential conversation, connect with ConductCom in person or email via [conduct@publiclab.org](mailto:conduct@publiclab.org). A minimum of two committee members will confer and respond as swiftly as possible. If you would prefer to speak privately with a representative of the nonprofit, please contact the executive director directly either in person or by email: [shannon@publiclab.org.](mailto:conduct@publiclab.org)
|
||||||
|
|
||||||
|
|
||||||
|
To submit a report anonymously for review by ConductCom, go online via phone or computer to our anonymous “contact” app, located at [http://bit.ly/PLReport](http://bit.ly/PLReport). This contact app will be monitored daily at 8am CST during in-person events like Barnraisings and weekly at all other times. During multi-day in-person events hosted by the Public Lab non-profit, there will also be a physical suggestion box available. This box will be monitored throughout the event and can also be used to let us know if you need us to check on an anonymous online submission sooner.
|
||||||
|
|
||||||
|
|
||||||
|
__Moderators Group:__ The moderators group is responsible for addressing immediate moderation issues that arise during online violations of the code over email lists and Public Lab community websites, as well as approving first-time posts and generally handling spam. Instructions on how to become a moderator, and, if you’ve been placed in moderation how to begin the process of getting out of moderation can be found at: https://publiclab.org/wiki/moderation.
|
||||||
|
|
||||||
|
****
|
||||||
|
|
||||||
|
## A Culture of Empathy
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Before you engage with someone on any level, be sure you have their consent. If your indications aren't being heard, you can also ask for help from other folks, especially Conduct Committee members and staff of the non-profit: "They aren't taking the hint. Will you help?" Turning a blind eye to hurtful interactions can be as bad for our community as the exchange itself. If you witness something, it's your responsibility to say something. This is how we keep each other accountable, encourage empathy, and keep our community safe.
|
||||||
|
|
||||||
|
## Guidelines for in-person community behavior
|
||||||
|
|
||||||
|
|
||||||
|
Do | Don’t
|
||||||
|
----------- | -----------
|
||||||
|
Respectfully share what method works best for you, while giving others space to think differently and contribute other ideas | Disparage entire groups/sets of people for their beliefs or methods
|
||||||
|
Ask permission to take pictures of and post about others on social media (see Media Consent, above)| Upload photos, tag or mention others online without their consent
|
||||||
|
Speak your own narrative, from your own unique culture | Caricature the cultural expressions of groups you are not a member of
|
||||||
|
Model inclusionary expertise - if others in the group appear to be “lost”, slow down; stop and ask for input | Present information in a way / at a level that no one else in the room can understand, with no attempt to include others in the discussion
|
||||||
|
Create events that are all-ages appropriate | Use language that excludes youth and their experiences as vital contributors
|
||||||
|
Give everyone a chance to talk, only interrupting if absolutely necessary - for example, Code of Conduct violations | Repeatedly disrupt a discussion
|
||||||
|
Stop, listen and ask for clarification if someone perceives your behavior or presentation as violating the Code of Conduct | Ignore others’ request to stop potentially harmful behavior, even if it was an accident
|
||||||
|
Cultivate a sense of humor based on other subjects, such as word play (especially puns!) | Joke using words related to actual or insulting descriptions of people
|
||||||
|
Use words that accurately describe the situation - For example, “The wind was ridiculously strong!” instead of “The wind was crazy!” | Use disability and mental/emotional health terminology to describe a situation metaphorically, especially if the phrasing is meant as an insult
|
||||||
|
Only discuss someone else’s lifestyle practices if they invite you to a conversation on the topic | Make unwelcomed comments regarding a person’s lifestyle practices, including those related to food, health, parenting, relationships, and employment
|
||||||
|
Ask someone before you hug them; keep your hands/body to yourself, even when joking, unless the other person has given verbal consent | Initiate physical contact or simulate physical contact without consent
|
||||||
|
Disengage and find another activity if someone did not invite you and is not engaging with you | Violate personal space by continuing your physical presence into private spaces without consent
|
||||||
|
Exercise the right to talk about your own identity if you want to, or not if you don’t want to | Deliberately “out” any aspect of a person’s identity without their consent
|
||||||
|
Use the pronouns people have specified for themselves | Purposely misgender someone (ie, refusing to use their correct gender pronouns) after they have told you their correct pronouns
|
||||||
|
|
||||||
|
|
||||||
|
## Additional guidelines for online community behavior
|
||||||
|
|
||||||
|
|
||||||
|
Online modes of interaction involve large numbers of people without the helpful presence of gestural, expression, and tonal cues regarding consent. Because of this, respectful and self-aware online conduct is both especially important and difficult. Our community has evolved specific guidelines for online interactions.
|
||||||
|
|
||||||
|
_If someone violates these guidelines, someone from the Moderators group will place them into moderation by changing that person’s posting permission on the relevant list, on the website, or both._
|
||||||
|
|
||||||
|
Our triple notification standard for moderation means a point person from the Moderators group will:
|
||||||
|
|
||||||
|
1. e-mail the person directly with a brief explanation of what was violated,
|
||||||
|
2. send a summary email to the rest of the moderators group,
|
||||||
|
3. if it happened on a public list (vs a website), notify the list that one of our members has been placed into moderation with a brief explanation of what is not tolerated.
|
||||||
|
|
||||||
|
|
||||||
|
If you wish to begin the process of getting out of moderation, respond to the email sent to you from [moderators@publiclab.org](mailto:moderators@publiclab.org). The Moderators group has the option to involve ConductCom.
|
||||||
|
|
||||||
|
|
||||||
|
Do | Don’t
|
||||||
|
-------|--------
|
||||||
|
Stay on topic to make long threads easier to follow |Send spurious one-line responses that effectively "spam" hundreds of people and lower the overall content quality of a conversation. (Exception: expressions of appreciation and encouragement!)
|
||||||
|
Start a new thread to help others follow along. Important if your response starts to significantly diverge from the original topic | Respond with off-topic information making it hard for the large group of readers to follow along
|
||||||
|
Write short and literal subject lines to help the readers of the list manage the volume of communication | Humor and euphemisms in subject lines are easily misunderstood, although enthusiasm is welcome!
|
||||||
|
Mind your tone. We are not having this conversation in person, so it is all the more important to maintain a tone of respect | Write in aggressive tone, disrespectful tone, mocking tone, off-color tone. Note: writing in all caps is regarded as shouting
|
||||||
|
|
||||||
|
## Media Consent
|
||||||
|
|
||||||
|
* ALWAYS check with parents about posting anything with minors.
|
||||||
|
* Never post the names of minors in conjunction with their photo.
|
||||||
|
* During multi-day events like Barnraisings most people will have signed media releases. Those who haven’t will be responsible for placing stickers on their nametags, and/or raising their hands in the moment to alert photographers to move them out of frame.
|
||||||
|
* For events where people have not signed blanket media release forms, the photographer is responsible for letting the room know that you are taking photos that will be posted online. Pay special attention to the presence of minors and their parent's wishes.
|
||||||
|
|
||||||
|
|
||||||
|
## Addendum for all staff
|
||||||
|
|
||||||
|
Staff are bound by their Employment Handbook, you must reference it. Additionally:
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|||||||
126
CONTRIBUTING.md
126
CONTRIBUTING.md
@@ -3,10 +3,6 @@ Contributing to Image Sequencer
|
|||||||
|
|
||||||
Happily accepting pull requests; to edit the core library, modify files in `./src/`. To build, run `npm install` followed by `grunt build`.
|
Happily accepting pull requests; to edit the core library, modify files in `./src/`. To build, run `npm install` followed by `grunt build`.
|
||||||
|
|
||||||
On ARM based devices, the `gl` module may require some libraries to be re-installed:
|
|
||||||
|
|
||||||
`sudo apt-get install -y build-essential xserver-xorg-dev libxext-dev libxi-dev libglu1-mesa-dev libglew-dev pkg-config` -- see https://github.com/stackgl/headless-gl#ubuntudebian for more.
|
|
||||||
|
|
||||||
Most contribution (we imagine) would be in the form of API-compatible modules, which need not be directly included.
|
Most contribution (we imagine) would be in the form of API-compatible modules, which need not be directly included.
|
||||||
|
|
||||||
## Jump To
|
## Jump To
|
||||||
@@ -16,8 +12,6 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
|
|||||||
* [Info File](#info-file)
|
* [Info File](#info-file)
|
||||||
* [Ideas](#Contribution-ideas)
|
* [Ideas](#Contribution-ideas)
|
||||||
* [Grunt Tasks](#grunt-tasks)
|
* [Grunt Tasks](#grunt-tasks)
|
||||||
* [UI Helper Methods](#ui-helper-methods)
|
|
||||||
* [Scripts](#scripts)
|
|
||||||
|
|
||||||
****
|
****
|
||||||
|
|
||||||
@@ -118,9 +112,9 @@ function ModuleName(options,UI) {
|
|||||||
];
|
];
|
||||||
```
|
```
|
||||||
### Running a browser-only module in node
|
### 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 web-based modules but since it runs the module in a headless browser, it supports all browser specific APIs.
|
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
|
The api must be used in the following format
|
||||||
```js
|
```js
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
@@ -197,7 +191,7 @@ There are four events in all:
|
|||||||
* `UI.onComplete(options.step)` must be emitted whenever the output of a draw call
|
* `UI.onComplete(options.step)` must be emitted whenever the output of a draw call
|
||||||
is ready. An argument, that is the DataURL of the output image must be passed in.
|
is ready. An argument, that is the DataURL of the output image must be passed in.
|
||||||
* `UI.onRemove(options.step)` is emitted automatically and the module should not emit it.
|
* `UI.onRemove(options.step)` is emitted automatically and the module should not emit it.
|
||||||
* `UI.notify(msg,id)` must be emitted when a notification has to be produced.
|
* `UI.notify(msg,id)` must be emmited when a notification has to be produced.
|
||||||
|
|
||||||
### Name and description
|
### Name and description
|
||||||
|
|
||||||
@@ -244,7 +238,7 @@ Also, A module may have output values. These must be defined as shown above.
|
|||||||
|
|
||||||
### Progress reporting
|
### Progress reporting
|
||||||
|
|
||||||
The default "loading spinner" can be optionally overridden with a custom progress object to draw progress on the CLI, following is a basic module format for the same:
|
The default "loading spinner" can be optionally overriden with a custom progress object to draw progress on the CLI, following is a basic module format for the same:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = function ModuleName(options,UI) {
|
module.exports = function ModuleName(options,UI) {
|
||||||
@@ -279,8 +273,7 @@ module.exports = function ModuleName(options,UI) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `progressObj` parameter of `draw()` is not consumed unless a custom progress bar needs to be drawn, for which this default spinner should be stopped with `progressObj.stop()` and image-sequencer is informed about the custom progress bar with `progressObj.overrideFlag = true;` following which this object can be overridden with custom progress object.
|
The `progressObj` parameter of `draw()` is not consumed unless a custom progress bar needs to be drawn, for which this default spinner should be stopped with `progressObj.stop()` and image-sequencer is informed about the custom progress bar with `progressObj.overrideFlag = true;` following which this object can be overriden with custom progress object.
|
||||||
|
|
||||||
|
|
||||||
### Module example
|
### Module example
|
||||||
|
|
||||||
@@ -292,7 +285,7 @@ For help integrating, please open an issue.
|
|||||||
|
|
||||||
## Meta Module
|
## Meta Module
|
||||||
|
|
||||||
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 generate meta modules dynamically with the function `createMetaModule` which can be called in the following ways
|
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
|
```js
|
||||||
|
|
||||||
@@ -370,29 +363,7 @@ module.exports =
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Linting
|
|
||||||
|
|
||||||
We are now using `eslint` and `husky` to help lint and format our code each time we commit. Eslint defines coding standards and helps in cleaning up the code. To run eslint for checking errors globally or within a specific file run:
|
|
||||||
|
|
||||||
```
|
|
||||||
npx eslint .
|
|
||||||
|
|
||||||
npx eslint <file path>
|
|
||||||
```
|
|
||||||
And to fix those errors globally or in a file, run these in your terminal:
|
|
||||||
```
|
|
||||||
npx eslint . --fix
|
|
||||||
|
|
||||||
npx eslint <file path> --fix
|
|
||||||
```
|
|
||||||
Be sure to not include the angular brackets(<>).
|
|
||||||
|
|
||||||
Husky ensures automation of the above steps with git-hooks(eg. git add, git commit..). However we don't want to check and fix changes of the entire codebase with each commit and that the fixes made by eslint appear unstaged and require us to commit them again and that is where lint-staged helps.
|
|
||||||
|
|
||||||
If we want `husky` to not verify the commit and push it anyway, use `git commit -m "message" --no-verify.`
|
|
||||||
|
|
||||||
## Grunt Tasks
|
## 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).
|
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.
|
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.
|
||||||
@@ -404,88 +375,3 @@ The following command is used for running the tasks: `grunt [task-name]`. Here `
|
|||||||
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.
|
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.
|
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.
|
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.
|
|
||||||
* `getScope()`: Returns the scope as a DOM element.
|
|
||||||
* `getDomElem()`: Returns the scoped element as a DOM element instead of a jquery object.
|
|
||||||
|
|
||||||
#### 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();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Scripts
|
|
||||||
The following shell scripts are present in the `scripts/` directory.
|
|
||||||
|
|
||||||
- `update-gh-pages`: This script can be used to update the `gh-pages` branch of this repo or a fork.
|
|
||||||
This script is not meant to be used directly as it runs in the current working directory.
|
|
||||||
If you run it on your primary local clone, it can **delete** the local changes. This script is made to be used in a github action
|
|
||||||
or in a temporary directory via another script, such as `update-demo`.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
1. Repo(to use as upstream) url in the form username/repo (default: publiclab/image-sequencer) NOTE: Github only
|
|
||||||
2. Branch to pull from eg: main or stable (default: stable)
|
|
||||||
3. CNAME URL (default: none)
|
|
||||||
4. Set the fourth argument to anything to bypass the warning. You will have to set this argument if you want to run this script in another script without needing
|
|
||||||
user interaction, such as in a github action.
|
|
||||||
|
|
||||||
- `update-demo`: A safe, interactive script that can be used to update the `gh-pages` branch of any image-sequencer fork.
|
|
||||||
This script is safe to use directly because it separately clones the repo in a temporary directory.
|
|
||||||
|
|
||||||
Arguments: None since it is a an *interactive* script, ie it asks the user for input.
|
|
||||||
|
|
||||||
****
|
|
||||||
|
|
||||||
# Comments
|
|
||||||
|
|
||||||
1. Methods must be described using [JSDoc comments](https://devdocs.io/jsdoc/)
|
|
||||||
2. Misc code comments should be inline unless it is a long sentence.
|
|
||||||
3. No use of continuous tenses, no pronouns.
|
|
||||||
4. No redundant comments.
|
|
||||||
5. Each comment should start with an uppercase letter and end with a full stop.
|
|
||||||
|
|||||||
86
Gruntfile.js
86
Gruntfile.js
@@ -1,106 +1,76 @@
|
|||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
grunt.loadNpmTasks('grunt-browserify');
|
grunt.loadNpmTasks("grunt-browserify");
|
||||||
grunt.loadNpmTasks('grunt-contrib-uglify-es');
|
grunt.loadNpmTasks("grunt-contrib-uglify-es");
|
||||||
grunt.loadNpmTasks('grunt-browser-sync');
|
grunt.loadNpmTasks("grunt-browser-sync");
|
||||||
grunt.loadNpmTasks('grunt-text-replace');
|
|
||||||
|
|
||||||
require('matchdep')
|
require("matchdep")
|
||||||
.filterDev('grunt-*')
|
.filterDev("grunt-*")
|
||||||
.forEach(grunt.loadNpmTasks);
|
.forEach(grunt.loadNpmTasks);
|
||||||
|
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
pkg: grunt.file.readJSON("package.json"),
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
options: {
|
options: {
|
||||||
livereload: true
|
livereload: true
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
files: ['src/**/*', 'Gruntfile.js', 'examples/lib/*', 'examples/demo.js'],
|
files: ["src/**/*", "Gruntfile.js", "examples/lib/*", "examples/demo.js"],
|
||||||
tasks: ['compile']
|
tasks: ["compile"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
browserify: {
|
browserify: {
|
||||||
options: {
|
|
||||||
alias: {
|
|
||||||
'gpu.js': './node_modules/gpu.js/src/index.js'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
core: {
|
core: {
|
||||||
src: ['src/ImageSequencer.js'],
|
src: ["src/ImageSequencer.js"],
|
||||||
dest: 'dist/image-sequencer.js'
|
dest: "dist/image-sequencer.js"
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
src: ['examples/demo.js'],
|
src: ["examples/demo.js"],
|
||||||
dest: 'dist/image-sequencer-ui.js'
|
dest: "dist/image-sequencer-ui.js"
|
||||||
},
|
},
|
||||||
prodcore: {
|
prodcore: {
|
||||||
src: ['src/ImageSequencer.js'],
|
src: ["src/ImageSequencer.js"],
|
||||||
dest: 'dist/image-sequencer.brow.js'
|
dest: "dist/image-sequencer.brow.js"
|
||||||
},
|
},
|
||||||
produi: {
|
produi: {
|
||||||
src: ['examples/demo.js'],
|
src: ["examples/demo.js"],
|
||||||
dest: 'dist/image-sequencer-ui.brow.js'
|
dest: "dist/image-sequencer-ui.brow.js"
|
||||||
},
|
|
||||||
tests: {
|
|
||||||
src: ['test/core/sequencer/meta-modules.js',
|
|
||||||
'test/core/sequencer/image-sequencer.js',
|
|
||||||
'test/core/sequencer/chain.js',
|
|
||||||
'test/core/sequencer/replace.js',
|
|
||||||
'test/core/sequencer/import-export.js',
|
|
||||||
'test/core/sequencer/run.js',
|
|
||||||
'test/core/sequencer/dynamic-imports.js',
|
|
||||||
'test/core/util/*.js'],
|
|
||||||
dest: './output/core-tests.js'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
replace: {
|
|
||||||
version: {
|
|
||||||
src: ['examples/sw.js'],
|
|
||||||
overwrite: true,
|
|
||||||
replacements: [{
|
|
||||||
from: /image-sequencer-static-v.*/g,
|
|
||||||
to: "image-sequencer-static-v<%= pkg.version %>';"
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
uglify: {
|
uglify: {
|
||||||
core: {
|
core: {
|
||||||
src: ['./dist/image-sequencer.js'],
|
src: ["./dist/image-sequencer.js"],
|
||||||
dest: './dist/image-sequencer.min.js'
|
dest: "./dist/image-sequencer.min.js"
|
||||||
},
|
},
|
||||||
ui: {
|
ui: {
|
||||||
src: ['dist/image-sequencer-ui.js'],
|
src: ['dist/image-sequencer-ui.js'],
|
||||||
dest: 'dist/image-sequencer-ui.min.js'
|
dest: 'dist/image-sequencer-ui.min.js'
|
||||||
},
|
},
|
||||||
prodcore: {
|
prodcore: {
|
||||||
src: ['dist/image-sequencer.brow.js'],
|
src: ["dist/image-sequencer.brow.js"],
|
||||||
dest: 'dist/image-sequencer.js'
|
dest: "dist/image-sequencer.js"
|
||||||
},
|
},
|
||||||
produi: {
|
produi: {
|
||||||
src: ['dist/image-sequencer-ui.brow.js'],
|
src: ["dist/image-sequencer-ui.brow.js"],
|
||||||
dest: 'dist/image-sequencer-ui.js'
|
dest: "dist/image-sequencer-ui.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
browserSync: {
|
browserSync: {
|
||||||
dev: {
|
dev: {
|
||||||
options: {
|
options: {
|
||||||
watchTask: true,
|
watchTask: true,
|
||||||
server: './'
|
server: "./"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Default (development): Watch files and build on change. */
|
/* Default (development): Watch files and build on change. */
|
||||||
grunt.registerTask('default', ['watch']);
|
grunt.registerTask("default", ["watch"]);
|
||||||
grunt.registerTask('build', ['browserify:core', 'browserify:ui', 'replace:version', 'uglify:core', 'uglify:ui']);
|
grunt.registerTask("build", ["browserify:core", "browserify:ui", "uglify:core", "uglify:ui"]);
|
||||||
grunt.registerTask('serve', ['browserify:core', 'browserify:ui', 'replace:version', 'browserSync', 'watch']);
|
grunt.registerTask("serve", ["browserify:core", "browserify:ui", "browserSync", "watch"]);
|
||||||
grunt.registerTask('compile', ['browserify:core', 'browserify:ui']);
|
grunt.registerTask("compile", ["browserify:core", "browserify:ui"]);
|
||||||
grunt.registerTask('production', ['browserify:prodcore', 'browserify:produi', 'replace:version', 'uglify:prodcore', 'uglify:produi']);
|
grunt.registerTask("production", ["browserify:prodcore", "browserify:produi", "uglify:prodcore", "uglify:produi"]);
|
||||||
|
|
||||||
grunt.registerTask('tests', ['browserify:tests']);
|
|
||||||
};
|
};
|
||||||
|
|||||||
104
README.md
104
README.md
@@ -1,19 +1,13 @@
|
|||||||
Image Sequencer
|
Image Sequencer
|
||||||
====
|
====
|
||||||
|
|
||||||
[](https://publiclab.org/conduct)
|
|
||||||
[](https://badge.fury.io/js/image-sequencer)
|
[](https://travis-ci.org/publiclab/image-sequencer) [](https://codeclimate.com/github/publiclab/image-sequencer/maintainability) 
|
||||||
[](https://travis-ci.org/publiclab/image-sequencer) [](https://codeclimate.com/github/publiclab/image-sequencer/maintainability) [](https://codecov.io/gh/publiclab/image-sequencer)
|
|
||||||
[](https://gitpod.io/#https://github.com/publiclab/image-sequencer/)
|
|
||||||
|
|
||||||
- **Latest Stable Demo**: https://sequencer.publiclab.org
|
- **Latest Stable Demo**: https://sequencer.publiclab.org
|
||||||
- **Latest Beta Demo**: https://beta.sequencer.publiclab.org
|
- **Latest Beta Demo**: https://beta.sequencer.publiclab.org
|
||||||
- **Stable Branch**: https://github.com/publiclab/image-sequencer/tree/stable/
|
- **Stable Branch**: https://github.com/publiclab/image-sequencer/tree/stable/
|
||||||
|
|
||||||
Begin running (and contributing to) this codebase immediately with [GitPod](https://gitpod.io) (this also opens the latest `main` branch code):
|
|
||||||
|
|
||||||
[](https://gitpod.io/#https://github.com/publiclab/image-sequencer)
|
|
||||||
|
|
||||||
## Why
|
## 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 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:
|
||||||
@@ -65,7 +59,7 @@ A diagram of this running 5 steps on a single sample image may help explain how
|
|||||||
This library conveniently works in the browser, in Node, and on the command line (CLI).
|
This library conveniently works in the browser, in Node, and on the command line (CLI).
|
||||||
|
|
||||||
### Unix based platforms
|
### 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 `npm run setup` followed by `npm start`.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
Our npm scripts do not support windows shells, please run the following snippet in PowerShell.
|
Our npm scripts do not support windows shells, please run the following snippet in PowerShell.
|
||||||
@@ -77,12 +71,6 @@ In case of a port conflict please run the following
|
|||||||
npm i -g http-server ; http-server -p 3000
|
npm i -g http-server ; http-server -p 3000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Online one-click setup for contributing
|
|
||||||
|
|
||||||
Contribute to ImageSequencer using a fully featured online development environment that will automatically: clone the repo, install the dependencies and start the webserver.
|
|
||||||
|
|
||||||
[](https://gitpod.io/from-referrer/)
|
|
||||||
|
|
||||||
### Browser
|
### 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.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)!
|
||||||
@@ -107,7 +95,7 @@ $ npm install image-sequencer -g
|
|||||||
```
|
```
|
||||||
$ npm run debug invert
|
$ npm run debug invert
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Usage
|
## Quick Usage
|
||||||
|
|
||||||
### Initializing the Sequencer
|
### Initializing the Sequencer
|
||||||
@@ -213,17 +201,15 @@ var sequencer = ImageSequencer();
|
|||||||
### Loading an Image into the Sequencer
|
### Loading an Image into the Sequencer
|
||||||
|
|
||||||
The `loadImage` method is used to load an image into the sequencer. It accepts
|
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
|
```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 `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
|
On browsers, it may be a DatURI, a local image or a URL (Unless this violates
|
||||||
CORS Restrictions). To sum up, these are accepted:
|
CORS Restrictions). To sum up, these are accepted:
|
||||||
|
|
||||||
* Images in the same domain (or directory - for a local implementation)
|
* Images in the same domain (or directory - for a local implementation)
|
||||||
* CORS-Proof images in another domain.
|
* CORS-Proof images in another domain.
|
||||||
* DataURLs
|
* DataURLs
|
||||||
@@ -233,7 +219,7 @@ The callback is called within the scope of a sequencer. For example:
|
|||||||
(addSteps is defined later)
|
(addSteps is defined later)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('SRC', function(){
|
sequencer.loadImage('SRC',function(){
|
||||||
this.addSteps('module-name');
|
this.addSteps('module-name');
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@@ -254,40 +240,8 @@ 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
|
If multiple images are to be added, `modules` is an array, which holds the names of modules
|
||||||
to be added, in that particular order.
|
to be added, in that particular order.
|
||||||
|
|
||||||
optional_options is just an optional parameter, in object form, which you might
|
optional_otions is just an optional parameter, in object form, which you might
|
||||||
want to provide to the modules.
|
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}')
|
|
||||||
```
|
|
||||||
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
@@ -444,7 +398,7 @@ Image sequencer supports stringifying a sequence which is appended to the url an
|
|||||||
channel{channel:green},invert{}
|
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()
|
channel(channel:green),invert()
|
||||||
```
|
```
|
||||||
@@ -483,7 +437,7 @@ sequencer.importJSON([
|
|||||||
To see this in action, please refer to line # 51 of the following:
|
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)
|
[test/core/modules/import-export.js](https://github.com/publiclab/image-sequencer/blob/main/test/core/modules/import-export.js)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Creating a User Interface
|
## Creating a User Interface
|
||||||
@@ -560,7 +514,7 @@ sequencer.setUI({
|
|||||||
|
|
||||||
Image Sequencer object supports one imageURL at a time.
|
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.
|
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
|
```js
|
||||||
s1 = new ImageSequencer(...);
|
s1 = new ImageSequencer(...);
|
||||||
@@ -590,37 +544,3 @@ sequencer2.run();
|
|||||||
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.
|
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.
|
||||||
|
|
||||||
## Using WebAssembly for heavy pixel processing
|
|
||||||
|
|
||||||
Any module which uses the `changePixel` function gets WebAssembly acceleration (`wasm`). Both node and browser code use WebAssembly and the only code which falls back to non-`wasm` code is the [browserified unit tests](https://github.com/publiclab/image-sequencer/blob/main/test/core/sequencer/benchmark.js).
|
|
||||||
|
|
||||||
The main advantage we get using `wasm` is blazing fast speed attained in processing pixels for many modules that is very clear from [checking module benchmarks](https://travis-ci.org/publiclab/image-sequencer/jobs/544415673#L1931).
|
|
||||||
|
|
||||||
|
|
||||||
The only limitation is that browser and node code for `wasm` had to be written separately, and switched between. This is because in browser we use `fetch` to retrieve the compiled `wasm` program while in node we use the `fs` module, each of which cannot be used in the other's environment.
|
|
||||||
|
|
||||||
|
|
||||||
`wasm` mode is enabled by default. If you need to force this mode to be on or off, you can use the `useWasm` option when initializing ImageSequencer:
|
|
||||||
|
|
||||||
```js
|
|
||||||
let sequencer = ImageSequencer({useWasm:true}) // for wasm mode or simply
|
|
||||||
|
|
||||||
let sequencer = ImageSequencer() // also for wasm mode i.e. default mode
|
|
||||||
|
|
||||||
let sequencer = ImageSequencer({useWasm:false}) //for non-wasm mode
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Experimental GIF processing support
|
|
||||||
|
|
||||||
ImageSequencer currently can process GIFs but only for most of the modules. Every frame of the GIF is manipulated sequentially (parallel processing would be preferable in the future).
|
|
||||||
The final frames are then converted back to a GIF but in the process, the time duration of each frame is lost and defaults to `0.1s`.
|
|
||||||
|
|
||||||
Modules that do not work:
|
|
||||||
1. ColorBar (Will get fixed upon fixing overlay as this is a meta module which uses overlay)
|
|
||||||
2. FisheyeGL
|
|
||||||
3. Overlay
|
|
||||||
4. Blend
|
|
||||||
5. Histogram
|
|
||||||
6. WebGL Distort
|
|
||||||
BIN
dist/manipulation.wasm
vendored
BIN
dist/manipulation.wasm
vendored
Binary file not shown.
774
docs/MODULES.md
774
docs/MODULES.md
@@ -3,258 +3,48 @@ Documentation of various Modules
|
|||||||
|
|
||||||
List of Module Documentations
|
List of Module Documentations
|
||||||
|
|
||||||
1. [Add QR](#Add-QR-module)
|
1. [Crop](#crop-module)
|
||||||
2. [Average](#average-module)
|
2. [Segmented-Colormap](#segmented-colormap-module)
|
||||||
3. [Blend](#blend-module)
|
3. [FisheyeGl](#fisheyeGl-module)
|
||||||
4. [Blur](#blur-module)
|
4. [Add QR](#Add-QR-module)
|
||||||
5. [Brightness](#brightness-module)
|
5. [Average](#average-module)
|
||||||
6. [Canvas-Resize](#canvas-resize-module)
|
6. [Blend](#blend-module)
|
||||||
7. [Channel](#channel-module)
|
7. [Blur](#blur-module)
|
||||||
8. [Colorbar](#colorbar-module)
|
8. [Brightness](#brightness-module)
|
||||||
9. [Colormap](#colormap-module)
|
9. [Channel](#channel-module)
|
||||||
10. [ColorTemperature](#color-temperature)
|
10. [Colorbar](#colorbar-module)
|
||||||
11. [Contrast](#contrast-module)
|
11. [Colormap](#colormap-module)
|
||||||
12. [Convolution](#convolution-module)
|
12. [Contrast](#contrast-module)
|
||||||
13. [Crop](#crop-module)
|
13. [Convolution](#convolution-module)
|
||||||
14. [DecodeQr](#decodeQr-module)
|
14. [DecodeQr](#decodeQr-module)
|
||||||
15. [Dither](#dither-module)
|
15. [Dither](#dither-module)
|
||||||
16. [DrawRectangle](#draw-rectangle-module)
|
16. [DrawRectangle](#draw-rectangle-module)
|
||||||
17. [Dynamic](#dynamic-module)
|
17. [Dynamic](#dynamic-module)
|
||||||
18. [Edge-Detect](#edge-detect-module)
|
18. [Edge-Detect](#edge-detect-module)
|
||||||
19. [Exposure](#exposure-module)
|
19. [FlipImage](#flipimage-module)
|
||||||
20. [FisheyeGl](#fisheyeGl-module)
|
20. [Gamma-Correction](#gamma-correction-module)
|
||||||
21. [FlipImage](#flipimage-module)
|
21. [Gradient](#gradient-module)
|
||||||
22. [Gamma-Correction](#gamma-correction-module)
|
22. [Histogram](#histogram-module)
|
||||||
23. [Gradient](#gradient-module)
|
23. [Import-image](#import-image-module)
|
||||||
24. [Grid-Overlay](#grid-overlay)
|
24. [Invert](#invert-module)
|
||||||
25. [Histogram](#histogram-module)
|
25. [Ndvi](#ndvi-module)
|
||||||
26. [Import-image](#import-image-module)
|
26. [Ndvi-Colormap](#ndvi-colormap-module)
|
||||||
27. [Invert](#invert-module)
|
27. [Overlay](#overlay-module)
|
||||||
28. [MinifyImage](#minify-image)
|
28. [PaintBucket](#paint-bucket-module)
|
||||||
29. [Ndvi](#ndvi-module)
|
29. [Resize](#resize-module)
|
||||||
30. [Ndvi-Colormap](#ndvi-colormap-module)
|
30. [ReplaceColor](#replacecolor-module)
|
||||||
31. [NoiseReduction](#noise-reduction)
|
31. [Rotate](#rotate-module)
|
||||||
32. [Overlay](#overlay-module)
|
32. [Saturation](#saturation-module)
|
||||||
33. [PaintBucket](#paint-bucket-module)
|
33. [Threshold](#threshold)
|
||||||
34. [ReplaceColor](#replacecolor-module)
|
34. [Tint](#tint)
|
||||||
35. [Resize](#resize-module)
|
35. [ColorTemperature](#color-temperature)
|
||||||
36. [Rotate](#rotate-module)
|
36. [Grid-Overlay](#grid-overlay)
|
||||||
37. [Saturation](#saturation-module)
|
|
||||||
38. [Segmented-Colormap](#segmented-colormap-module)
|
|
||||||
39. [Sharpen](#sharpening-module)
|
|
||||||
40. [Text-Overlay](#text-overlay)
|
|
||||||
41. [Threshold](#threshold)
|
|
||||||
42. [Tint](#tint)
|
|
||||||
43. [WebGL-Distort](#webgl-distort-module)
|
|
||||||
44. [White-Balance](#white-balance-module)
|
|
||||||
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('average',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## blend-module
|
|
||||||
|
|
||||||
This module is used for blending two images. For More info read: _[wiki](https://en.wikipedia.org/wiki/Blend_modes)_
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('blend',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following properties:
|
|
||||||
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
|
|
||||||
* blendMode: Blending mode to use for blending two images by default it uses the given function
|
|
||||||
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })
|
|
||||||
|
|
||||||
[More info for different blend modes can be found here](http://docs.gimp.org/en/gimp-concepts-layer-modes.html)
|
|
||||||
|
|
||||||
|
|
||||||
## Blob Analysis
|
|
||||||
|
|
||||||
This module uses Opencv.js for detecting and marking blob/region in microscopic images. It requires an opencv.js file to
|
|
||||||
be loaded before using the functionalities which is currently being loaded to the webpage via script.It supports both environments, Node.js and browser for processing.
|
|
||||||
|
|
||||||
As the size of opencv.js file is quite large, the future versions will focus on loading it asynchronously, on demand of the the module to optimise performance.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('blob-analysis')
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
## blur-module
|
|
||||||
|
|
||||||
This module is used for applying a Gaussian blur effect.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('blur',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
|
||||||
|
|
||||||
|
|
||||||
## brightness-module
|
|
||||||
|
|
||||||
This module is used for changing the brightness of the image.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('brightness',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* brightness : brightness of the image in percentage (0 to 100; default 100)
|
|
||||||
|
|
||||||
|
|
||||||
## canvas-resize-module
|
|
||||||
|
|
||||||
This module is used for resizing the canvas of the image.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('canvas-resize',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* width: final width of the canvas (default 1000)
|
|
||||||
* height: final height of the canvas (default 1000)
|
|
||||||
* x: x-coordinate of the top left of the image on the canvas (default 500)
|
|
||||||
* y: y-coordinate of the top left of the image on the canvas (default 500)
|
|
||||||
|
|
||||||
|
|
||||||
## channel-module
|
|
||||||
|
|
||||||
This module is used for forming a grayscale image by applying one of the three primary colors.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('channel',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* channel : color of the channel (red, green, blue; default green)
|
|
||||||
|
|
||||||
|
|
||||||
## colorbar-module
|
|
||||||
|
|
||||||
This module is used for displaying an image with a colorbar.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('colorbar',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following properties:
|
|
||||||
* colormap : Name of the Colormap(default, greyscale, stretched, fastie, brntogrn, blutoredjet, colors16; default: default)
|
|
||||||
* x : X-position of the image on which the new image is overlayed (default 0)
|
|
||||||
* y : Y-position of the image on which the new image is overlayed (default 0)
|
|
||||||
* h : height of resulting cropped image (default : 50% of input image width )
|
|
||||||
|
|
||||||
|
|
||||||
## colormap-module
|
|
||||||
|
|
||||||
This module is used for mapping brightness values (average of red, green & blue) to a given color lookup table, made up of a set of one more color gradients.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('colormap',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* colormap : Name of the Colormap ( greyscale, stretched, fastie, brntogrn, blutoredjet, colors16)
|
|
||||||
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
|
|
||||||
|
|
||||||
## contrast-module
|
|
||||||
|
|
||||||
This module is used for changing the contrast of the image.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('contrast',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* contrast : contrast for the given image (-100 to 100; default : 70)
|
|
||||||
|
|
||||||
|
|
||||||
## convolution-module
|
|
||||||
|
|
||||||
This module is used for performing image-convolution.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('convolution',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following properties:
|
|
||||||
* constantFactor : a constant factor, multiplies all the kernel values by that factor (default : 1/9)
|
|
||||||
* kernelValues : nine space separated numbers representing the kernel values in left to right and top to bottom format(default : 1 1 1 1 1 1 1 1 1)
|
|
||||||
|
|
||||||
|
|
||||||
## crop-module
|
## crop-module
|
||||||
|
|
||||||
This module is used to crop an image.
|
This module is used to crop an image.
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -274,105 +64,34 @@ Where `options` is an object having the properties `x`, `y`, `w`, `h`. This diag
|
|||||||
* `options.h` : half of image height
|
* `options.h` : half of image height
|
||||||
|
|
||||||
|
|
||||||
## decodeQr-module
|
## segmented-colormap-module
|
||||||
|
|
||||||
|
This module is used to map the pixels of the image to a segmented colormap.
|
||||||
|
|
||||||
This module is used for decoding a QR in image (if present).
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
.addSteps('decode-qr',options)
|
.addSteps('segmented-colormap',options)
|
||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
## dither-module
|
where `options` is an object with the property `colormap`. `options.colormap` can be:
|
||||||
|
|
||||||
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.
|
* "default" : [[0, [0, 0, 255], [38, 195, 195]], [0.5, [0, 150, 0], [255, 255, 0]], [0.75, [255, 255, 0], [255, 50, 50]]]
|
||||||
|
|
||||||
[more info on wikipedia](https://en.wikipedia.org/wiki/Dither)
|
* "greyscale" : [[0, [0, 0, 0], [255, 255, 255]], [1, [255, 255, 255], [255, 255, 255]]]
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
* "stretched" : [[0, [0, 0, 255], [0, 0, 255]], [0.1, [0, 0, 255], [38, 195, 195]], [0.5, [0, 150, 0], [255, 255, 0]], [0.7, [255, 255, 0], [255, 50, 50]], [0.9, [255, 50, 50], [255, 50, 50]]]
|
||||||
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
|
* "fastie" : [[0, [255, 255, 255], [0, 0, 0]], [0.167, [0, 0, 0], [255, 255, 255]], [0.33, [255, 255, 255], [0, 0, 0]], [0.5, [0, 0, 0], [140, 140, 255]], [0.55, [140, 140, 255], [0, 255, 0]], [0.63, [0, 255, 0], [255, 255, 0]], [0.75, [255, 255, 0], [255, 0, 0]], [0.95, [255, 0, 0], [255, 0, 255]]]
|
||||||
|
|
||||||
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.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('dynamic',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following properties:
|
|
||||||
* red : expression for red channel (R, G, B and A as inputs; default r)
|
|
||||||
* green : expression for green channel (R, G, B and A as inputs; default g)
|
|
||||||
* blue : expression for blue channel (R, G, B and A as inputs; default b)
|
|
||||||
* monochrome: fallback for other channels if none provided (default : r+g+b/3)
|
|
||||||
|
|
||||||
|
|
||||||
## edge-detect-module
|
|
||||||
|
|
||||||
This module is used for detecting images.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('edge-detect',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following properties:
|
|
||||||
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
|
||||||
* highThresholdRatio : Upper Threshold Ratio ( default : 0.2)
|
|
||||||
* lowThresholdratio : Lower Threshold Ratio ( default : 0.2)
|
|
||||||
|
|
||||||
|
|
||||||
## exposure-module
|
|
||||||
|
|
||||||
This module is used for changing the exposure of the image.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('exposure',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* exposure: exposure value for the new image (-3 to 4; default 1)
|
|
||||||
|
|
||||||
|
* A custom array.
|
||||||
|
|
||||||
## fisheyeGl-module
|
## fisheyeGl-module
|
||||||
|
|
||||||
This module is used for correcting Fisheye or Lens Distortion
|
This module is used for correcting Fisheye or Lens Distortion
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -390,12 +109,246 @@ where `options` is an object with the following properties:
|
|||||||
* x : Field of View x (0 to 2; default 1)
|
* x : Field of View x (0 to 2; default 1)
|
||||||
* y : Field of View y (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.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('average',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
## blend-module
|
||||||
|
|
||||||
|
This module is used for blending two images .
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('blend',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* offset: step of image with which current image is to be blended(Two steps back is -2, three steps back is -3 etc; default -2)
|
||||||
|
* func: function used to blend two images (default : function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] })
|
||||||
|
|
||||||
|
## blur-module
|
||||||
|
|
||||||
|
This module is used for applying a Gaussian blur effect.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('blur',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
||||||
|
|
||||||
|
## brightness-module
|
||||||
|
|
||||||
|
This module is used for changing the brightness of the image.
|
||||||
|
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('brightness',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* brightness : brightness of the image in percentage (0 to 100; default 100)
|
||||||
|
|
||||||
|
## channel-module
|
||||||
|
|
||||||
|
This module is used for forming a grayscale image by applying one of the three primary colors.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('channel',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* channel : color of the channel (red, green, blue; default green)
|
||||||
|
|
||||||
|
## colorbar-module
|
||||||
|
|
||||||
|
This module is used for displaying an image with a colorbar.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('colorbar',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* colormap : Name of the Colormap(default, greyscale, stretched, fastie, brntogrn, blutoredjet, colors16; default: default)
|
||||||
|
* x : X-position of the image on which the new image is overlayed (default 0)
|
||||||
|
* y : Y-position of the image on which the new image is overlayed (default 0)
|
||||||
|
* h : height of resulting cropped image (default : 50% of input image width )
|
||||||
|
|
||||||
|
## colormap-module
|
||||||
|
|
||||||
|
This module is used for mapping brightness values (average of red, green & blue) to a given color lookup table, made up of a set of one more color gradients.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('colormap',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* colormap : Name of the Colormap ( greyscale, stretched, fastie, brntogrn, blutoredjet, colors16)
|
||||||
|
|
||||||
|
## contrast-module
|
||||||
|
|
||||||
|
This module is used for changing the contrast of the image.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('contrast',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* contrast : contrast for the given image (-100 to 100; default : 70)
|
||||||
|
|
||||||
|
## convolution-module
|
||||||
|
|
||||||
|
This module is used for performing image-convolution.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('convolution',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* constantFactor : a constant factor, multiplies all the kernel values by that factor (default : 1/9)
|
||||||
|
* kernelValues : nine space separated numbers representing the kernel values in left to right and top to bottom format(default : 1 1 1 1 1 1 1 1 1)
|
||||||
|
|
||||||
|
## decodeQr-module
|
||||||
|
|
||||||
|
This module is used for decoding a QR in image (if present).
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('decode-qr',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('dynamic',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* red : expression for red channel (R, G, B and A as inputs; default r)
|
||||||
|
* green : expression for green channel (R, G, B and A as inputs; default g)
|
||||||
|
* blue : expression for blue channel (R, G, B and A as inputs; default b)
|
||||||
|
* monochrome: fallback for other channels if none provided (default : r+g+b/3)
|
||||||
|
|
||||||
|
## edge-detect-module
|
||||||
|
|
||||||
|
This module is used for detecting images.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('edge-detect',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* blur : Intensity of Gaussian blur (0 to 5; default 2)
|
||||||
|
* highThresholdRatio : Upper Threshold Ratio ( default : 0.2)
|
||||||
|
* lowThresholdratio : Lower Threshold Ratio ( default : 0.2)
|
||||||
|
|
||||||
## flipimage-module
|
## flipimage-module
|
||||||
|
|
||||||
This module is used for flipping the image on the selected axis.
|
This module is used for flipping the image on the selected axis.
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
.addSteps('flip-image',options)
|
.addSteps('flip-image',options)
|
||||||
@@ -420,7 +373,6 @@ This module is used for applying gamma correction.
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* adjustment : Inverse of actual gamma factor (default 0.2)
|
* adjustment : Inverse of actual gamma factor (default 0.2)
|
||||||
|
|
||||||
|
|
||||||
## gradient-module
|
## gradient-module
|
||||||
|
|
||||||
This module is used for finding gradient of the image.
|
This module is used for finding gradient of the image.
|
||||||
@@ -432,23 +384,6 @@ This module is used for finding gradient of the image.
|
|||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
|
|
||||||
## histogram-module
|
## histogram-module
|
||||||
|
|
||||||
This module is used for calculating histogram of the image.
|
This module is used for calculating histogram of the image.
|
||||||
@@ -463,7 +398,6 @@ This module is used for calculating histogram of the image.
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* gradient : boolean value used to toggle gradient along x-axis (true or false; default true)
|
* gradient : boolean value used to toggle gradient along x-axis (true or false; default true)
|
||||||
|
|
||||||
|
|
||||||
## import-image-module
|
## import-image-module
|
||||||
|
|
||||||
This module is used for importing a new image and replacing the original with it.
|
This module is used for importing a new image and replacing the original with it.
|
||||||
@@ -478,7 +412,6 @@ This module is used for importing a new image and replacing the original with it
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* url : url of the new image (local image url or data url;default : "./images/monarch.png")
|
* url : url of the new image (local image url or data url;default : "./images/monarch.png")
|
||||||
|
|
||||||
|
|
||||||
## invert-module
|
## invert-module
|
||||||
|
|
||||||
This module is used for inverting the image.
|
This module is used for inverting the image.
|
||||||
@@ -490,21 +423,6 @@ This module is used for inverting the image.
|
|||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Minify Image
|
|
||||||
|
|
||||||
This module minifies the image using lossy compression that is the image-dimensions are not lost but the size is reduced.
|
|
||||||
|
|
||||||
The module supports jpg/jpeg/webp images in browser; but the node version supports all of the types.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('minify-image')
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## ndvi-module
|
## ndvi-module
|
||||||
|
|
||||||
This module is used for applying ndvi technique to the image.
|
This module is used for applying ndvi technique to the image.
|
||||||
@@ -519,7 +437,6 @@ This module is used for applying ndvi technique to the image.
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* filter : filter for NDVI (blue or red; default red)
|
* filter : filter for NDVI (blue or red; default red)
|
||||||
|
|
||||||
|
|
||||||
## ndvi-colormap-module
|
## ndvi-colormap-module
|
||||||
|
|
||||||
This module is used for demonstrating ndvi and colormap properties consecutively.
|
This module is used for demonstrating ndvi and colormap properties consecutively.
|
||||||
@@ -531,22 +448,6 @@ This module is used for demonstrating ndvi and colormap properties consecutively
|
|||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Noise-Reduction
|
|
||||||
|
|
||||||
Noise in an image are atypical pixels that are not representing the color or the exposure of the scene correctly. This Noise Reduction module reduces the noise in the image by using either median filtering or mean filtering techniques to change the RGB value of the pixels to create a smoother and fuller image.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('noise-reduction',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
where `options` is an object with the property `method`. `options.method` can be:
|
|
||||||
* Median Filtering: Set the RGB value of the pixel to the median RGB pixel value of all adjacent pixels (maximum 8 adjacent pixels and itself)
|
|
||||||
* Mean Filtering: Set the RGB value of the pixel to the mean RGB pixel value of all adjacent pixels (maximum 8 adjacent pixels and itself)
|
|
||||||
|
|
||||||
|
|
||||||
## overlay-module
|
## overlay-module
|
||||||
|
|
||||||
This module is used for overlaying an Image over another .
|
This module is used for overlaying an Image over another .
|
||||||
@@ -563,10 +464,10 @@ where `options` is an object with the following properties:
|
|||||||
* y : Y-position of the image on which the new image is overlayed (default 0)
|
* y : Y-position of the image on which the new image is overlayed (default 0)
|
||||||
* offset : offset to the step on which the output of the last step is overlayed (default -2)
|
* offset : offset to the step on which the output of the last step is overlayed (default -2)
|
||||||
|
|
||||||
|
|
||||||
## paint-bucket-module
|
## paint-bucket-module
|
||||||
|
|
||||||
This module fills any polygonal shape with the specified color in pixels.
|
This module fills any polygonal shape with the specified color in pixels.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -581,6 +482,19 @@ where `options` is an object with the following property:
|
|||||||
* fillColor : they are four spaced seperated numbers representing the RGBA values of fill-color (default "100 100 100 255")
|
* 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)
|
* tolerance : it is the % tolerance (default 10)
|
||||||
|
|
||||||
|
## resize-module
|
||||||
|
|
||||||
|
This module is used for resizing an image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('resize',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* resize : Percentage value of resize (default 125%)
|
||||||
|
|
||||||
## replacecolor-module
|
## replacecolor-module
|
||||||
|
|
||||||
@@ -598,22 +512,6 @@ where `options` is an object with the following properties:
|
|||||||
* color : three space separated numbers representing the RGB values of color to be replaced (default "228 86 81")
|
* 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)
|
* tolerance : it is the % tolerance (default 50)
|
||||||
|
|
||||||
|
|
||||||
## resize-module
|
|
||||||
|
|
||||||
This module is used for resizing an image.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('resize',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
|
||||||
* resize : Percentage value of resize (default 125%)
|
|
||||||
|
|
||||||
|
|
||||||
## rotate-module
|
## rotate-module
|
||||||
|
|
||||||
This module is used for rotating an image.
|
This module is used for rotating an image.
|
||||||
@@ -628,7 +526,6 @@ This module is used for rotating an image.
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* rotate : angular value for rotation in degrees (between 0 and 360; default 0)
|
* rotate : angular value for rotation in degrees (between 0 and 360; default 0)
|
||||||
|
|
||||||
|
|
||||||
## saturation-module
|
## saturation-module
|
||||||
|
|
||||||
This module is used for changing the saturation of the image.
|
This module is used for changing the saturation of the image.
|
||||||
@@ -643,63 +540,11 @@ This module is used for changing the saturation of the image.
|
|||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* saturation : saturation for the new image (between 0 and 2; default 0)
|
* saturation : saturation for the new image (between 0 and 2; default 0)
|
||||||
|
|
||||||
|
|
||||||
## segmented-colormap-module
|
|
||||||
|
|
||||||
This module is used to map the pixels of the image to a segmented colormap.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('segmented-colormap',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the property `colormap`. `options.colormap` can be:
|
|
||||||
|
|
||||||
* "default" : [[0, [0, 0, 255], [38, 195, 195]], [0.5, [0, 150, 0], [255, 255, 0]], [0.75, [255, 255, 0], [255, 50, 50]]]
|
|
||||||
|
|
||||||
* "greyscale" : [[0, [0, 0, 0], [255, 255, 255]], [1, [255, 255, 255], [255, 255, 255]]]
|
|
||||||
|
|
||||||
* "stretched" : [[0, [0, 0, 255], [0, 0, 255]], [0.1, [0, 0, 255], [38, 195, 195]], [0.5, [0, 150, 0], [255, 255, 0]], [0.7, [255, 255, 0], [255, 50, 50]], [0.9, [255, 50, 50], [255, 50, 50]]]
|
|
||||||
|
|
||||||
* "fastie" : [[0, [255, 255, 255], [0, 0, 0]], [0.167, [0, 0, 0], [255, 255, 255]], [0.33, [255, 255, 255], [0, 0, 0]], [0.5, [0, 0, 0], [140, 140, 255]], [0.55, [140, 140, 255], [0, 255, 0]], [0.63, [0, 255, 0], [255, 255, 0]], [0.75, [255, 255, 0], [255, 0, 0]], [0.95, [255, 0, 0], [255, 0, 255]]]
|
|
||||||
|
|
||||||
* A custom array.
|
|
||||||
|
|
||||||
|
|
||||||
## sharpen-module
|
|
||||||
|
|
||||||
This module is used to sharpen the pixels of the image using a 3x3 convolution filter.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('sharpen',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
|
|
||||||
where `options` is an object with the property `sharpenStrength`, which can be set to achieve the desired level of sharpening on the image.
|
|
||||||
|
|
||||||
|
|
||||||
## Text Overlay
|
|
||||||
|
|
||||||
The modules allows to add text to image in both browser and node environment. We have the options to modify the font-size and also support few font-styles. The text color can also be modified.
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.loadImage('PATH')
|
|
||||||
.addSteps('grid-overlay',options)
|
|
||||||
.run()
|
|
||||||
```
|
|
||||||
The options can take various attributes like,
|
|
||||||
var options = { text : 'Hello World', size : '12'};
|
|
||||||
|
|
||||||
|
|
||||||
## Threshold
|
## Threshold
|
||||||
|
|
||||||
Thresholding is used to create binary images.
|
Thresholding is used to create binary images.
|
||||||
#### Usage
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
@@ -714,7 +559,8 @@ where `options` is an object with the following property:
|
|||||||
## Tint
|
## Tint
|
||||||
|
|
||||||
It adds color tint to an image
|
It adds color tint to an image
|
||||||
#### Usage
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
@@ -726,36 +572,32 @@ where `options` is an object with the following property:
|
|||||||
* factor : amount of tint (default 0.5)
|
* factor : amount of tint (default 0.5)
|
||||||
|
|
||||||
|
|
||||||
## webgl-distort-module
|
## Color Temperature
|
||||||
|
|
||||||
This module is used for transforming the perspective of images based on corner coordinates.
|
This changes the color temperature of the image.
|
||||||
#### Usage
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
.addSteps('webgl-distort',options)
|
.addSteps('color-temperature',options)
|
||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* nw: top-left corner x and y coordinates separated by a comma (default "0,100")
|
* temperature : temperature between 0 - 40,000 kelvin (default 6000)
|
||||||
* ne: top-right corner x and y coordinates separated by a comma (default "1023,-50")
|
|
||||||
* se: bottom-right corner x and y coordinates separated by a comma (default "1223,867")
|
|
||||||
* sw: bottom-left corner x and y coordinates separated by a comma (default "100,767")
|
|
||||||
|
|
||||||
|
## Grid Overlay
|
||||||
|
|
||||||
## white-balance-module
|
This adds the grid over an image.
|
||||||
|
|
||||||
This module is used for rendering neutral colors of an image correctly based on the whitest pixel in the image.
|
## Usage
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('PATH')
|
sequencer.loadImage('PATH')
|
||||||
.addSteps('white-balance',options)
|
.addSteps('grid-overlay',options)
|
||||||
.run()
|
.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
where `options` is an object with the following property:
|
where `options` is an object with the following property:
|
||||||
* red: red component of the whitest pixel (default 255)
|
* options.x : The value at which the grid line should start in x-axis.
|
||||||
* green: green component of the whitest pixel (default 255)
|
* options.y : The value at which the grid line should start in y-axis.
|
||||||
* blue: blue component of the whitest pixel (default 255)
|
* color : Color for the grid on the image.
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
/* https://github.com/theleagueof/league-spartan */
|
/* https://github.com/theleagueof/league-spartan */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'League Spartan';
|
font-family: 'League Spartan';
|
||||||
src: url('https://cdn.jsdelivr.net/npm/fontsource-league-spartan@3/files/league-spartan-latin-600-normal.woff2') format('woff2'),
|
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
|
||||||
url('https://cdn.jsdelivr.net/npm/fontsource-league-spartan@3/files/league-spartan-latin-600-normal.woff') format('woff');
|
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-weight: bold;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@@ -29,7 +33,7 @@ body > .container-fluid {
|
|||||||
|
|
||||||
.center-align {
|
.center-align {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: left;
|
justify-content: center;
|
||||||
text-align:center;
|
text-align:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,10 +46,6 @@ body > .container-fluid {
|
|||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mouse {
|
|
||||||
cursor: pointer !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nomargin {
|
.nomargin {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
@@ -63,25 +63,14 @@ body > .container-fluid {
|
|||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hover {
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
.dropzone input {
|
.dropzone input {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.import-image-zone {
|
|
||||||
margin: 10px auto 30px auto;
|
|
||||||
max-width: 250px;
|
|
||||||
min-width: 230px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.import-image-zone input {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover {
|
|
||||||
border: 4px dashed #888888;
|
|
||||||
background: #F0F0F0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step {
|
.step {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -114,10 +103,7 @@ body > .container-fluid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#add-step-btn{
|
#add-step-btn{
|
||||||
width: 100%
|
margin-left: 10px;
|
||||||
}
|
|
||||||
.selectize-input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#addStep .labels {
|
#addStep .labels {
|
||||||
@@ -151,16 +137,10 @@ body > .container-fluid {
|
|||||||
margin: 0px 0px 0px 10px;
|
margin: 0px 0px 0px 10px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(max-width: 768px) {
|
|
||||||
#dropzone {
|
|
||||||
margin: 0 0% 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#dwnld {
|
#dwnld {
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#gif_element {
|
#gif_element {
|
||||||
@@ -172,8 +152,8 @@ body > .container-fluid {
|
|||||||
|
|
||||||
#move-up {
|
#move-up {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 30px;
|
bottom: 50px;
|
||||||
right: 20px;
|
right: 40px;
|
||||||
z-index: 550;
|
z-index: 550;
|
||||||
display: none;
|
display: none;
|
||||||
background:transparent;
|
background:transparent;
|
||||||
@@ -181,17 +161,11 @@ body > .container-fluid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#move-up i {
|
#move-up i {
|
||||||
font-size:50px;
|
font-size:60px;
|
||||||
opacity:0.7;
|
opacity:0.7;
|
||||||
color:#BABABA;
|
color:#BABABA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px), (max-height 700px) {
|
|
||||||
#move-up {
|
|
||||||
display: none !important; /* !important is used to override the jQuery style */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-circle{
|
.btn-circle{
|
||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
min-height: 80px;
|
min-height: 80px;
|
||||||
@@ -270,14 +244,13 @@ a.name-header{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.step-column{
|
.step-column{
|
||||||
display:flex;
|
display:flex;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trash-container button.btn-xs {
|
.trash-container button.btn-xs {
|
||||||
position: relative;
|
margin-top: -5px !important;
|
||||||
bottom: 7px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleIcon {
|
.toggleIcon {
|
||||||
@@ -294,110 +267,8 @@ a.name-header{
|
|||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
.save-button{
|
.save-button{
|
||||||
margin-top:20px;
|
margin-top:20px;
|
||||||
margin-bottom:0px;
|
margin-bottom:0px;
|
||||||
align:center;
|
align:center;
|
||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-tooltip:hover{
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-tooltip:focus{
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-tooltip:focus-within{
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.general-tooltip{
|
|
||||||
position: relative;
|
|
||||||
bottom: 7px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
#version-number-text {
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 100px;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
#version-number-top-right {
|
|
||||||
position: fixed;
|
|
||||||
right: 2%;
|
|
||||||
top: 5%;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
/* Non float rightward alignment*/
|
|
||||||
.right {
|
|
||||||
margin-left: auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#update-prompt-modal,.notify-box {
|
|
||||||
visibility: hidden;
|
|
||||||
min-width: 250px;
|
|
||||||
margin-left: -125px;
|
|
||||||
background-color: #333;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1000;
|
|
||||||
left: 10%;
|
|
||||||
top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#update-prompt-modal {
|
|
||||||
width: 30vw;
|
|
||||||
margin: 0.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notify-box {
|
|
||||||
width:34vw;
|
|
||||||
padding:18px;
|
|
||||||
border-radius:8px;
|
|
||||||
margin-left:0.8rem;
|
|
||||||
text-align:left;
|
|
||||||
color:#333;
|
|
||||||
background:#c3c3c3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bootstrap class for display none remove it after updating to version v4 */
|
|
||||||
.d-none {
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bootstrap class for display block remove it after updating to version v4 */
|
|
||||||
.d-block {
|
|
||||||
display:block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#update-prompt-modal.show,.notify-box {
|
|
||||||
visibility: visible;
|
|
||||||
-webkit-animation: fadein 0.5s;
|
|
||||||
animation: fadein 0.5s;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes fadein {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes fadein {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
323
examples/demo.js
323
examples/demo.js
@@ -1,91 +1,52 @@
|
|||||||
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||||
setupCache = require('./lib/cache.js'),
|
setupCache = require('./lib/cache.js'),
|
||||||
intermediateHtmlStepUi = require('./lib/intermediateHtmlStepUi.js'),
|
intermediateHtmlStepUi = require('./lib/intermediateHtmlStepUi.js'),
|
||||||
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||||
urlHash = require('./lib/urlHash.js'),
|
urlHash = require('./lib/urlHash.js'),
|
||||||
insertPreview = require('./lib/insertPreview.js'),
|
insertPreview = require('./lib/insertPreview.js');
|
||||||
versionManagement = require('./lib/versionManagement.js'),
|
|
||||||
isGIF = require('../src/util/isGif');
|
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
sequencer = ImageSequencer();
|
||||||
|
|
||||||
window.onload = function () {
|
function refreshOptions() {
|
||||||
sequencer = ImageSequencer(); // Set the global sequencer variable
|
|
||||||
|
|
||||||
options = {
|
|
||||||
sortField: 'text',
|
|
||||||
openOnFocus: false,
|
|
||||||
onInitialize: function () {
|
|
||||||
this.$control.on('click', () => {
|
|
||||||
this.ignoreFocusOpen = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
// Trigger onFocus and open dropdown.
|
|
||||||
this.ignoreFocusOpen = false;
|
|
||||||
}, 50);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// Open dropdown after timeout of onClick.
|
|
||||||
onFocus: function () {
|
|
||||||
if (!this.ignoreFocusOpen) {
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
versionManagement.getLatestVersionNumber(function(versionNumber) {
|
|
||||||
console.log('The latest NPM version number for Image Sequencer (from GitHub) is v' + versionNumber);
|
|
||||||
});
|
|
||||||
console.log('The local version number for Image Sequencer is v' + versionManagement.getLocalVersionNumber());
|
|
||||||
|
|
||||||
function displayVersionNumber() {
|
|
||||||
$('#version-number-text').text('Image Sequencer v' + versionManagement.getLocalVersionNumber());
|
|
||||||
$('#version-number-top-right').text('v' + versionManagement.getLocalVersionNumber());
|
|
||||||
}
|
|
||||||
displayVersionNumber();
|
|
||||||
|
|
||||||
function refreshOptions(options) {
|
|
||||||
// Default options if parameter is empty.
|
|
||||||
if (options == undefined) options = { sortField: 'text' };
|
|
||||||
// Load information of all modules (Name, Inputs, Outputs)
|
// Load information of all modules (Name, Inputs, Outputs)
|
||||||
var modulesInfo = sequencer.modulesInfo();
|
var modulesInfo = sequencer.modulesInfo();
|
||||||
|
|
||||||
var addStepSelect = $('#addStep select');
|
var addStepSelect = $("#addStep select");
|
||||||
addStepSelect.html('');
|
addStepSelect.html("");
|
||||||
|
|
||||||
// Add modules to the addStep dropdown
|
// Add modules to the addStep dropdown
|
||||||
for (var m in modulesInfo) {
|
for (var m in modulesInfo) {
|
||||||
if (modulesInfo[m] && modulesInfo[m].name)
|
if (modulesInfo[m] && modulesInfo[m].name)
|
||||||
addStepSelect.append(
|
addStepSelect.append(
|
||||||
'<option value="' + m + '">' + modulesInfo[m].name + '</option>'
|
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Null option
|
// Null option
|
||||||
addStepSelect.append('<option value="" disabled selected>Select a Module</option>');
|
addStepSelect.append('<option value="" disabled selected>Select a Module</option>');
|
||||||
addStepSelect.selectize(options);
|
addStepSelect.selectize({
|
||||||
|
sortField: 'text'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
refreshOptions(options);
|
refreshOptions();
|
||||||
|
|
||||||
$(window).on('scroll', scrollFunction);
|
$(window).on('scroll', scrollFunction);
|
||||||
|
|
||||||
/**
|
function scrollFunction() {
|
||||||
* @description Method to toggle the scroll-up arrow.
|
|
||||||
*/
|
|
||||||
function scrollFunction(A, B) {
|
|
||||||
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
||||||
|
|
||||||
$('#move-up').css({
|
$('#move-up').css({
|
||||||
display: shouldDisplay ? 'block' : 'none'
|
display: shouldDisplay ? 'block' : 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @description Method to scroll to the top of the page.
|
|
||||||
*/
|
|
||||||
function topFunction() {
|
function topFunction() {
|
||||||
$('body').animate({scrollTop: 0});
|
$('body').animate({scrollTop: 0});
|
||||||
$(':root').animate({scrollTop: 0});
|
$(':root').animate({scrollTop: 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#move-up').on('click', topFunction);
|
$('#move-up').on("click",topFunction);
|
||||||
|
|
||||||
|
|
||||||
// UI for each step:
|
// UI for each step:
|
||||||
@@ -94,114 +55,109 @@ window.onload = function () {
|
|||||||
// UI for the overall demo:
|
// UI for the overall demo:
|
||||||
var ui = defaultHtmlSequencerUi(sequencer);
|
var ui = defaultHtmlSequencerUi(sequencer);
|
||||||
|
|
||||||
// Load image data from URL `src` parameter.
|
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||||
if (urlHash.getUrlHashParameter('src')) {
|
if (urlHash.getUrlHashParameter('src')) {
|
||||||
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
||||||
} else {
|
} else {
|
||||||
sequencer.loadImage('images/tulips.png', ui.onLoad);
|
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
var resetSequence = function () {
|
var resetSequence = function(){
|
||||||
var r = confirm('Do you want to reset the sequence?');
|
var r=confirm("Do you want to reset the sequence?");
|
||||||
if (r)
|
if (r)
|
||||||
{
|
window.location = "/";
|
||||||
window.location.hash = '';
|
}
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$('#addStep select').on('change', ui.selectNewStepUi);
|
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||||
$('#addStep #add-step-btn').on('click', ui.addStepUi);
|
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||||
$('#resetButton').on('click', resetSequence);
|
$("#resetButton").on("click",resetSequence);
|
||||||
|
|
||||||
// Module Selector quick buttons click handler.
|
//Module button radio selection
|
||||||
$('.radio-group .radio').on('click', function () {
|
$('.radio-group .radio').on("click", function() {
|
||||||
$(this).parent().find('.radio').removeClass('selected');
|
$(this).parent().find('.radio').removeClass('selected');
|
||||||
$(this).addClass('selected');
|
$(this).addClass('selected');
|
||||||
newStep = $(this).attr('data-value');
|
newStep = $(this).attr('data-value');
|
||||||
|
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||||
$('#addStep select').val(newStep);
|
$("#addStep select").val(newStep);
|
||||||
ui.selectNewStepUi(newStep);
|
ui.selectNewStepUi(newStep);
|
||||||
ui.addStepUi(newStep);
|
ui.addStepUi(newStep);
|
||||||
$(this).removeClass('selected');
|
$(this).removeClass('selected');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
$('#download-btn').click(function() {
|
||||||
* @method displayMessageOnSaveSequence
|
$('.step-thumbnail:last()').trigger("click");
|
||||||
* @description When a sequence is saved to a browser, notification is displayed.
|
return false;
|
||||||
* @returns {Null}
|
});
|
||||||
*/
|
|
||||||
function displayMessageOnSaveSequence() {
|
function displayMessageOnSaveSequence(){
|
||||||
$('.savesequencemsg').fadeIn();
|
$(".savesequencemsg").fadeIn();
|
||||||
setTimeout(function () {
|
setTimeout(function() {
|
||||||
$('.savesequencemsg').fadeOut();
|
$(".savesequencemsg").fadeOut();
|
||||||
}, 3000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||||
function saveSequence() { // 1. save seq
|
$('#save-seq').click(() => {
|
||||||
var result = window.prompt('Please give a name to your sequence... (Saved sequence will only be available in this browser).');
|
var result = window.prompt("Please give a name to your sequence... (Saved sequence will only be available in this browser).");
|
||||||
if (result) {
|
if(result){
|
||||||
result = result + ' (local)';
|
result = result + " (local)";
|
||||||
sequencer.saveSequence(result, sequencer.toString()); // 1.a study saveSequence
|
sequencer.saveSequence(result, sequencer.toString());
|
||||||
sequencer.loadModules();
|
sequencer.loadModules();
|
||||||
displayMessageOnSaveSequence();
|
displayMessageOnSaveSequence();
|
||||||
refreshOptions();
|
refreshOptions();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$('#saveButton').on('click', function () {
|
|
||||||
// Different handlers triggered for different dropdown options.
|
|
||||||
|
|
||||||
let dropDownValue = $('#selectSaveOption option:selected').val();
|
|
||||||
|
|
||||||
if (dropDownValue == 'save-image') {
|
|
||||||
$('.download-btn:last()').trigger('click');
|
|
||||||
}
|
|
||||||
else if (dropDownValue == 'save-gif') {
|
|
||||||
handleSavePNG();
|
|
||||||
}
|
|
||||||
else if (dropDownValue == 'save-seq') {
|
|
||||||
saveSequence();
|
|
||||||
} else if(dropDownValue == 'save-pdf') {
|
|
||||||
savePDF(getLastImage());
|
|
||||||
}
|
|
||||||
else if (dropDownValue == 'save-to-publiclab.org' ){
|
|
||||||
SaveToPubliclab();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let isWorkingOnGifGeneration = false;
|
var isWorkingOnGifGeneration = false;
|
||||||
|
|
||||||
$('.js-view-as-gif').on('click', function (event) { // GIF generation and display
|
$('.js-view-as-gif').on('click', function(event) {
|
||||||
if (isWorkingOnGifGeneration) return; // Prevent multiple button clicks
|
// Prevent user from triggering generation multiple times
|
||||||
|
if (isWorkingOnGifGeneration) return;
|
||||||
|
|
||||||
isWorkingOnGifGeneration = true;
|
isWorkingOnGifGeneration = true;
|
||||||
|
|
||||||
var button = event.target;
|
var button = event.target;
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
button.innerHTML = '<i class="fa fa-circle-o-notch fa-spin"></i>';
|
button.innerHTML='<i class="fa fa-circle-o-notch fa-spin"></i>'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get GIF resources from previous steps
|
// Select all images from previous steps
|
||||||
let options = getGifResources();
|
var imgs = document.getElementsByClassName("step-thumbnail");
|
||||||
|
|
||||||
gifshot.createGIF(options, function (obj) { // GIF generation
|
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) {
|
if (!obj.error) {
|
||||||
// Final GIF encoded with base64 format
|
// Final gif encoded with base64 format
|
||||||
var image = obj.image;
|
var image = obj.image;
|
||||||
var animatedImage = document.createElement('img');
|
var animatedImage = document.createElement('img');
|
||||||
|
|
||||||
animatedImage.id = 'gif_element';
|
animatedImage.id = "gif_element";
|
||||||
animatedImage.src = image;
|
animatedImage.src = image;
|
||||||
|
|
||||||
let modal = $('#js-download-gif-modal');
|
|
||||||
|
|
||||||
$('#js-download-as-gif-button').one('click', function () {
|
var modal = $('#js-download-gif-modal');
|
||||||
downloadGif(image); // Trigger GIF download
|
|
||||||
|
$("#js-download-as-gif-button").one("click", function() {
|
||||||
|
// Trigger download
|
||||||
|
download(image, "index.gif", "image/gif");
|
||||||
|
|
||||||
|
// Close modal
|
||||||
modal.modal('hide');
|
modal.modal('hide');
|
||||||
});
|
})
|
||||||
|
|
||||||
var gifContainer = document.getElementById('js-download-modal-gif-container');
|
var gifContainer = document.getElementById("js-download-modal-gif-container");
|
||||||
|
|
||||||
// Clear previous results
|
// Clear previous results
|
||||||
gifContainer.innerHTML = '';
|
gifContainer.innerHTML = '';
|
||||||
@@ -209,6 +165,7 @@ window.onload = function () {
|
|||||||
// Insert image
|
// Insert image
|
||||||
gifContainer.appendChild(animatedImage);
|
gifContainer.appendChild(animatedImage);
|
||||||
|
|
||||||
|
|
||||||
// Open modal
|
// Open modal
|
||||||
modal.modal();
|
modal.modal();
|
||||||
|
|
||||||
@@ -223,132 +180,46 @@ window.onload = function () {
|
|||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
button.innerHTML = 'View GIF';
|
button.innerHTML = 'View GIF';
|
||||||
isWorkingOnGifGeneration = false;
|
isWorkingOnGifGeneration = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function getGifResources() {
|
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
||||||
// Returns an object with specific gif options
|
|
||||||
let imgs = document.getElementsByClassName('step-thumbnail');
|
|
||||||
var imgSrcs = [];
|
|
||||||
|
|
||||||
// Pushes image sources of all the modules in the DOM
|
|
||||||
for (var i = 0; i < imgs.length; i++) {
|
|
||||||
imgSrcs.push(imgs[i].src);
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = { // GIF frame options
|
|
||||||
'gifWidth': imgs[0].width,
|
|
||||||
'gifHeight': imgs[0].height,
|
|
||||||
'images': imgSrcs,
|
|
||||||
'frameDuration': 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSavePNG() {
|
|
||||||
let options = getGifResources();
|
|
||||||
gifshot.createGIF(options, function(obj){
|
|
||||||
|
|
||||||
downloadGif(obj.image);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data URL for the last image in the sequence.
|
|
||||||
* @return {string} The data URL for the last image in the sequence.
|
|
||||||
*/
|
|
||||||
function getLastImage() {
|
|
||||||
// Get the image from the last step.
|
|
||||||
let imgs = document.getElementsByClassName('step-thumbnail');
|
|
||||||
let lastStepImage = imgs[imgs.length - 1];
|
|
||||||
return lastStepImage.getAttribute('src');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download the given image URL as a PDF file.
|
|
||||||
* @param {string} imageDataURL - The data URL for the image.
|
|
||||||
*/
|
|
||||||
function savePDF(imageDataURL) {
|
|
||||||
sequencer.getImageDimensions(imageDataURL, function(dimensions) {
|
|
||||||
if (isGIF(imageDataURL)) {
|
|
||||||
// Get the dimensions of the image.
|
|
||||||
let pageWidth = dimensions.width;
|
|
||||||
let pageHeight = dimensions.height;
|
|
||||||
|
|
||||||
// Create a new pdf with the same dimensions as the image.
|
|
||||||
const pdf = new jsPDF({
|
|
||||||
orientation: pageHeight > pageWidth ? 'portrait' : 'landscape',
|
|
||||||
unit: 'px',
|
|
||||||
format: [pageHeight, pageWidth]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the image to the pdf with dimensions equal to the internal dimensions of the page.
|
|
||||||
pdf.addImage(imageDataURL, 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight());
|
|
||||||
|
|
||||||
// Save the pdf with the filename specified here:
|
|
||||||
pdf.save('index.pdf');
|
|
||||||
}
|
|
||||||
else console.log('GIFs cannot be converted to PDF');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function downloadGif(image) {
|
|
||||||
download(image, 'index.gif', 'image/gif'); // Downloadjs library function
|
|
||||||
}
|
|
||||||
|
|
||||||
function SaveToPubliclab() {
|
|
||||||
function postToPL(imgSrc) {
|
|
||||||
var uniq = Date.now();
|
|
||||||
$('body').append('<form method="post" id="postToPL' + uniq + '" action="https://publiclab.org/post" target="postToPLWindow"><input type="hidden" name="datauri_main_image" /></form>');
|
|
||||||
f = $('#postToPL' + uniq)[0];
|
|
||||||
f.datauri_main_image.value = imgSrc;
|
|
||||||
window.open('', 'postToPLWindow');
|
|
||||||
f.submit();
|
|
||||||
}
|
|
||||||
postToPL($('img')[sequencer.steps.length - 1].src);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image selection and drag/drop handling from examples/lib/imageSelection.js
|
|
||||||
sequencer.setInputStep({
|
sequencer.setInputStep({
|
||||||
dropZoneSelector: '#dropzone',
|
dropZoneSelector: "#dropzone",
|
||||||
fileInputSelector: '#fileInput',
|
fileInputSelector: "#fileInput",
|
||||||
takePhotoSelector: '#take-photo',
|
takePhotoSelector: "#take-photo",
|
||||||
onLoad: function onFileReaderLoad(progress) {
|
onLoad: function onFileReaderLoad(progress) {
|
||||||
var reader = progress.target;
|
var reader = progress.target;
|
||||||
var step = sequencer.steps[0];
|
var step = sequencer.steps[0];
|
||||||
var util = intermediateHtmlStepUi(sequencer);
|
var util= intermediateHtmlStepUi(sequencer);
|
||||||
step.output.src = reader.result;
|
step.output.src = reader.result;
|
||||||
sequencer.run({ index: 0 });
|
sequencer.run({ index: 0 });
|
||||||
if (typeof step.options !== 'undefined')
|
if(typeof step.options !=="undefined")
|
||||||
step.options.step.imgElement.src = reader.result;
|
step.options.step.imgElement.src = reader.result;
|
||||||
else
|
else
|
||||||
step.imgElement.src = reader.result;
|
step.imgElement.src = reader.result;
|
||||||
|
insertPreview.updatePreviews(reader.result,'#addStep');
|
||||||
insertPreview.updatePreviews(reader.result, document.querySelector('#addStep'));
|
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'.insertDiv');
|
||||||
DefaultHtmlStepUi(sequencer).updateDimensions(step);
|
|
||||||
},
|
},
|
||||||
onTakePhoto: function (url) {
|
onTakePhoto: function (url) {
|
||||||
var step = sequencer.steps[0];
|
var step = sequencer.steps[0];
|
||||||
step.output.src = url;
|
step.output.src = url;
|
||||||
sequencer.run({ index: 0 });
|
sequencer.run({ index: 0 });
|
||||||
if (typeof step.options !== 'undefined')
|
if(typeof step.options !=="undefined")
|
||||||
step.options.step.imgElement.src = url;
|
step.options.step.imgElement.src = url;
|
||||||
else
|
else
|
||||||
step.imgElement.src = url;
|
step.imgElement.src = url;
|
||||||
insertPreview.updatePreviews(url, document.querySelector('#addStep'));
|
insertPreview.updatePreviews(url,'#addStep');
|
||||||
DefaultHtmlStepUi(sequencer).updateDimensions(step);
|
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'.insertDiv');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setupCache();
|
setupCache();
|
||||||
|
|
||||||
if (urlHash.getUrlHashParameter('src')) { // Gets the sequence from the URL
|
if (urlHash.getUrlHashParameter('src')) {
|
||||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'), document.querySelector('#addStep'));
|
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'#addStep');
|
||||||
} else {
|
} else {
|
||||||
insertPreview.updatePreviews('images/tulips.png', document.querySelector('#addStep'));
|
insertPreview.updatePreviews("images/tulips.png",'#addStep');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -9,16 +9,11 @@
|
|||||||
<meta name="theme-color" content="#428bca">
|
<meta name="theme-color" content="#428bca">
|
||||||
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
|
<!--Adding meta Tag for search engine optimisation-->
|
||||||
<!--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:description"
|
<meta property="og:site_name" content="sequencer.publiclab.org">
|
||||||
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:url" content="https://sequencer.publiclab.org">
|
||||||
<meta property="og:site_name" content="sequencer.publiclab.org">
|
<meta property="og:title" content="Image Sequencer">
|
||||||
<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>
|
<title>Image Sequencer</title>
|
||||||
|
|
||||||
@@ -27,53 +22,33 @@
|
|||||||
<script src="../src/ui/prepareDynamic.js"></script>
|
<script src="../src/ui/prepareDynamic.js"></script>
|
||||||
<script src="../dist/image-sequencer.js" charset="utf-8"></script>
|
<script src="../dist/image-sequencer.js" charset="utf-8"></script>
|
||||||
<script src="../dist/image-sequencer-ui.js" charset="utf-8"></script>
|
<script src="../dist/image-sequencer-ui.js" charset="utf-8"></script>
|
||||||
<script src="../node_modules/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js"></script>
|
|
||||||
<!-- for crop module: -->
|
<!-- for crop module: -->
|
||||||
<script src="../node_modules/imgareaselect/jquery.imgareaselect.dev.js"></script>
|
<script src="../node_modules/imgareaselect/jquery.imgareaselect.dev.js"></script>
|
||||||
<script src="../node_modules/gifshot/dist/gifshot.min.js" type="text/javascript"></script>
|
<script src="../node_modules/gifshot/dist/gifshot.min.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<!-- Download.js for large files -->
|
<!-- Download.js for large files -->
|
||||||
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript" ></script>
|
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript"/>
|
||||||
|
|
||||||
<!-- jspdf to enable save image as pdf -->
|
<script src="lib/scrollToTop.js"></script>
|
||||||
<script src="../node_modules/jspdf/dist/jspdf.min.js" type="text/javascript" ></script>
|
|
||||||
|
|
||||||
<!-- <script src="lib/scrollToTop.js"></script> -->
|
|
||||||
<script src="../node_modules/selectize/dist/js/standalone/selectize.min.js"></script>
|
<script src="../node_modules/selectize/dist/js/standalone/selectize.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="../node_modules/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css" rel="stylesheet">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="demo.css">
|
<link rel="stylesheet" href="demo.css">
|
||||||
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
<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">
|
<link href="../node_modules/selectize/dist/css/selectize.default.css" rel="stylesheet">
|
||||||
<!-- for crop module: -->
|
<!-- 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 href="./selectize.default.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="demo.css">
|
<link rel="stylesheet" href="demo.css">
|
||||||
|
|
||||||
<div id="update-prompt-modal">A new version of image sequencer is available. Click <a href="#" id="reload">here</a> to update.</div>
|
|
||||||
|
|
||||||
<div class="notify-box d-none">
|
|
||||||
<strong>Failed To Load Image</strong>
|
|
||||||
<button type="button" class="ml-2 mb-1 close" id="close-popup"><span>×</span></button>
|
|
||||||
<div class="notify-msg">
|
|
||||||
Can not Load Image Due to CORS Error Learn more about this
|
|
||||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors" target="_blank">here</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<header class="text-center">
|
<header class="text-center">
|
||||||
<h1><a href="/" target='_blank' class="name-header">Image Sequencer</a></h1>
|
<h1><a href="/" target='_blank' class="name-header">Image Sequencer</a></h1>
|
||||||
<p>
|
<p>
|
||||||
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original
|
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it
|
||||||
image, it
|
|
||||||
creates a new image at each step in a sequence.
|
creates a new image at each step in a sequence.
|
||||||
<a href="https://publiclab.org/image-sequencer">Learn more</a>
|
<a href="https://publiclab.org/image-sequencer">Learn more</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -82,19 +57,18 @@
|
|||||||
<a href="https://github.com/publiclab/image-sequencer">
|
<a href="https://github.com/publiclab/image-sequencer">
|
||||||
<i class="fa fa-github"></i>
|
<i class="fa fa-github"></i>
|
||||||
</a>
|
</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>
|
</p>
|
||||||
<span id="version-number-top-right"></span>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="dropzone" class="dropzone">
|
<div id="dropzone" class="dropzone">
|
||||||
<p id="dropzone-text">
|
<p>
|
||||||
<i>Select or drag in an image to start!</i>
|
<i>Select or drag in an image to start!</i>
|
||||||
</p>
|
</p>
|
||||||
<center>
|
<center>
|
||||||
<input type="file" id="fileInput" value="" accept="image/*"><br />
|
<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>
|
<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>
|
<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="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>
|
<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>
|
<canvas id="canvas" width="400" height="300" style="display:none"></canvas>
|
||||||
@@ -106,153 +80,143 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<p class="alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules in browser's localStorage.
|
<p class = "alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules.</p>
|
||||||
</p>
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col-sm-8">
|
||||||
<div class="col-sm-8">
|
<section id="addStep" class="panel panel-primary">
|
||||||
<section id="addStep" class="panel panel-primary">
|
<div class="form-inline">
|
||||||
<div class="form-inline">
|
<div class="panel-body">
|
||||||
<div class="panel-body">
|
<div style="display:flex; justify-content:center;">
|
||||||
<div style="display:flex; justify-content:center;">
|
</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>
|
</div>
|
||||||
<p class="info">Select a new module to add to your sequence.</p>
|
<p>Resize</p>
|
||||||
<div class="row center-align radio-group">
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="radio" data-value="resize">
|
<div class="radio" data-value="brightness">
|
||||||
<i class="fa fa-arrows-alt fa-4x i-over"></i>
|
<i class="fa fa-sun-o 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>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<p>Brightness</p>
|
||||||
<div class="col-lg-8">
|
</div>
|
||||||
|
<div>
|
||||||
<select id="selectStep" class="text-center">
|
<div class="radio" data-value="contrast">
|
||||||
<!-- The default null selection has been appended manually in demo.js
|
<i class="fa fa-adjust fa-4x i-over"></i>
|
||||||
This is because the options in select are overritten when options are appended.-->
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-4">
|
|
||||||
<button class="btn btn-primary btn-lg" name="add" id="add-step-btn">Add Step</button></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row center-align">
|
<p>Contrast</p>
|
||||||
<button id="resetButton" class="btn btn-default btn-lg"
|
</div>
|
||||||
style=" margin: 20px 35px 0px 35px; width:100%;">Clear All Steps</button>
|
<div>
|
||||||
|
<div class="radio" data-value="saturation">
|
||||||
|
<i class="fa fa-tint fa-4x i-over i-small"></i>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</section>
|
<div class="row center-align">
|
||||||
|
<div class="col-md-8">
|
||||||
<div class="modal fade" id="js-download-gif-modal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog" role="document">
|
<select id="selectStep" >
|
||||||
<div class="modal-content">
|
<!-- The default null selection has been appended manually in demo.js
|
||||||
<div class="modal-header">
|
This is because the options in select are overritten when options are appended.-->
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
</select>
|
||||||
aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">Your gif is ready</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id="js-download-modal-gif-container">
|
|
||||||
<!-- Gif should appear here -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>
|
|
||||||
|
|
||||||
<button id="js-download-as-gif-button" class="btn btn-primary">Download</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button></div>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="modal fade" id="js-download-gif-modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">Your gif is ready</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="js-download-modal-gif-container">
|
||||||
|
<!-- Gif should appear here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>
|
||||||
|
|
||||||
|
<button id="js-download-as-gif-button" class="btn btn-primary">Download</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<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 mouse" id="selectSaveOption" style="margin-top:20px">
|
|
||||||
<option value="save-image">Save as PNG</option>
|
|
||||||
<option value="save-gif">Save as GIF (all steps)</option>
|
|
||||||
<option value="save-pdf">Save as PDF</option>
|
|
||||||
<option value="save-seq">Save sequence</option>
|
|
||||||
<option value="save-seq-string">Save sequence string</option>
|
|
||||||
<option value="save-to-publiclab.org">Save to PublicLab.org</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
</div>
|
||||||
<hr style="margin:20px;">
|
<div class="col-sm-4">
|
||||||
<center><button class="btn btn-default btn-sm" id="clear-cache">Clear offline cache</button></center>
|
<section id="dwnld" class="panel panel-primary">
|
||||||
<div class="row">
|
<div class="form-inline">
|
||||||
<div class="col-md-6">
|
<div class="panel-body">
|
||||||
<h2>Need Help?</h2>
|
<div style="text-align:center;">
|
||||||
<p>
|
<h2 style="margin-top:20px">Save</h2>
|
||||||
<a class="btn btn-default" href="https://github.com/publiclab/image-sequencer/issues">Ask a question</a>
|
<select class="form-control input-md" id="selectSaveOption" style="margin-top:20px">
|
||||||
<a class="btn btn-default" href="https://gitter.im/publiclab/image-sequencer" target="_blank">Ask in our chatroom </a>
|
<option>Save as PNG</option>
|
||||||
</p>
|
<option>Save as GIF (all steps)</option>
|
||||||
</div>
|
<option>Save sequence</option>
|
||||||
<div class="col-md-6">
|
<option>Save sequence string</option>
|
||||||
<h2>Improve this tool</h2>
|
</select>
|
||||||
<p>
|
<p><button id="saveButton" class="btn btn-primary btn-lg save-button">Save</button></p>
|
||||||
This is an open source toolkit which you can help improve on Github
|
<p><button class="btn btn-default btn-lg js-view-as-gif" id="gif">Preview GIF</button></p>
|
||||||
</p>
|
</div>
|
||||||
<p>
|
|
||||||
<a class="btn btn-default" href="https://github.com/publiclab/image-sequencer">View the code »</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
</section>
|
||||||
<p id="version-number-text">Loading Version Number</p>
|
</div>
|
||||||
|
</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>
|
||||||
</footer>
|
<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>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<button id="move-up"><i class="fa fa-arrow-circle-o-up"></i></button>
|
<button id="move-up"><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function() {
|
||||||
var sequencer;
|
var sequencer;
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<script async src="../node_modules/opencv.js/opencv.js" type="text/javascript"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +1,39 @@
|
|||||||
var setupCache = function() {
|
var setupCache = function() {
|
||||||
let newWorker; // When sw.js is changed, this is the new service worker generated.
|
|
||||||
|
|
||||||
// Toggle a CSS class to display a popup prompting the user to fetch a new version.
|
|
||||||
function showUpdateModal() {
|
|
||||||
$('#update-prompt-modal').addClass('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a new service worker has been loaded, the button in the update prompt
|
|
||||||
* modal should trigger the skipWaiting event to replace the current
|
|
||||||
* service worker with the new one.
|
|
||||||
*/
|
|
||||||
$('#reload').on('click', function() {
|
|
||||||
newWorker.postMessage({ action: 'skipWaiting' });
|
|
||||||
});
|
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
// Register the service worker.
|
|
||||||
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||||
.then(function(registration) {
|
.then(function(registration) {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
return new Promise(function(resolve,reject){
|
installingWorker.onstatechange = () => {
|
||||||
|
console.log(installingWorker)
|
||||||
registration.addEventListener('updatefound', () => {
|
if (installingWorker.state === 'installed') {
|
||||||
// When sw.js has been changed, get a reference to the new service worker.
|
location.reload();
|
||||||
newWorker = registration.installing;
|
}
|
||||||
|
}
|
||||||
if(!newWorker){
|
console.log('Registration successful, scope is:', registration.scope);
|
||||||
return reject(new Error('error in installing service worker'));
|
})
|
||||||
}
|
.catch(function(error) {
|
||||||
|
console.log('Service worker registration failed, error:', error);
|
||||||
newWorker.addEventListener('statechange', () => {
|
|
||||||
// Check if service worker state has changed.
|
|
||||||
switch(newWorker.state) {
|
|
||||||
case 'installed':
|
|
||||||
if(navigator.serviceWorker.controller) {
|
|
||||||
// New service worker available; prompt the user to update.
|
|
||||||
showUpdateModal();
|
|
||||||
$('#reload').on('click',(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
console.log('New Service Worker Installed Successfully');
|
|
||||||
location.reload();
|
|
||||||
return resolve();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// No updates available; do nothing.
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'redundant':
|
|
||||||
return reject(new Error('installing new service worker now became redundant'));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}).catch(err => {
|
|
||||||
console.log('Failed In Registering Service Worker: ',err);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the event listener for when the service worker updates.
|
|
||||||
* When the service worker updates, reload the page.
|
|
||||||
*/
|
|
||||||
let refreshing;
|
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', function() {
|
|
||||||
if(refreshing) return;
|
|
||||||
window.location.reload();
|
|
||||||
refreshing = true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
caches.keys().then(function(cacheNames) {
|
caches.keys().then(function(cacheNames) {
|
||||||
cacheNames.forEach(function(cacheName) {
|
cacheNames.forEach(function(cacheName) {
|
||||||
$('#clear-cache').append(' ' + cacheName);
|
$("#clear-cache").append(" " + cacheName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearCache = () => {
|
$("#clear-cache").click(function() {
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
return caches.keys()
|
caches.keys().then(function(cacheNames) {
|
||||||
.then(function(cache) {
|
cacheNames.forEach(function(cacheName) {
|
||||||
return Promise.all(cache.map(function(cacheItem) {
|
caches.delete(cacheName);
|
||||||
return caches.delete(cacheItem);
|
});
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$('#clear-cache').click(function() {
|
|
||||||
clearCache();
|
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = setupCache;
|
module.exports = setupCache;
|
||||||
|
|||||||
@@ -1,62 +1,52 @@
|
|||||||
var urlHash = require('./urlHash.js');
|
var urlHash = require('./urlHash.js');
|
||||||
insertPreview = require('./insertPreview.js');
|
|
||||||
function DefaultHtmlSequencerUi(_sequencer, options) {
|
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var addStepSel = options.addStepSel = options.addStepSel || '#addStep';
|
var addStepSel = options.addStepSel = options.addStepSel || "#addStep";
|
||||||
var removeStepSel = options.removeStepSel = options.removeStepSel || 'button.remove';
|
var removeStepSel = options.removeStepSel = options.removeStepSel || "button.remove";
|
||||||
var selectStepSel = options.selectStepSel = options.selectStepSel || '#selectStep';
|
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||||
|
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
importStepsFromUrlHash();
|
importStepsFromUrlHash();
|
||||||
if ($('#selectStep').val() === 'none')
|
if ($('#selectStep').val()==='none')
|
||||||
$(addStepSel + ' #add-step-btn').prop('disabled', true);
|
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||||
handleSaveSequence();
|
handleSaveSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
// look up needed steps from Url Hash:
|
// look up needed steps from Url Hash:
|
||||||
function importStepsFromUrlHash() {
|
function importStepsFromUrlHash() {
|
||||||
var hash = urlHash.getUrlHashParameter('steps');
|
var hash = urlHash.getUrlHashParameter("steps");
|
||||||
|
|
||||||
if (hash) {
|
if (hash) {
|
||||||
_sequencer.importString(hash);
|
_sequencer.importString(hash);
|
||||||
_sequencer.run({ index: 0 });
|
_sequencer.run({ index: 0 });
|
||||||
}
|
}
|
||||||
urlHash.setUrlHashParameter('steps', sequencer.toString());
|
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNewStepUi() {
|
function selectNewStepUi() {
|
||||||
var m = $(addStepSel + ' select').val();
|
var m = $(addStepSel + " select").val();
|
||||||
if(m) $(addStepSel + ' .info').html(_sequencer.modulesInfo(m).description);
|
if(!m) m = arguments[0];
|
||||||
$(addStepSel + ' #add-step-btn').prop('disabled', false);
|
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||||
|
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStepUi() {
|
function removeStepUi() {
|
||||||
var index = $(removeStepSel).index(this) + 1;
|
var index = $(removeStepSel).index(this) + 1;
|
||||||
// If last step is removed.
|
|
||||||
if(sequencer.steps.length==index+1){
|
|
||||||
console.log("inside")
|
|
||||||
insertPreview.updatePreviews(sequencer.steps[index-1].output.src, document.querySelector('#addStep'));
|
|
||||||
}
|
|
||||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||||
// remove from URL hash too
|
// remove from URL hash too
|
||||||
urlHash.setUrlHashParameter('steps', sequencer.toString());
|
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||||
//disable save-sequence button if all steps are removed
|
//disable save-sequence button if all steps are removed
|
||||||
handleSaveSequence();
|
handleSaveSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStepUi() {
|
function addStepUi() {
|
||||||
|
if ($(addStepSel + " select").val() == "none") return;
|
||||||
if ($(addStepSel + ' select').val() == ''){
|
|
||||||
alert('Please Select a Step to Proceed');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newStepName;
|
var newStepName = $(addStepSel + " select").val();
|
||||||
if(typeof arguments[0] !== 'string')
|
|
||||||
newStepName = $(addStepSel + ' select option').html().toLowerCase().split(' ').join('-');
|
if(!newStepName) newStepName = arguments[0]
|
||||||
else newStepName = arguments[0];
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* after adding the step we run the sequencer from defined step
|
* 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
|
* and since loadImage is not a part of the drawarray the step lies at current
|
||||||
@@ -65,28 +55,28 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
|||||||
var sequenceLength = 1;
|
var sequenceLength = 1;
|
||||||
if (sequencer.sequences[newStepName]) {
|
if (sequencer.sequences[newStepName]) {
|
||||||
sequenceLength = sequencer.sequences[newStepName].length;
|
sequenceLength = sequencer.sequences[newStepName].length;
|
||||||
} else if (sequencer.modules[newStepName][1]['length']) {
|
} else if (sequencer.modules[newStepName][1]["length"]) {
|
||||||
sequenceLength = sequencer.modules[newStepName][1]['length'];
|
sequenceLength = sequencer.modules[newStepName][1]["length"];
|
||||||
}
|
}
|
||||||
_sequencer
|
_sequencer
|
||||||
.addSteps(newStepName, options)
|
.addSteps(newStepName, options)
|
||||||
.run({ index: _sequencer.steps.length - sequenceLength - 1 });
|
.run({ index: _sequencer.steps.length - sequenceLength - 1 });
|
||||||
$(addStepSel + ' .info').html('Select a new module to add to your sequence.');
|
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||||
$(addStepSel + ' select').val('none');
|
$(addStepSel + " select").val("none");
|
||||||
|
|
||||||
//enable save-sequence button if disabled initially
|
//enable save-sequence button if disabled initially
|
||||||
handleSaveSequence();
|
handleSaveSequence();
|
||||||
|
|
||||||
// add to URL hash too
|
// add to URL hash too
|
||||||
urlHash.setUrlHashParameter('steps', _sequencer.toString());
|
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSaveSequence(){
|
function handleSaveSequence(){
|
||||||
var stepCount = sequencer.steps.length;
|
var stepCount=sequencer.steps.length;
|
||||||
if(stepCount < 2)
|
if(stepCount<2)
|
||||||
$(' #save-seq').prop('disabled', true);
|
$(" #save-seq").prop("disabled", true);
|
||||||
else
|
else
|
||||||
$(' #save-seq').prop('disabled', false);
|
$(" #save-seq").prop("disabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -95,7 +85,7 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
|||||||
selectNewStepUi: selectNewStepUi,
|
selectNewStepUi: selectNewStepUi,
|
||||||
removeStepUi: removeStepUi,
|
removeStepUi: removeStepUi,
|
||||||
addStepUi: addStepUi
|
addStepUi: addStepUi
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DefaultHtmlSequencerUi;
|
module.exports = DefaultHtmlSequencerUi;
|
||||||
|
|||||||
@@ -8,41 +8,29 @@
|
|||||||
// output values, step information.
|
// output values, step information.
|
||||||
// See documetation for more details.
|
// See documetation for more details.
|
||||||
|
|
||||||
const intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js'),
|
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||||
urlHash = require('./urlHash.js'),
|
var urlHash = require('./urlHash.js');
|
||||||
_ = require('lodash'),
|
var _ = require('lodash');
|
||||||
insertPreview = require('./insertPreview.js');
|
var mapHtmlTypes = require('./mapHtmltypes');
|
||||||
mapHtmlTypes = require('./mapHtmltypes'),
|
|
||||||
scopeQuery = require('./scopeQuery'),
|
|
||||||
isGIF = require('../../src/util/isGif');
|
|
||||||
|
|
||||||
function DefaultHtmlStepUi(_sequencer, options) {
|
function DefaultHtmlStepUi(_sequencer, options) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var stepsEl = options.stepsEl || document.querySelector('#steps');
|
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||||
var selectStepSel = options.selectStepSel = options.selectStepSel || '#selectStep';
|
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||||
|
|
||||||
function onSetup(step, stepOptions) {
|
function onSetup(step, stepOptions) {
|
||||||
if (step.options && step.options.description)
|
if (step.options && step.options.description)
|
||||||
step.description = step.options.description;
|
step.description = step.options.description;
|
||||||
|
|
||||||
let stepDocsLink = '';
|
|
||||||
if (step.moduleInfo) stepDocsLink = step.moduleInfo['docs-link'] || '';
|
|
||||||
|
|
||||||
step.ui = // Basic UI markup for the step
|
step.ui =
|
||||||
'\
|
'\
|
||||||
<div class="container-fluid step-container">\
|
<div class="container-fluid step-container">\
|
||||||
<div class="panel panel-default">\
|
<div class="panel panel-default">\
|
||||||
<div class="panel-heading">\
|
<div class="panel-heading">\
|
||||||
<div class="trash-container pull-right">\
|
<div class="trash-container pull-right"></div>\
|
||||||
<a type="button" target="_blank" href="https://developer.mozilla.org/en-US/docs/WebAssembly" style="display: none;" class="btn btn-link general-tooltip wasm-tooltip" data-toggle="tooltip" data-html="true" data-original-title="<div style=\'text-align: center\'><p>This step is Web Assembly accelerated. Click to Read More</div>">\
|
<h3 class="panel-title">' +
|
||||||
<i class="fa fa-bolt"></i>\
|
'<span class="toggle">' +step.name + ' <span class="caret toggleIcon rotated"></span>\
|
||||||
</a>\
|
|
||||||
<button type="button" class="btn btn-link ' + step.name + ' general-tooltip dimension-tooltip" data-toggle="tooltip" data-html="true" data-original-title="">\
|
|
||||||
<i class="fa fa-info-circle"></i>\
|
|
||||||
</button>\
|
|
||||||
</div>\
|
|
||||||
<h3 class="panel-title">' +
|
|
||||||
'<span class="toggle mouse">' + 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>\
|
<span class="load-spin pull-right" style="display:none;padding:1px 8px;"><i class="fa fa-circle-o-notch fa-spin"></i></span>\
|
||||||
</h3>\
|
</h3>\
|
||||||
</div>\
|
</div>\
|
||||||
@@ -51,7 +39,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
<div class="row step">\
|
<div class="row step">\
|
||||||
<div class="col-md-4 details container-fluid">\
|
<div class="col-md-4 details container-fluid">\
|
||||||
<div class="cal collapse in"><p>' +
|
<div class="cal collapse in"><p>' +
|
||||||
'<a href="' + stepDocsLink + '">' + (step.description || '') + '</a>' +
|
'<i>' + (step.description || "") + '</i>' +
|
||||||
'</p></div>\
|
'</p></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<div class="col-md-8 cal collapse in step-column">\
|
<div class="col-md-8 cal collapse in step-column">\
|
||||||
@@ -68,7 +56,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
</div>';
|
</div>';
|
||||||
|
|
||||||
var tools =
|
var tools =
|
||||||
'<div class="trash" style="display: inline-block">\
|
'<div class="trash">\
|
||||||
<button confirm="Are you sure?" class="remove btn btn-default btn-xs">\
|
<button confirm="Are you sure?" class="remove btn btn-default btn-xs">\
|
||||||
<i class="fa fa-trash"></i>\
|
<i class="fa fa-trash"></i>\
|
||||||
</button>\
|
</button>\
|
||||||
@@ -77,205 +65,148 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
var util = intermediateHtmlStepUi(_sequencer, step);
|
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||||
|
|
||||||
var parser = new DOMParser();
|
var parser = new DOMParser();
|
||||||
step.ui = parser.parseFromString(step.ui, 'text/html'); // Convert the markup string to a DOM node.
|
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||||
step.ui = step.ui.querySelector('div.container-fluid');
|
step.ui = step.ui.querySelector("div.container-fluid");
|
||||||
|
step.linkElements = step.ui.querySelectorAll("a");
|
||||||
step.$step = scopeQuery.scopeSelector(step.ui); // Shorthand methods for scoped DOM queries. Read the docs [CONTRIBUTING.md](https://github.com/publiclab/image-sequencer/blob/main/CONTRIBUTING.md) for more info.
|
step.imgElement = step.ui.querySelector("a img.img-thumbnail");
|
||||||
step.$stepAll = scopeQuery.scopeSelectorAll(step.ui);
|
|
||||||
let {$step, $stepAll} = step;
|
|
||||||
|
|
||||||
step.linkElements = step.ui.querySelectorAll('a'); // All the anchor tags in the step UI
|
|
||||||
step.imgElement = $step('a img.img-thumbnail')[0]; // The output image
|
|
||||||
|
|
||||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||||
var merged = Object.assign(inputs, outputs); // Combine outputs with inputs
|
var merged = Object.assign(inputs, outputs); // combine outputs w inputs
|
||||||
|
|
||||||
for (var paramName in merged) {
|
for (var paramName in merged) {
|
||||||
var isInput = inputs.hasOwnProperty(paramName);
|
var isInput = inputs.hasOwnProperty(paramName);
|
||||||
var html = '';
|
var html = "";
|
||||||
var inputDesc = isInput ? mapHtmlTypes(inputs[paramName]) : {};
|
var inputDesc = isInput ? mapHtmlTypes(inputs[paramName]) : {};
|
||||||
if (!isInput) {
|
if (!isInput) {
|
||||||
html += '<span class="output"></span>';
|
html += '<span class="output"></span>';
|
||||||
}
|
} else if (inputDesc.type.toLowerCase() == "select") {
|
||||||
else if (inputDesc.type.toLowerCase() == 'select') {
|
|
||||||
|
|
||||||
html += '<select class="form-control target" name="' + paramName + '">';
|
html += '<select class="form-control target" name="' + paramName + '">';
|
||||||
for (var option in inputDesc.values) {
|
for (var option in inputDesc.values) {
|
||||||
html += '<option>' + inputDesc.values[option] + '</option>';
|
html += "<option>" + inputDesc.values[option] + "</option>";
|
||||||
}
|
}
|
||||||
html += '</select>';
|
html += "</select>";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let paramVal = step.options[paramName] || inputDesc.default;
|
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.id == 'color-picker') { // Separate input field for color-picker
|
if (inputDesc.type.toLowerCase() == "range") {
|
||||||
html +=
|
html +=
|
||||||
'<div id="color-picker" class="input-group colorpicker-component">' +
|
'"min="' +
|
||||||
'<input class="form-control color-picker-target" type="' +
|
inputDesc.min +
|
||||||
inputDesc.type +
|
'"max="' +
|
||||||
'" name="' +
|
inputDesc.max +
|
||||||
paramName +
|
'"step="' +
|
||||||
'" value="' +
|
(inputDesc.step ? inputDesc.step : 1)+ '">' + '<span>' + paramVal + '</span>';
|
||||||
paramVal + '">' + '<span class="input-group-addon"><i></i></span>' +
|
|
||||||
'</div>';
|
|
||||||
}
|
|
||||||
else if(inputDesc.type === 'button'){
|
|
||||||
html = '<div><button name="' + paramName + '" type="' + inputDesc.type + '" >\
|
|
||||||
<i class="fa fa-crosshairs"></i></button>\
|
|
||||||
<span>click to select coordinates</span>\
|
|
||||||
</div>';
|
|
||||||
}
|
|
||||||
else { // Non color-picker input types and other than a button
|
|
||||||
|
|
||||||
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 += '">';
|
|
||||||
}
|
}
|
||||||
|
else html += '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
var div = document.createElement('div');
|
var div = document.createElement("div");
|
||||||
div.className = 'row';
|
div.className = "row";
|
||||||
div.setAttribute('name', paramName);
|
div.setAttribute("name", paramName);
|
||||||
var description = inputs[paramName].desc || paramName;
|
var description = inputs[paramName].desc || paramName;
|
||||||
div.innerHTML =
|
div.innerHTML =
|
||||||
'<div class=\'det cal collapse in\'>\
|
"<div class='det cal collapse in'>\
|
||||||
<label for=\'' +
|
<label for='" +
|
||||||
paramName +
|
paramName +
|
||||||
'\'>' +
|
"'>" +
|
||||||
description +
|
description +
|
||||||
'</label>\
|
"</label>\
|
||||||
' +
|
" +
|
||||||
html +
|
html +
|
||||||
'\
|
"\
|
||||||
</div>';
|
</div>";
|
||||||
$step('div.details').append(div);
|
step.ui.querySelector("div.details").appendChild(div);
|
||||||
}
|
}
|
||||||
$step('div.panel-footer').append( // Save button
|
$(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>'
|
'<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('div.panel-footer').prepend( // Markup for tools: download and insert step buttons
|
$(step.ui.querySelector("div.panel-footer")).prepend(
|
||||||
'<button class="pull-right btn btn-default btn-sm insert-step" >\
|
'<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>\
|
<span class="insert-text"><i class="fa fa-plus"></i> Insert Step</span><span class="no-insert-text" style="display:none">Close</span>\
|
||||||
<button class="pull-right btn btn-default btn-sm download-btn" style="margin-right:2px" >\
|
|
||||||
<i class="fa fa-download"></i>\
|
|
||||||
</button>'
|
</button>'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step.name != 'load-image') {
|
if (step.name != "load-image") {
|
||||||
$step('div.trash-container')
|
step.ui
|
||||||
|
.querySelector("div.trash-container")
|
||||||
.prepend(
|
.prepend(
|
||||||
parser.parseFromString(tools, 'text/html').querySelector('div')
|
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||||
);
|
);
|
||||||
|
$(step.ui.querySelectorAll(".remove")).on('click', function() {notify('Step Removed','remove-notification')});
|
||||||
$stepAll('.remove').on('click', function() {notify('Step Removed', 'remove-notification');}); // Notification on removal of a step
|
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||||
$step('.insert-step').on('click', function() { util.insertStep(step.ID); }); // Insert a step in between the sequence
|
|
||||||
// Insert the step's UI in the right place
|
// Insert the step's UI in the right place
|
||||||
|
|
||||||
if (stepOptions.index == _sequencer.steps.length) {
|
if (stepOptions.index == _sequencer.steps.length) {
|
||||||
stepsEl.appendChild(step.ui);
|
stepsEl.appendChild(step.ui);
|
||||||
$('#steps .step-container:nth-last-child(1) .insert-step').prop('disabled', true);
|
$("#steps .step-container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||||
if($('#steps .step-container:nth-last-child(2)'))
|
if($("#steps .step-container:nth-last-child(2)"))
|
||||||
$('#steps .step-container:nth-last-child(2) .insert-step').prop('disabled', false);
|
$("#steps .step-container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the load-image insert-step button when there are steps after load-image
|
|
||||||
// The logical operator is `> 0` because the number of steps is found before adding the step, actual logic is `steps.length + 1 > 1` which is later simplified.
|
|
||||||
if (_sequencer.steps.length > 0) $('#load-image .insert-step').prop('disabled', false);
|
|
||||||
else $('#load-image .insert-step').prop('disabled', true);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#load-image').append(step.ui); // Default UI without extra tools for the first step(load image)
|
$("#load-image").append(step.ui);
|
||||||
|
|
||||||
$step('div.panel-footer').prepend( `
|
|
||||||
<button class="right btn btn-default btn-sm insert-step" disabled="true">
|
|
||||||
<span class="insert-text"><i class="fa fa-plus"></i> Insert Step</span>
|
|
||||||
<span class="no-insert-text" style="display:none">Close</span>
|
|
||||||
</button>`
|
|
||||||
);
|
|
||||||
|
|
||||||
$step('.insert-step').on('click', function() { util.insertStep(step.ID); });
|
|
||||||
}
|
}
|
||||||
$step('.toggle').on('click', () => { // Step container dropdown
|
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||||
$step('.toggleIcon').toggleClass('rotated');
|
$(step.ui.querySelector('.toggleIcon')).toggleClass('rotated');
|
||||||
$stepAll('.cal').collapse('toggle');
|
$(step.ui.querySelectorAll(".cal")).collapse('toggle');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(step.imgElement).on("mousemove", _.debounce(() => imageHover(step), 150));
|
||||||
|
|
||||||
$(step.imgElement).on('mousemove', _.debounce(() => imageHover(step), 150)); // Shows the pixel coordinates on hover
|
function saveOptions(e) {
|
||||||
$(step.imgElement).on('click', (e) => {e.preventDefault(); });
|
|
||||||
$stepAll('#color-picker').colorpicker();
|
|
||||||
|
|
||||||
function saveOptions(e) { // 1. SAVE OPTIONS
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (optionsChanged){
|
if (optionsChanged){
|
||||||
$step('div.details')
|
$(step.ui.querySelector("div.details"))
|
||||||
.find('input,select')
|
.find("input,select")
|
||||||
.each(function(i, input) {
|
.each(function(i, input) {
|
||||||
$(input)
|
$(input)
|
||||||
.data('initValue', $(input).val())
|
.data('initValue', $(input).val())
|
||||||
.data('hasChangedBefore', false);
|
.data('hasChangedBefore', false);
|
||||||
step.options[$(input).attr('name')] = $(input).val();
|
step.options[$(input).attr("name")] = $(input).val();
|
||||||
});
|
});
|
||||||
_sequencer.run({ index: step.index - 1 });
|
_sequencer.run({ index: step.index - 1 });
|
||||||
|
|
||||||
// Modify the URL hash
|
// modify the url hash
|
||||||
urlHash.setUrlHashParameter('steps', _sequencer.toString());
|
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||||
// Disable the save button
|
// disable the save button
|
||||||
$step('.btn-save').prop('disabled', true);
|
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||||
optionsChanged = false;
|
optionsChanged = false;
|
||||||
changedInputs = 0;
|
changedInputs = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method handleInputValueChange
|
|
||||||
* @description Enables the save button on input change
|
|
||||||
* @param {*} currentValue The current value of the input
|
|
||||||
* @param {*} initValue The initial/old value of the input
|
|
||||||
* @param {Boolean} hasChangedBefore Whether the input was changed before
|
|
||||||
* @returns {Boolean} True if the value has changed
|
|
||||||
*/
|
|
||||||
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
||||||
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
||||||
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
||||||
optionsChanged = changedInputs > 0;
|
optionsChanged = changedInputs > 0;
|
||||||
|
|
||||||
$step('.btn-save').prop('disabled', !optionsChanged);
|
$(step.ui.querySelector('.btn-save')).prop('disabled', !optionsChanged);
|
||||||
return inputChanged;
|
return inputChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
var
|
var
|
||||||
changedInputs = 0,
|
changedInputs = 0,
|
||||||
optionsChanged = false;
|
optionsChanged = false;
|
||||||
$step('.input-form').on('submit', saveOptions);
|
$(step.ui.querySelector('.input-form')).on('submit', saveOptions);
|
||||||
$stepAll('.target').each(function(i, input) {
|
$(step.ui.querySelectorAll('.target')).each(function(i, input) {
|
||||||
$(input)
|
$(input)
|
||||||
.data('initValue', $(input).val())
|
.data('initValue', $(input).val())
|
||||||
.data('hasChangedBefore', false)
|
.data('hasChangedBefore', false)
|
||||||
.on('input change', function() {
|
.on('input', function() {
|
||||||
$(this)
|
$(this)
|
||||||
.focus()
|
.focus()
|
||||||
.data('hasChangedBefore',
|
.data('hasChangedBefore',
|
||||||
@@ -283,227 +214,131 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
$(this).val(),
|
$(this).val(),
|
||||||
$(this).data('initValue'),
|
$(this).data('initValue'),
|
||||||
$(this).data('hasChangedBefore')
|
$(this).data('hasChangedBefore')
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
$stepAll('.color-picker-target').each(function(i, input) {
|
|
||||||
$(input)
|
|
||||||
.data('initValue', $(input).val())
|
|
||||||
.data('hasChangedBefore', false)
|
|
||||||
.on('input change', function() {
|
|
||||||
$(this)
|
|
||||||
.data('hasChangedBefore',
|
|
||||||
handleInputValueChange(
|
|
||||||
$(this).val(),
|
|
||||||
$(this).data('initValue'),
|
|
||||||
$(this).data('hasChangedBefore')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$('input[type="range"]').on('input', function() {
|
$('input[type="range"]').on('input', function() {
|
||||||
$(this).next().html($(this).val());
|
$(this).next().html($(this).val());
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onDraw({$step, $stepAll}) {
|
function onDraw(step) {
|
||||||
$step('.load').show();
|
$(step.ui.querySelector(".load")).show();
|
||||||
$step('img').hide();
|
$(step.ui.querySelector("img")).hide();
|
||||||
$stepAll('.load-spin').show();
|
$(step.ui.querySelectorAll(".load-spin")).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onComplete(step) {
|
function onComplete(step) {
|
||||||
let {$step, $stepAll} = step;
|
$(step.ui.querySelector("img")).show();
|
||||||
$step('img').show();
|
$(step.ui.querySelectorAll(".load-spin")).hide();
|
||||||
$stepAll('.load-spin').hide();
|
$(step.ui.querySelector(".load")).hide();
|
||||||
$step('.load').hide();
|
|
||||||
|
|
||||||
$stepAll('.download-btn').off('click');
|
step.imgElement.src = (step.name == "load-image") ? step.output.src : step.output;
|
||||||
|
var imgthumbnail = step.ui.querySelector(".img-thumbnail");
|
||||||
step.imgElement.src = (step.name == 'load-image') ? step.output.src : step.output;
|
|
||||||
var imgthumbnail = $step('.img-thumbnail').getDomElem();
|
|
||||||
for (let index = 0; index < step.linkElements.length; index++) {
|
for (let index = 0; index < step.linkElements.length; index++) {
|
||||||
if (step.linkElements[index].contains(imgthumbnail))
|
if (step.linkElements[index].contains(imgthumbnail))
|
||||||
step.linkElements[index].href = step.imgElement.src;
|
step.linkElements[index].href = step.imgElement.src;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use a generalized version of this.
|
// TODO: use a generalized version of this
|
||||||
function fileExtension(output) {
|
function fileExtension(output) {
|
||||||
return output.split('/')[1].split(';')[0];
|
return output.split("/")[1].split(";")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
$stepAll('.download-btn').on('click', () => {
|
for (let index = 0; index < step.linkElements.length; index++) {
|
||||||
|
|
||||||
function dataURLtoBlob(dataurl) {
|
step.linkElements[index].download = step.name + "." + fileExtension(step.imgElement.src);
|
||||||
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
step.linkElements[index].target = "_blank";
|
||||||
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
}
|
||||||
while(n--){
|
|
||||||
u8arr[n] = bstr.charCodeAt(n);
|
|
||||||
}
|
|
||||||
return new Blob([u8arr], {type:mime});
|
|
||||||
}
|
|
||||||
|
|
||||||
var element = document.createElement('a');
|
|
||||||
|
|
||||||
element.setAttribute('download', step.name + '.' + fileExtension(step.imgElement.src));
|
|
||||||
element.style.display = 'none';
|
|
||||||
document.body.appendChild(element);
|
|
||||||
var blob = dataURLtoBlob(step.output);
|
|
||||||
var objurl = URL.createObjectURL(blob);
|
|
||||||
element.setAttribute('href', objurl);
|
|
||||||
|
|
||||||
element.click();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fill inputs with stored step options
|
// fill inputs with stored step options
|
||||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||||
for (var i in inputs) {
|
for (var i in inputs) {
|
||||||
if (step.options[i] !== undefined) {
|
if (step.options[i] !== undefined) {
|
||||||
if (inputs[i].type.toLowerCase() === 'input')
|
if (inputs[i].type.toLowerCase() === "input")
|
||||||
$step('div[name="' + i + '"] input')
|
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||||
.val(step.options[i])
|
.val(step.options[i])
|
||||||
.data('initValue', step.options[i]);
|
.data('initValue', step.options[i]);
|
||||||
if (inputs[i].type.toLowerCase() === 'select')
|
if (inputs[i].type.toLowerCase() === "select")
|
||||||
$step('div[name="' + i + '"] select')
|
$(step.ui.querySelector('div[name="' + i + '"] select'))
|
||||||
.val(String(step.options[i]))
|
.val(step.options[i])
|
||||||
.data('initValue', step.options[i]);
|
.data('initValue', step.options[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var i in outputs) {
|
for (var i in outputs) {
|
||||||
if (step[i] !== undefined)
|
if (step[i] !== undefined)
|
||||||
$step('div[name="' + i + '"] input')
|
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||||
.val(step[i]);
|
.val(step[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
updateDimensions(step);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (step.name === 'load-image') insertPreview.updatePreviews(step.output.src, document.querySelector('#addStep'));
|
|
||||||
else insertPreview.updatePreviews(step.output, document.querySelector('#addStep'));
|
|
||||||
|
|
||||||
// Handle the wasm bolt display
|
|
||||||
|
|
||||||
if (step.useWasm) {
|
|
||||||
if (step.wasmSuccess) $step('.wasm-tooltip').fadeIn();
|
|
||||||
else $step('.wasm-tooltip').fadeOut();
|
|
||||||
}
|
|
||||||
else $step('.wasm-tooltip').fadeOut();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @description Updates Dimension of the image
|
|
||||||
* @param {Object} step - Current Step
|
|
||||||
* @returns {void}
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function updateDimensions(step){
|
|
||||||
_sequencer.getImageDimensions(step.imgElement.src, function (dim) {
|
|
||||||
step.ui.querySelector('.' + step.name).attributes['data-original-title'].value = `<div style="text-align: center"><p>Image Width: ${dim.width} px<br>Image Height: ${dim.height} px</br>${isGIF(step.output) ? `Frames: ${dim.frames}` : ''}</div>`;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method imageHover
|
|
||||||
* @description Handler to display image coordinates on hover.
|
|
||||||
* @param {Object} step Current step variable
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function imageHover(step){
|
function imageHover(step){
|
||||||
|
|
||||||
var img = $(step.imgElement);
|
var img = $(step.imgElement);
|
||||||
|
|
||||||
let customXCoord = '20'; //default x coordinate
|
img.mousemove(function(e) {
|
||||||
let customYCoord = '20'; //default y coordinate
|
|
||||||
|
|
||||||
const customButton = $('button[name="Custom-Coordinates"]');
|
|
||||||
img.click(function(e) {
|
|
||||||
customXCoord = e.offsetX;
|
|
||||||
customYCoord = e.offsetY;
|
|
||||||
customButton.click(function() {
|
|
||||||
$('input[name="x"]').val(customXCoord);
|
|
||||||
$('input[name="y"]').val(customYCoord);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
img.mousemove(function(e) {
|
|
||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
canvas.width = img.width();
|
canvas.width = img.width();
|
||||||
canvas.height = img.height();
|
canvas.height = img.height();
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
context.drawImage(this, 0, 0);
|
context.drawImage(this,0,0);
|
||||||
|
|
||||||
var offset = $(this).offset();
|
var offset = $(this).offset();
|
||||||
var xPos = e.pageX - offset.left;
|
var xPos = e.pageX - offset.left;
|
||||||
var yPos = e.pageY - offset.top;
|
var yPos = e.pageY - offset.top;
|
||||||
var myData = context.getImageData(xPos, yPos, 1, 1);
|
var myData = context.getImageData(xPos, yPos, 1, 1);
|
||||||
img[0].title = 'rgb: ' + myData.data[0] + ',' + myData.data[1] + ',' + myData.data[2];//+ rgbdata;
|
img[0].title = "rgb: " +myData.data[0]+","+ myData.data[1]+","+myData.data[2];//+ rgbdata;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRemove(step) {
|
function onRemove(step) {
|
||||||
step.ui.remove();
|
step.ui.remove();
|
||||||
$('#steps .step-container:nth-last-child(1) .insert-step').prop('disabled', true);
|
$("#steps .step-container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||||
|
$('div[class*=imgareaselect-]').remove();
|
||||||
// Enable the load-image insert-step button when there are steps after load-image
|
|
||||||
// The logical operator is `> 2` because the number of steps is found before removing the step, actual logic is `steps.length - 1 > 1` which is later simplified.
|
|
||||||
if (_sequencer.steps.length - 1 > 1) $('#load-image .insert-step').prop('disabled', false);
|
|
||||||
else $('#load-image .insert-step').prop('disabled', true);
|
|
||||||
|
|
||||||
$(step.imgElement).imgAreaSelect({
|
|
||||||
remove: true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPreview() {
|
function getPreview() {
|
||||||
return step.imgElement;
|
return step.imgElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function notify(msg,id){
|
||||||
* @method notify
|
if ($('#'+id).length == 0) {
|
||||||
* @description General purpose DOM toast notification
|
|
||||||
* @param {String} msg Message to be displayed
|
|
||||||
* @param {String} id A unique identifier for the notification
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function notify(msg, id){
|
|
||||||
if ($('#' + id).length == 0) {
|
|
||||||
var notification = document.createElement('span');
|
var notification = document.createElement('span');
|
||||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
||||||
notification.id = id;
|
notification.id = id;
|
||||||
notification.classList.add('notification');
|
notification.classList.add("notification");
|
||||||
|
|
||||||
$('body').append(notification);
|
$('body').append(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#' + id).fadeIn(500).delay(200).fadeOut(500);
|
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getPreview: getPreview,
|
getPreview: getPreview,
|
||||||
onSetup: onSetup,
|
onSetup: onSetup,
|
||||||
onComplete: onComplete,
|
onComplete: onComplete,
|
||||||
onRemove: onRemove,
|
onRemove: onRemove,
|
||||||
onDraw: onDraw,
|
onDraw: onDraw,
|
||||||
notify: notify,
|
notify: notify,
|
||||||
imageHover: imageHover,
|
imageHover: imageHover
|
||||||
updateDimensions: updateDimensions
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof window === 'undefined'){
|
if(typeof window === "undefined"){
|
||||||
module.exports = {
|
module.exports={
|
||||||
DefaultHtmlStepUi: DefaultHtmlStepUi
|
DefaultHtmlStepUi: DefaultHtmlStepUi
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DefaultHtmlStepUi;
|
module.exports = DefaultHtmlStepUi;
|
||||||
|
|
||||||
|
|||||||
@@ -1,79 +1,55 @@
|
|||||||
// Generate downscaled preview images for quick buttons.
|
function generatePreview(previewStepName, customValues, path, selector) {
|
||||||
function generatePreview(previewStepName, customValues, path, DomNode) {
|
|
||||||
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%)');
|
|
||||||
$(DomNode.querySelector('.radio-group')).find('.radio').each(function() {
|
|
||||||
if ($(this).attr('data-value') === previewStepName) {
|
|
||||||
$(this).find('img').remove();
|
|
||||||
$(this).append(img);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadPreview() {
|
var previewSequencer = ImageSequencer();
|
||||||
if (previewStepName === 'crop') {
|
function insertPreview(src) {
|
||||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
var img = document.createElement('img');
|
||||||
}
|
img.classList.add('img-thumbnail')
|
||||||
else {
|
img.classList.add('no-border');
|
||||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
img.src = src;
|
||||||
}
|
$(img).css("max-width", "200%");
|
||||||
}
|
$(img).css("transform", "translateX(-20%)");
|
||||||
if(previewStepName === 'resize')
|
$(selector + ' .radio-group').find('div').each(function() {
|
||||||
insertPreview(path);
|
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||||
else
|
$(this).find('div').append(img);
|
||||||
previewSequencer.loadImage(path, loadPreview);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function updatePreviews(src, DomNode) {
|
|
||||||
$(DomNode).find('img').remove();
|
|
||||||
|
|
||||||
var previewSequencerSteps = {
|
|
||||||
'resize': '125%',
|
|
||||||
'brightness': '175',
|
|
||||||
'saturation': '0.5',
|
|
||||||
'rotate': 90,
|
|
||||||
'contrast': 90,
|
|
||||||
'crop': {
|
|
||||||
'x': 0,
|
|
||||||
'y': 0,
|
|
||||||
'w': '50%',
|
|
||||||
'h': '50%',
|
|
||||||
'noUI': true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var img = new Image();
|
|
||||||
|
|
||||||
img.onload = function(){
|
|
||||||
var height = img.height;
|
|
||||||
var width = img.width;
|
|
||||||
|
|
||||||
let percentage = (80 / height) * 100; // Take the min resize value that fits the preview area => (new-width/orig_ht) - '80 as the preview area has 80*80 dimension.
|
|
||||||
percentage = Math.max((80 / width) * 100, percentage); // Make sure that one dimension doesn't resize greater, leading distorting preview-area fitting.
|
|
||||||
percentage = Math.ceil(percentage);
|
|
||||||
|
|
||||||
var sequencer = ImageSequencer();
|
|
||||||
|
|
||||||
sequencer.loadImage(src, function(){
|
|
||||||
this.addSteps('resize', {['resize']: percentage + '%'});
|
|
||||||
this.run((src)=>{
|
|
||||||
Object.keys(previewSequencerSteps).forEach(function (step, index) {
|
|
||||||
generatePreview(step, Object.values(previewSequencerSteps)[index], src, DomNode);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
};
|
|
||||||
img.src = src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function loadPreview() {
|
||||||
|
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 = {
|
||||||
|
"resize": "125%",
|
||||||
|
"brightness": "175",
|
||||||
|
"saturation": "0.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 = {
|
module.exports = {
|
||||||
generatePreview : generatePreview,
|
generatePreview : generatePreview,
|
||||||
updatePreviews : updatePreviews
|
updatePreviews : updatePreviews
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
var urlHash = require('./urlHash.js'),
|
var urlHash = require('./urlHash.js'),
|
||||||
insertPreview = require('./insertPreview.js');
|
insertPreview = require('./insertPreview.js');
|
||||||
|
|
||||||
/**
|
|
||||||
* @method IntermediateHtmlStepUi
|
|
||||||
* @description Inserts a module selector in between the current sequence
|
|
||||||
* @param {Object} _sequencer Sequencer instance
|
|
||||||
* @param {Object} step Current step variable
|
|
||||||
* @param {Object} options Optional options Object
|
|
||||||
* @returns {Object} Object containing the insertStep function
|
|
||||||
*/
|
|
||||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||||
function stepUI() {
|
function stepUI() {
|
||||||
// Basic markup for the selector
|
|
||||||
return '<div class="row insertDiv collapse">\
|
return '<div class="row insertDiv collapse">\
|
||||||
<section class="panel panel-primary .insert-step">\
|
<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>\
|
<button class="btn btn-default close-insert-box"><i class="fa fa-times" aria-hidden="true"></i> Close</button>\
|
||||||
@@ -64,7 +55,7 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
|||||||
</select>\
|
</select>\
|
||||||
<div>\
|
<div>\
|
||||||
<div class="col-md-4">\
|
<div class="col-md-4">\
|
||||||
<button class="btn btn-primary btn-lg insert-save-btn add-step-btn" name="add">Add Step</button>\
|
<button class="btn btn-success btn-lg insert-save-btn add-step-btn" name="add">Add Step</button>\
|
||||||
<div>\
|
<div>\
|
||||||
</div>\
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
@@ -73,100 +64,100 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
|||||||
</div>';
|
</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method toggleDiv
|
function selectNewStepUi() {
|
||||||
* @description Toggles the module selector dropdown.
|
var insertSelect = $(step.ui.querySelector('.insert-step-select'))
|
||||||
* @param {Object} $step $step util function
|
var m = insertSelect.val();
|
||||||
* @param {Fucntion} callback Optional callback function
|
$(step.ui.querySelector('.insertDiv .info')).html(_sequencer.modulesInfo(m).description);
|
||||||
* @returns {Null}
|
$(step.ui.querySelector('.insertDiv .add-step-btn')).prop("disabled", false);
|
||||||
*/
|
}
|
||||||
var toggleDiv = function($step, callback = function(){}){
|
|
||||||
$step('.insertDiv').collapse('toggle');
|
|
||||||
if ($step('.insert-text').css('display') != 'none'){
|
var toggleDiv = function(callback = function(){}){
|
||||||
$step('.insert-text').fadeToggle(200, function(){$step('.no-insert-text').fadeToggle(200, callback);});
|
$(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 {
|
else {
|
||||||
$step('.no-insert-text').fadeToggle(200, function(){$step('.insert-text').fadeToggle(200, callback);});
|
$(step.ui.querySelector('.no-insert-text')).fadeToggle(200, function(){$(step.ui.querySelector('.insert-text')).fadeToggle(200, callback)})
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method insertStep
|
|
||||||
* @description Handler to insert selected module in the sequence
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
insertStep = function (id) {
|
insertStep = function (id) {
|
||||||
const $step = step.$step,
|
|
||||||
$stepAll = step.$stepAll;
|
|
||||||
var modulesInfo = _sequencer.modulesInfo();
|
var modulesInfo = _sequencer.modulesInfo();
|
||||||
var parser = new DOMParser();
|
var parser = new DOMParser();
|
||||||
var addStepUI = stepUI();
|
var addStepUI = stepUI();
|
||||||
addStepUI = parser.parseFromString(addStepUI, 'text/html').querySelector('div');
|
addStepUI = parser.parseFromString(addStepUI, "text/html").querySelector("div")
|
||||||
|
|
||||||
if ($step('.insertDiv').length > 0){
|
if ($(step.ui.querySelector('.insertDiv')).length > 0){
|
||||||
toggleDiv($step);
|
toggleDiv();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
step.ui
|
step.ui
|
||||||
.querySelector('div.step')
|
.querySelector("div.step")
|
||||||
.insertAdjacentElement('afterend',
|
.insertAdjacentElement('afterend',
|
||||||
addStepUI
|
addStepUI
|
||||||
);
|
);
|
||||||
toggleDiv($step, function(){
|
toggleDiv(function(){
|
||||||
if (step.name === 'load-image') insertPreview.updatePreviews(step.output.src, $step('.insertDiv').getDomElem());
|
insertPreview.updatePreviews(step.output, '.insertDiv');
|
||||||
else insertPreview.updatePreviews(step.output, $step('.insertDiv').getDomElem());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(step.ui.querySelector('.insertDiv .close-insert-box')).off('click').on('click', function(){toggleDiv(function(){})});
|
||||||
$step('.insertDiv .close-insert-box').off('click').on('click', function(){
|
|
||||||
toggleDiv($step);
|
var insertStepSelect = $(step.ui.querySelector('.insert-step-select'));
|
||||||
$step('.insertDiv').removeClass('insertDiv');
|
insertStepSelect.html("");
|
||||||
});
|
|
||||||
|
|
||||||
var insertStepSelect = $step('.insert-step-select');
|
|
||||||
insertStepSelect.html('');
|
|
||||||
|
|
||||||
// Add modules to the insertStep dropdown
|
// Add modules to the insertStep dropdown
|
||||||
for (var m in modulesInfo) {
|
for (var m in modulesInfo) {
|
||||||
if (modulesInfo[m] && modulesInfo[m].name)
|
if (modulesInfo[m] !== undefined)
|
||||||
insertStepSelect.append(
|
insertStepSelect.append(
|
||||||
'<option value="' + m + '">' + modulesInfo[m].name + '</option>'
|
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
insertStepSelect.selectize({
|
insertStepSelect.selectize({
|
||||||
sortField: 'text'
|
sortField: 'text'
|
||||||
});
|
});
|
||||||
|
$(step.ui.querySelector('.inserDiv .add-step-btn')).prop('disabled', true);
|
||||||
$('.insertDiv .radio-group .radio').on('click', function () {
|
|
||||||
var newStepName = $(this).attr('data-value'); // Get the name of the module to be inserted
|
insertStepSelect.append('<option value="" disabled selected>Select a Module</option>');
|
||||||
id = $($step('.insertDiv').parents()[3]).prevAll().length;
|
$(step.ui.querySelector('.insertDiv .radio-group .radio')).on("click", function () {
|
||||||
insert(id, $step, newStepName); // Insert the selected module
|
$(this).parent().find('.radio').removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
newStep = $(this).attr('data-value');
|
||||||
|
$(step.ui.querySelector('.insert-step-select')).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('.insertDiv .add-step-btn').on('click', function () {
|
function insert(id) {
|
||||||
var newStepName = insertStepSelect.val();
|
|
||||||
id = $($step('.insertDiv').parents()[3]).prevAll().length;
|
options = options || {};
|
||||||
insert(id, $step, newStepName); });
|
var insertStepSelect = $(step.ui.querySelector('.insert-step-select'));
|
||||||
};
|
if (insertStepSelect.val() == "none") return;
|
||||||
|
|
||||||
|
var newStepName = insertStepSelect.val()
|
||||||
|
toggleDiv();
|
||||||
|
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());
|
||||||
|
|
||||||
/**
|
|
||||||
* @method insert
|
|
||||||
* @description Inserts the specified step at the specified index in the sequence
|
|
||||||
* @param {Number} id Index of the step
|
|
||||||
* @param {Function} $step $step util function
|
|
||||||
* @param {String} newStepName Name of the new step
|
|
||||||
*/
|
|
||||||
function insert(id, $step, newStepName) {
|
|
||||||
toggleDiv($step);
|
|
||||||
$step('.insertDiv').removeClass('insertDiv');
|
|
||||||
_sequencer.insertSteps(id + 1, newStepName).run({ index: id });
|
|
||||||
urlHash.setUrlHashParameter('steps', _sequencer.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
insertStep
|
insertStep
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
module.exports = IntermediateHtmlStepUi;
|
module.exports = IntermediateHtmlStepUi;
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,28 @@
|
|||||||
/**
|
|
||||||
* @description Maps module input types to their respective html <input> tag types.
|
|
||||||
* @param {Object} inputInfo Object containing the type and optionally min/max for range type inputs.
|
|
||||||
*/
|
|
||||||
function mapHtmlTypes(inputInfo){
|
function mapHtmlTypes(inputInfo){
|
||||||
var htmlType;
|
var htmlType;
|
||||||
switch(inputInfo.type.toLowerCase()){
|
switch(inputInfo.type.toLowerCase()){
|
||||||
case 'integer':
|
case 'integer':
|
||||||
htmlType = inputInfo.min != undefined ? 'range' : 'number';
|
htmlType = inputInfo.min != undefined ? 'range' : 'number';
|
||||||
if (htmlType === 'range') inputInfo.step = inputInfo.step || 1; // default range step size for integer
|
break;
|
||||||
break;
|
case 'string':
|
||||||
case 'string':
|
htmlType = 'text';
|
||||||
htmlType = 'text';
|
break;
|
||||||
break;
|
case 'select':
|
||||||
case 'select':
|
htmlType = 'select';
|
||||||
htmlType = 'select';
|
break;
|
||||||
break;
|
case 'percentage':
|
||||||
case 'percentage':
|
htmlType = 'number';
|
||||||
htmlType = 'number';
|
break;
|
||||||
break;
|
case 'float':
|
||||||
case 'float':
|
htmlType = inputInfo.min != undefined ? 'range' : 'text';
|
||||||
htmlType = inputInfo.min != undefined ? 'range' : 'text';
|
break;
|
||||||
if (htmlType === 'range') inputInfo.step = inputInfo.step || 0.1; // default range step size for float
|
default:
|
||||||
break;
|
htmlType = 'text';
|
||||||
case 'coordinate-input':
|
break;
|
||||||
htmlType = 'button';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
htmlType = 'text';
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
var response = Object.assign({}, inputInfo);
|
var response = inputInfo;
|
||||||
response.type = htmlType;
|
response.type = htmlType;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = mapHtmlTypes;
|
module.exports = mapHtmlTypes;
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* @method $scope
|
|
||||||
* @param {"DOMNode"} scope A DOM Node as the scope
|
|
||||||
* @returns {Function} Constructor for the scopeSelector Object.
|
|
||||||
*/
|
|
||||||
function $scope(scope) {
|
|
||||||
return function(queryString){
|
|
||||||
var element = $(scope.querySelector(queryString));
|
|
||||||
|
|
||||||
element.elem = function(queryString){
|
|
||||||
return new $scope(scope)(queryString);
|
|
||||||
};
|
|
||||||
element.elemAll = function(queryString){
|
|
||||||
return new $scopeAll(scope)(queryString);
|
|
||||||
};
|
|
||||||
element.getDomElem = function(i = 0){
|
|
||||||
return element[i];
|
|
||||||
};
|
|
||||||
element.getScope = () => scope;
|
|
||||||
|
|
||||||
return element;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @method $scopeAll
|
|
||||||
* @param {"DOMNode"} scope A DOM Node as the scope
|
|
||||||
* @returns {Function} Constructor for the scopeSelectorAll Object.
|
|
||||||
*/
|
|
||||||
function $scopeAll(scope){
|
|
||||||
return function(queryString){
|
|
||||||
var element = $(scope.querySelectorAll(queryString));
|
|
||||||
|
|
||||||
element.elem = function(queryString){
|
|
||||||
return new $scope(scope)(queryString);
|
|
||||||
};
|
|
||||||
element.elemAll = function(queryString){
|
|
||||||
return new $scopeAll(scope)(queryString);
|
|
||||||
};
|
|
||||||
element.getDomElem = function(i = 0){
|
|
||||||
return element[i];
|
|
||||||
};
|
|
||||||
element.getScope = () => scope;
|
|
||||||
|
|
||||||
return element;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @method scopeSelector
|
|
||||||
* @description A scoped jQuery selector
|
|
||||||
* @param {"DOMNode"} scope A DOM Node as the scope
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
function scopeSelector(scope){
|
|
||||||
return $scope(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @method scopeSelectorAll
|
|
||||||
* @description A scoped jQuery multiple selector
|
|
||||||
* @param {"DOMNode} scope A DOM Node as the scope
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
function scopeSelectorAll(scope){
|
|
||||||
return $scopeAll(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
scopeSelector,
|
|
||||||
scopeSelectorAll
|
|
||||||
};
|
|
||||||
@@ -42,8 +42,8 @@ function setUrlHashParameter(param, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getUrlHashParameter: getUrlHashParameter,
|
getUrlHashParameter: getUrlHashParameter,
|
||||||
setUrlHashParameter: setUrlHashParameter,
|
setUrlHashParameter: setUrlHashParameter,
|
||||||
getUrlHashParameters: getUrlHashParameters,
|
getUrlHashParameters: getUrlHashParameters,
|
||||||
setUrlHashParameters: setUrlHashParameters
|
setUrlHashParameters: setUrlHashParameters
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* Functions for getting version information.
|
|
||||||
* Note: these functions are not used by the service worker to check for updates;
|
|
||||||
* the service worker updates whenever sw.js has changed.
|
|
||||||
* sw.js is changed when grunt replace:version is run. This task is run during
|
|
||||||
* grunt build, serve, and productions tasks.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const package = require('../../package.json');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current version number from package.json on the homepage.
|
|
||||||
* @param {function} callback The function that uses the version number.
|
|
||||||
*/
|
|
||||||
function getLatestVersionNumber(callback) {
|
|
||||||
// Get the homepage reference from the local package.json.
|
|
||||||
var homepage = package.homepage;
|
|
||||||
var request = new XMLHttpRequest();
|
|
||||||
request.onreadystatechange = function() {
|
|
||||||
if (request.readyState == 4 && request.status == 200) {
|
|
||||||
var response = JSON.parse(this.responseText);
|
|
||||||
var latestVersionNumber = response.version;
|
|
||||||
|
|
||||||
// Do something with the version number using a callback function.
|
|
||||||
if (callback)
|
|
||||||
callback(latestVersionNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the package.json file from online using a GET request.
|
|
||||||
request.open("GET", homepage + "/package.json", true);
|
|
||||||
request.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the version number from the local package.json file.
|
|
||||||
function getLocalVersionNumber() {
|
|
||||||
return package.version;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getLatestVersionNumber,
|
|
||||||
getLocalVersionNumber
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Error 502 | Bad Gateway</title>
|
|
||||||
<style>
|
|
||||||
body{
|
|
||||||
background-color:#d3d3d3;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size:20px;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
text-align: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color:blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<p>Error 502: something went wrong.</p>
|
|
||||||
<p>It seems that you are not connected to internet.<br>Please try after some time.</p>
|
|
||||||
<a href="/">Go To Home Page</a>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,14 +1,7 @@
|
|||||||
const staticCacheName = 'image-sequencer-static-v3.7.2';
|
const staticCacheName = 'image-sequencer-static-v3';
|
||||||
self.addEventListener('install', function(e) {
|
|
||||||
e.waitUntil(
|
self.addEventListener('install', event => {
|
||||||
caches.open(staticCacheName).then(function(cache) {
|
console.log('Attempting to install service worker');
|
||||||
console.log('Attempting to install service worker');
|
|
||||||
return cache.addAll([
|
|
||||||
'/',
|
|
||||||
'/examples/offline.html'
|
|
||||||
]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('activate', function(e) {
|
self.addEventListener('activate', function(e) {
|
||||||
@@ -24,38 +17,19 @@ self.addEventListener('activate', function(e) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('fetch', function(event) {
|
self.addEventListener('fetch', function(event) {
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
// Try to fetch the latest data first.
|
caches.open(staticCacheName).then(function(cache) {
|
||||||
fetch(event.request)
|
return cache.match(event.request).then(function (response) {
|
||||||
.then(function(response) {
|
return response || fetch(event.request).then(function(response) {
|
||||||
return caches.open(staticCacheName)
|
if(event.request.method == "GET")
|
||||||
.then(function(cache) {
|
cache.put(event.request, response.clone());
|
||||||
if(event.request.method == 'GET'){
|
return response;
|
||||||
cache.put(event.request.url, response.clone());
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(function(err) {
|
|
||||||
// Now the request has been failed so show cached data.
|
|
||||||
return caches.match(event.request).then(function(res){
|
|
||||||
if (res === undefined) {
|
|
||||||
// Display offline page
|
|
||||||
return caches.match('offline.html');
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// When the update modal sends a 'skipWaiting' message, call the skipWaiting method.
|
|
||||||
self.addEventListener('message', function(event) {
|
|
||||||
if(event.data.action === 'skipWaiting') {
|
|
||||||
self.skipWaiting();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
88
index.js
88
index.js
@@ -1,5 +1,89 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
var cli = require('./src/cli');
|
require('./src/ImageSequencer');
|
||||||
|
sequencer = ImageSequencer({ ui: false });
|
||||||
|
var fs = require('fs')
|
||||||
|
var program = require('commander');
|
||||||
|
var utils = require('./src/CliUtils')
|
||||||
|
|
||||||
cli(process.argv);
|
var saveSequence = require('./src/cli/saveSequence.js')
|
||||||
|
var installModule = require('./src/cli/installModule.js')
|
||||||
|
var sequencerSteps = require('./src/cli/sequencerSteps.js')
|
||||||
|
|
||||||
|
function exit(message) {
|
||||||
|
console.error(message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
program
|
||||||
|
.version("0.1.0")
|
||||||
|
.option("-i, --image [PATH/URL]", "Input image URL")
|
||||||
|
.option("-s, --step [step-name]", "Name of the step to be added.")
|
||||||
|
.option("-o, --output [PATH]", "Directory where output will be stored.")
|
||||||
|
.option("-b, --basic", "Basic mode outputs only final image")
|
||||||
|
.option("-c, --config [Object]", "Options for the step")
|
||||||
|
.option("--save-sequence [string]", "Name space separated with Stringified sequence")
|
||||||
|
.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 {
|
||||||
|
// Parse step into an array to allow for multiple steps.
|
||||||
|
if (!program.step) exit("No steps passed");
|
||||||
|
program.step = program.step.split(" ");
|
||||||
|
|
||||||
|
// User must input an image.
|
||||||
|
if (!program.image) exit("Can't read file.");
|
||||||
|
|
||||||
|
// User must input an image.
|
||||||
|
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)))
|
||||||
|
exit("Please ensure all steps are valid.");
|
||||||
|
|
||||||
|
// If there's no user defined output directory, select a default directory.
|
||||||
|
program.output = program.output || "./output/";
|
||||||
|
|
||||||
|
// Set sequencer to log module outputs, if any.
|
||||||
|
sequencer.setUI({
|
||||||
|
onComplete: function(step) {
|
||||||
|
// Get information of outputs.
|
||||||
|
step.info = sequencer.modulesInfo(step.name);
|
||||||
|
|
||||||
|
for (var output in step.info.outputs) {
|
||||||
|
console.log("[" + program.step + "]: " + output + " = " + step[output]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notify: function(msg) {
|
||||||
|
console.log('\x1b[36m%s\x1b[0m','🌟 '+msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Finally, if everything is alright, load the image, add the steps and run the sequencer.
|
||||||
|
sequencer.loadImages(program.image, function() {
|
||||||
|
console.warn(
|
||||||
|
"\x1b[33m%s\x1b[0m",
|
||||||
|
"Please wait \n output directory generated will be empty until the execution is complete"
|
||||||
|
);
|
||||||
|
|
||||||
|
//Generate the Output Directory
|
||||||
|
var outputFilename = program.output.split('/').slice(-1)[0];
|
||||||
|
if (outputFilename.includes('.')) {
|
||||||
|
// user did give an output filename we have to remove it from dir
|
||||||
|
program.output = program.output.split('/').slice(0, -1).join('/');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
outputFilename = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sequencerSteps(program, sequencer, outputFilename)
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
launch: {
|
|
||||||
args: ['--no-sandbox', '--disable-setuid-sandbox'], // https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#setting-up-chrome-linux-sandbox
|
|
||||||
headless: process.env.HEADLESS !== 'false',
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
command: 'grunt serve',
|
|
||||||
port:3000,
|
|
||||||
launchTimeout: 5000000,
|
|
||||||
},
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
preset: 'jest-puppeteer',
|
|
||||||
testRegex: './*\\.test\\.js$',
|
|
||||||
verbose: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
40304
package-lock.json
generated
40304
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
88
package.json
88
package.json
@@ -1,27 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "image-sequencer",
|
"name": "image-sequencer",
|
||||||
"version": "3.7.2",
|
"version": "3.0.1",
|
||||||
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
||||||
"main": "src/ImageSequencer.js",
|
"main": "src/ImageSequencer.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"debug": "TEST=true node ./index.js -i ./examples/images/monarch.png -s invert",
|
"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/*.js | tap-spec;",
|
"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 | 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\"",
|
||||||
"benchmark": "node test/core/sequencer/benchmark.js | tap-spec;",
|
"test-ui": "jasmine test/spec/*.js",
|
||||||
"gif-test": "node test/core/gifs/gif-test.js | tap-spec;",
|
"setup": "npm i && npm i -g grunt grunt-cli && grunt build",
|
||||||
"core-tests": "cat ./output/core-tests.js | tape-run --render=\"tap-spec\"",
|
|
||||||
"test-all": "npm run test && npm run benchmark && npm run gif-test && grunt tests && npm run core-tests",
|
|
||||||
"test-ui": "node node_modules/jasmine/bin/jasmine test/ui/spec/*.js",
|
|
||||||
"test-ui-2": "node ./node_modules/.bin/jest",
|
|
||||||
"test-cli": "node test/cli/*.js | tap-spec",
|
|
||||||
"setup": "npm i && npm i -g grunt grunt-cli && npm rebuild --build-from-source && grunt build",
|
|
||||||
"start": "grunt serve"
|
"start": "grunt serve"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
|
||||||
"*.js": [
|
|
||||||
"./node_modules/.bin/eslint --fix",
|
|
||||||
"git add"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/publiclab/image-sequencer.git"
|
"url": "git+https://github.com/publiclab/image-sequencer.git"
|
||||||
@@ -36,88 +24,56 @@
|
|||||||
"url": "https://github.com/publiclab/image-sequencer/issues"
|
"url": "https://github.com/publiclab/image-sequencer/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"atob": "^2.1.2",
|
"bootstrap": "~3.4.0",
|
||||||
"base64-img": "^1.0.4",
|
"buffer": "~5.2.1",
|
||||||
"bootstrap": "^3.4.1",
|
"commander": "^2.11.0",
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"data-uri-to-buffer": "^2.0.0",
|
||||||
"buffer": "~6.0.2",
|
|
||||||
"commander": "^9.0.0",
|
|
||||||
"compressorjs": "^1.0.5",
|
|
||||||
"data-uri-to-buffer": "^4.0.1",
|
|
||||||
"downloadjs": "^1.4.7",
|
"downloadjs": "^1.4.7",
|
||||||
"eslint": "^8.0.0",
|
|
||||||
"expr-eval": "^2.0.2",
|
|
||||||
"fisheyegl": "^0.1.2",
|
"fisheyegl": "^0.1.2",
|
||||||
"font-awesome": "~4.7.0",
|
"font-awesome": "~4.7.0",
|
||||||
|
"geotiff": "^1.0.0-beta.6",
|
||||||
"get-pixels": "~3.3.0",
|
"get-pixels": "~3.3.0",
|
||||||
"gifshot": "^0.4.5",
|
"gifshot": "^0.4.5",
|
||||||
"glfx": "0.0.4",
|
|
||||||
"gpu.js": "^2.3.1",
|
|
||||||
"imgareaselect": "git+https://git@github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
|
||||||
"image-sequencer-invert": "^1.0.0",
|
"image-sequencer-invert": "^1.0.0",
|
||||||
"imagejs": "git+https://git@github.com/glennjones/imagejs.git#1119a31e6eabc87563bc573cd62c11bd487ce8a9",
|
"imagejs": "0.0.9",
|
||||||
"imagemin": "^7.0.1",
|
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
||||||
"imagemin-jpegtran": "^7.0.0",
|
|
||||||
"imagemin-pngquant": "^9.0.1",
|
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"jasmine": "^4.0.2",
|
|
||||||
"jpegtran-bin": "^7.0.0",
|
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
"jsdom": "^20.0.0",
|
"jsdom": "^14.0.0",
|
||||||
"jspdf": "^2.1.1",
|
|
||||||
"jsqr": "^1.1.1",
|
"jsqr": "^1.1.1",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"ndarray": "^1.0.18",
|
"ndarray": "^1.0.18",
|
||||||
"opencv.js": "^1.2.1",
|
"ndarray-gaussian-filter": "^1.0.0",
|
||||||
"ora": "^5.1.0",
|
"ora": "^3.0.0",
|
||||||
"pace": "0.0.4",
|
"pace": "0.0.4",
|
||||||
"pngquant-bin": "^6.0.0",
|
|
||||||
"puppeteer": "^1.14.0",
|
"puppeteer": "^1.14.0",
|
||||||
"qrcode": "^1.3.3",
|
"qrcode": "^1.3.3",
|
||||||
"readline-sync": "^1.4.7",
|
"readline-sync": "^1.4.7",
|
||||||
"save-pixels": "~2.3.4",
|
"save-pixels": "~2.3.4",
|
||||||
"selectize": "^0.12.6",
|
"selectize": "^0.12.6",
|
||||||
"spawn-sync": "^2.0.0",
|
"urify": "^2.1.1"
|
||||||
"urify": "^2.1.1",
|
|
||||||
"webgl-distort": "0.0.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.4.3",
|
"base64-img": "^1.0.4",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.4.3",
|
"browserify": "16.2.3",
|
||||||
"@babel/plugin-syntax-object-rest-spread": "^7.2.0",
|
|
||||||
"babelify": "^10.0.0",
|
|
||||||
"browserify": "17.0.0",
|
|
||||||
"canvas": "^2.8.0",
|
|
||||||
"eslint": "^8.0.0",
|
|
||||||
"grunt": "^1.0.3",
|
"grunt": "^1.0.3",
|
||||||
"grunt-browser-sync": "^2.2.0",
|
"grunt-browser-sync": "^2.2.0",
|
||||||
"grunt-browserify": "^5.0.0",
|
"grunt-browserify": "^5.0.0",
|
||||||
"grunt-contrib-concat": "^2.0.0",
|
"grunt-contrib-concat": "^1.0.1",
|
||||||
"grunt-contrib-uglify-es": "^3.3.0",
|
"grunt-contrib-uglify-es": "^3.3.0",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-text-replace": "^0.4.0",
|
|
||||||
"husky": "^8.0.1",
|
|
||||||
"image-filter-core": "~2.0.2",
|
"image-filter-core": "~2.0.2",
|
||||||
"image-filter-threshold": "~2.0.1",
|
"image-filter-threshold": "~2.0.1",
|
||||||
"jasmine-core": "^4.0.0",
|
"jasmine-core": "^3.3.0",
|
||||||
"jasmine-jquery": "^2.1.1",
|
"jasmine-jquery": "^2.1.1",
|
||||||
"jasmine-spec-reporter": "^7.0.0",
|
"jasmine-spec-reporter": "^4.2.1",
|
||||||
"jest": "^29.0.0",
|
|
||||||
"jest-puppeteer": "^6.0.0",
|
|
||||||
"lint-staged": "^13.0.0",
|
|
||||||
"looks-same": "^7.0.0",
|
"looks-same": "^7.0.0",
|
||||||
"matchdep": "^2.0.0",
|
"matchdep": "^2.0.0",
|
||||||
"resemblejs": "^4.0.1",
|
|
||||||
"tap-spec": "^5.0.0",
|
"tap-spec": "^5.0.0",
|
||||||
"tape": "^5.2.0",
|
"tape": "^4.9.2",
|
||||||
"tape-run": "^10.0.0",
|
"tape-run": "^5.0.0",
|
||||||
"uglify-es": "^3.3.7"
|
"uglify-es": "^3.3.7"
|
||||||
},
|
},
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "lint-staged"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"homepage": "https://sequencer.publiclab.org",
|
"homepage": "https://sequencer.publiclab.org",
|
||||||
"bin": {
|
"bin": {
|
||||||
"sequencer": "./index.js"
|
"sequencer": "./index.js"
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
scriptsDir=$(realpath $(dirname $0))
|
|
||||||
|
|
||||||
echo -ne "Enter the repo to push to in the form username/repo (required): "
|
|
||||||
read -e pushRepo
|
|
||||||
|
|
||||||
echo -ne "Enter repo URL to pull from (upstream) in the form username/repo (default: publiclab/image-sequencer): "
|
|
||||||
read -e repoInput
|
|
||||||
|
|
||||||
echo -ne "Enter branch name (default: stable): "
|
|
||||||
read -e branchInput
|
|
||||||
|
|
||||||
echo -ne "Enter CNAME URL(default: none): "
|
|
||||||
read -e cnameUrlInput
|
|
||||||
|
|
||||||
tempDir=$(mktemp -d)
|
|
||||||
pushd $tempDir > /dev/null
|
|
||||||
|
|
||||||
git clone https://github.com/$pushRepo
|
|
||||||
pushd image-sequencer > /dev/null
|
|
||||||
|
|
||||||
$scriptsDir/update-gh-pages "$repoInput" "$branchInput" "$cnameUrlInput" "no warn"
|
|
||||||
|
|
||||||
popd > /dev/null
|
|
||||||
popd > /dev/null
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e # So that nothing wrong is published
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
echo -e "\033[1;31m
|
|
||||||
------IMPORTANT------
|
|
||||||
THIS SCRIPT IS NOT MEANT TO BE USED DIRECTLY, PLEASE NEWLY CLONE THE REPO IN A SEPARATE DIRECTORY AND USE THE SCRIPT THERE.
|
|
||||||
USING THIS SCRIPT IN YOUR MAIN CLONE MAY DELETE YOUR LOCAL CHANGES.
|
|
||||||
This script is made to be reusable: If you want to manually update the demo, \
|
|
||||||
use the interactive script \`update-demo\`. This script can also be used in a github action.
|
|
||||||
|
|
||||||
You can set the 4th argument to anything to bypass this warning. \
|
|
||||||
Setting the 4th argument means that the first 3 arguments are also set which means that you know what you are doing (I assume).
|
|
||||||
------IMPORTANT------
|
|
||||||
\033[0m"
|
|
||||||
|
|
||||||
echo -ne "Do you still want to continue? [Y/n]: "
|
|
||||||
read -e yN
|
|
||||||
|
|
||||||
case $yN in
|
|
||||||
[yY][eE][sS] | [yY])
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Constants ---
|
|
||||||
deps="jquery bootstrap imgareaselect gifshot downloadjs selectize font-awesome bootstrap-colorpicker jspdf opencv.js/opencv.js" # A list of node_module dependencies to force commit
|
|
||||||
# --- Constants ---
|
|
||||||
|
|
||||||
# --- Arguments ---
|
|
||||||
# $1: Repo(to use as upstream) url in the form username/repo (default: publiclab/image-sequencer) NOTE: Github only
|
|
||||||
# $2: Branch to pull from eg: main or stable (default: stable)
|
|
||||||
# $3: CNAME URL (default: none)
|
|
||||||
# $4: Set the fourth argument to anything to bypass the warning.
|
|
||||||
|
|
||||||
if [[ "$1" != "" ]];
|
|
||||||
then
|
|
||||||
repo=$1
|
|
||||||
else
|
|
||||||
repo="publiclab/image-sequencer"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$2" != "" ]];
|
|
||||||
then
|
|
||||||
branch=$2
|
|
||||||
else
|
|
||||||
branch="stable"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$3" != "" ]];
|
|
||||||
then
|
|
||||||
CNAMEURL=$3
|
|
||||||
else
|
|
||||||
CNAMEURL=""
|
|
||||||
fi
|
|
||||||
# --- Arguments ---
|
|
||||||
|
|
||||||
# --- Main Script ---
|
|
||||||
if [[ "$4" == "" ]]; # Set a 4th argument to anything to bypass this warning.
|
|
||||||
then
|
|
||||||
warn
|
|
||||||
fi
|
|
||||||
|
|
||||||
git checkout gh-pages
|
|
||||||
git remote add upstream https://github.com/$repo
|
|
||||||
git fetch upstream
|
|
||||||
|
|
||||||
git reset --hard upstream/$branch
|
|
||||||
|
|
||||||
echo -e "Running setup script."
|
|
||||||
npm run setup
|
|
||||||
|
|
||||||
echo -e "Building dist files."
|
|
||||||
grunt production
|
|
||||||
|
|
||||||
if [ ! -f CNAME ];
|
|
||||||
then
|
|
||||||
echo -e "Creating CNAME"
|
|
||||||
touch CNAME
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo $CNAMEURL > CNAME
|
|
||||||
|
|
||||||
echo -e "Removing unnecessary files."
|
|
||||||
rm -R docs/
|
|
||||||
rm -R test/
|
|
||||||
rm CONTRIBUTING.md
|
|
||||||
rm index.js
|
|
||||||
|
|
||||||
echo -e "Copying important files from src/"
|
|
||||||
cp src/ui/prepareDynamic.js prepareDynamic.js
|
|
||||||
|
|
||||||
echo "Removing src/"
|
|
||||||
rm -R src/
|
|
||||||
mkdir -p src/ui/
|
|
||||||
mv prepareDynamic.js src/ui/prepareDynamic.js
|
|
||||||
|
|
||||||
echo -e "git add dist and node_modules dependencies."
|
|
||||||
git add .
|
|
||||||
|
|
||||||
for dep in $deps; # Force add node_modules dependencies
|
|
||||||
do
|
|
||||||
git add -f node_modules/$dep
|
|
||||||
done
|
|
||||||
|
|
||||||
git add -f dist/image-sequencer.js
|
|
||||||
git add -f dist/image-sequencer-ui.js
|
|
||||||
|
|
||||||
echo -e "committing and pusing."
|
|
||||||
git commit --no-verify -m "update"
|
|
||||||
git push -f
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
# --- Main Script ---
|
|
||||||
42
spec/defaultHtmlSequencerUi.spec.js
Normal file
42
spec/defaultHtmlSequencerUi.spec.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
61
spec/defaultHtmlStepUi.spec.js
Normal file
61
spec/defaultHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
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')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
26
spec/insertPreview.spec.js
Normal file
26
spec/insertPreview.spec.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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 +1,19 @@
|
|||||||
describe('Intermediate step HTML', function() {
|
describe('Intermediate step HTML', function() {
|
||||||
|
|
||||||
var IntermediateHtmlStepUi = require('../../../examples/lib/intermediateHtmlStepUi');
|
var IntermediateHtmlStepUi = require('../examples/lib/intermediateHtmlStepUi')
|
||||||
var sequencer = require('../../../src/ImageSequencer')();
|
var sequencer = require('../src/ImageSequencer')()
|
||||||
var intermediateHtmlStepUi;
|
var intermediateHtmlStepUi;
|
||||||
|
|
||||||
beforeEach(()=>{
|
beforeEach(()=>{
|
||||||
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer);
|
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer)
|
||||||
|
|
||||||
spyOn(intermediateHtmlStepUi, 'insertStep');
|
spyOn(intermediateHtmlStepUi,'insertStep')
|
||||||
|
|
||||||
intermediateHtmlStepUi.insertStep();
|
intermediateHtmlStepUi.insertStep()
|
||||||
});
|
})
|
||||||
|
|
||||||
it('insert step ui', function() {
|
it('insert step ui', function() {
|
||||||
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled();
|
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
});
|
})
|
||||||
11
spec/support/jasmine.json
Normal file
11
spec/support/jasmine.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"spec_dir": "spec",
|
||||||
|
"spec_files": [
|
||||||
|
"**/*[sS]pec.js"
|
||||||
|
],
|
||||||
|
"helpers": [
|
||||||
|
"helpers/**/*.js"
|
||||||
|
],
|
||||||
|
"stopSpecOnExpectationFailure": false,
|
||||||
|
"random": true
|
||||||
|
}
|
||||||
@@ -1,40 +1,40 @@
|
|||||||
describe('URL manipulation methods', function() {
|
describe('URL manipulation methods', function() {
|
||||||
|
|
||||||
var UrlHash = require('../../../examples/lib/urlHash');
|
var UrlHash = require('../examples/lib/urlHash')
|
||||||
var urlHash;
|
var urlHash;
|
||||||
var params = {
|
var params = {
|
||||||
module: 'brightness',
|
module: 'brightness',
|
||||||
brightness: 50
|
brightness: 50
|
||||||
};
|
}
|
||||||
|
|
||||||
beforeEach(()=>{
|
beforeEach(()=>{
|
||||||
urlHash = UrlHash;
|
urlHash = UrlHash
|
||||||
|
|
||||||
spyOn(urlHash, 'getUrlHashParameters');
|
spyOn(urlHash,'getUrlHashParameters')
|
||||||
spyOn(urlHash, 'getUrlHashParameter');
|
spyOn(urlHash,'getUrlHashParameter')
|
||||||
spyOn(urlHash, 'setUrlHashParameters');
|
spyOn(urlHash,'setUrlHashParameters')
|
||||||
spyOn(urlHash, 'setUrlHashParameter');
|
spyOn(urlHash,'setUrlHashParameter')
|
||||||
|
|
||||||
urlHash.getUrlHashParameters();
|
urlHash.getUrlHashParameters()
|
||||||
urlHash.getUrlHashParameter('module');
|
urlHash.getUrlHashParameter('module')
|
||||||
urlHash.setUrlHashParameters(params);
|
urlHash.setUrlHashParameters(params)
|
||||||
urlHash.setUrlHashParameter('module', 'brightness');
|
urlHash.setUrlHashParameter('module','brightness')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('gets url hash params from window hash', function() {
|
it('gets url hash params from window hash', function() {
|
||||||
expect(urlHash.getUrlHashParameters).toHaveBeenCalled();
|
expect(urlHash.getUrlHashParameters).toHaveBeenCalled()
|
||||||
});
|
})
|
||||||
|
|
||||||
it('gets url hash param from params object', function() {
|
it('gets url hash param from params object', function() {
|
||||||
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module');
|
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('accepts param object and sets url hash params', function() {
|
it('accepts param object and sets url hash params', function() {
|
||||||
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params);
|
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('accepts param key-value pair and sets url hash params', function() {
|
it('accepts param key-value pair and sets url hash params', function() {
|
||||||
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module', 'brightness');
|
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module','brightness')
|
||||||
});
|
})
|
||||||
|
|
||||||
});
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// add steps to the sequencer
|
// add steps to the sequencer
|
||||||
function AddStep(_sequencer, name, o) {
|
function AddStep(_sequencer, name, o) {
|
||||||
return require('./InsertStep')(_sequencer, -1, name, o);
|
return require('./InsertStep')(_sequencer,-1,name,o);
|
||||||
}
|
}
|
||||||
module.exports = AddStep;
|
module.exports = AddStep;
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
var fs = require('fs');
|
var fs = require('fs')
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function checks if the directory exists, if not it creates one on the given path
|
* This function checks if the directory exists, if not it creates one on the given path
|
||||||
* Callback is called with argument error if an error is encountered
|
* Callback is called with argument error if an error is encountered
|
||||||
*/
|
*/
|
||||||
function makedir(path, callback){
|
function makedir(path,callback){
|
||||||
fs.access(path, function(err){
|
fs.access(path,function(err){
|
||||||
if(err) fs.mkdir(path, function(err){
|
if(err) fs.mkdir(path,function(err){
|
||||||
if(err) callback(err);
|
if(err) callback(err);
|
||||||
callback();
|
callback();
|
||||||
|
});
|
||||||
|
else callback()
|
||||||
});
|
});
|
||||||
else callback();
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||||
function validateSteps(steps, sequencer) {
|
function validateSteps(steps, sequencer) {
|
||||||
@@ -37,9 +37,9 @@ function validateConfig(config_, options_) {
|
|||||||
for (var input in options_) {
|
for (var input in options_) {
|
||||||
if (!config_[options_[input]]) {
|
if (!config_[options_[input]]) {
|
||||||
console.error(
|
console.error(
|
||||||
'\x1b[31m%s\x1b[0m',
|
"\x1b[31m%s\x1b[0m",
|
||||||
`Options Object does not have the required details "${
|
`Options Object does not have the required details "${
|
||||||
options_[input]
|
options_[input]
|
||||||
}" not specified. Fallback case activated`
|
}" not specified. Fallback case activated`
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
@@ -52,7 +52,7 @@ function validateConfig(config_, options_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = exports = {
|
module.exports = exports = {
|
||||||
makedir: makedir,
|
makedir: makedir,
|
||||||
validateSteps: validateSteps,
|
validateSteps: validateSteps,
|
||||||
validateConfig: validateConfig
|
validateConfig: validateConfig
|
||||||
};
|
}
|
||||||
@@ -2,7 +2,7 @@ var fs = require('fs');
|
|||||||
var getDirectories = function(rootDir, cb) {
|
var getDirectories = function(rootDir, cb) {
|
||||||
fs.readdir(rootDir, function(err, files) {
|
fs.readdir(rootDir, function(err, files) {
|
||||||
var dirs = [];
|
var dirs = [];
|
||||||
if (typeof (files) == 'undefined' || files.length == 0) {
|
if (typeof (files) == "undefined" || files.length == 0) {
|
||||||
cb(dirs);
|
cb(dirs);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -21,15 +21,15 @@ var getDirectories = function(rootDir, cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = function ExportBin(dir = './output/', ref, basic, filename) {
|
module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
||||||
|
|
||||||
// If user did not give an output filename so we can continue without doing anything
|
// If user did not give an output filename so we can continue without doing anything
|
||||||
dir = (dir[dir.length - 1] == '/') ? dir : dir + '/';
|
dir = (dir[dir.length - 1] == "/") ? dir : dir + "/";
|
||||||
if (ref.options.inBrowser) return false;
|
if (ref.options.inBrowser) return false;
|
||||||
fs.access(dir, function(err) {
|
fs.access(dir, function(err) {
|
||||||
if (err) console.error(err);
|
if (err) console.error(err)
|
||||||
});
|
});
|
||||||
if (filename && basic) {
|
if (filename && basic) {
|
||||||
var steps = ref.steps;
|
var steps = ref.steps;
|
||||||
@@ -53,17 +53,17 @@ module.exports = function ExportBin(dir = './output/', ref, basic, filename) {
|
|||||||
var datauri = steps.slice(-1)[0].output.src;
|
var datauri = steps.slice(-1)[0].output.src;
|
||||||
var ext = steps.slice(-1)[0].output.format;
|
var ext = steps.slice(-1)[0].output.format;
|
||||||
var buffer = require('data-uri-to-buffer')(datauri);
|
var buffer = require('data-uri-to-buffer')(datauri);
|
||||||
fs.writeFile(root + 'image' + '_' + (steps.length - 1) + '.' + ext, buffer, function() { });
|
fs.writeFile(root + "image" + "_" + (steps.length - 1) + "." + ext, buffer, function() { });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (var i in steps) {
|
for (var i in steps) {
|
||||||
var datauri = steps[i].output.src;
|
var datauri = steps[i].output.src;
|
||||||
var ext = steps[i].output.format;
|
var ext = steps[i].output.format;
|
||||||
var buffer = require('data-uri-to-buffer')(datauri);
|
var buffer = require('data-uri-to-buffer')(datauri);
|
||||||
fs.writeFile(root + 'image' + '_' + i + '.' + ext, buffer, function() { });
|
fs.writeFile(root + "image" + "_" + i + "." + ext, buffer, function() { });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
function objTypeOf(object){
|
function objTypeOf(object){
|
||||||
return Object.prototype.toString.call(object).split(' ')[1].slice(0, -1);
|
return Object.prototype.toString.call(object).split(" ")[1].slice(0,-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrimitive(object){
|
function getPrimitive(object){
|
||||||
return (objTypeOf(object) == 'Array') ? object[0] : object;
|
return (objTypeOf(object)=='Array')?object[0]:object;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeArray(input) {
|
function makeArray(input) {
|
||||||
return (objTypeOf(input) == 'Array') ? input : [input];
|
return (objTypeOf(input)=="Array")?input:[input];
|
||||||
}
|
}
|
||||||
|
|
||||||
function copy(a) {
|
function copy(a) {
|
||||||
if (!typeof(a) == 'object') return a;
|
if (!typeof(a) == "object") return a;
|
||||||
if (objTypeOf(a) == 'Array') return a.slice();
|
if (objTypeOf(a) == "Array") return a.slice();
|
||||||
if (objTypeOf(a) == 'Object') {
|
if (objTypeOf(a) == "Object") {
|
||||||
var b = {};
|
var b = {};
|
||||||
for (var v in a) {
|
for (var v in a) {
|
||||||
b[v] = copy(a[v]);
|
b[v] = copy(a[v]);
|
||||||
@@ -23,80 +23,80 @@ function copy(a) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatInput(args, format, images) {
|
function formatInput(args,format,images) {
|
||||||
var json_q = {};
|
var json_q = {};
|
||||||
var format_i = format;
|
var format_i = format;
|
||||||
if (format == '+')
|
if (format == "+")
|
||||||
format = ['string_a', 'o_object'];
|
format = ['string_a', 'o_object'];
|
||||||
else if (format == '-')
|
else if (format == "-")
|
||||||
format = ['number_a'];
|
format = ['number_a'];
|
||||||
else if (format == '^')
|
else if (format == "^")
|
||||||
format = ['number', 'string', 'o_object'];
|
format = ['number', 'string', 'o_object'];
|
||||||
else if (format == 'r')
|
else if (format == "r")
|
||||||
format = ['o_number'];
|
format = ['o_number'];
|
||||||
else if (format == 'l')
|
else if (format == "l")
|
||||||
format = ['string', 'o_function'];
|
format = ['string','o_function'];
|
||||||
|
|
||||||
|
|
||||||
if(format[format.length - 1] == 'o_object') {
|
if(format[format.length-1] == "o_object") {
|
||||||
if(objTypeOf(args[args.length - 1]) != 'Object')
|
if(objTypeOf(args[args.length-1]) != "Object")
|
||||||
args.push({});
|
args.push({});
|
||||||
}
|
}
|
||||||
else if (format[format.length - 1] == 'o_number') {
|
else if (format[format.length-1] == "o_number") {
|
||||||
if(typeof(args[args.length - 1]) != 'number' && objTypeOf(args[0]) != 'Object')
|
if(typeof(args[args.length-1]) != "number" && objTypeOf(args[0])!="Object")
|
||||||
args.push(1);
|
args.push(1);
|
||||||
}
|
}
|
||||||
else if (format[format.length - 1] == 'o_function') {
|
else if (format[format.length-1] == "o_function") {
|
||||||
if(objTypeOf(args[args.length - 1]) != 'Function' && objTypeOf(args[0]) != 'Object')
|
if(objTypeOf(args[args.length-1]) != "Function" && objTypeOf(args[0])!="Object")
|
||||||
args.push(function(){});
|
args.push(function(){});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(args.length == format.length) {//making of arrays
|
if(args.length == format.length) {//making of arrays
|
||||||
for (var i in format) {
|
for (var i in format) {
|
||||||
if (format[i].substr(format[i].length - 2, 2) == '_a')
|
if (format[i].substr(format[i].length-2,2)=="_a")
|
||||||
args[i] = makeArray(args[i]);
|
args[i] = makeArray(args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length == 1 ) {
|
if (args.length == 1 ) {
|
||||||
if(format_i == 'r') json_q = {0:copy(args[0])};
|
if(format_i == "r") json_q = {0:copy(args[0])};
|
||||||
else if(format_i == '-') {
|
else if(format_i == "-") {
|
||||||
json_q = [];
|
json_q=[];
|
||||||
json_q = copy(args[0]);
|
json_q= copy(args[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (format_i == 'r' ) {
|
else if (format_i == "r" ) {
|
||||||
for (var img in args[0]) json_q = {0:args[0]};
|
for (var img in args[0]) json_q = {0:args[0]};
|
||||||
}
|
}
|
||||||
else if (format_i == 'l') {
|
else if (format_i == "l") {
|
||||||
json_q = {
|
json_q = {
|
||||||
image: args[0],
|
image: args[0],
|
||||||
callback: args[1]
|
callback: args[1]
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
json_q = [];
|
json_q = [];
|
||||||
if(format_i == '+') {
|
if(format_i == "+") {
|
||||||
for(var s in args[0]) {
|
for(var s in args[0]) {
|
||||||
json_q.push({
|
json_q.push({
|
||||||
name: args[0][s],
|
name: args[0][s],
|
||||||
o: args[1]
|
o: args[1]
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(format_i == '^') {
|
if(format_i == "^") {
|
||||||
var size = this.steps.length;
|
var size = this.steps.length;
|
||||||
var index = args[0];
|
var index = args[0];
|
||||||
index = (index == size) ? index : index % size;
|
index = (index==size)?index:index%size;
|
||||||
if (index < 0) index += size + 1;
|
if (index<0) index += size+1;
|
||||||
json_q.push({
|
json_q.push({
|
||||||
index: index,
|
index: index,
|
||||||
name: args[1],
|
name: args[1],
|
||||||
o: args[2]
|
o: args[2]
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,30 @@
|
|||||||
if (typeof window !== 'undefined') { isBrowser = true; }
|
if (typeof window !== 'undefined') { isBrowser = true }
|
||||||
else { var isBrowser = false; }
|
else { var isBrowser = false }
|
||||||
require('./util/getStep.js');
|
require('./util/getStep.js');
|
||||||
|
|
||||||
/**
|
|
||||||
* @method ImageSequencer
|
|
||||||
* @param {Object|Float32Array} options Optional options
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
ImageSequencer = function ImageSequencer(options) {
|
ImageSequencer = function ImageSequencer(options) {
|
||||||
|
|
||||||
var str = require('./Strings.js')(this.steps, modulesInfo, addSteps, copy);
|
var sequencer = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
|
|
||||||
var sequencer = (this.name == 'ImageSequencer') ? this : this.sequencer;
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.inBrowser = options.inBrowser === undefined ? isBrowser : options.inBrowser;
|
options.inBrowser = options.inBrowser === undefined ? isBrowser : options.inBrowser;
|
||||||
options.sequencerCounter = 0;
|
options.sequencerCounter = 0;
|
||||||
|
|
||||||
function objTypeOf(object) {
|
function objTypeOf(object) {
|
||||||
return Object.prototype.toString.call(object).split(' ')[1].slice(0, -1);
|
return Object.prototype.toString.call(object).split(" ")[1].slice(0, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method log
|
|
||||||
* @description Logs colored messages to the console using ASCII color codes
|
|
||||||
* @param {String} color ASCII color code
|
|
||||||
* @param {String} msg Message to be logged to the console
|
|
||||||
*/
|
|
||||||
function log(color, msg) {
|
function log(color, msg) {
|
||||||
if (options.ui != 'none') {
|
if (options.ui != "none") {
|
||||||
if (arguments.length == 1) console.log(arguments[0]);
|
if (arguments.length == 1) console.log(arguments[0]);
|
||||||
else if (arguments.length == 2) console.log(color, msg);
|
else if (arguments.length == 2) console.log(color, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method copy
|
|
||||||
* @description Returns a clone of the input object.
|
|
||||||
* @param {Object|Float32Array} a The Object/Array to be cloned
|
|
||||||
* @returns {Object|Float32Array}
|
|
||||||
*/
|
|
||||||
function copy(a) {
|
function copy(a) {
|
||||||
if (!typeof (a) == 'object') return a;
|
if (!typeof (a) == "object") return a;
|
||||||
if (objTypeOf(a) == 'Array') return a.slice();
|
if (objTypeOf(a) == "Array") return a.slice();
|
||||||
if (objTypeOf(a) == 'Object') {
|
if (objTypeOf(a) == "Object") {
|
||||||
var b = {};
|
var b = {};
|
||||||
for (var v in a) {
|
for (var v in a) {
|
||||||
b[v] = copy(a[v]);
|
b[v] = copy(a[v]);
|
||||||
}
|
}
|
||||||
@@ -52,7 +34,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeArray(input) {
|
function makeArray(input) {
|
||||||
return (objTypeOf(input) == 'Array') ? input : [input];
|
return (objTypeOf(input) == "Array") ? input : [input];
|
||||||
}
|
}
|
||||||
|
|
||||||
var image,
|
var image,
|
||||||
@@ -70,10 +52,10 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
for (o in sequencer) {
|
for (o in sequencer) {
|
||||||
modules[o] = sequencer[o];
|
modules[o] = sequencer[o];
|
||||||
}
|
}
|
||||||
sequences = JSON.parse(window.localStorage.getItem('sequences')); // Get saved sequences from localStorage
|
sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
||||||
if (!sequences) {
|
if (!sequences) {
|
||||||
sequences = {};
|
sequences = {};
|
||||||
window.localStorage.setItem('sequences', JSON.stringify(sequences)); // Set the localStorage entry as an empty Object by default
|
window.localStorage.setItem('sequences', JSON.stringify(sequences));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,132 +63,103 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
// if (options.imageSelect || options.inBrowser) addStep('image-select');
|
// if (options.imageSelect || options.inBrowser) addStep('image-select');
|
||||||
// else if (options.imageUrl) loadImage(imageUrl);
|
// else if (options.imageUrl) loadImage(imageUrl);
|
||||||
|
|
||||||
/**
|
|
||||||
* @method addSteps
|
|
||||||
* @description Adds one of more steps to the sequence.
|
|
||||||
* @return {Object}
|
|
||||||
*/
|
|
||||||
function addSteps() {
|
function addSteps() {
|
||||||
var this_ = (this.name == 'ImageSequencer') ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = [];
|
var args = [];
|
||||||
var json_q = {};
|
var json_q = {};
|
||||||
for (var arg in arguments) { args.push(copy(arguments[arg])); } // Get all the module names from the arguments
|
for (var arg in arguments) { args.push(copy(arguments[arg])); }
|
||||||
json_q = formatInput.call(this_, args, '+');
|
json_q = formatInput.call(this_, args, "+");
|
||||||
|
|
||||||
inputlog.push({ method: 'addSteps', json_q: copy(json_q) });
|
inputlog.push({ method: "addSteps", json_q: copy(json_q) });
|
||||||
for (var j in json_q)
|
for (var j in json_q)
|
||||||
require('./AddStep')(this_, json_q[j].name, json_q[j].o);
|
require("./AddStep")(this_, json_q[j].name, json_q[j].o);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method removeStep
|
|
||||||
* @description Removes the step at the specified index from the sequence.
|
|
||||||
* @param {Object} ref ImageSequencer instance
|
|
||||||
* @param {Number} index Index of the step to be removed
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function removeStep(ref, index) {
|
function removeStep(ref, index) {
|
||||||
// Remove the step from images[image].steps and redraw remaining images
|
//remove the step from images[image].steps and redraw remaining images
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
// var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
//var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
thisStep = ref.steps[index];
|
thisStep = ref.steps[index];
|
||||||
thisStep.UI.onRemove(thisStep.options.step);
|
thisStep.UI.onRemove(thisStep.options.step);
|
||||||
ref.steps.splice(index, 1);
|
ref.steps.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
//tell the UI a step has been removed
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method removeSteps
|
|
||||||
* @description Removes one or more steps from the sequence
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function removeSteps() {
|
function removeSteps() {
|
||||||
var indices;
|
var indices;
|
||||||
var this_ = (this.name == 'ImageSequencer') ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||||
|
|
||||||
var json_q = formatInput.call(this_, args, '-');
|
var json_q = formatInput.call(this_, args, "-");
|
||||||
inputlog.push({ method: 'removeSteps', json_q: copy(json_q) });
|
inputlog.push({ method: "removeSteps", json_q: copy(json_q) });
|
||||||
|
|
||||||
indices = json_q.sort(function(a, b) { return b - a; });
|
indices = json_q.sort(function(a, b) { return b - a });
|
||||||
for (var i in indices)
|
for (var i in indices)
|
||||||
removeStep(this_, indices[i]);
|
removeStep(this_, indices[i]);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method insertSteps
|
|
||||||
* @description Inserts steps at the specified index
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function insertSteps() {
|
function insertSteps() {
|
||||||
var this_ = (this.name == 'ImageSequencer') ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = [];
|
var args = []
|
||||||
for (var arg in arguments) args.push(arguments[arg]);
|
for (var arg in arguments) args.push(arguments[arg]);
|
||||||
|
|
||||||
var json_q = formatInput.call(this_, args, '^');
|
var json_q = formatInput.call(this_, args, "^");
|
||||||
inputlog.push({ method: 'insertSteps', json_q: copy(json_q) });
|
inputlog.push({ method: "insertSteps", json_q: copy(json_q) });
|
||||||
|
|
||||||
var details = json_q;
|
var details = json_q;
|
||||||
details = details.sort(function(a, b) { return b.index - a.index; });
|
details = details.sort(function(a, b) { return b.index - a.index });
|
||||||
for (var i in details)
|
for (var i in details)
|
||||||
require('./InsertStep')(this_, details[i].index, details[i].name, details[i].o);
|
require("./InsertStep")(this_, details[i].index, details[i].name, details[i].o);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Config is an object which contains the runtime configuration like progress bar
|
||||||
* @method run
|
// information and index from which the sequencer should run
|
||||||
* @param {Object} config Object which contains the runtime configuration like progress bar information and index from which the sequencer should run.
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
function run(config) {
|
function run(config) {
|
||||||
var progressObj, index = 0;
|
var progressObj, index = 0;
|
||||||
config = config || { mode: 'no-arg' };
|
config = config || { mode: 'no-arg' };
|
||||||
if (config.index) index = config.index;
|
if (config.index) index = config.index;
|
||||||
|
|
||||||
if (config.mode != 'no-arg' && typeof config != 'function') {
|
if (config.mode != "no-arg" && typeof config != 'function') {
|
||||||
if (config.progressObj) progressObj = config.progressObj;
|
if (config.progressObj) progressObj = config.progressObj;
|
||||||
delete arguments['0'];
|
delete arguments['0'];
|
||||||
}
|
}
|
||||||
|
|
||||||
var this_ = (this.name == 'ImageSequencer') ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||||
|
|
||||||
var callback = function() { };
|
var callback = function() { };
|
||||||
for (var arg in args)
|
for (var arg in args)
|
||||||
if (objTypeOf(args[arg]) == 'Function')
|
if (objTypeOf(args[arg]) == "Function")
|
||||||
callback = args.splice(arg, 1)[0]; // Callback is formed
|
callback = args.splice(arg, 1)[0]; //callback is formed
|
||||||
|
|
||||||
var json_q = formatInput.call(this_, args, 'r');
|
var json_q = formatInput.call(this_, args, "r");
|
||||||
|
|
||||||
require('./Run')(this_, json_q, callback, index, progressObj);
|
require('./Run')(this_, json_q, callback, index, progressObj);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method loadImages
|
|
||||||
* @description Loads an image via dataURL or normal URL. Read the docs(https://github.com/publiclab/image-sequencer/blob/main/README.md) for more info.
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function loadImages() {
|
function loadImages() {
|
||||||
var args = [];
|
var args = [];
|
||||||
var prevSteps = this.getSteps().slice(1).map(step=>step.options.name);
|
var prevSteps = this.getSteps().slice(1).map(step=>step.options.name)
|
||||||
var sequencer = this;
|
var sequencer = this;
|
||||||
sequencer.image = arguments[0];
|
sequencer.image = arguments[0];
|
||||||
for (var arg in arguments) args.push(copy(arguments[arg]));
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
||||||
var json_q = formatInput.call(this, args, 'l');
|
var json_q = formatInput.call(this, args, "l");
|
||||||
if(this.getSteps().length != 0){
|
if(this.getSteps().length!=0){
|
||||||
this.options.sequencerCounter = 0;
|
this.options.sequencerCounter = 0;
|
||||||
inputlog = [];
|
inputlog = [];
|
||||||
this.steps = [];
|
this.steps = [];
|
||||||
}
|
}
|
||||||
inputlog.push({ method: 'loadImages', json_q: copy(json_q) });
|
inputlog.push({ method: "loadImages", json_q: copy(json_q) });
|
||||||
var ret = {
|
var ret = {
|
||||||
name: 'ImageSequencer Wrapper',
|
name: "ImageSequencer Wrapper",
|
||||||
sequencer: this,
|
sequencer: this,
|
||||||
addSteps: this.addSteps,
|
addSteps: this.addSteps,
|
||||||
removeSteps: this.removeSteps,
|
removeSteps: this.removeSteps,
|
||||||
@@ -216,64 +169,40 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
setUI: this.setUI
|
setUI: this.setUI
|
||||||
};
|
};
|
||||||
function loadPrevSteps(ref){
|
function loadPrevSteps(ref){
|
||||||
if(prevSteps.length != 0){
|
if(prevSteps.length!=0){
|
||||||
ref.addSteps(prevSteps);
|
ref.addSteps(prevSteps)
|
||||||
prevSteps = [];
|
prevSteps=[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
require('./ui/LoadImage')(sequencer, 'image', json_q.image, function() {
|
require('./ui/LoadImage')(sequencer, "image", json_q.image, function() {
|
||||||
loadPrevSteps(sequencer);
|
loadPrevSteps(sequencer);
|
||||||
json_q.callback.call(ret);
|
json_q.callback.call(ret);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method replaceImage
|
|
||||||
* @description Replaces the current image in the sequencer
|
|
||||||
* @param {String} selector DOM selector string for the image input
|
|
||||||
* @param {*} steps Current steps Object
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
function replaceImage(selector, steps, options) {
|
function replaceImage(selector, steps, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.callback = options.callback || function() { };
|
options.callback = options.callback || function() { };
|
||||||
return require('./ReplaceImage')(this, selector, steps, options);
|
return require('./ReplaceImage')(this, selector, steps, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//returns the steps added
|
||||||
* @method getSteps
|
|
||||||
* @description Returns the current sequence of steps
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function getSteps(){
|
function getSteps(){
|
||||||
return this.steps;
|
return this.steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method setUI
|
|
||||||
* @description To set up a UI for ImageSequencer via different callback methods. Read the docs(https://github.com/publiclab/image-sequencer/blob/main/README.md) for more info.
|
|
||||||
* @param {Object} UI Object containing UI callback methods. Read the docs(https://github.com/publiclab/image-sequencer/blob/main/README.md) for more info.
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function setUI(UI) {
|
function setUI(UI) {
|
||||||
this.events = require('./ui/UserInterface')(UI);
|
this.events = require('./ui/UserInterface')(UI);
|
||||||
}
|
}
|
||||||
|
|
||||||
var exportBin = function(dir, basic, filename) {
|
var exportBin = function(dir, basic, filename) {
|
||||||
return require('./ExportBin')(dir, this, basic, filename);
|
return require('./ExportBin')(dir, this, basic, filename);
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method modulesInfo
|
|
||||||
* @description Returns information about the given module or all the available modules
|
|
||||||
* @param {String} name Module name
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
function modulesInfo(name) {
|
function modulesInfo(name) {
|
||||||
var modulesdata = {};
|
var modulesdata = {}
|
||||||
if (name == 'load-image') return {};
|
if (name == "load-image") return {};
|
||||||
if (arguments.length == 0) {
|
if (arguments.length == 0) {
|
||||||
for (var modulename in this.modules) {
|
for (var modulename in this.modules) {
|
||||||
modulesdata[modulename] = modules[modulename][1];
|
modulesdata[modulename] = modules[modulename][1];
|
||||||
@@ -283,39 +212,150 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (modules[name]){
|
if (modules[name]){
|
||||||
modulesdata = modules[name][1];
|
modulesdata = modules[name][1];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
modulesdata = { 'inputs': sequences[name]['options'] };
|
modulesdata = { 'inputs': sequences[name]['options'] };
|
||||||
}
|
}
|
||||||
return modulesdata;
|
return modulesdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Genates a CLI string for the current sequence
|
||||||
* @method loadNewModule
|
function toCliString() {
|
||||||
* @description Adds a new local module to sequencer. Read the docs(https://github.com/publiclab/image-sequencer/blob/main/README.md) for mode info.
|
var cliStringSteps = `"`, cliOptions = {};
|
||||||
* @param {String} name Name of the new module
|
for (var step in this.steps) {
|
||||||
* @param {Object} options An Object containing path and info about the new module.
|
var name = (typeof this.steps[step].options !== "undefined")? this.steps[step].options.name : this.steps[step].name
|
||||||
* @returns {Object}
|
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)}'`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (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) {
|
function loadNewModule(name, options) {
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
} else if (Array.isArray(options)) {
|
} else if (Array.isArray(options)) {
|
||||||
// Contains the array of module and info
|
// contains the array of module and info
|
||||||
this.modules[name] = options;
|
this.modules[name] = options;
|
||||||
|
|
||||||
} else if (options.func && options.info) {
|
} else if (options.func && options.info) {
|
||||||
// Passed in options object
|
// passed in options object
|
||||||
this.modules[name] = [
|
this.modules[name] = [
|
||||||
options.func, options.info
|
options.func, options.info
|
||||||
];
|
];
|
||||||
|
|
||||||
} else if (options.path && !this.inBrowser) {
|
} else if (options.path && !this.inBrowser) {
|
||||||
// Load from path(only in node)
|
// load from path(only in node)
|
||||||
const module = [
|
const module = [
|
||||||
require(`${options.path}/Module.js`),
|
require(`${options.path}/Module.js`),
|
||||||
require(`${options.path}/info.json`)
|
require(`${options.path}/info.json`)
|
||||||
@@ -325,32 +365,18 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @method saveNewModule
|
|
||||||
* @description Saves a new local module to ImageSequencer
|
|
||||||
* @param {String} name Name of the new module
|
|
||||||
* @param {String} path Path to the new module
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function saveNewModule(name, path) {
|
function saveNewModule(name, path) {
|
||||||
if (options.inBrowser) {
|
if (options.inBrowser) {
|
||||||
// Not for browser context
|
// Not for browser context
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var mods = fs.readFileSync('./src/Modules.js').toString();
|
var mods = fs.readFileSync('./src/Modules.js').toString();
|
||||||
mods = mods.substr(0, mods.length - 1) + ' \'' + name + '\': require(\'' + path + '\'),\n}';
|
mods = mods.substr(0, mods.length - 1) + " '" + name + "': require('" + path + "'),\n}";
|
||||||
fs.writeFileSync('./src/Modules.js', mods);
|
fs.writeFileSync('./src/Modules.js', mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function saveSequence(name, sequenceString) {
|
||||||
* @method saveSequence
|
const sequence = stringToJSON(sequenceString);
|
||||||
* @description Saves a sequence on the browser localStorage.
|
|
||||||
* @param {String} name Name for the sequence
|
|
||||||
* @param {String} sequenceString Sequence data as a string
|
|
||||||
* @returns {Null}
|
|
||||||
*/
|
|
||||||
function saveSequence(name, sequenceString) { // 4. save sequence
|
|
||||||
const sequence = str.stringToJSON(sequenceString);
|
|
||||||
// Save the given sequence string as a module
|
// Save the given sequence string as a module
|
||||||
if (options.inBrowser) {
|
if (options.inBrowser) {
|
||||||
// Inside the browser we save the meta-modules using the Web Storage API
|
// Inside the browser we save the meta-modules using the Web Storage API
|
||||||
@@ -367,7 +393,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadModules() {
|
function loadModules() {
|
||||||
// loadModules function loads the modules and saved sequences.
|
// This function loads the modules and saved sequences
|
||||||
this.modules = require('./Modules');
|
this.modules = require('./Modules');
|
||||||
if (options.inBrowser)
|
if (options.inBrowser)
|
||||||
this.sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
this.sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
||||||
@@ -375,10 +401,9 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
this.sequences = require('./SavedSequences.json');
|
this.sequences = require('./SavedSequences.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Literals and objects
|
//literals and objects
|
||||||
name: 'ImageSequencer',
|
name: "ImageSequencer",
|
||||||
options: options,
|
options: options,
|
||||||
inputlog: inputlog,
|
inputlog: inputlog,
|
||||||
modules: modules,
|
modules: modules,
|
||||||
@@ -387,7 +412,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
steps: steps,
|
steps: steps,
|
||||||
image: image,
|
image: image,
|
||||||
|
|
||||||
// User functions
|
//user functions
|
||||||
loadImages: loadImages,
|
loadImages: loadImages,
|
||||||
loadImage: loadImages,
|
loadImage: loadImages,
|
||||||
addSteps: addSteps,
|
addSteps: addSteps,
|
||||||
@@ -398,17 +423,14 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
setUI: setUI,
|
setUI: setUI,
|
||||||
exportBin: exportBin,
|
exportBin: exportBin,
|
||||||
modulesInfo: modulesInfo,
|
modulesInfo: modulesInfo,
|
||||||
toCliString: str.toCliString,
|
toCliString: toCliString,
|
||||||
detectStringSyntax: str.detectStringSyntax,
|
toString: toString,
|
||||||
parseStringSyntax: str.parseStringSyntax,
|
stepToString: stepToString,
|
||||||
stringToSteps: str.stringToSteps,
|
toJSON: toJSON,
|
||||||
toString: str.toString,
|
stringToJSON: stringToJSON,
|
||||||
stepToString: str.stepToString,
|
stringToJSONstep: stringToJSONstep,
|
||||||
toJSON: str.toJSON,
|
importString: importString,
|
||||||
stringToJSON: str.stringToJSON,
|
importJSON: importJSON,
|
||||||
stringToJSONstep: str.stringToJSONstep,
|
|
||||||
importString: str.importString,
|
|
||||||
importJSON: str.importJSON,
|
|
||||||
loadNewModule: loadNewModule,
|
loadNewModule: loadNewModule,
|
||||||
saveNewModule: saveNewModule,
|
saveNewModule: saveNewModule,
|
||||||
createMetaModule: require('./util/createMetaModule'),
|
createMetaModule: require('./util/createMetaModule'),
|
||||||
@@ -416,14 +438,13 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
loadModules: loadModules,
|
loadModules: loadModules,
|
||||||
getSteps:getSteps,
|
getSteps:getSteps,
|
||||||
|
|
||||||
// Other functions
|
//other functions
|
||||||
log: log,
|
log: log,
|
||||||
objTypeOf: objTypeOf,
|
objTypeOf: objTypeOf,
|
||||||
copy: copy,
|
copy: copy,
|
||||||
getImageDimensions: require('./util/getImageDimensions'),
|
|
||||||
|
|
||||||
setInputStep: require('./ui/SetInputStep')(sequencer)
|
setInputStep: require('./ui/SetInputStep')(sequencer)
|
||||||
};
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
module.exports = ImageSequencer;
|
module.exports = ImageSequencer;
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ function InsertStep(ref, index, name, o) {
|
|||||||
return ref.importJSON(ref.sequences[name]);
|
return ref.importJSON(ref.sequences[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref.detectStringSyntax(name)) {
|
|
||||||
return ref.stringToSteps(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertStep(index, name, o_) {
|
function insertStep(index, name, o_) {
|
||||||
if (ref.modules[name]) var moduleInfo = ref.modules[name][1];
|
if (ref.modules[name]) var moduleInfo = ref.modules[name][1];
|
||||||
@@ -21,17 +18,15 @@ function InsertStep(ref, index, name, o) {
|
|||||||
o.number = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
o.number = ref.options.sequencerCounter++; //Gives a Unique ID to each step
|
||||||
o.name = o_.name || name || moduleInfo.name;
|
o.name = o_.name || name || moduleInfo.name;
|
||||||
o.description = o_.description || moduleInfo.description;
|
o.description = o_.description || moduleInfo.description;
|
||||||
o.moduleInfo = o_.moduleInfo || moduleInfo;
|
|
||||||
o.selector = o_.selector || 'ismod-' + name;
|
o.selector = o_.selector || 'ismod-' + name;
|
||||||
o.container = o_.container || ref.options.selector;
|
o.container = o_.container || ref.options.selector;
|
||||||
o.inBrowser = ref.options.inBrowser;
|
o.inBrowser = ref.options.inBrowser;
|
||||||
o.useWasm = (ref.options.useWasm === false) ? false : true;
|
|
||||||
if (index == -1) index = ref.steps.length;
|
if (index == -1) index = ref.steps.length;
|
||||||
|
|
||||||
o.step = {
|
o.step = {
|
||||||
name: o.name,
|
name: o.name,
|
||||||
description: o.description,
|
description: o.description,
|
||||||
moduleInfo: o.moduleInfo,
|
|
||||||
ID: o.number,
|
ID: o.number,
|
||||||
inBrowser: ref.options.inBrowser,
|
inBrowser: ref.options.inBrowser,
|
||||||
ui: ref.options.ui,
|
ui: ref.options.ui,
|
||||||
@@ -45,7 +40,7 @@ function InsertStep(ref, index, name, o) {
|
|||||||
let step = stepsArray[i];
|
let step = stepsArray[i];
|
||||||
ref.insertSteps(index + Number.parseInt(i), step['name'], step['options']);
|
ref.insertSteps(index + Number.parseInt(i), step['name'], step['options']);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Tell UI that a step has been set up.
|
// Tell UI that a step has been set up.
|
||||||
o = o || {};
|
o = o || {};
|
||||||
|
|||||||
@@ -5,16 +5,13 @@ module.exports = {
|
|||||||
'add-qr': require('./modules/AddQR'),
|
'add-qr': require('./modules/AddQR'),
|
||||||
'average': require('./modules/Average'),
|
'average': require('./modules/Average'),
|
||||||
'blend': require('./modules/Blend'),
|
'blend': require('./modules/Blend'),
|
||||||
'blob-analysis': require('./modules/BlobAnalysis'),
|
|
||||||
'blur': require('./modules/Blur'),
|
'blur': require('./modules/Blur'),
|
||||||
'brightness': require('./modules/Brightness'),
|
'brightness': require('./modules/Brightness'),
|
||||||
'canvas-resize': require('./modules/CanvasResize'),
|
'canvas-resize': require('./modules/CanvasResize'),
|
||||||
'channel': require('./modules/Channel'),
|
'channel': require('./modules/Channel'),
|
||||||
'colorbar': require('./modules/Colorbar'),
|
'colorbar': require('./modules/Colorbar'),
|
||||||
'color-halftone': require('./modules/ColorHalftone'),
|
|
||||||
'color-temperature': require('./modules/ColorTemperature'),
|
'color-temperature': require('./modules/ColorTemperature'),
|
||||||
'colormap': require('./modules/Colormap'),
|
'colormap': require('./modules/Colormap'),
|
||||||
'constrained-crop': require('./modules/ConstrainedCrop'),
|
|
||||||
'contrast': require('./modules/Contrast'),
|
'contrast': require('./modules/Contrast'),
|
||||||
'convolution': require('./modules/Convolution'),
|
'convolution': require('./modules/Convolution'),
|
||||||
'crop': require('./modules/Crop'),
|
'crop': require('./modules/Crop'),
|
||||||
@@ -31,25 +28,17 @@ module.exports = {
|
|||||||
'gradient': require('./modules/Gradient'),
|
'gradient': require('./modules/Gradient'),
|
||||||
'grid-overlay': require('./modules/GridOverlay'),
|
'grid-overlay': require('./modules/GridOverlay'),
|
||||||
'import-image': require('./modules/ImportImage'),
|
'import-image': require('./modules/ImportImage'),
|
||||||
'mask': require('./modules/Mask'),
|
'invert': require('image-sequencer-invert'),
|
||||||
'minify-image': require('./modules/MinifyImage'),
|
|
||||||
// 'invert': require('image-sequencer-invert'), this code imports the invert module from a different repository altogether (using a require statement)
|
|
||||||
// Which is a powerful feature of ImageSequencer, the modules are independent of the rest of the library's source.
|
|
||||||
'invert': require('./modules/Invert'),
|
|
||||||
'ndvi': require('./modules/Ndvi'),
|
'ndvi': require('./modules/Ndvi'),
|
||||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||||
'noise-reduction': require('./modules/NoiseReduction'),
|
|
||||||
'overlay': require('./modules/Overlay'),
|
|
||||||
'paint-bucket': require('./modules/PaintBucket'),
|
'paint-bucket': require('./modules/PaintBucket'),
|
||||||
|
'overlay': require('./modules/Overlay'),
|
||||||
'replace-color': require('./modules/ReplaceColor'),
|
'replace-color': require('./modules/ReplaceColor'),
|
||||||
'resize': require('./modules/Resize'),
|
'resize': require('./modules/Resize'),
|
||||||
'rotate': require('./modules/Rotate'),
|
'rotate': require('./modules/Rotate'),
|
||||||
'saturation': require('./modules/Saturation'),
|
'saturation': require('./modules/Saturation'),
|
||||||
'shadow': require('./modules/Shadow'),
|
|
||||||
'sharpen': require('./modules/Sharpen'),
|
|
||||||
'text-overlay': require('./modules/TextOverlay'),
|
'text-overlay': require('./modules/TextOverlay'),
|
||||||
'threshold': require('./modules/Threshold'),
|
'threshold': require('./modules/Threshold'),
|
||||||
'tint': require('./modules/Tint'),
|
'tint': require('./modules/Tint'),
|
||||||
'webgl-distort': require('./modules/WebglDistort'),
|
|
||||||
'white-balance': require('./modules/WhiteBalance')
|
'white-balance': require('./modules/WhiteBalance')
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Uses a given image as input and replaces it with the output.
|
// Uses a given image as input and replaces it with the output.
|
||||||
// Works only in the browser.
|
// Works only in the browser.
|
||||||
function ReplaceImage(ref, selector, steps, options) {
|
function ReplaceImage(ref,selector,steps,options) {
|
||||||
if(!ref.options.inBrowser) return false; // This isn't for Node.js
|
if(!ref.options.inBrowser) return false; // This isn't for Node.js
|
||||||
var tempSequencer = ImageSequencer({ui: false});
|
var tempSequencer = ImageSequencer({ui: false});
|
||||||
var this_ = ref;
|
var this_ = ref;
|
||||||
@@ -26,27 +26,23 @@ function ReplaceImage(ref, selector, steps, options) {
|
|||||||
// https://github.com/publiclab/image-sequencer/issues/241
|
// https://github.com/publiclab/image-sequencer/issues/241
|
||||||
// https://stackoverflow.com/a/20048852/1116657
|
// https://stackoverflow.com/a/20048852/1116657
|
||||||
var raw = '';
|
var raw = '';
|
||||||
var i, j, subArray, chunk = 5000;
|
var i,j,subArray,chunk = 5000;
|
||||||
for (i = 0, j = arr.length; i < j; i += chunk) {
|
for (i=0,j=arr.length; i<j; i+=chunk) {
|
||||||
subArray = arr.subarray(i, i + chunk);
|
subArray = arr.subarray(i,i+chunk);
|
||||||
raw += String.fromCharCode.apply(null, subArray);
|
raw += String.fromCharCode.apply(null, subArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
var base64 = btoa(raw);
|
var base64 = btoa(raw);
|
||||||
var dataURL = 'data:image/' + ext + ';base64,' + base64;
|
var dataURL="data:image/"+ext+";base64," + base64;
|
||||||
make(dataURL);
|
make(dataURL);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(url.substr(0, 11).toLowerCase() != 'data:image/') xmlHTTP.send();
|
if(url.substr(0,11).toLowerCase()!="data:image/") xmlHTTP.send();
|
||||||
else make(url);
|
else make(url);
|
||||||
|
|
||||||
function make(url) {
|
function make(url) {
|
||||||
tempSequencer.loadImage(url, function(){
|
tempSequencer.loadImage(url, function(){
|
||||||
// this.addSteps(steps).run({stop:function(){}},function(out){
|
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){
|
|
||||||
img.src = out;
|
img.src = out;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -54,8 +50,8 @@ function ReplaceImage(ref, selector, steps, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < images.length; i++) {
|
for (var i = 0; i < images.length; i++) {
|
||||||
replaceImage(images[i], steps);
|
replaceImage(images[i],steps);
|
||||||
if (i == images.length - 1)
|
if (i == images.length-1)
|
||||||
options.callback();
|
options.callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/Run.js
38
src/Run.js
@@ -5,7 +5,7 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
|
|
||||||
function drawStep(drawarray, pos) {
|
function drawStep(drawarray, pos) {
|
||||||
if (pos == drawarray.length && drawarray[pos - 1] !== undefined) {
|
if (pos == drawarray.length && drawarray[pos - 1] !== undefined) {
|
||||||
if (ref.objTypeOf(callback) == 'Function' && ref.steps.slice(-1)[0].output) {
|
if (ref.objTypeOf(callback) == "Function" && ref.steps.slice(-1)[0].output) {
|
||||||
var steps = ref.steps;
|
var steps = ref.steps;
|
||||||
var out = steps[steps.length - 1].output.src;
|
var out = steps[steps.length - 1].output.src;
|
||||||
callback(out);
|
callback(out);
|
||||||
@@ -25,7 +25,7 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
};
|
};
|
||||||
step.getIndex = function getIndex() {
|
step.getIndex = function getIndex() {
|
||||||
return i;
|
return i;
|
||||||
};
|
}
|
||||||
|
|
||||||
for (var util in getStepUtils) {
|
for (var util in getStepUtils) {
|
||||||
if (getStepUtils.hasOwnProperty(util)) {
|
if (getStepUtils.hasOwnProperty(util)) {
|
||||||
@@ -43,10 +43,8 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
inputForNextStep,
|
inputForNextStep,
|
||||||
function onEachStep() {
|
function onEachStep() {
|
||||||
|
|
||||||
// This output is accessible by UI
|
// This output is accessible by UI
|
||||||
ref.steps[i].options.step.output = ref.steps[i].output.src;
|
ref.steps[i].options.step.output = ref.steps[i].output.src;
|
||||||
ref.steps[i].options.step.wasmSuccess = ref.steps[i].output.wasmSuccess || false;
|
|
||||||
ref.steps[i].options.step.useWasm = ref.steps[i].output.useWasm || false;
|
|
||||||
|
|
||||||
// Tell UI that step has been drawn.
|
// Tell UI that step has been drawn.
|
||||||
ref.steps[i].UI.onComplete(ref.steps[i].options.step);
|
ref.steps[i].UI.onComplete(ref.steps[i].options.step);
|
||||||
@@ -60,26 +58,26 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
|
|
||||||
function drawSteps(json_q) {
|
function drawSteps(json_q) {
|
||||||
var drawarray = [],
|
var drawarray = [],
|
||||||
no_steps = ref.steps.length,
|
no_steps = ref.steps.length,
|
||||||
init = json_q[0];
|
init = json_q[0];
|
||||||
for (var i = 0; i < no_steps - init; i++) {
|
for (var i = 0; i < no_steps - init; i++) {
|
||||||
drawarray.push({i: init + i });
|
drawarray.push({i: init + i });
|
||||||
}
|
}
|
||||||
drawStep(drawarray, ind);
|
drawStep(drawarray, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(json_q) {
|
function filter(json_q) {
|
||||||
|
|
||||||
if (json_q[0] == 0 && ref.steps.length == 1)
|
if (json_q[0] == 0 && ref.steps.length == 1)
|
||||||
delete json_q[0];
|
delete json_q[0];
|
||||||
else if (json_q[0] == 0) json_q[0]++;
|
else if (json_q[0] == 0) json_q[0]++;
|
||||||
var prevstep = ref.steps[json_q[0] - 1];
|
var prevstep = ref.steps[json_q[0] - 1];
|
||||||
while (
|
while (
|
||||||
typeof prevstep == 'undefined' ||
|
typeof prevstep == "undefined" ||
|
||||||
typeof prevstep.output == 'undefined'
|
typeof prevstep.output == "undefined"
|
||||||
) {
|
) {
|
||||||
prevstep = ref.steps[--json_q[0] - 1];
|
prevstep = ref.steps[--json_q[0] - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return json_q;
|
return json_q;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ const dataUriToBuffer = require('data-uri-to-buffer');
|
|||||||
const savePixels = require('save-pixels');
|
const savePixels = require('save-pixels');
|
||||||
|
|
||||||
module.exports = function(input) {
|
module.exports = function(input) {
|
||||||
input.getPixels = getPixels;
|
input.getPixels = getPixels;
|
||||||
input.pixelManipulation = pixelManipulation;
|
input.pixelManipulation = pixelManipulation;
|
||||||
input.lodash = lodash;
|
input.lodash = lodash;
|
||||||
input.dataUriToBuffer = dataUriToBuffer;
|
input.dataUriToBuffer = dataUriToBuffer;
|
||||||
input.savePixels = savePixels;
|
input.savePixels = savePixels;
|
||||||
return input;
|
return input;
|
||||||
};
|
}
|
||||||
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
|
|
||||||
};
|
|
||||||
};
|
|
||||||
102
src/cli/index.js
102
src/cli/index.js
@@ -1,102 +0,0 @@
|
|||||||
require('../ImageSequencer');
|
|
||||||
sequencer = ImageSequencer({ ui: true });
|
|
||||||
var fs = require('fs');
|
|
||||||
var { Command } = require('commander');
|
|
||||||
var utils = require('../CliUtils');
|
|
||||||
|
|
||||||
var saveSequence = require('./saveSequence.js');
|
|
||||||
var installModule = require('./installModule.js');
|
|
||||||
var sequencerSteps = require('./sequencerSteps.js');
|
|
||||||
|
|
||||||
function exit(message) {
|
|
||||||
console.error(message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function executeSteps(program) {
|
|
||||||
// Set sequencer to log module outputs, if any.
|
|
||||||
sequencer.setUI({
|
|
||||||
onComplete: function (step) {
|
|
||||||
// Get information of outputs.
|
|
||||||
step.info = sequencer.modulesInfo(step.name);
|
|
||||||
|
|
||||||
for (var output in step.info.outputs) {
|
|
||||||
console.log('[' + program.step + ']: ' + output + ' = ' + step[output]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
notify: function (msg) {
|
|
||||||
console.log('\x1b[36m%s\x1b[0m', '🌟 ' + msg);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Finally, if everything is alright, load the image, add the steps and run the sequencer.
|
|
||||||
sequencer.loadImages(program.image, function () {
|
|
||||||
console.warn(
|
|
||||||
'\x1b[33m%s\x1b[0m',
|
|
||||||
'Please wait \n output directory generated will be empty until the execution is complete'
|
|
||||||
);
|
|
||||||
|
|
||||||
//Generate the Output Directory
|
|
||||||
var outputFilename = program.output.split('/').slice(-1)[0];
|
|
||||||
if (outputFilename.includes('.')) {
|
|
||||||
// user did give an output filename we have to remove it from dir
|
|
||||||
program.output = program.output.split('/').slice(0, -1).join('/');
|
|
||||||
} else {
|
|
||||||
outputFilename = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
sequencerSteps(program, sequencer, outputFilename);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseSteps(program) {
|
|
||||||
// Parse step into an array to allow for multiple steps.
|
|
||||||
if (!program.step) exit('No steps passed');
|
|
||||||
program.step = program.step.split(' ');
|
|
||||||
|
|
||||||
// User must input an image.
|
|
||||||
if (!program.image) exit('Can\'t read file.');
|
|
||||||
|
|
||||||
// User must input an image.
|
|
||||||
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))
|
|
||||||
exit('Please ensure all steps are valid.');
|
|
||||||
|
|
||||||
// If there's no user defined output directory, select a default directory.
|
|
||||||
program.output = program.output || './output/';
|
|
||||||
|
|
||||||
executeSteps(program);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cli(args) {
|
|
||||||
|
|
||||||
let program = new Command();
|
|
||||||
|
|
||||||
program
|
|
||||||
.version('0.1.0')
|
|
||||||
.option('-i, --image [PATH/URL]', 'Input image URL')
|
|
||||||
.option('-s, --step [step-name]', 'Name of the step to be added.')
|
|
||||||
.option('-o, --output [PATH]', 'Directory where output will be stored.')
|
|
||||||
.option('-b, --basic', 'Basic mode outputs only final image')
|
|
||||||
.option('-c, --config [Object]', 'Options for the step')
|
|
||||||
.option(
|
|
||||||
'--save-sequence [string]',
|
|
||||||
'Name space separated with Stringified sequence'
|
|
||||||
)
|
|
||||||
.option(
|
|
||||||
'--install-module [string]',
|
|
||||||
'Module name space seaprated npm package name'
|
|
||||||
)
|
|
||||||
.parse(args);
|
|
||||||
|
|
||||||
const options = program.opts();
|
|
||||||
if (options.saveSequence) saveSequence(options, sequencer);
|
|
||||||
else if (options.installModule) installModule(options, sequencer);
|
|
||||||
else parseSteps(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = cli;
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
var childProcess = require('child_process');
|
var childProcess = require('child_process')
|
||||||
var Spinner = require('ora');
|
var Spinner = require('ora');
|
||||||
|
|
||||||
module.exports = function (program, sequencer) {
|
module.exports = function (program, sequencer) {
|
||||||
console.log(
|
console.log(
|
||||||
'\x1b[33m%s\x1b[0m',
|
"\x1b[33m%s\x1b[0m",
|
||||||
'Please wait while your Module is being Installed...\nThis may take a while!'
|
"Please wait while your Module is being Installed...\nThis may take a while!"
|
||||||
);
|
);
|
||||||
|
|
||||||
var params = program.installModule.split(' ');
|
var params = program.installModule.split(' ');
|
||||||
var spinner = Spinner('Now Installing...').start();
|
var spinner = Spinner("Now Installing...").start();
|
||||||
childProcess.execSync(`npm i ${params[1]}`);
|
childProcess.execSync(`npm i ${params[1]}`)
|
||||||
sequencer.saveNewModule(params[0], params[1]);
|
sequencer.saveNewModule(params[0], params[1]);
|
||||||
sequencer.loadNewModule(params[0], require(params[1]));
|
sequencer.loadNewModule(params[0], require(params[1]));
|
||||||
spinner.stop();
|
spinner.stop();
|
||||||
console.log('\x1b[32m%s\x1b[0m', 'Your module was installed successfully!!');
|
console.log("\x1b[32m%s\x1b[0m", "Your module was installed successfully!!");
|
||||||
};
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
module.exports = function (program, sequencer) {
|
module.exports = function (program, sequencer) {
|
||||||
|
|
||||||
var params = program.saveSequence.split(' ');
|
var params = program.saveSequence.split(' ');
|
||||||
sequencer.saveSequence(params[0], params[1]);
|
sequencer.saveSequence(params[0], params[1]);
|
||||||
console.log('\x1b[32m', 'Your sequence was saved successfully!!');
|
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||||
|
|
||||||
};
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
var Spinner = require('ora');
|
var Spinner = require('ora');
|
||||||
var readlineSync = require('readline-sync');
|
var readlineSync = require('readline-sync');
|
||||||
var utils = require('../CliUtils');
|
var utils = require('../CliUtils')
|
||||||
|
|
||||||
module.exports = function (program, sequencer, outputFilename) {
|
module.exports = function (program, sequencer, outputFilename) {
|
||||||
utils.makedir(program.output, () => {
|
utils.makedir(program.output, () => {
|
||||||
console.log('Files will be exported to "' + program.output + '"');
|
console.log('Files will be exported to "' + program.output + '"');
|
||||||
|
|
||||||
if (program.basic)
|
if (program.basic)
|
||||||
console.log('Basic mode is enabled, outputting only final image');
|
console.log("Basic mode is enabled, outputting only final image");
|
||||||
|
|
||||||
// Iterate through the steps and retrieve their inputs.
|
// Iterate through the steps and retrieve their inputs.
|
||||||
program.step.forEach(function(step) {
|
program.step.forEach(function(step) {
|
||||||
@@ -15,7 +15,7 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
|
|
||||||
// If inputs exists, print to console.
|
// If inputs exists, print to console.
|
||||||
if (Object.keys(options).length) {
|
if (Object.keys(options).length) {
|
||||||
console.log('[' + step + ']: Inputs');
|
console.log("[" + step + "]: Inputs");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If inputs exists, print them out with descriptions.
|
// If inputs exists, print them out with descriptions.
|
||||||
@@ -23,9 +23,9 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
// 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
|
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||||
console.log(
|
console.log(
|
||||||
new Array(step.length + 5).join(' ') +
|
new Array(step.length + 5).join(" ") +
|
||||||
input +
|
input +
|
||||||
': ' +
|
": " +
|
||||||
options[input].desc
|
options[input].desc
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -33,18 +33,18 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
if (program.config) {
|
if (program.config) {
|
||||||
try {
|
try {
|
||||||
var config = JSON.parse(program.config);
|
var config = JSON.parse(program.config);
|
||||||
console.log('The parsed options object: ', config);
|
console.log(`The parsed options object: `, config);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(
|
console.error(
|
||||||
'\x1b[31m%s\x1b[0m',
|
"\x1b[31m%s\x1b[0m",
|
||||||
'Options(Config) is not a not valid JSON Fallback activate'
|
`Options(Config) is not a not valid JSON Fallback activate`
|
||||||
);
|
);
|
||||||
program.config = false;
|
program.config = false;
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (program.config && utils.validateConfig(config, options)) {
|
if (program.config && utils.validateConfig(config, options)) {
|
||||||
console.log('Now using Options object');
|
console.log("Now using Options object");
|
||||||
Object.keys(options).forEach(function(input) {
|
Object.keys(options).forEach(function(input) {
|
||||||
options[input] = config[input];
|
options[input] = config[input];
|
||||||
});
|
});
|
||||||
@@ -52,15 +52,15 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
// If inputs exist, iterate through them and prompt for values.
|
// If inputs exist, iterate through them and prompt for values.
|
||||||
Object.keys(options).forEach(function(input) {
|
Object.keys(options).forEach(function(input) {
|
||||||
var value = readlineSync.question(
|
var value = readlineSync.question(
|
||||||
'[' +
|
"[" +
|
||||||
step +
|
step +
|
||||||
']: Enter a value for ' +
|
"]: Enter a value for " +
|
||||||
input +
|
input +
|
||||||
' (' +
|
" (" +
|
||||||
options[input].type +
|
options[input].type +
|
||||||
', default: ' +
|
", default: " +
|
||||||
options[input].default +
|
options[input].default +
|
||||||
'): '
|
"): "
|
||||||
);
|
);
|
||||||
options[input] = value;
|
options[input] = value;
|
||||||
});
|
});
|
||||||
@@ -71,7 +71,7 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
|
|
||||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||||
if (!process.env.TEST)
|
if (!process.env.TEST)
|
||||||
spinnerObj = Spinner('Your Image is being processed..').start();
|
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||||
|
|
||||||
// Run the sequencer.
|
// Run the sequencer.
|
||||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||||
@@ -81,8 +81,8 @@ module.exports = function (program, sequencer, outputFilename) {
|
|||||||
//check if spinner was not overriden stop it
|
//check if spinner was not overriden stop it
|
||||||
if (!spinnerObj.overrideFlag) {
|
if (!spinnerObj.overrideFlag) {
|
||||||
spinnerObj.succeed();
|
spinnerObj.succeed();
|
||||||
console.log('\nDone!!');
|
console.log(`\nDone!!`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
@@ -1,64 +1,51 @@
|
|||||||
const _ = require('lodash'),
|
|
||||||
parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
|
|
||||||
module.exports = function AddQR(options, UI) {
|
module.exports = function AddQR(options, UI) {
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
var output;
|
options.size = options.size || defaults.size;
|
||||||
getPixels = require('get-pixels');
|
options.qrCodeString = options.qrCodeString || "https://github.com/publiclab/image-sequencer";
|
||||||
|
var output;
|
||||||
|
getPixels = require('get-pixels');
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
options.size = Number(options.size || defaults.size);
|
progressObj.stop(true);
|
||||||
options.qrCodeString = options.qrCodeString || defaults.qrCodeString;
|
progressObj.overrideFlag = true;
|
||||||
options.startingX = options.startingX || defaults.startingX;
|
|
||||||
options.startingY = options.startingY || defaults.startingY;
|
|
||||||
progressObj.stop(true);
|
|
||||||
progressObj.overrideFlag = true;
|
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
function extraManipulation(pixels, setRenderState, generateOutput) {
|
return getPixels(input.src, function (err, oldPixels) {
|
||||||
let iw = pixels.shape[0], // Width of Original Image
|
function changePixel(r, g, b, a) {
|
||||||
ih = pixels.shape[1]; // Height of Original Image
|
return [r, g, b, a];
|
||||||
const oldPixels = _.cloneDeep(pixels);
|
}
|
||||||
setRenderState(false); // Prevent rendering of final output image until extraManipulation completes.
|
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the inputs.
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
parseCornerCoordinateInputs({iw, ih},
|
output: output,
|
||||||
{
|
changePixel: changePixel,
|
||||||
startingX: { valInp: options.startingX, type: 'horizontal'},
|
extraManipulation: extraManipulation,
|
||||||
startingY: { valInp: options.startingY, type: 'vertical' },
|
format: input.format,
|
||||||
}, function(opt, cord){
|
image: options.image,
|
||||||
options.startingX = Math.floor(cord.startingX.valInp);
|
inBrowser: options.inBrowser,
|
||||||
options.startingY = Math.floor(cord.startingY.valInp);
|
callback: callback
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
|
||||||
require('./QR')(options, pixels, oldPixels, () => {
|
|
||||||
setRenderState(true); // Allow rendering in the callback.
|
|
||||||
generateOutput();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
return {
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
|
||||||
ui: options.step.ui,
|
|
||||||
extraManipulation: extraManipulation,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,37 +1,48 @@
|
|||||||
const pixelSetter = require('../../util/pixelSetter.js'),
|
module.exports = exports = function (options, pixels, oldPixels, callback) {
|
||||||
getPixels = require('get-pixels'),
|
var QRCode = require('qrcode')
|
||||||
QRCode = require('qrcode');
|
QRCode.toDataURL(options.qrCodeString, function (err, url) {
|
||||||
module.exports = exports = function (options, pixels, oldPixels, cb) {
|
var getPixels = require("get-pixels");
|
||||||
|
getPixels(url, function (err, qrPixels) {
|
||||||
|
if (err) {
|
||||||
|
console.log("Bad image path", image);
|
||||||
|
}
|
||||||
|
|
||||||
QRCode.toDataURL(options.qrCodeString, {width: options.size, scale: 1}, function (error, url) {
|
var imagejs = require('imagejs');
|
||||||
getPixels(url, function (err, qrPixels) {
|
var bitmap = new imagejs.Bitmap({ width: qrPixels.shape[0], height: qrPixels.shape[1] });
|
||||||
if (err) {
|
bitmap._data.data = qrPixels.data;
|
||||||
console.log('get-pixels error: ', err);
|
var resized = bitmap.resize({
|
||||||
}
|
width: options.size, height: options.size,
|
||||||
|
algorithm: "bicubicInterpolation"
|
||||||
|
});
|
||||||
|
|
||||||
const width = oldPixels.shape[0],
|
qrPixels.data = resized._data.data;
|
||||||
height = oldPixels.shape[1];
|
qrPixels.shape = [options.size, options.size, 4];
|
||||||
|
qrPixels.stride[1] = 4 * options.size;
|
||||||
|
|
||||||
const xe = Math.min(options.startingX, width - options.size), // Starting pixel coordinates
|
var width = oldPixels.shape[0],
|
||||||
ye = Math.min(options.startingY, height - options.size);
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
for (let x = xe; x < Math.min(xe + options.size, width); x++) {
|
else {
|
||||||
for (let y = ye; y < Math.min(ye + options.size, height); y++) {
|
pixels.set(m, n, 0, oldPixels.get(m, n, 0))
|
||||||
pixelSetter(
|
pixels.set(m, n, 1, oldPixels.get(m, n, 1))
|
||||||
x,
|
pixels.set(m, n, 2, oldPixels.get(m, n, 2))
|
||||||
y,
|
pixels.set(m, n, 3, oldPixels.get(m, n, 3))
|
||||||
[
|
}
|
||||||
qrPixels.get(x - xe, y - ye, 0),
|
|
||||||
qrPixels.get(x - xe, y - ye, 1),
|
|
||||||
qrPixels.get(x - xe, y - ye, 2),
|
|
||||||
qrPixels.get(x - xe, y - ye, 3)
|
|
||||||
],
|
|
||||||
pixels
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cb) cb();
|
}
|
||||||
});
|
}
|
||||||
});
|
callback();
|
||||||
};
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "add-qr",
|
"name": "Add QR",
|
||||||
"description": "Adds QR corresponding to the given string",
|
"description": "Adds QR corresponding to the given string",
|
||||||
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
@@ -12,16 +12,6 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"desc": "input string to generate QR code",
|
"desc": "input string to generate QR code",
|
||||||
"default": "https://github.com/publiclab/image-sequencer"
|
"default": "https://github.com/publiclab/image-sequencer"
|
||||||
},
|
|
||||||
"startingX": {
|
|
||||||
"type": "string",
|
|
||||||
"desc": "X-position (measured from left) from where QR starts",
|
|
||||||
"default": "0"
|
|
||||||
},
|
|
||||||
"startingY": {
|
|
||||||
"type": "string",
|
|
||||||
"desc": "Y-position (measured from top) from where QR starts",
|
|
||||||
"default": "0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#add-qr-module"
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#add-qr-module"
|
||||||
|
|||||||
@@ -3,70 +3,72 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function Average(options, UI) {
|
module.exports = function Average(options, UI) {
|
||||||
|
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
options.step.metadata = options.step.metadata || {};
|
options.step.metadata = options.step.metadata || {};
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
// do the averaging
|
// do the averaging
|
||||||
function extraManipulation(pixels) {
|
function extraManipulation(pixels) {
|
||||||
var i = 0, sum = [0, 0, 0, 0];
|
var i = 0, sum = [0, 0, 0, 0];
|
||||||
while (i < pixels.data.length) {
|
while (i < pixels.data.length) {
|
||||||
sum[0] += pixels.data[i++];
|
sum[0] += pixels.data[i++];
|
||||||
sum[1] += pixels.data[i++];
|
sum[1] += pixels.data[i++];
|
||||||
sum[2] += pixels.data[i++];
|
sum[2] += pixels.data[i++];
|
||||||
sum[3] += pixels.data[i++];
|
sum[3] += pixels.data[i++];
|
||||||
}
|
}
|
||||||
|
|
||||||
let divisor = pixels.data.length / 4;
|
let divisor = pixels.data.length / 4;
|
||||||
|
|
||||||
sum[0] = Math.floor(sum[0] / divisor);
|
sum[0] = Math.floor(sum[0] / divisor);
|
||||||
sum[1] = Math.floor(sum[1] / divisor);
|
sum[1] = Math.floor(sum[1] / divisor);
|
||||||
sum[2] = Math.floor(sum[2] / divisor);
|
sum[2] = Math.floor(sum[2] / divisor);
|
||||||
sum[3] = Math.floor(sum[3] / divisor);
|
sum[3] = Math.floor(sum[3] / divisor);
|
||||||
|
|
||||||
i = 0;
|
i = 0
|
||||||
while (i < pixels.data.length) {
|
while (i < pixels.data.length) {
|
||||||
pixels.data[i++] = sum[0];
|
pixels.data[i++] = sum[0];
|
||||||
pixels.data[i++] = sum[1];
|
pixels.data[i++] = sum[1];
|
||||||
pixels.data[i++] = sum[2];
|
pixels.data[i++] = sum[2];
|
||||||
pixels.data[i++] = sum[3];
|
pixels.data[i++] = sum[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
// report back and store average in metadata:
|
// report back and store average in metadata:
|
||||||
options.step.metadata.averages = sum;
|
options.step.metadata.averages = 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) {
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
|
||||||
if (options.step.average === undefined) options.step.average = '';
|
|
||||||
options.step.average += 'rgba(' + sum.join(', ') + ')';
|
|
||||||
return pixels;
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
options: options,
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
|
||||||
ui: options.step.ui,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
extraManipulation: extraManipulation,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,13 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "average",
|
"name": "Average",
|
||||||
"description": "Average all pixel color",
|
"description": "Average all pixel color",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
},
|
},
|
||||||
"outputs": {
|
|
||||||
"average": {
|
|
||||||
"type": "string",
|
|
||||||
"desc": "The average value of all the pixels."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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#average-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +1,75 @@
|
|||||||
module.exports = function Blend(options, UI, util) {
|
module.exports = function Dynamic(options, UI, util) {
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
|
||||||
options.func = options.blend || defaults.blend;
|
options.func = options.func || defaults.blend;
|
||||||
options.offset = options.offset || defaults.offset;
|
options.offset = options.offset || defaults.offset;
|
||||||
options.blendMode = options.blendMode || defaults.blendMode;
|
|
||||||
|
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
// This function is called on every draw.
|
// This function is called on every draw.
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
var getPixels = require('get-pixels');
|
// convert to runnable code:
|
||||||
|
if (typeof options.func === "string") eval('options.func = ' + options.func);
|
||||||
|
|
||||||
// convert offset as string to int
|
var getPixels = require('get-pixels');
|
||||||
if (typeof options.offset === 'string') options.offset = parseInt(options.offset);
|
|
||||||
|
|
||||||
// save first image's pixels
|
// convert offset as string to int
|
||||||
var priorStep = this.getStep(options.offset);
|
if (typeof options.offset === "string") options.offset = parseInt(options.offset);
|
||||||
|
|
||||||
if (priorStep.output === undefined) {
|
// save first image's pixels
|
||||||
this.output = input;
|
var priorStep = this.getStep(options.offset);
|
||||||
UI.notify('Offset Unavailable', 'offset-notification');
|
|
||||||
callback();
|
if (priorStep.output === undefined) {
|
||||||
|
this.output = input;
|
||||||
|
UI.notify('Offset Unavailable', 'offset-notification');
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
getPixels(priorStep.output.src, function(err, pixels) {
|
||||||
|
options.firstImagePixels = pixels;
|
||||||
|
|
||||||
|
function changePixel(r2, g2, b2, a2, x, y) {
|
||||||
|
// blend!
|
||||||
|
let p = options.firstImagePixels;
|
||||||
|
return options.func(
|
||||||
|
r2, g2, b2, a2,
|
||||||
|
p.get(x, y, 0),
|
||||||
|
p.get(x, y, 1),
|
||||||
|
p.get(x, y, 2),
|
||||||
|
p.get(x, y, 3)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
|
// This output is accessible by Image Sequencer
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// run PixelManipulatin on second image's pixels
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
changePixel: changePixel,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
inBrowser: options.inBrowser,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// see http://docs.gimp.org/en/gimp-concepts-layer-modes.html for other blend modes
|
return {
|
||||||
|
options: options,
|
||||||
const multiply_mode = function (i, m) {
|
draw: draw,
|
||||||
return ~~( (i * m) / 255 );
|
|
||||||
};
|
|
||||||
const divide_mode = function (i, m) {
|
|
||||||
return ~~( (256 * i) / (m + 1) );
|
|
||||||
};
|
|
||||||
|
|
||||||
const overlay_mode = function (i, m) {
|
|
||||||
return ~~( (i / 255) * (i + ((2 * m) / 255) * (255 - i)) );
|
|
||||||
};
|
|
||||||
|
|
||||||
const screen_mode = function (i, m) {
|
|
||||||
return ~~( 255 - ((255 - m) * (255 - i)) / 255 );
|
|
||||||
};
|
|
||||||
|
|
||||||
const sof_light_mode = function (i, m) {
|
|
||||||
var Rs = screen_mode(i, m);
|
|
||||||
return ~~( ((((255 - i) * m) + Rs) * i) / 255 );
|
|
||||||
};
|
|
||||||
|
|
||||||
const color_dodge = function (i, m) {
|
|
||||||
return ~~( (256 * i) / (255 - m + 1) );
|
|
||||||
};
|
|
||||||
|
|
||||||
const burn_mode = function (i, m) {
|
|
||||||
return ~~( 255 - (256 * (255 - i)) / (m + 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
const grain_extract_mode = function (i, m) {
|
|
||||||
return ~~( i - m + 128 );
|
|
||||||
};
|
|
||||||
|
|
||||||
const grain_merge_mode = function (i, m) {
|
|
||||||
return ~~( i + m - 128 );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
getPixels(priorStep.output.src, function(err, pixels) {
|
|
||||||
options.firstImagePixels = pixels;
|
|
||||||
|
|
||||||
// Convert to runnable code.
|
|
||||||
if (typeof options.func === 'string') eval('options.func = ' + options.func);
|
|
||||||
|
|
||||||
function changePixel(r2, g2, b2, a2, x, y) {
|
|
||||||
// blend!
|
|
||||||
let p = options.firstImagePixels;
|
|
||||||
let r1 = p.get(x, y, 0),
|
|
||||||
g1 = p.get(x, y, 1),
|
|
||||||
b1 = p.get(x, y, 2),
|
|
||||||
a1 = p.get(x, y, 3);
|
|
||||||
|
|
||||||
const blends = {
|
|
||||||
'Color Dodge': () => [color_dodge(r2, r1), color_dodge(g2, g1), color_dodge(b2, b1), 255],
|
|
||||||
'Multiply': () => [multiply_mode(r2, r1), multiply_mode(g2, g1), multiply_mode(b2, b1), multiply_mode(a2, a1)],
|
|
||||||
'Divide': () => [divide_mode(r2, r1), divide_mode(g2, g1), divide_mode(b2, b1), 255],
|
|
||||||
'Overlay': () => [overlay_mode(r2, r1), overlay_mode(g2, g1), overlay_mode(b2, b1), 255],
|
|
||||||
'Screen': () => [screen_mode(r2, r1), screen_mode(g2, g1), screen_mode(b2, b1), 255],
|
|
||||||
'Soft Light': () => [sof_light_mode(r2, r1), sof_light_mode(g2, g1), sof_light_mode(b2, b1), 255],
|
|
||||||
'Color Burn': () => [burn_mode(r2, r1), burn_mode(g2, g1), burn_mode(b2, b1), 255],
|
|
||||||
'Grain Extract': () => [grain_extract_mode(r2, r1), grain_extract_mode(g2, g1), grain_extract_mode(b2, b1), 255],
|
|
||||||
'Grain Merge': () => [grain_merge_mode(r2, r1), grain_merge_mode(g2, g1), grain_merge_mode(b2, b1), 255]
|
|
||||||
};
|
|
||||||
|
|
||||||
if(options.blendMode == 'custom')
|
|
||||||
return options.func(
|
|
||||||
r2, g2, b2, a2, r1, g1, b1, a1
|
|
||||||
);
|
|
||||||
else {
|
|
||||||
return blends[options.blendMode]();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
|
||||||
}
|
|
||||||
|
|
||||||
// run PixelManipulatin on second image's pixels
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
output: output,
|
||||||
ui: options.step.ui,
|
UI: UI
|
||||||
changePixel: changePixel,
|
}
|
||||||
format: input.format,
|
}
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,34 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "blend",
|
"name": "Blend",
|
||||||
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2.",
|
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"offset": {
|
"offset": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"desc": "Choose which image to blend the current image with. Two steps back is -2, three steps back is -3 etc.",
|
"desc": "Choose which image to blend the current image with. Two steps back is -2, three steps back is -3 etc.",
|
||||||
"default": -2
|
"default": -2
|
||||||
},
|
},
|
||||||
"blendMode": {
|
|
||||||
"type": "select",
|
|
||||||
"desc": "Name of the Blend Mode to use",
|
|
||||||
"default": "custom",
|
|
||||||
"values": [
|
|
||||||
"custom",
|
|
||||||
"Multiply",
|
|
||||||
"Divide",
|
|
||||||
"Overlay",
|
|
||||||
"Screen",
|
|
||||||
"Soft Light",
|
|
||||||
"Color Burn",
|
|
||||||
"Color Dodge",
|
|
||||||
"Grain Extract",
|
|
||||||
"Grain Merge"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"blend": {
|
"blend": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"desc": "Function to use to blend the two images.",
|
"desc": "Function to use to blend the two images.",
|
||||||
"default": "function(r1, g1, b1, a1, r2, g2, b2, a2, x, y) { return [ r2, g2, b2, a2 ] }"
|
"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#blend-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
module.exports = function(pixels){
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = pixels.shape[0];
|
|
||||||
canvas.height = pixels.shape[1];
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
ctx.putImageData(new ImageData(new Uint8ClampedArray(pixels.data), pixels.shape[0], pixels.shape[1]), 0, 0);
|
|
||||||
|
|
||||||
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
||||||
|
|
||||||
|
|
||||||
let src = cv.matFromImageData(imgData);
|
|
||||||
let dst = new cv.Mat();
|
|
||||||
let gray = new cv.Mat();
|
|
||||||
let opening = new cv.Mat();
|
|
||||||
let imageBg = new cv.Mat();
|
|
||||||
let imageFg = new cv.Mat();
|
|
||||||
let distTrans = new cv.Mat();
|
|
||||||
let unknown = new cv.Mat();
|
|
||||||
let markers = new cv.Mat();
|
|
||||||
|
|
||||||
// Gray and Threshold the image
|
|
||||||
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
|
|
||||||
cv.threshold(gray, gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU);
|
|
||||||
|
|
||||||
// Get background
|
|
||||||
let M = cv.Mat.ones(3, 3, cv.CV_8U);
|
|
||||||
cv.erode(gray, gray, M);
|
|
||||||
cv.dilate(gray, opening, M);
|
|
||||||
cv.dilate(opening, imageBg, M, new cv.Point(-1, -1), 3);
|
|
||||||
|
|
||||||
// Distance transform
|
|
||||||
cv.distanceTransform(opening, distTrans, cv.DIST_L2, 5);
|
|
||||||
cv.normalize(distTrans, distTrans, 1, 0, cv.NORM_INF);
|
|
||||||
|
|
||||||
// Get foreground
|
|
||||||
cv.threshold(distTrans, imageFg, 0.7 * 1, 255, cv.THRESH_BINARY);
|
|
||||||
imageFg.convertTo(imageFg, cv.CV_8U, 1, 0);
|
|
||||||
cv.subtract(imageBg, imageFg, unknown);
|
|
||||||
|
|
||||||
// Get connected components markers
|
|
||||||
cv.connectedComponents(imageFg, markers);
|
|
||||||
for (let i = 0; i < markers.rows; i++) {
|
|
||||||
for (let j = 0; j < markers.cols; j++) {
|
|
||||||
markers.intPtr(i, j)[0] = markers.ucharPtr(i, j)[0] + 1;
|
|
||||||
if (unknown.ucharPtr(i, j)[0] == 255) {
|
|
||||||
markers.intPtr(i, j)[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cv.cvtColor(src, src, cv.COLOR_RGBA2RGB, 0);
|
|
||||||
cv.watershed(src, markers);
|
|
||||||
|
|
||||||
// Grow barriers
|
|
||||||
for (let i = 0; i < markers.rows; i++) {
|
|
||||||
for (let j = 0; j < markers.cols; j++) {
|
|
||||||
if (markers.intPtr(i, j)[0] == -1) {
|
|
||||||
src.ucharPtr(i, j)[0] = 255; // Red
|
|
||||||
src.ucharPtr(i, j)[1] = 0; // Green
|
|
||||||
src.ucharPtr(i, j)[2] = 0; // Blue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cv.imshow(canvas, src);
|
|
||||||
|
|
||||||
src.delete(); dst.delete(); gray.delete(); opening.delete(); imageBg.delete();
|
|
||||||
imageFg.delete(); distTrans.delete(); unknown.delete(); markers.delete(); M.delete();
|
|
||||||
|
|
||||||
var myImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
||||||
pixels.data = myImageData.data;
|
|
||||||
|
|
||||||
return pixels;
|
|
||||||
};
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
module.exports = function BlobAnalysis(options, UI){
|
|
||||||
|
|
||||||
var output;
|
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
|
||||||
|
|
||||||
progressObj.stop(true);
|
|
||||||
progressObj.overrideFlag = true;
|
|
||||||
|
|
||||||
var step = this;
|
|
||||||
|
|
||||||
function extraManipulation(pixels, setRenderState, generateOutput){
|
|
||||||
setRenderState(false);
|
|
||||||
if (!options.inBrowser) {
|
|
||||||
require('../_nomodule/gl-context')(input, callback, step, options);
|
|
||||||
} else{
|
|
||||||
pixels = require('./BlobAnalysis')(pixels);
|
|
||||||
setRenderState(true);
|
|
||||||
generateOutput();
|
|
||||||
}
|
|
||||||
return pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
|
||||||
}
|
|
||||||
|
|
||||||
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,7 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Blob Analysis",
|
|
||||||
"description": "Blob/Region identification for microscopic images.",
|
|
||||||
"inputs": {},
|
|
||||||
"requires": ["webgl", "browser"],
|
|
||||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blob-analysis"
|
|
||||||
}
|
|
||||||
@@ -1,65 +1,84 @@
|
|||||||
// Generates a 5x5 Gaussian kernel
|
|
||||||
function kernelGenerator(sigma = 1) {
|
|
||||||
|
|
||||||
let kernel = [],
|
|
||||||
sum = 0;
|
|
||||||
|
|
||||||
if (sigma == 0) sigma += 0.05;
|
|
||||||
|
|
||||||
const s = 2 * Math.pow(sigma, 2);
|
|
||||||
|
|
||||||
for (let y = -2; y <= 2; y++) {
|
|
||||||
kernel.push([]);
|
|
||||||
for (let x = -2; x <= 2; x++) {
|
|
||||||
let r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
|
||||||
kernel[y + 2].push(Math.exp(-(r / s)));
|
|
||||||
sum += kernel[y + 2][x + 2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let x = 0; x < 5; x++){
|
|
||||||
for (let y = 0; y < 5; y++){
|
|
||||||
kernel[y][x] = (kernel[y][x] / sum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return kernel;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = exports = function(pixels, blur) {
|
module.exports = exports = function(pixels, blur) {
|
||||||
const pixelSetter = require('../../util/pixelSetter.js');
|
let kernel = kernelGenerator(blur, 1), oldpix = require('lodash').cloneDeep(pixels);
|
||||||
|
kernel = flipKernel(kernel);
|
||||||
|
|
||||||
let kernel = kernelGenerator(blur), // Generate the Gaussian kernel based on the sigma input.
|
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||||
pixs = { // Separates the rgb channel pixels to convolve on the GPU.
|
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||||
r: [],
|
let neighboutPos = getNeighbouringPixelPositions([i, j]);
|
||||||
g: [],
|
let acc = [0.0, 0.0, 0.0, 0.0];
|
||||||
b: [],
|
for (let a = 0; a < kernel.length; a++) {
|
||||||
};
|
for (let b = 0; b < kernel.length; b++) {
|
||||||
|
acc[0] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 0) * kernel[a][b]);
|
||||||
for (let y = 0; y < pixels.shape[1]; y++){
|
acc[1] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 1) * kernel[a][b]);
|
||||||
pixs.r.push([]);
|
acc[2] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 2) * kernel[a][b]);
|
||||||
pixs.g.push([]);
|
acc[3] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 3) * kernel[a][b]);
|
||||||
pixs.b.push([]);
|
}
|
||||||
|
}
|
||||||
for (let x = 0; x < pixels.shape[0]; x++){
|
pixels.set(i, j, 0, acc[0]);
|
||||||
pixs.r[y].push(pixels.get(x, y, 0));
|
pixels.set(i, j, 1, acc[1]);
|
||||||
pixs.g[y].push(pixels.get(x, y, 1));
|
pixels.set(i, j, 2, acc[2]);
|
||||||
pixs.b[y].push(pixels.get(x, y, 2));
|
}
|
||||||
}
|
}
|
||||||
}
|
return pixels;
|
||||||
|
|
||||||
const convolve = require('../_nomodule/gpuUtils').convolve; // GPU convolution function.
|
|
||||||
|
|
||||||
const conPix = convolve([pixs.r, pixs.g, pixs.b], kernel); // Convolves the pixels (all channels separately) on the GPU.
|
|
||||||
|
|
||||||
for (let y = 0; y < pixels.shape[1]; y++){
|
//Generates a 3x3 Gaussian kernel
|
||||||
for (let x = 0; x < pixels.shape[0]; x++){
|
function kernelGenerator(sigma, size) {
|
||||||
var pixelvalue = [Math.max(0, Math.min(conPix[0][y][x], 255)),
|
|
||||||
Math.max(0, Math.min(conPix[1][y][x], 255)),
|
/*
|
||||||
Math.max(0, Math.min(conPix[2][y][x], 255))];
|
Trying out a variable radius kernel not working as of now
|
||||||
pixelSetter(x, y, pixelvalue, pixels); // Sets the image pixels according to the blurred values.
|
*/
|
||||||
|
// const coeff = (1.0/(2.0*Math.PI*sigma*sigma))
|
||||||
|
// const expCoeff = -1 * (1.0/2.0 * sigma * sigma)
|
||||||
|
// let e = Math.E
|
||||||
|
// let result = []
|
||||||
|
// for(let i = -1 * size;i<=size;i++){
|
||||||
|
// let arr = []
|
||||||
|
// for(let j= -1 * size;j<=size;j++){
|
||||||
|
// arr.push(coeff * Math.pow(e,expCoeff * ((i * i) + (j*j))))
|
||||||
|
// }
|
||||||
|
// result.push(arr)
|
||||||
|
// }
|
||||||
|
// let sum = result.reduce((sum,val)=>{
|
||||||
|
// return val.reduce((sumInner,valInner)=>{
|
||||||
|
// return sumInner+valInner
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// result = result.map(arr=>arr.map(val=>(val + 0.0)/(sum + 0.0)))
|
||||||
|
|
||||||
|
// return result
|
||||||
|
|
||||||
|
return [
|
||||||
|
[2.0 / 159.0, 4.0 / 159.0, 5.0 / 159.0, 4.0 / 159.0, 2.0 / 159.0],
|
||||||
|
[4.0 / 159.0, 9.0 / 159.0, 12.0 / 159.0, 9.0 / 159.0, 4.0 / 159.0],
|
||||||
|
[5.0 / 159.0, 12.0 / 159.0, 15.0 / 159.0, 12.0 / 159.0, 5.0 / 159.0],
|
||||||
|
[4.0 / 159.0, 9.0 / 159.0, 12.0 / 159.0, 9.0 / 159.0, 4.0 / 159.0],
|
||||||
|
[2.0 / 159.0, 4.0 / 159.0, 5.0 / 159.0, 4.0 / 159.0, 2.0 / 159.0]
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
function getNeighbouringPixelPositions(pixelPosition) {
|
||||||
|
let x = pixelPosition[0], y = pixelPosition[1], result = [];
|
||||||
|
|
||||||
return pixels;
|
for (let i = -2; i <= 2; i++) {
|
||||||
};
|
let arr = [];
|
||||||
|
for (let j = -2; j <= 2; j++)
|
||||||
|
arr.push([x + i, y + j]);
|
||||||
|
|
||||||
|
result.push(arr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flipKernel(kernel) {
|
||||||
|
let result = [];
|
||||||
|
for (let i = kernel.length - 1; i >= 0; i--) {
|
||||||
|
let arr = [];
|
||||||
|
for (let j = kernel[i].length - 1; j >= 0; j--) {
|
||||||
|
arr.push(kernel[i][j]);
|
||||||
|
}
|
||||||
|
result.push(arr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,43 +3,42 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function Blur(options, UI) {
|
module.exports = function Blur(options, UI) {
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
options.blur = options.blur || defaults.blur;
|
options.blur = options.blur || defaults.blur;
|
||||||
options.blur = parseFloat(options.blur);
|
var output;
|
||||||
var output;
|
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('./Blur')(pixels, options.blur);
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
|
// This output is accessible by Image Sequencer
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
|
||||||
function extraManipulation(pixels) {
|
|
||||||
pixels = require('./Blur')(pixels, options.blur);
|
|
||||||
return pixels;
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
options: options,
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
|
||||||
ui: options.step.ui,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
extraManipulation: extraManipulation,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "blur",
|
"name": "Blur",
|
||||||
"description": "Applies a Gaussian blur given by the intensity value",
|
"description": "Applies a Gaussian blur given by the intensity value",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"blur": {
|
"blur": {
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
"default": 2,
|
"default": 2,
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 5,
|
"max": 5,
|
||||||
"step": 0.05
|
"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#blur-module"
|
||||||
|
|||||||
@@ -3,54 +3,55 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function Brightness(options, UI) {
|
module.exports = function Brightness(options, UI) {
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
options.brightness = options.brightness || defaults.brightness;
|
options.brightness = options.brightness || defaults.brightness;
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In this case progress is handled by changepixel internally otherwise progressObj
|
In this case progress is handled by changepixel internally otherwise progressObj
|
||||||
needs to be overriden and used
|
needs to be overriden and used
|
||||||
For eg. progressObj = new SomeProgressModule()
|
For eg. progressObj = new SomeProgressModule()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var step = this, val = (options.brightness) / 100.0;
|
var step = this, val = (options.brightness) / 100.0;;
|
||||||
|
|
||||||
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
r = Math.min(val * r, 255);
|
|
||||||
g = Math.min(val * g, 255);
|
|
||||||
b = Math.min(val * b, 255);
|
|
||||||
return [r, g, b, a];
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
options: options,
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
|
||||||
ui: options.step.ui, //don't pass this in if you don't want your module to support progress bars
|
|
||||||
changePixel: changePixel,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "brightness",
|
"name": "Brightness",
|
||||||
"description": "Change the brightness of the image by given percent value",
|
"description": "Change the brightness of the image by given percent value",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"brightness": {
|
"brightness": {
|
||||||
|
|||||||
@@ -3,58 +3,61 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function canvasResize(options, UI) {
|
module.exports = function canvasResize(options, UI) {
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
const pixelSetter = require('../../util/pixelSetter.js');
|
var output;
|
||||||
|
|
||||||
var output;
|
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
|
||||||
|
|
||||||
options.width = parseInt(options.width || defaults.width);
|
function draw(input, callback, progressObj) {
|
||||||
options.height = parseInt(options.height || defaults.height);
|
|
||||||
options.x = parseInt(options.x || defaults.x);
|
|
||||||
options.y = parseInt(options.y || defaults.y);
|
|
||||||
|
|
||||||
progressObj.stop(true);
|
options.width = options.width || defaults.width;
|
||||||
progressObj.overrideFlag = true;
|
options.height = options.height || defaults.height;
|
||||||
|
options.x = options.x || defaults.x;
|
||||||
|
options.y = options.y || defaults.y;
|
||||||
|
|
||||||
var step = this;
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
function extraManipulation(pixels) {
|
var step = this;
|
||||||
|
|
||||||
let newPixels = require('ndarray')(new Uint8Array(4 * options.width * options.height).fill(0), [options.width, options.height, 4]);
|
function extraManipulation(pixels) {
|
||||||
let iMax = options.width - options.x,
|
|
||||||
jMax = options.height - options.y;
|
let newPixels = require('ndarray')(new Uint8Array(4 * options.width * options.height).fill(255), [options.width, options.height, 4]);
|
||||||
for (let i = 0; i < iMax && i < pixels.shape[0]; i++) {
|
let iMax = options.width - options.x,
|
||||||
for (let j = 0; j < jMax && j < pixels.shape[1]; j++) {
|
jMax = options.height - options.y;
|
||||||
let x = i + options.x, y = j + options.y;
|
for (let i = 0; i < iMax && i < pixels.shape[0]; i++) {
|
||||||
pixelSetter(x, y, [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2), pixels.get(i, j, 3)], newPixels);
|
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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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 {
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
options: options,
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
output: output,
|
|
||||||
ui: options.step.ui,
|
|
||||||
extraManipulation: extraManipulation,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "canvas-resize",
|
"name": "Resize Canvas",
|
||||||
"description": "This module resizes the canvas and overlays the ouput of the previous step at given location",
|
"description": "This module resizes the canvas and overlays the ouput of the previous step at given location",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"width": {
|
"width": {
|
||||||
@@ -22,6 +22,5 @@
|
|||||||
"desc": "Y-cord of the top left corner of the image on the canvas",
|
"desc": "Y-cord of the top left corner of the image on the canvas",
|
||||||
"default": 500
|
"default": 500
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#canvas-resize-module"
|
|
||||||
}
|
}
|
||||||
@@ -17,24 +17,25 @@ module.exports = function Channel(options, UI) {
|
|||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
function changePixel(r, g, b, a) {
|
function changePixel(r, g, b, a) {
|
||||||
if (options.channel === 'red') return [r, 0, 0, a];
|
if (options.channel === "red") return [r, 0, 0, a];
|
||||||
if (options.channel === 'green') return [0, g, 0, a];
|
if (options.channel === "green") return [0, g, 0, a];
|
||||||
if (options.channel === 'blue') return [0, 0, b, a];
|
if (options.channel === "blue") return [0, 0, b, a];
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
function output(image, datauri, mimetype) {
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
|
||||||
|
// This output is accesible by Image Sequencer
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
output: output,
|
output: output,
|
||||||
ui: options.step.ui,
|
|
||||||
changePixel: changePixel,
|
changePixel: changePixel,
|
||||||
format: input.format,
|
format: input.format,
|
||||||
image: options.image,
|
image: options.image,
|
||||||
inBrowser: options.inBrowser,
|
inBrowser: options.inBrowser,
|
||||||
callback: callback,
|
callback: callback
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,5 +46,5 @@ module.exports = function Channel(options, UI) {
|
|||||||
draw: draw,
|
draw: draw,
|
||||||
output: output,
|
output: output,
|
||||||
UI: UI
|
UI: UI
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "channel",
|
"name": "Channel",
|
||||||
"description": "Displays only one color channel of an image -- default is green",
|
"description": "Displays only one color channel of an image -- default is green",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"channel": {
|
"channel": {
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Generate halftone versions of CMYK channels and blend them with varying rotations as in analog print color separation processes.
|
|
||||||
* Simulates a CMYK halftone rendering of the image by multiplying pixel values with a four rotated 2D sine wave patterns, one each for cyan, magenta, yellow, and black.
|
|
||||||
* http://evanw.github.io/glfx.js/docs/#colorHalftone
|
|
||||||
*/
|
|
||||||
module.exports = function ColorHalftone(options, UI) {
|
|
||||||
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
|
||||||
|
|
||||||
var output;
|
|
||||||
var fx = require('glfx');
|
|
||||||
|
|
||||||
var dataURItoBlob = function dataURItoBlob(dataURI) {
|
|
||||||
// convert base64/URLEncoded data component to raw binary data held in a string
|
|
||||||
var byteString;
|
|
||||||
if (dataURI.split(',')[0].indexOf('base64') >= 0)
|
|
||||||
byteString = atob(dataURI.split(',')[1]);
|
|
||||||
else
|
|
||||||
byteString = unescape(dataURI.split(',')[1]);
|
|
||||||
|
|
||||||
// separate out the mime component
|
|
||||||
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
|
|
||||||
|
|
||||||
// write the bytes of the string to a typed array
|
|
||||||
var ia = new Uint8Array(byteString.length);
|
|
||||||
for (var i = 0; i < byteString.length; i++) {
|
|
||||||
ia[i] = byteString.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Blob([ia], { type: mimeString });
|
|
||||||
};
|
|
||||||
|
|
||||||
var canvasToBlobUrl = function canvasToBlobUrl(canvas) {
|
|
||||||
|
|
||||||
var blob = dataURItoBlob(canvas.toDataURL('image/png'));
|
|
||||||
return window.URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
var colorHalftone = function colorHalftone(id, options, download) {
|
|
||||||
|
|
||||||
// try to create a WebGL canvas (will fail if WebGL isn't supported)
|
|
||||||
try {
|
|
||||||
var canvas = fx.canvas(1500, 1500);
|
|
||||||
} catch (e) {
|
|
||||||
alert(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert the image to a texture
|
|
||||||
var imageEl = document.getElementById(id);
|
|
||||||
|
|
||||||
var image = new Image();
|
|
||||||
|
|
||||||
image.onload = function() {
|
|
||||||
|
|
||||||
var texture = canvas.texture(image);
|
|
||||||
|
|
||||||
canvas.draw(texture,
|
|
||||||
image.width, // * ratio,
|
|
||||||
image.height// * ratio
|
|
||||||
);
|
|
||||||
|
|
||||||
canvas.colorHalftone(
|
|
||||||
image.width / 2,
|
|
||||||
image.height / 2,
|
|
||||||
parseFloat(options.angle),
|
|
||||||
parseFloat(options.size)
|
|
||||||
).update();
|
|
||||||
|
|
||||||
var burl = canvasToBlobUrl(canvas);
|
|
||||||
|
|
||||||
if (download) {
|
|
||||||
|
|
||||||
window.open(burl);
|
|
||||||
|
|
||||||
} else { // replace the image
|
|
||||||
|
|
||||||
// keep non-blob version in case we have to fall back:
|
|
||||||
// image.src = canvas.toDataURL('image/png');
|
|
||||||
// window.location = canvas.toDataURL('image/png');
|
|
||||||
imageEl.src = burl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
$(image).hide();
|
|
||||||
image.src = imageEl.src;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
function draw(input, callback) {
|
|
||||||
|
|
||||||
var step = this;
|
|
||||||
|
|
||||||
options.angle = options.angle || defaults.angle;
|
|
||||||
options.size = options.size || defaults.size;
|
|
||||||
|
|
||||||
if (!options.inBrowser) {
|
|
||||||
// this.output = input;
|
|
||||||
// callback();
|
|
||||||
require('../_nomodule/gl-context')(input, callback, step, options);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var image = document.createElement('img');
|
|
||||||
image.onload = () => {
|
|
||||||
colorHalftone(
|
|
||||||
'img',
|
|
||||||
options
|
|
||||||
);
|
|
||||||
image.onload = () => {
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = image.naturalWidth; // or 'width' if you want a special/scaled size
|
|
||||||
canvas.height = image.naturalHeight; // or 'height' if you want a special/scaled size
|
|
||||||
canvas.getContext('2d').drawImage(image, 0, 0);
|
|
||||||
|
|
||||||
step.output = { src: canvas.toDataURL('image/png'), format: 'png' };
|
|
||||||
image.remove();
|
|
||||||
callback();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
image.src = input.src;
|
|
||||||
image.id = 'img';
|
|
||||||
document.body.appendChild(image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
module.exports = [
|
|
||||||
require('./Module'),
|
|
||||||
require('./info.json')
|
|
||||||
];
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "color-halftone",
|
|
||||||
"requires": ["webgl"],
|
|
||||||
"description": "Generate halftone versions of CMYK channels and blend them with varying rotations as in analog print color separation processes.",
|
|
||||||
"inputs": {
|
|
||||||
"angle": {
|
|
||||||
"type": "float",
|
|
||||||
"desc": "angle of rotation of the halftone patterns in radians",
|
|
||||||
"default": "0.25",
|
|
||||||
"min": "0",
|
|
||||||
"max": "1.57",
|
|
||||||
"step": "0.05"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "integer",
|
|
||||||
"desc": "the diameter of a dot in pixels",
|
|
||||||
"default": "4",
|
|
||||||
"min": "3",
|
|
||||||
"max": "20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#color-halftone-module"
|
|
||||||
}
|
|
||||||
@@ -1,81 +1,81 @@
|
|||||||
module.exports = function ColorTemperature(options, UI) {
|
module.exports = function ColorTemperature(options, UI) {
|
||||||
|
|
||||||
const pixelSetter = require('../../util/pixelSetter.js');
|
|
||||||
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
|
||||||
|
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
options.temperature = options.temperature || defaults.temperature;
|
options.temperature = (options.temperature > "40000") ? "40000" : options.temperature
|
||||||
options.temperature = (options.temperature > 40000) ? 40000 : options.temperature;
|
|
||||||
options.temperature = (options.temperature < 0) ? 0 : options.temperature;
|
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
function extraManipulation(pixels) {
|
function extraManipulation(pixels) {
|
||||||
|
|
||||||
let temp = parseInt(options.temperature);
|
let temp = parseInt(options.temperature)
|
||||||
temp /= 100;
|
temp /= 100
|
||||||
|
|
||||||
let r, g, b;
|
let r, g, b;
|
||||||
|
|
||||||
if (temp <= 66) {
|
if (temp <= 66) {
|
||||||
r = 255;
|
r = 255;
|
||||||
g = Math.min(Math.max(99.4708025861 * Math.log(temp) - 161.1195681661, 0), 255);
|
g = Math.min(Math.max(99.4708025861 * Math.log(temp) - 161.1195681661, 0), 255);
|
||||||
} else {
|
} else {
|
||||||
r = Math.min(Math.max(329.698727446 * Math.pow(temp - 60, -0.1332047592), 0), 255);
|
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);
|
g = Math.min(Math.max(288.1221695283 * Math.pow(temp - 60, -0.0755148492), 0), 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp >= 66) {
|
if (temp >= 66) {
|
||||||
b = 255;
|
b = 255;
|
||||||
} else if (temp <= 19) {
|
} else if (temp <= 19) {
|
||||||
b = 0;
|
b = 0;
|
||||||
} else {
|
} else {
|
||||||
b = temp - 10;
|
b = temp - 10;
|
||||||
b = Math.min(Math.max(138.5177312231 * Math.log(b) - 305.0447927307, 0), 255);
|
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 i = 0; i < pixels.shape[0]; i++) {
|
||||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||||
|
|
||||||
var rgbdata = [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2)];
|
r_data = pixels.get(i, j, 0)
|
||||||
rgbdata[0] = (255 / r) * rgbdata[0];
|
r_new_data = (255 / r) * r_data
|
||||||
rgbdata[1] = (255 / g) * rgbdata[1];
|
pixels.set(i, j, 0, r_new_data)
|
||||||
rgbdata[2] = (255 / b) * rgbdata[2];
|
|
||||||
pixelSetter(i, j, rgbdata, pixels);
|
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 pixels;
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
inBrowser: options.inBrowser,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image, datauri, mimetype, wasmSuccess) {
|
return {
|
||||||
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
}
|
||||||
output: output,
|
|
||||||
ui: options.step.ui,
|
|
||||||
extraManipulation: extraManipulation,
|
|
||||||
format: input.format,
|
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback,
|
|
||||||
useWasm:options.useWasm
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
module.exports = [
|
module.exports = [
|
||||||
require('./Module'),
|
require('./Module'),
|
||||||
require('./info.json')
|
require('./info.json')
|
||||||
];
|
]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user