mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-07 17:00:02 +01:00
Compare commits
239 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8beec96be | ||
|
|
5e33c69736 | ||
|
|
bd68245a12 | ||
|
|
c6457323cc | ||
|
|
e1a113cde1 | ||
|
|
24fb0ca9e4 | ||
|
|
a2fb2689a6 | ||
|
|
0be9e3f33b | ||
|
|
30e9f359d5 | ||
|
|
3c1b6f2019 | ||
|
|
96299ed6f7 | ||
|
|
2f21bec80a | ||
|
|
3d1bbe5940 | ||
|
|
0865bc44d2 | ||
|
|
055b17c75f | ||
|
|
bf2fd7ede6 | ||
|
|
1e08d7c1da | ||
|
|
ac57b32ec6 | ||
|
|
9f5a7bb49a | ||
|
|
af033d15c6 | ||
|
|
273f1eb494 | ||
|
|
6a450c743e | ||
|
|
bed23c8974 | ||
|
|
3c5f0a2a30 | ||
|
|
ffed3d1af1 | ||
|
|
92aaaa9a42 | ||
|
|
6dd7738476 | ||
|
|
600ddece58 | ||
|
|
29b0571c64 | ||
|
|
cc0c5411d9 | ||
|
|
194e6fc441 | ||
|
|
fdb38f7fdf | ||
|
|
c3abdaf3aa | ||
|
|
761142d9d3 | ||
|
|
81b06d1b42 | ||
|
|
75dc23fb55 | ||
|
|
f42aa2fd67 | ||
|
|
e0ed73a24e | ||
|
|
c2bc12a112 | ||
|
|
fa30c1b30f | ||
|
|
53db6bd2ce | ||
|
|
f4a80a0490 | ||
|
|
9836314f1f | ||
|
|
6e193d48fc | ||
|
|
1a0ae054c8 | ||
|
|
b638ceb1db | ||
|
|
f09df0d042 | ||
|
|
044a120468 | ||
|
|
2d8b93020a | ||
|
|
90c57af332 | ||
|
|
78cbaa262b | ||
|
|
ddde6e1e2e | ||
|
|
2d8bb53402 | ||
|
|
b47de40292 | ||
|
|
0a091a611f | ||
|
|
2274ce6785 | ||
|
|
58c6cbff24 | ||
|
|
6153dbfdaa | ||
|
|
6b305a02f5 | ||
|
|
57e4849d35 | ||
|
|
3081dccf19 | ||
|
|
fa047ce6a9 | ||
|
|
d0bf9de71a | ||
|
|
0cd3156c06 | ||
|
|
8880a580dd | ||
|
|
c445070937 | ||
|
|
d792f21147 | ||
|
|
ad60c91d6b | ||
|
|
3c2d6542dc | ||
|
|
b64e7cefc0 | ||
|
|
eb3b3df800 | ||
|
|
0e6e1837a6 | ||
|
|
dc361a3ab8 | ||
|
|
3d2d7844b6 | ||
|
|
8fd4efc621 | ||
|
|
413a235594 | ||
|
|
0e87c8b1df | ||
|
|
4fd814dd95 | ||
|
|
17d79c4b44 | ||
|
|
85a53325d2 | ||
|
|
81719a9e13 | ||
|
|
fc02e7aea0 | ||
|
|
f68983d6d7 | ||
|
|
b5fcba3c54 | ||
|
|
f6b1f7b201 | ||
|
|
2399e511a0 | ||
|
|
cfdb54359c | ||
|
|
9e5f252fd4 | ||
|
|
2e9689b905 | ||
|
|
c72beb7359 | ||
|
|
e5d26815d7 | ||
|
|
73b917f036 | ||
|
|
0248bc7124 | ||
|
|
89345f32b3 | ||
|
|
4e5f8728fa | ||
|
|
c2477bc3f7 | ||
|
|
ef4a4d3055 | ||
|
|
20d49456fd | ||
|
|
2aa7e9b96c | ||
|
|
52c9c35398 | ||
|
|
a522e13613 | ||
|
|
f41f564bd9 | ||
|
|
1a98247858 | ||
|
|
4369137336 | ||
|
|
595d66ecd5 | ||
|
|
6d9f656a1e | ||
|
|
69ed689ad7 | ||
|
|
107b4c22e4 | ||
|
|
e5d36ca317 | ||
|
|
eb595d6139 | ||
|
|
2bdd532848 | ||
|
|
d104ea744b | ||
|
|
bc122af258 | ||
|
|
11476d5084 | ||
|
|
a2157be2da | ||
|
|
b71e9dec12 | ||
|
|
aad1f823d3 | ||
|
|
b520622bfd | ||
|
|
6028520197 | ||
|
|
a60acd5a72 | ||
|
|
0fc8007e79 | ||
|
|
5bdaea3688 | ||
|
|
e353465dce | ||
|
|
39c70d1304 | ||
|
|
611016b022 | ||
|
|
f77cface7b | ||
|
|
f3291e201f | ||
|
|
901cf6a96c | ||
|
|
7f4f9a0950 | ||
|
|
3a39d2b4bb | ||
|
|
3ab02125cb | ||
|
|
d5aac98a29 | ||
|
|
8ff09e26cc | ||
|
|
d7b175eceb | ||
|
|
ee5a3a5e4f | ||
|
|
35b95a68b1 | ||
|
|
5288973a48 | ||
|
|
d49acd504e | ||
|
|
ac9086e4ef | ||
|
|
94e4dfe1b9 | ||
|
|
056e57af8b | ||
|
|
9fedf4b9c7 | ||
|
|
300d972718 | ||
|
|
e2f1fb9729 | ||
|
|
3e5cec32e4 | ||
|
|
8a96bd8cac | ||
|
|
7cd89c4481 | ||
|
|
980966ecfa | ||
|
|
eebf149532 | ||
|
|
59898d72fe | ||
|
|
23f4851bb5 | ||
|
|
6bab70ad09 | ||
|
|
327b421284 | ||
|
|
98e4eca24f | ||
|
|
a93440093b | ||
|
|
0c2d2a47d8 | ||
|
|
16debae154 | ||
|
|
3e30c0f7ed | ||
|
|
fd78285ac7 | ||
|
|
4eb386eb47 | ||
|
|
f27b09793c | ||
|
|
a56e8a3b16 | ||
|
|
b666ad510b | ||
|
|
809fb0b37a | ||
|
|
a4818d70d8 | ||
|
|
537cc41b36 | ||
|
|
95f8dad901 | ||
|
|
ceca433806 | ||
|
|
1e719936c4 | ||
|
|
1ae20b536a | ||
|
|
753e73f355 | ||
|
|
a26a441b20 | ||
|
|
7ae8a2ddf7 | ||
|
|
c81f5c6caf | ||
|
|
6d381c0df8 | ||
|
|
6a2f106b4c | ||
|
|
65a6b77b78 | ||
|
|
c688817ffc | ||
|
|
ca67bf1ece | ||
|
|
88a31e564e | ||
|
|
2161d58e50 | ||
|
|
108e87996a | ||
|
|
f152a78e70 | ||
|
|
5af30d9046 | ||
|
|
ddf4bd0dae | ||
|
|
3712f0c1cf | ||
|
|
f672dc814a | ||
|
|
98c71b18a8 | ||
|
|
3ca4081042 | ||
|
|
cd6f61d71a | ||
|
|
20cf3277ea | ||
|
|
bf13d5807a | ||
|
|
ef10fb77f1 | ||
|
|
19110c4677 | ||
|
|
d209cd46b1 | ||
|
|
4bdc5b6583 | ||
|
|
4576e497db | ||
|
|
1311119787 | ||
|
|
9e1a12c58d | ||
|
|
948f67fb60 | ||
|
|
8685dcb66c | ||
|
|
2243a4b8f7 | ||
|
|
7fe16735b3 | ||
|
|
a17d1a6ccd | ||
|
|
5f57123503 | ||
|
|
d2ff6f2d6c | ||
|
|
361be0074c | ||
|
|
f9376808fd | ||
|
|
85c92626e4 | ||
|
|
b30b539dab | ||
|
|
e5e372d89d | ||
|
|
11b65604cd | ||
|
|
c762f1ad5d | ||
|
|
965399a2b4 | ||
|
|
3df5ca3802 | ||
|
|
7e594c4168 | ||
|
|
5e28f901eb | ||
|
|
48eafe806f | ||
|
|
6638e9bdb4 | ||
|
|
bf80c2b2b6 | ||
|
|
e512e98921 | ||
|
|
9168c15cf9 | ||
|
|
276a637ac3 | ||
|
|
1d085c7f20 | ||
|
|
802b281096 | ||
|
|
67408ca338 | ||
|
|
a67fe91d0d | ||
|
|
09669fe858 | ||
|
|
768117a078 | ||
|
|
2e7e042baa | ||
|
|
b300dc2d1f | ||
|
|
fef021911b | ||
|
|
70654a5aac | ||
|
|
338e610fe7 | ||
|
|
06d2aaf1e2 | ||
|
|
5a362f5c9a | ||
|
|
76826d431d | ||
|
|
88364decf6 | ||
|
|
bb17e9452f |
35
.github/ISSUE_TEMPLATE.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
### Please describe the problem (or idea)
|
||||||
|
|
||||||
|
> What happened just before the problem occurred? Or what problem could this idea solve?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> What did you expect to see that you didn't?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Please show us where to look
|
||||||
|
|
||||||
|
http://sequencer.publiclab.org...
|
||||||
|
|
||||||
|
|
||||||
|
### What's your PublicLab.org username?
|
||||||
|
|
||||||
|
> This can help us diagnose the issue:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Browser, version, and operating system
|
||||||
|
|
||||||
|
> Many bugs are related to these -- please help us track it down and reproduce what you're seeing!
|
||||||
|
|
||||||
|
|
||||||
|
****
|
||||||
|
|
||||||
|
## Thank you!
|
||||||
|
|
||||||
|
Your help makes Public Lab better! We *deeply* appreciate your helping refine and improve this site.
|
||||||
|
|
||||||
|
To learn how to write really great issues, which increases the chances they'll be resolved, see:
|
||||||
|
|
||||||
|
https://publiclab.org/wiki/developers#Contributing+for+non-coders
|
||||||
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Fixes #[Add issue number here.]
|
||||||
|
|
||||||
|
Make sure these boxes are checked before your pull request (PR) is ready to be reviewed and merged. Thanks!
|
||||||
|
|
||||||
|
* [ ] tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with `npm test`
|
||||||
|
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
||||||
|
* [ ] PR is descriptively titled
|
||||||
|
* [ ] ask `@publiclab/is-reviewers` for help, in a comment below
|
||||||
|
|
||||||
|
> We're happy to help you get this ready -- don't be afraid to ask for help, and **don't be discouraged** if your tests fail at first!
|
||||||
|
|
||||||
|
If tests do fail, click on the red `X` to learn why by reading the logs.
|
||||||
|
|
||||||
|
Please be sure you've reviewed our contribution guidelines at https://publiclab.org/contributing-to-public-lab-software
|
||||||
|
|
||||||
|
Thanks!
|
||||||
25
.github/config.yml
vendored
Normal file
25
.github/config.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Configuration for welcome - https://github.com/behaviorbot/welcome
|
||||||
|
|
||||||
|
# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
|
||||||
|
|
||||||
|
# Comment to be posted to on first time issues
|
||||||
|
newIssueWelcomeComment: |
|
||||||
|
Thanks for opening your first issue here! Please follow the issue template to help us help you 👍🎉😄
|
||||||
|
If you have screenshots to share demonstrating the issue, that's really helpful! 📸 You can [make a gif](https://www.cockos.com/licecap/) too!
|
||||||
|
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
|
||||||
|
|
||||||
|
# Comment to be posted to on PRs from first time contributors in your repository
|
||||||
|
newPRWelcomeComment: |
|
||||||
|
Thanks for opening this pull request!
|
||||||
|
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
|
||||||
|
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||||
|
|
||||||
|
# Comment to be posted to on pull requests merged by a first time user
|
||||||
|
firstPRMergeComment: |
|
||||||
|
Congrats on merging your first pull request! 🙌🎉⚡️
|
||||||
|
Your code will likely be published to https://sequencer.publiclab.org in the next few days.
|
||||||
|
In the meantime, can you tell us your Twitter handle so we can thank you properly?
|
||||||
|
Now that you've completed this, you can help someone else take their first step!
|
||||||
|
See: [Public Lab's coding community!](https://code.publiclab.org)
|
||||||
|
|
||||||
|
# It is recommended to include as many gifs and emojis as possible
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -40,5 +40,9 @@ todo.txt
|
|||||||
test.js
|
test.js
|
||||||
output.txt
|
output.txt
|
||||||
output/
|
output/
|
||||||
|
test/core/modules/test_outputs
|
||||||
|
test/core/modules/test_outputs/*
|
||||||
node_modules/
|
node_modules/
|
||||||
node_modules/*
|
node_modules/*
|
||||||
|
test_outputs
|
||||||
|
/test_outputs
|
||||||
45
.npmignore
Normal file
45
.npmignore
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
todo.txt
|
||||||
|
test.js
|
||||||
|
output.txt
|
||||||
|
output/
|
||||||
|
|
||||||
|
examples/
|
||||||
|
icons/
|
||||||
|
|
||||||
|
.travis.yml
|
||||||
|
Gruntfile.js
|
||||||
|
yarn.lock
|
||||||
12
.travis.yml
12
.travis.yml
@@ -1,16 +1,22 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- '4'
|
|
||||||
- '5'
|
|
||||||
- '6'
|
- '6'
|
||||||
- '7' # Node.js 7 is most stable version
|
- '8'
|
||||||
|
- '10'
|
||||||
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
|
||||||
|
- chmod +x ./cc-test-reporter
|
||||||
|
- ./cc-test-reporter before-build
|
||||||
script:
|
script:
|
||||||
- npm test
|
- npm test
|
||||||
|
- npm run test-ui
|
||||||
- grunt build
|
- grunt build
|
||||||
|
after_script:
|
||||||
|
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
|
|||||||
114
CODE_OF_CONDUCT.md
Normal file
114
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +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, PO Box 426113, Cambridge, MA 02142_
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
@@ -10,13 +10,13 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
|
|||||||
* [README.md](https://github.com/publiclab/image-sequencer)
|
* [README.md](https://github.com/publiclab/image-sequencer)
|
||||||
* [Contributing Modules](#contributing-modules)
|
* [Contributing Modules](#contributing-modules)
|
||||||
* [Info File](#info-file)
|
* [Info File](#info-file)
|
||||||
* [Ideas](#ideas)
|
* [Ideas](#Contribution-ideas)
|
||||||
|
|
||||||
****
|
****
|
||||||
|
|
||||||
## Contribution ideas
|
## Contribution-ideas
|
||||||
|
|
||||||
See [this issue](https://github.com/publiclab/image-sequencer/issues/118) for a range of ideas for new contributions, and links to possibly helpful libraries. Also see the [new features issues list](https://github.com/publiclab/image-sequencer/labels/new-feature).
|
See [this issue](https://github.com/publiclab/image-sequencer/issues/118) for a range of ideas for new contributions and links to possibly helpful libraries, or you can solve an [existing issue](https://github.com/publiclab/image-sequencer/labels/module). Also see the [new features issues list](https://github.com/publiclab/image-sequencer/labels/new-feature).
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
|
|
||||||
@@ -175,6 +175,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 emmited when a notification has to be produced.
|
||||||
|
|
||||||
### Name and description
|
### Name and description
|
||||||
|
|
||||||
@@ -271,16 +272,20 @@ For help integrating, please open an issue.
|
|||||||
IMAGE SEQUENCER supports "meta modules" -- modules made of other modules. The syntax and structure of these meta modules is very similar to standard modules. Sequencer can also genarate meta modules dynamically with the function `createMetaModule` which can be called in the following ways
|
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
|
||||||
// stepsString is a stringified sequence
|
|
||||||
sequencer.createMetaModule(stepsString,info)
|
|
||||||
|
|
||||||
/* stepsArray is the array of objects in this format
|
/* Mapping function is a function which gets the inputs of the module as argument
|
||||||
* [
|
* and returns an array with steps mapped to their options
|
||||||
* {name: "moduleName",options: {}},
|
* See https://github.com/publiclab/image-sequencer/blob/main/src/modules/Colorbar/Module.js for example
|
||||||
* {name: "moduleName",options: {}}
|
*/
|
||||||
* ]
|
|
||||||
|
/* Module options is an object with the following keys
|
||||||
|
* infoJson: the info.json object for the module
|
||||||
|
*/
|
||||||
|
sequencer.createMetaModule(mappingFunction,moduleOptions)
|
||||||
|
|
||||||
|
/* createMetaModule returns an array of module function and info just like normal
|
||||||
|
* modules. These can also be loaded into sequencer dynamically like other modules
|
||||||
*/
|
*/
|
||||||
sequencer.createMetaModule(stepsArray,info)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A Meta module can also be contributed like a normal module with an info and a Module.js. A basic Meta module shall follow the following format
|
A Meta module can also be contributed like a normal module with an info and a Module.js. A basic Meta module shall follow the following format
|
||||||
@@ -288,12 +293,17 @@ A Meta module can also be contributed like a normal module with an info and a Mo
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// Module.js
|
// Module.js
|
||||||
module.exports = function metaModuleFun(){
|
module.exports = require('../../util/createMetaModule.js')(
|
||||||
this.expandSteps([
|
function mapFunction(options) {
|
||||||
{ 'name': 'module-name', 'options': {} },
|
|
||||||
{ 'name': 'module-name', options: {} }
|
return [
|
||||||
]);
|
{ 'name': 'module-name', 'options': {} },
|
||||||
}
|
{ 'name': 'module-name', 'options': {} },
|
||||||
|
];
|
||||||
|
}, {
|
||||||
|
infoJson: require('./info.json')
|
||||||
|
}
|
||||||
|
)[0];
|
||||||
```
|
```
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -301,7 +311,8 @@ module.exports = function metaModuleFun(){
|
|||||||
{
|
{
|
||||||
"name": "meta-moduleName",
|
"name": "meta-moduleName",
|
||||||
"description": "",
|
"description": "",
|
||||||
"length": //Integer representing number of steps in the metaModule
|
"inputs": {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -316,19 +327,22 @@ module.exports = [
|
|||||||
All of the above can also be combined together to form a single file module.
|
All of the above can also be combined together to form a single file module.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
||||||
// MetaModule.js
|
// MetaModule.js
|
||||||
module.export = [
|
module.exports =
|
||||||
function (){
|
sequencer.createMetaModule(
|
||||||
this.expandSteps([
|
function mapFunction(options) {
|
||||||
{ 'name': 'module-name', 'options': {} },
|
|
||||||
{ 'name': 'module-name', options: {} }
|
return [
|
||||||
]);
|
{ 'name': 'module-name', 'options': {} },
|
||||||
},
|
{ 'name': 'module-name', 'options': {} },
|
||||||
{
|
];
|
||||||
"name": "meta-moduleName",
|
}, {
|
||||||
"description": "",
|
infoJson: {
|
||||||
"length": //Integer representing number of steps in the metaModule
|
"name": "meta-moduleName",
|
||||||
}
|
"description": "",
|
||||||
]
|
"inputs": {
|
||||||
```
|
}
|
||||||
The length is absolutely required for a meta-module, since sequencer is optimized to re-run minimum number of steps when a step is added in the UI which is 1 in the case of normal modules, if the added step is a meta-module the length of the sequence governs the number of steps to re-run.
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
21
Gruntfile.js
21
Gruntfile.js
@@ -15,22 +15,30 @@ module.exports = function(grunt) {
|
|||||||
livereload: true
|
livereload: true
|
||||||
},
|
},
|
||||||
source: {
|
source: {
|
||||||
files: ["src/**/*", "Gruntfile.js"],
|
files: ["src/**/*", "Gruntfile.js", "examples/lib/*","examples/demo.js"],
|
||||||
tasks: ["build:js"]
|
tasks: ["browserify"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
browserify: {
|
browserify: {
|
||||||
dist: {
|
core: {
|
||||||
src: ["src/ImageSequencer.js"],
|
src: ["src/ImageSequencer.js"],
|
||||||
dest: "dist/image-sequencer.js"
|
dest: "dist/image-sequencer.js"
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
src: ["examples/demo.js"],
|
||||||
|
dest: "dist/image-sequencer-ui.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
uglify: {
|
uglify: {
|
||||||
dist: {
|
core: {
|
||||||
src: ["./dist/image-sequencer.js"],
|
src: ["./dist/image-sequencer.js"],
|
||||||
dest: "./dist/image-sequencer.min.js"
|
dest: "./dist/image-sequencer.min.js"
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
src: ['dist/image-sequencer-ui.js'],
|
||||||
|
dest: 'dist/image-sequencer-ui.min.js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
browserSync: {
|
browserSync: {
|
||||||
@@ -45,6 +53,7 @@ module.exports = function(grunt) {
|
|||||||
|
|
||||||
/* 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:dist", "uglify:dist"]);
|
grunt.registerTask("build", ["browserify", "uglify"]);
|
||||||
grunt.registerTask("serve", ["browserify:dist", "uglify:dist", "browserSync", "watch"]);
|
grunt.registerTask("serve", ["browserify", "browserSync", "watch"]);
|
||||||
|
grunt.registerTask("compile", ["browserify"]);
|
||||||
};
|
};
|
||||||
|
|||||||
311
README.md
311
README.md
@@ -5,22 +5,26 @@ Image Sequencer
|
|||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
Image Sequencer is different from other image processing systems in that it's _non-destructive_: instead of modifying the original image, it **creates a new image at each step in a sequence**. This is because it:
|
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:
|
||||||
|
|
||||||
* produces a legible trail of operations, to "show your work" for evidential, educational, or reproducibility reasons
|
* produces a legible trail of operations, to "show your work" for evidential, educational, or reproducibility reasons
|
||||||
* makes the creation of new tools or "modules" simpler -- each must accept an input image, and produce an output image
|
* makes the creation of new tools or "modules" simpler -- each must accept an input image, and produce an output image
|
||||||
* allows many images to be run through the same sequence of steps
|
* allows many images to run through the same sequence of steps
|
||||||
* works identically in the browser, on Node.js, and on the commandline
|
* works identically in the browser, on Node.js, and on the command line
|
||||||
|
|
||||||
|
The following diagrams attempt to explain how the applications various components interconnect:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
It is also for prototyping some other related ideas:
|
It also for prototypes other related ideas:
|
||||||
|
|
||||||
* filter-like image processing -- applying a transform to any image from a given source, like a proxy. I.e. every image tile of a satellite imagery web map
|
* filter-like image processing -- apply a transform to an image from a given source, like a proxy. I.e. [every image tile of a satellite imagery web map](https://publiclab.org/notes/warren/05-10-2018/prototype-filter-map-tiles-in-real-time-in-a-browser-with-imagesequencer-ndvi-landsat)
|
||||||
* test-based image processing -- the ability to create a sequence of steps that do the same task as some other image processing tool, provable with example before/after images to compare with
|
* test-based image processing -- the ability to create a sequence of steps that do the same task as other image processing tools, provable with example before/after images to compare with
|
||||||
* logging of each step to produce an evidentiary record of modifications to an original image
|
* logging each step -- to produce an evidentiary record of modifications to an original image
|
||||||
* cascading changes -- change an earlier step's settings, and see those changes affect later steps
|
* cascading changes -- change an earlier step's settings, and see those changes affect later steps
|
||||||
* "small modules"-based extensibility: see [Contributing](https://github.com/publiclab/image-sequencer/blob/master/CONTRIBUTING.md)
|
* "small modules" -- based extensibility: see [Contributing](https://github.com/publiclab/image-sequencer/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -45,7 +49,20 @@ A diagram of this running 5 steps on a single sample image may help explain how
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
This library works in the browser, in Node, and on the commandline (CLI), which we think is great. You can start a local environement to test the UI with `npm start`
|
This library conveniently works in the browser, in Node, and on the command line (CLI).
|
||||||
|
|
||||||
|
### Unix based platforms
|
||||||
|
You can set up a local environment to test the UI with `sudo npm run setup` followed by `npm start`
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
Our npm scripts do not support windows shells, please run the following snippet in PowerShell.
|
||||||
|
```powershell
|
||||||
|
npm i ; npm i -g grunt grunt-cli ; grunt serve
|
||||||
|
```
|
||||||
|
In case of a port conflict please run the following
|
||||||
|
```powershell
|
||||||
|
npm i -g http-server ; http-server -p 3000
|
||||||
|
```
|
||||||
|
|
||||||
### Browser
|
### Browser
|
||||||
|
|
||||||
@@ -54,7 +71,7 @@ Just include [image-sequencer.js](https://publiclab.github.io/image-sequencer/di
|
|||||||
### Node (via NPM)
|
### Node (via NPM)
|
||||||
|
|
||||||
(You must have NPM for this)
|
(You must have NPM for this)
|
||||||
Add `image-sequencer` to your list of dependancies and run `$ npm install`
|
Add `image-sequencer` to your list of dependencies and run `$ npm install`
|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
|
|
||||||
@@ -71,22 +88,30 @@ $ npm install image-sequencer -g
|
|||||||
```
|
```
|
||||||
$ npm run debug invert
|
$ npm run debug invert
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Usage
|
## Quick Usage
|
||||||
|
|
||||||
|
### Initializing the Sequencer
|
||||||
|
|
||||||
|
The Image Sequencer Library exports a function ImageSequencer which initializes a sequencer.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var sequencer = ImageSequencer();
|
||||||
|
```
|
||||||
|
|
||||||
Image Sequencer can be used to run modules on an HTML Image Element using the
|
Image Sequencer can be used to run modules on an HTML Image Element using the
|
||||||
`replaceImage` method. The method accepts two parameters - `selector` and `steps`.
|
`replaceImage` method, which accepts two parameters - `selector` and `steps`.
|
||||||
`selector` is a CSS selector. If it matches multiple images, all images will be
|
`selector` is a CSS selector. If it matches multiple images, all images will be
|
||||||
modified. `steps` may be the name of a module or array of names of modules.
|
modified. `steps` may be the name of a module or array of names of modules.
|
||||||
|
|
||||||
Note: Browser CORS Restrictions apply. Some browsers may not allow local images
|
Note: Browser CORS Restrictions apply. Some browsers may not allow local images
|
||||||
form other folders, and throw a Security Error instead.
|
from other folders, and throw a Security Error instead.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.replaceImage(selector,steps,optional_options);
|
sequencer.replaceImage(selector,steps,optional_options);
|
||||||
```
|
```
|
||||||
|
|
||||||
`optional_options` allows to pass additional arguments to the module itself.
|
`optional_options` allows passing additional arguments to the module itself.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@@ -95,6 +120,14 @@ For example:
|
|||||||
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
sequencer.replaceImage('#photo',['invert','ndvi-red']);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Data URL usage
|
||||||
|
|
||||||
|
Since Image Sequencer uses data-urls, you can initiate a new sequence by providing an image in the [data URL format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs), which will import into the demo and run:
|
||||||
|
|
||||||
|
[Try this example link with a very small Data URL](http://sequencer.publiclab.org/examples/#src=data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z&steps=invert{})
|
||||||
|
|
||||||
|
To produce a data URL from an HTML image, see [this nice blog post with example code](https://davidwalsh.name/convert-image-data-uri-javascript).
|
||||||
|
|
||||||
## CLI Usage
|
## CLI Usage
|
||||||
|
|
||||||
Image Sequencer also provides a CLI for applying operations to local files. The CLI takes the following arguments:
|
Image Sequencer also provides a CLI for applying operations to local files. The CLI takes the following arguments:
|
||||||
@@ -123,12 +156,12 @@ The CLI also can take multiple steps at once, like so:
|
|||||||
|
|
||||||
But for this, double quotes must wrap the space-separated steps.
|
But for this, double quotes must wrap the space-separated steps.
|
||||||
|
|
||||||
Options for the steps can be passed in one line as json in the details option like
|
Options for the steps can be passed in one line as JSON in the details option like
|
||||||
```
|
```
|
||||||
$ ./index.js -i [PATH] -s "brightness" -c '{"brightness":50}'
|
$ ./index.js -i [PATH] -s "brightness" -c '{"brightness":50}'
|
||||||
|
|
||||||
```
|
```
|
||||||
Or the values can be given through terminal prompt like
|
Or the values can be given through the terminal prompt like
|
||||||
|
|
||||||
<img width="1436" alt="screen shot 2018-02-14 at 5 18 50 pm" src="https://user-images.githubusercontent.com/25617855/36202790-3c6e8204-11ab-11e8-9e17-7f3387ab0158.png">
|
<img width="1436" alt="screen shot 2018-02-14 at 5 18 50 pm" src="https://user-images.githubusercontent.com/25617855/36202790-3c6e8204-11ab-11e8-9e17-7f3387ab0158.png">
|
||||||
|
|
||||||
@@ -137,7 +170,7 @@ Or the values can be given through terminal prompt like
|
|||||||
sequencer --save-sequence "invert-colormap invert(),colormap()"
|
sequencer --save-sequence "invert-colormap invert(),colormap()"
|
||||||
```
|
```
|
||||||
|
|
||||||
`install-module` option can be used to install new modules from npm. You can register this module in your sequencer with a custom name space sepated with the npm package name. Below is an example for the `image-sequencer-invert` module.
|
`install-module` option can be used to install new modules from npm. You can register this module in your sequencer with a custom namespace separated with the npm package name. Below is an example of the `image-sequencer-invert` module.
|
||||||
```shell
|
```shell
|
||||||
sequencer --install-module "invert image-sequencer-invert"
|
sequencer --install-module "invert image-sequencer-invert"
|
||||||
```
|
```
|
||||||
@@ -175,7 +208,7 @@ CORS Restrictions). To sum up, these are accepted:
|
|||||||
* DataURLs
|
* DataURLs
|
||||||
|
|
||||||
return value: **none** (A callback should be used to ensure the image gets loaded)
|
return value: **none** (A callback should be used to ensure the image gets loaded)
|
||||||
The callback is called within the scope of a the sequencer. For example:
|
The callback is called within the scope of a sequencer. For example:
|
||||||
(addSteps is defined later)
|
(addSteps is defined later)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -189,7 +222,7 @@ In this case, only `'SRC'`.
|
|||||||
|
|
||||||
### Adding steps to the image
|
### Adding steps to the image
|
||||||
|
|
||||||
The `addSteps` method is used to add steps on the image. One or more steps can
|
The `addSteps` method is used to add steps to the image. One or more steps can
|
||||||
be added at a time. Each step is called a module.
|
be added at a time. Each step is called a module.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -197,11 +230,11 @@ sequencer.addSteps(modules, optional_options);
|
|||||||
```
|
```
|
||||||
|
|
||||||
If only one module is to be added, `modules` is simply the name of the module.
|
If only one module is to be added, `modules` is simply the name of the module.
|
||||||
If multiple images are to be added, `modules` is an array of the names of modules
|
If multiple images are to be added, `modules` is an array, which holds the names of modules
|
||||||
which are to be added, in that particular order.
|
to be added, in that particular order.
|
||||||
|
|
||||||
optional_otions is just additional parameters, 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. It's an optional parameter.
|
want to provide to the modules.
|
||||||
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
return value: **`sequencer`** (To allow method chaining)
|
||||||
|
|
||||||
@@ -218,7 +251,7 @@ sequencer.run();
|
|||||||
Sequencer can be run with a custom config object
|
Sequencer can be run with a custom config object
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// The config object enables custom progress bars in node environment and
|
// The config object enables custom progress bars in a node environment and
|
||||||
// ability to run the sequencer from a particular index(of the steps array)
|
// ability to run the sequencer from a particular index(of the steps array)
|
||||||
|
|
||||||
sequencer.run(config);
|
sequencer.run(config);
|
||||||
@@ -242,7 +275,7 @@ sequencer.run(function callback(out){
|
|||||||
// "out" is the DataURL of the final image.
|
// "out" is the DataURL of the final image.
|
||||||
});
|
});
|
||||||
sequencer.run(config,function callback(out){
|
sequencer.run(config,function callback(out){
|
||||||
// the callback is supported with all types of invocations
|
// the callback is supported by all types of invocations
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -252,7 +285,7 @@ return value: **`sequencer`** (To allow method chaining)
|
|||||||
### Removing a step from the sequencer
|
### Removing a step from the sequencer
|
||||||
|
|
||||||
The `removeSteps` method is used to remove unwanted steps from the sequencer.
|
The `removeSteps` method is used to remove unwanted steps from the sequencer.
|
||||||
It accepts the index of the step as an input, or an array of the unwanted indices
|
It accepts the index of the step as an input or an array of the unwanted indices,
|
||||||
if there are more than one.
|
if there are more than one.
|
||||||
|
|
||||||
For example, if the modules ['ndvi-red','crop','invert'] were added in this order,
|
For example, if the modules ['ndvi-red','crop','invert'] were added in this order,
|
||||||
@@ -272,14 +305,14 @@ return value: **`sequencer`** (To allow method chaining)
|
|||||||
### Inserting a step in between the sequencer
|
### Inserting a step in between the sequencer
|
||||||
|
|
||||||
The `insertSteps` method can be used to insert one or more steps at a given index
|
The `insertSteps` method can be used to insert one or more steps at a given index
|
||||||
in the sequencer. It accepts the index where the module is to be inserted, name of
|
in the sequencer. It accepts the index where the module is to be inserted, the name of
|
||||||
the module, and an optional options parameter. `index` is the index of the inserted
|
the module, and an optional options parameter. `index` is the index of the inserted
|
||||||
step. Only one step can be inserted at a time. `optional_options` plays the same
|
step. Only one step can be inserted at a time. `optional_options` plays the same
|
||||||
role it played in `addSteps`.
|
role it played in `addSteps`.
|
||||||
|
|
||||||
Indexes can be negative. Negative sign with an index means that counting will be
|
Indexes can be negative. Negative sign with an index means that counting will be
|
||||||
done in reverse order. If the index is out of bounds, the counting will wrap in
|
done in reverse order. If the index is out of bounds, the counting will wrap in
|
||||||
the original direction of counting. So, an `index` of -1 means that the module is
|
the original direction of counting. So, an `index` of -1 means the module is
|
||||||
inserted at the end.
|
inserted at the end.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -290,7 +323,7 @@ return value: **`sequencer`** (To allow method chaining)
|
|||||||
|
|
||||||
### Importing an independent module
|
### Importing an independent module
|
||||||
|
|
||||||
The `loadNewModule` method can be used to import a new module inside sequencer. Modules can be downloaded via npm, yarn or cdn and are imported with a custom name. If you wish to load a new module at runtime, it will need to avoid using `require()` -- unless it is compiled with a system like browserify or webpack.
|
The `loadNewModule` method can be used to import a new module inside the sequencer. Modules can be downloaded via npm, yarn or CDN and are imported with a custom name. If you wish to load a new module at runtime, it will need to avoid using `require()` -- unless it is compiled with a system like browserify or webpack.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const module = require('sequencer-moduleName')
|
const module = require('sequencer-moduleName')
|
||||||
@@ -305,12 +338,11 @@ Methods can be chained on the Image Sequencer:
|
|||||||
* run() can not be in the middle of the chain.
|
* run() can not be in the middle of the chain.
|
||||||
* If the chain starts with loadImage() or loadImages(), the following methods are
|
* If the chain starts with loadImage() or loadImages(), the following methods are
|
||||||
applied only to the newly loaded images.
|
applied only to the newly loaded images.
|
||||||
* If no name is provided to the image, a name will be generated for it. The name will
|
|
||||||
be of the form "image<number>". For ex: "image1", "image2", "image3", etc.
|
|
||||||
|
|
||||||
Valid Chains:
|
Valid Chains:
|
||||||
```js
|
```js
|
||||||
sequencer.loadImage('red',function(){
|
sequencer.loadImage(function(){
|
||||||
this.addSteps('invert').run(function(out){
|
this.addSteps('invert').run(function(out){
|
||||||
//do something with ouptut.
|
//do something with ouptut.
|
||||||
});
|
});
|
||||||
@@ -325,156 +357,20 @@ sequencer.addSteps('invert').run().addSteps('ndvi-red');
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Multiple Images
|
|
||||||
Image Sequencer is capable of handling multiple images at once.
|
|
||||||
|
|
||||||
### Initializing a sequencer with multiple images.
|
## Fetching current steps
|
||||||
This is just like before.
|
|
||||||
```js
|
|
||||||
var sequencer = ImageSequencer();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loading Multiple Images into the Sequencer
|
The `getSteps` method can be used to get the array of current steps in `this` instance of sequencer.For example
|
||||||
|
|
||||||
Multiple images can be loaded by the method `loadImages`. Everything is the same,
|
|
||||||
except that now, a unique identification called `image_name` has to be provided
|
|
||||||
with each image. This is a string literal.
|
|
||||||
|
|
||||||
* 3/2 parameters :
|
|
||||||
```js
|
|
||||||
sequencer.loadImages(image_name,
|
|
||||||
image_src,optional_callback);
|
|
||||||
```
|
|
||||||
* 1/2 parameters (JSON) :
|
|
||||||
```js
|
|
||||||
sequencer.loadImages({
|
|
||||||
images: {
|
|
||||||
image1_name: image_src,
|
|
||||||
image2_name: image_src,
|
|
||||||
...
|
|
||||||
},
|
|
||||||
callback: optional_callback
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
return value: **none**
|
|
||||||
|
|
||||||
|
|
||||||
### Adding Steps on Multiple Images
|
|
||||||
|
|
||||||
The same method `addSteps` is used for this. There's just a slight obvious change
|
|
||||||
in the syntax that the image name has to be supplied too. `image_name` as well as
|
|
||||||
`module_name` in the following examples can be either strings or arrays of strings.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
sequencer.addSteps(image_name,module_name,optional_options);
|
sequencer.getSteps()
|
||||||
```
|
```
|
||||||
|
|
||||||
If no Image Name is specified, the module is added to **all** images.
|
returns an array of steps associated with the current sequencer.
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.addSteps(module_name,optional_options);
|
|
||||||
```
|
|
||||||
|
|
||||||
All this can be passed in as JSON:
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.addSteps({
|
|
||||||
image1_name: {name: module_name, o: optional_options},
|
|
||||||
image2_name: {name: module_name, o: optional_options},
|
|
||||||
...
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
|
||||||
|
|
||||||
|
|
||||||
### Running a Sequencer with multiple images
|
|
||||||
|
|
||||||
The same `run` method can be used with a slight change in syntax.
|
|
||||||
The `run` method accepts parameters `image` and `from`. `from` is the index from
|
|
||||||
where the function starts generating output. By default, it will run across all
|
|
||||||
the steps. (from = 1) If no image is specified, the sequencer will be run over **all
|
|
||||||
the images**. `image_name` may be an array of image names.
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.run(); //All images from first step
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.run(image_name,from); //Image 'image' from 'from'
|
|
||||||
```
|
|
||||||
|
|
||||||
The `run` method also accepts an optional callback just like before:
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.run(image_name,from,function(out){
|
|
||||||
// This gets called back.
|
|
||||||
// "out" is the DataURL of final image.
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
JSON Input is also acceptable.
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.run({
|
|
||||||
image1_name: from,
|
|
||||||
image2_name: from,
|
|
||||||
...
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
|
||||||
|
|
||||||
|
|
||||||
### Removing Steps from an Image
|
|
||||||
|
|
||||||
Similarly, `removeSteps` can also accept an `image_name` parameter. Either, both,
|
|
||||||
or none of `image_name` and `steps` them may be an array. JSON input is also acceptable.
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.removeSteps("image_name",[steps]);
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.removeSteps("image_name",step);
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.removeSteps({
|
|
||||||
image1_name: [steps],
|
|
||||||
image2_name: [steps],
|
|
||||||
...
|
|
||||||
});
|
|
||||||
```
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
|
||||||
|
|
||||||
|
|
||||||
### Inserting steps on an image
|
|
||||||
|
|
||||||
The `insertSteps` method can also accept an `image_name` parameter. `image_name`
|
|
||||||
may be an array. Everything else remains the same. JSON Inout is acceptable too.
|
|
||||||
|
|
||||||
```js
|
|
||||||
sequencer.insertSteps("image",index,"module_name",o);
|
|
||||||
```
|
|
||||||
```js
|
|
||||||
sequencer.insertSteps([image],index,"module_name",o);
|
|
||||||
```
|
|
||||||
```js
|
|
||||||
sequencer.insertSteps({
|
|
||||||
image1: [
|
|
||||||
{index:index1, name: module_name1, o:optional_options1},
|
|
||||||
{index:index2, name: module_name2, o:optional_options2},
|
|
||||||
...
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
return value: **`sequencer`** (To allow method chaining)
|
|
||||||
|
|
||||||
## Saving Sequences
|
## Saving Sequences
|
||||||
|
|
||||||
IMAGE SEQUENCER supports saving a sequence of modules and their associated settings in a simple string syntax. These sequences can be saved in the local storage inside the browser and inside a json file in node.js. sequences can be saved in node context using the CLI option
|
IMAGE SEQUENCER supports saving a sequence of modules and their associated settings in a simple string syntax. These sequences can be saved in the local storage of the browser and inside a JSON file in node.js. sequences can be saved in node context using the CLI option
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
--save-sequence "name stringified-sequence"
|
--save-sequence "name stringified-sequence"
|
||||||
@@ -495,7 +391,7 @@ Image sequencer supports stringifying a sequence which is appended to the url an
|
|||||||
channel{channel:green},invert{}
|
channel{channel:green},invert{}
|
||||||
```
|
```
|
||||||
|
|
||||||
Sequencer also supports use of `()` in place of `{}` for backwards compatibility with older links.(This syntax is deprecated and should be avoided as far as possible)
|
Sequencer also supports the use of `()` in place of `{}` for backward compatibility with older links. (This syntax is deprecated and should be avoided as far as possible)
|
||||||
```
|
```
|
||||||
channel(channel:green),invert()
|
channel(channel:green),invert()
|
||||||
```
|
```
|
||||||
@@ -514,6 +410,29 @@ Image Sequencer can also generate a string for usage in the CLI for the current
|
|||||||
sequencer.toCliString()
|
sequencer.toCliString()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Importing steps using JSON array
|
||||||
|
|
||||||
|
Image sequencer provides the following core API function to import the given sequence of JSON steps into sequencer.
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.importJSON(obj)
|
||||||
|
```
|
||||||
|
It can be implemented the following way for example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.importJSON([
|
||||||
|
{ name: 'blur', options: {} }
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
where name is the name of step to be added, options object can be the one used to provide various params to the sequencer which can customise the default ones.
|
||||||
|
|
||||||
|
To see this in action, please refer to line # 51 of the following:
|
||||||
|
|
||||||
|
[test/core/modules/import-export.js](https://github.com/publiclab/image-sequencer/blob/main/test/core/modules/import-export.js)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Creating a User Interface
|
## Creating a User Interface
|
||||||
|
|
||||||
Image Sequencer provides the following events which can be used to generate a UI:
|
Image Sequencer provides the following events which can be used to generate a UI:
|
||||||
@@ -528,6 +447,10 @@ for a module. This can be used, for instance, to update the DIV with the new ima
|
|||||||
and remove the loading GIF generated above.
|
and remove the loading GIF generated above.
|
||||||
* `onRemove` : This event is triggered when a module is removed. This can be used,
|
* `onRemove` : This event is triggered when a module is removed. This can be used,
|
||||||
for instance, to remove the DIV generated above.
|
for instance, to remove the DIV generated above.
|
||||||
|
* `notify` : This event is triggered whenever we need to shoot a notification to the
|
||||||
|
user-interface.For example when the step is not available, we can shoot a notification,
|
||||||
|
by sending appropriate message.For HTML UI it adds a DOM node to the browser, for CLI
|
||||||
|
and node , it logs the notification output to the respective console.
|
||||||
|
|
||||||
How to define these functions:
|
How to define these functions:
|
||||||
|
|
||||||
@@ -536,7 +459,8 @@ sequencer.setUI({
|
|||||||
onSetup: function(step) {},
|
onSetup: function(step) {},
|
||||||
onDraw: function(step) {},
|
onDraw: function(step) {},
|
||||||
onComplete: function(step) {},
|
onComplete: function(step) {},
|
||||||
onRemove: function(step) {}
|
onRemove: function(step) {},
|
||||||
|
notify: function(msg,id) {}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -579,10 +503,37 @@ sequencer.setUI({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: `identity.imageName` is the "name" of that particular image. This name can
|
## Using multiple images on same sequencer:
|
||||||
be specified while loading the image via `sequencer.loadImage("name","SRC")`. If
|
|
||||||
not specified, the name of a loaded image defaults to a name like "image1",
|
|
||||||
"image2", et cetra.
|
|
||||||
|
|
||||||
Details of all modules can be sought using `sequencer.modulesInfo()`.
|
Image Sequencer object supports one imageURL at a time.
|
||||||
|
|
||||||
|
Adding a seccond image to same sequencer will result to adding same set of steps added to prior image and flushing out the previous one.
|
||||||
|
|
||||||
|
```js
|
||||||
|
s1 = new ImageSequencer(...);
|
||||||
|
s1.loadImage(url1);
|
||||||
|
s1.addSteps('blur');
|
||||||
|
s1.run();
|
||||||
|
s1.addImage(url2);
|
||||||
|
s1.run();
|
||||||
|
```
|
||||||
|
However if we want to use more than one image, we can either initialize a sequencer for each image like:
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer1 = new ImageSequencer(...);
|
||||||
|
sequencer1.loadImage(...);
|
||||||
|
sequencer1.addSteps(steps);
|
||||||
|
sequencer1.run();
|
||||||
|
|
||||||
|
sequencer2 = new ImageSequencer(...);
|
||||||
|
sequencer2.loadImage(...);
|
||||||
|
sequencer2.addSteps(steps);
|
||||||
|
sequencer2.run();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note**: Details of all modules can be sought using `sequencer.modulesInfo()`.
|
||||||
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.
|
||||||
|
|||||||
18085
dist/image-sequencer-ui.js
vendored
Normal file
18085
dist/image-sequencer-ui.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
dist/image-sequencer-ui.min.js
vendored
Normal file
1
dist/image-sequencer-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
51891
dist/image-sequencer.js
vendored
51891
dist/image-sequencer.js
vendored
File diff suppressed because one or more lines are too long
2
dist/image-sequencer.min.js
vendored
2
dist/image-sequencer.min.js
vendored
File diff suppressed because one or more lines are too long
523
docs/MODULES.md
523
docs/MODULES.md
@@ -1,7 +1,46 @@
|
|||||||
Documentation of various Modules
|
Documentation of various Modules
|
||||||
===
|
===
|
||||||
|
|
||||||
## Crop Module (crop)
|
List of Module Documentations
|
||||||
|
|
||||||
|
1. [Crop](#crop-module)
|
||||||
|
2. [Segmented-Colormap](#segmented-colormap-module)
|
||||||
|
3. [FisheyeGl](#fisheyeGl-module)
|
||||||
|
4. [Add QR](#Add-QR-module)
|
||||||
|
5. [Average](#average-module)
|
||||||
|
6. [Blend](#blend-module)
|
||||||
|
7. [Blur](#blur-module)
|
||||||
|
8. [Brightness](#brightness-module)
|
||||||
|
9. [Channel](#channel-module)
|
||||||
|
10. [Colorbar](#colorbar-module)
|
||||||
|
11. [Colormap](#colormap-module)
|
||||||
|
12. [Contrast](#contrast-module)
|
||||||
|
13. [Convolution](#convolution-module)
|
||||||
|
14. [DecodeQr](#decodeQr-module)
|
||||||
|
15. [Dither](#dither-module)
|
||||||
|
16. [DrawRectangle](#draw-rectangle-module)
|
||||||
|
17. [Dynamic](#dynamic-module)
|
||||||
|
18. [Edge-Detect](#edge-detect-module)
|
||||||
|
19. [FlipImage](#flipimage-module)
|
||||||
|
20. [Gamma-Correction](#gamma-correction-module)
|
||||||
|
21. [Gradient](#gradient-module)
|
||||||
|
22. [Histogram](#histogram-module)
|
||||||
|
23. [Import-image](#import-image-module)
|
||||||
|
24. [Invert](#invert-module)
|
||||||
|
25. [Ndvi](#ndvi-module)
|
||||||
|
26. [Ndvi-Colormap](#ndvi-colormap-module)
|
||||||
|
27. [Overlay](#overlay-module)
|
||||||
|
28. [PaintBucket](#paint-bucket-module)
|
||||||
|
29. [Resize](#resize-module)
|
||||||
|
30. [ReplaceColor](#replacecolor-module)
|
||||||
|
31. [Rotate](#rotate-module)
|
||||||
|
32. [Saturation](#saturation-module)
|
||||||
|
33. [Threshold](#threshold)
|
||||||
|
34. [Tint](#tint)
|
||||||
|
35. [WhiteBalance](#white-balance)
|
||||||
|
|
||||||
|
|
||||||
|
## crop-module
|
||||||
|
|
||||||
This module is used to crop an image.
|
This module is used to crop an image.
|
||||||
|
|
||||||
@@ -24,7 +63,7 @@ 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
|
||||||
|
|
||||||
|
|
||||||
## Segmented Colormap Module (segmented-colormap)
|
## segmented-colormap-module
|
||||||
|
|
||||||
This module is used to map the pixels of the image to a segmented colormap.
|
This module is used to map the pixels of the image to a segmented colormap.
|
||||||
|
|
||||||
@@ -48,7 +87,7 @@ where `options` is an object with the property `colormap`. `options.colormap` ca
|
|||||||
|
|
||||||
* A custom array.
|
* A custom array.
|
||||||
|
|
||||||
## FisheyeGl (fisheye-gl)
|
## fisheyeGl-module
|
||||||
|
|
||||||
This module is used for correcting Fisheye or Lens Distortion
|
This module is used for correcting Fisheye or Lens Distortion
|
||||||
|
|
||||||
@@ -68,3 +107,481 @@ where `options` is an object with the following properties:
|
|||||||
* scale : The ratio to which the original image is to be scaled (0 to 20; default 1.5)
|
* scale : The ratio to which the original image is to be scaled (0 to 20; default 1.5)
|
||||||
* x : Field of View x (0 to 2; default 1)
|
* 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
|
||||||
|
|
||||||
|
This module is used for flipping the image on the selected axis.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('flip-image',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* Axis : select the required axis (default : vertical)
|
||||||
|
|
||||||
|
|
||||||
|
## gamma-correction-module
|
||||||
|
|
||||||
|
This module is used for applying gamma correction.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('gamma-correction',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* adjustment : Inverse of actual gamma factor (default 0.2)
|
||||||
|
|
||||||
|
## gradient-module
|
||||||
|
|
||||||
|
This module is used for finding gradient of the image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('gradient',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
## histogram-module
|
||||||
|
|
||||||
|
This module is used for calculating histogram of the image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('histogram',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* gradient : boolean value used to toggle gradient along x-axis (true or false; default true)
|
||||||
|
|
||||||
|
## import-image-module
|
||||||
|
|
||||||
|
This module is used for importing a new image and replacing the original with it.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('import-image',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* url : url of the new image (local image url or data url;default : "./images/monarch.png")
|
||||||
|
|
||||||
|
## invert-module
|
||||||
|
|
||||||
|
This module is used for inverting the image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('invert',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
## ndvi-module
|
||||||
|
|
||||||
|
This module is used for applying ndvi technique to the image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('ndvi',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* filter : filter for NDVI (blue or red; default red)
|
||||||
|
|
||||||
|
## ndvi-colormap-module
|
||||||
|
|
||||||
|
This module is used for demonstrating ndvi and colormap properties consecutively.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('ndvi-colormap',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
## overlay-module
|
||||||
|
|
||||||
|
This module is used for overlaying an Image over another .
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('overlay',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* x : X-position of the image on which the new image is overlayed (default 0)
|
||||||
|
* y : Y-position of the image on which the new image is overlayed (default 0)
|
||||||
|
* offset : offset to the step on which the output of the last step is overlayed (default -2)
|
||||||
|
|
||||||
|
## paint-bucket-module
|
||||||
|
|
||||||
|
This module fills any polygonal shape with the specified color in pixels.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('paint-bucket',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* startingX : it is the value of the starting x-cordinate (default 10)
|
||||||
|
* startingY : it is the value of the starting y-cordinate (default 10)
|
||||||
|
* fillColor : they are four spaced seperated numbers representing the RGBA values of fill-color (default "100 100 100 255")
|
||||||
|
* tolerance : it is the % tolerance (default 10)
|
||||||
|
|
||||||
|
## resize-module
|
||||||
|
|
||||||
|
This module is used for resizing an image.
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
This module is used in replacing the color with grey or any desired color.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('replace-color',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
where `options` is an object with the following properties:
|
||||||
|
* replaceMethod : replaces with the desired color (default greyscale)
|
||||||
|
* replaceColor : three space separated numbers representing the RGB values of color to be filled (default "0 0 255")
|
||||||
|
* color : three space separated numbers representing the RGB values of color to be replaced (default "228 86 81")
|
||||||
|
* tolerance : it is the % tolerance (default 50)
|
||||||
|
|
||||||
|
## rotate-module
|
||||||
|
|
||||||
|
This module is used for rotating an image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('rotate',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* rotate : angular value for rotation in degrees (between 0 and 360; default 0)
|
||||||
|
|
||||||
|
## saturation-module
|
||||||
|
|
||||||
|
This module is used for changing the saturation of the image.
|
||||||
|
#### Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('saturation',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* saturation : saturation for the new image (between 0 and 2; default 0)
|
||||||
|
|
||||||
|
## Threshold
|
||||||
|
|
||||||
|
Thresholding is used to create binary images.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('threshold',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* threshold : it allows to select the types of thresholding (default "manual thresholding")
|
||||||
|
* input : it allows to select the range of thresholding value (default 120)
|
||||||
|
|
||||||
|
|
||||||
|
## Tint
|
||||||
|
|
||||||
|
It adds color tint to an image
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('tint',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* color : RGB values seperated by a space (default "0 0 255")
|
||||||
|
* factor : amount of tint (default 0.5)
|
||||||
|
|
||||||
|
|
||||||
|
## White Balance
|
||||||
|
|
||||||
|
This Change the colour balance of the image by adjusting the colour temperature.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
sequencer.loadImage('PATH')
|
||||||
|
.addSteps('white-balance',options)
|
||||||
|
.run()
|
||||||
|
```
|
||||||
|
where `options` is an object with the following property:
|
||||||
|
* temperature : temperature between 0 - 40,000 kelvin (default 6000)
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,30 @@ h1 {
|
|||||||
color: #445;
|
color: #445;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center-align {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.nomargin {
|
.nomargin {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dropzone {
|
.form-control[type="range"] {
|
||||||
|
padding: 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropzone {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
margin: 0 20% 30px;
|
margin: 0 20% 30px;
|
||||||
border: 4px dashed #ccc;
|
border: 4px dashed #ccc;
|
||||||
@@ -44,7 +59,7 @@ h1 {
|
|||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dropzone input {
|
.dropzone input {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +100,20 @@ h1 {
|
|||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.load-spin{
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
#addStep {
|
#addStep {
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#add-step-btn{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#addStep .labels {
|
#addStep .labels {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
@@ -108,6 +132,133 @@ h1 {
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
#save-seq {
|
#save-seq {
|
||||||
|
display: block;
|
||||||
|
margin: 0px 10px 0px 0px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#gif {
|
||||||
|
display: block;
|
||||||
|
margin: 0px 0px 0px 10px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
#dwnld {
|
||||||
|
max-width: 500px;
|
||||||
|
margin: 20px auto;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gif_element {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#move-up {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 50px;
|
||||||
|
right: 40px;
|
||||||
|
z-index: 550;
|
||||||
|
display: none;
|
||||||
|
background:transparent;
|
||||||
|
border:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#move-up i {
|
||||||
|
font-size:60px;
|
||||||
|
opacity:0.7;
|
||||||
|
color:#BABABA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-circle{
|
||||||
|
min-width: 80px;
|
||||||
|
min-height: 80px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 6px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.42;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.radio{
|
||||||
|
cursor:pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-border {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.savesequencemsg{
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
background-color: #808b96;
|
||||||
|
padding:4px;
|
||||||
|
color:white;
|
||||||
|
border-radius:3px;
|
||||||
|
font-size:2rem;
|
||||||
|
position:fixed;
|
||||||
|
bottom:2px;
|
||||||
|
left:50%;
|
||||||
|
min-width:14rem;
|
||||||
|
text-align:center;
|
||||||
|
display:none;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetButton {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i-over {
|
||||||
|
position: absolute;
|
||||||
|
left: 15px;
|
||||||
|
top: 15px;
|
||||||
|
z-index: 2;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i-small {
|
||||||
|
left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 767px) {
|
||||||
|
.center-align {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.name-header{
|
||||||
|
text-decoration: none;
|
||||||
|
color: #445;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-column{
|
||||||
|
display:flex;
|
||||||
|
flex-direction:row;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
.step-image{
|
||||||
|
width:100%;
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
align-items:center;
|
||||||
|
}
|
||||||
|
|||||||
198
examples/demo.js
198
examples/demo.js
@@ -1,3 +1,10 @@
|
|||||||
|
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||||
|
setupCache = require('./lib/cache.js'),
|
||||||
|
intermediateHtmlStepUi = require('./lib/intermediateHtmlStepUi.js'),
|
||||||
|
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||||
|
urlHash = require('./lib/urlHash.js'),
|
||||||
|
insertPreview = require('./lib/insertPreview.js');
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
sequencer = ImageSequencer();
|
sequencer = ImageSequencer();
|
||||||
|
|
||||||
@@ -10,40 +17,207 @@ window.onload = function() {
|
|||||||
|
|
||||||
// Add modules to the addStep dropdown
|
// Add modules to the addStep dropdown
|
||||||
for (var m in modulesInfo) {
|
for (var m in modulesInfo) {
|
||||||
addStepSelect.append(
|
if (modulesInfo[m] && modulesInfo[m].name)
|
||||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
addStepSelect.append(
|
||||||
);
|
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
// Null option
|
||||||
|
addStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||||
|
addStepSelect.selectize({
|
||||||
|
sortField: 'text'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
refreshOptions();
|
refreshOptions();
|
||||||
|
|
||||||
|
$(window).on('scroll', scrollFunction);
|
||||||
|
|
||||||
|
function scrollFunction() {
|
||||||
|
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
||||||
|
|
||||||
|
$('#move-up').css({
|
||||||
|
display: shouldDisplay ? 'block' : 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function topFunction() {
|
||||||
|
$('body').animate({scrollTop: 0});
|
||||||
|
$(':root').animate({scrollTop: 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#move-up').on("click",topFunction);
|
||||||
|
|
||||||
|
|
||||||
// UI for each step:
|
// UI for each step:
|
||||||
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||||
|
|
||||||
// UI for the overall demo:
|
// UI for the overall demo:
|
||||||
var ui = DefaultHtmlSequencerUi(sequencer);
|
var ui = defaultHtmlSequencerUi(sequencer);
|
||||||
|
|
||||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||||
|
if (urlHash.getUrlHashParameter('src')) {
|
||||||
|
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
||||||
|
} else {
|
||||||
|
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resetSequence = function(){
|
||||||
|
var r=confirm("Do you want to reset the sequence?");
|
||||||
|
if (r)
|
||||||
|
window.location = "/";
|
||||||
|
}
|
||||||
|
|
||||||
$("#addStep select").on("change", ui.selectNewStepUi);
|
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||||
$("#addStep button").on("click", ui.addStepUi);
|
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||||
|
$("#resetButton").on("click",resetSequence);
|
||||||
|
|
||||||
|
//Module button radio selection
|
||||||
|
$('.radio-group .radio').on("click", function() {
|
||||||
|
$(this).parent().find('.radio').removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
newStep = $(this).attr('data-value');
|
||||||
|
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||||
|
$("#addStep select").val(newStep);
|
||||||
|
ui.selectNewStepUi();
|
||||||
|
ui.addStepUi();
|
||||||
|
$(this).removeClass('selected');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#download-btn').click(function() {
|
||||||
|
$('.step-thumbnail:last()').trigger("click");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function displayMessageOnSaveSequence(){
|
||||||
|
$(".savesequencemsg").fadeIn();
|
||||||
|
setTimeout(function() {
|
||||||
|
$(".savesequencemsg").fadeOut();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||||
$('#save-seq').click(() => {
|
$('#save-seq').click(() => {
|
||||||
sequencer.saveSequence(window.prompt("Please give a name to your sequence..."), sequencer.toString());
|
var result = window.prompt("Please give a name to your sequence... (Saved sequence will only be available in this browser).");
|
||||||
sequencer.loadModules();
|
if(result){
|
||||||
refreshOptions();
|
result = result + " (local)";
|
||||||
|
sequencer.saveSequence(result, sequencer.toString());
|
||||||
|
sequencer.loadModules();
|
||||||
|
displayMessageOnSaveSequence();
|
||||||
|
refreshOptions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var isWorkingOnGifGeneration = false;
|
||||||
|
|
||||||
|
$('.js-view-as-gif').on('click', function(event) {
|
||||||
|
// Prevent user from triggering generation multiple times
|
||||||
|
if (isWorkingOnGifGeneration) return;
|
||||||
|
|
||||||
|
isWorkingOnGifGeneration = true;
|
||||||
|
|
||||||
|
var button = event.target;
|
||||||
|
button.disabled = true;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Select all images from previous steps
|
||||||
|
var imgs = document.getElementsByClassName("step-thumbnail");
|
||||||
|
|
||||||
|
var imgSrcs = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < imgs.length; i++) {
|
||||||
|
imgSrcs.push(imgs[i].src);
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
'gifWidth': imgs[0].width,
|
||||||
|
'gifHeight': imgs[0].height,
|
||||||
|
'images': imgSrcs,
|
||||||
|
'frameDuration': 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
gifshot.createGIF(options, function(obj) {
|
||||||
|
if (!obj.error) {
|
||||||
|
// Final gif encoded with base64 format
|
||||||
|
var image = obj.image;
|
||||||
|
var animatedImage = document.createElement('img');
|
||||||
|
|
||||||
|
animatedImage.id = "gif_element";
|
||||||
|
animatedImage.src = image;
|
||||||
|
|
||||||
|
|
||||||
|
var modal = $('#js-download-gif-modal');
|
||||||
|
|
||||||
|
$("#js-download-as-gif-button").one("click", function() {
|
||||||
|
// Trigger download
|
||||||
|
download(image, "index.gif", "image/gif");
|
||||||
|
|
||||||
|
// Close modal
|
||||||
|
modal.modal('hide');
|
||||||
|
})
|
||||||
|
|
||||||
|
var gifContainer = document.getElementById("js-download-modal-gif-container");
|
||||||
|
|
||||||
|
// Clear previous results
|
||||||
|
gifContainer.innerHTML = '';
|
||||||
|
|
||||||
|
// Insert image
|
||||||
|
gifContainer.appendChild(animatedImage);
|
||||||
|
|
||||||
|
|
||||||
|
// Open modal
|
||||||
|
modal.modal();
|
||||||
|
|
||||||
|
button.disabled = false;
|
||||||
|
isWorkingOnGifGeneration = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
button.disabled = false;
|
||||||
|
isWorkingOnGifGeneration = false;
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
// 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",
|
||||||
onLoad: function onFileReaderLoad(progress) {
|
onLoad: function onFileReaderLoad(progress) {
|
||||||
var reader = progress.target;
|
var reader = progress.target;
|
||||||
var step = sequencer.images.image1.steps[0];
|
var step = sequencer.steps[0];
|
||||||
|
var util= intermediateHtmlStepUi(sequencer);
|
||||||
step.output.src = reader.result;
|
step.output.src = reader.result;
|
||||||
sequencer.run({ index: 0 });
|
sequencer.run({ index: 0 });
|
||||||
step.options.step.imgElement.src = reader.result;
|
if(typeof step.options !=="undefined")
|
||||||
|
step.options.step.imgElement.src = reader.result;
|
||||||
|
else
|
||||||
|
step.imgElement.src = reader.result;
|
||||||
|
insertPreview.updatePreviews(reader.result,'addStep');
|
||||||
|
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'insertStep');
|
||||||
|
},
|
||||||
|
onTakePhoto: function (url) {
|
||||||
|
var step = sequencer.steps[0];
|
||||||
|
step.output.src = url;
|
||||||
|
sequencer.run({ index: 0 });
|
||||||
|
if(typeof step.options !=="undefined")
|
||||||
|
step.options.step.imgElement.src = url;
|
||||||
|
else
|
||||||
|
step.imgElement.src = url;
|
||||||
|
insertPreview.updatePreviews(url,'addStep');
|
||||||
|
insertPreview.updatePreviews(sequencer.steps[0].imgElement.src,'insertStep');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
setupCache();
|
||||||
|
|
||||||
|
if (urlHash.getUrlHashParameter('src')) {
|
||||||
|
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'addStep');
|
||||||
|
} else {
|
||||||
|
insertPreview.updatePreviews("images/tulips.png",'addStep');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -7,8 +7,9 @@
|
|||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
||||||
|
<meta name="theme-color" content="#428bca">
|
||||||
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
<title>Image Sequencer</title>
|
<title>Image Sequencer</title>
|
||||||
|
|
||||||
@@ -16,30 +17,33 @@
|
|||||||
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||||
<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="lib/urlHash.js" charset="utf-8"></script>
|
<script src="../dist/image-sequencer-ui.js" charset="utf-8"></script>
|
||||||
<script src="lib/defaultHtmlStepUi.js" charset="utf-8"></script>
|
|
||||||
<script src="lib/defaultHtmlSequencerUi.js" charset="utf-8"></script>
|
|
||||||
<script src="demo.js" charset="utf-8"></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>
|
||||||
|
|
||||||
|
<!-- Download.js for large files -->
|
||||||
|
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript"/>
|
||||||
|
|
||||||
|
<script src="lib/scrollToTop.js"></script>
|
||||||
|
<script src="../node_modules/selectize/dist/js/standalone/selectize.min.js"></script>
|
||||||
</head>
|
</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 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/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="../node_modules/selectize/dist/css/selectize.default.css" rel="stylesheet">
|
||||||
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
|
||||||
<!-- for crop module: -->
|
<!-- for crop module: -->
|
||||||
<link href="../node_modules/imgareaselect/distfiles/css/imgareaselect-default.css" rel="stylesheet">
|
<link href="./selectize.default.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="demo.css">
|
<link rel="stylesheet" href="demo.css">
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<header class="text-center">
|
<header class="text-center">
|
||||||
<h1>Image Sequencer</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 image, it
|
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it
|
||||||
creates a new image at each step in a sequence.
|
creates a new image at each step in a sequence.
|
||||||
@@ -49,42 +53,173 @@
|
|||||||
Open Source
|
Open Source
|
||||||
<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> by
|
</a>
|
||||||
<a href="https://publiclab.org">Public Lab</a>
|
by <a href= "https://publiclab.org" title = "Publiclab Website"><i class = "fa fa-globe"></i> Publiclab</a>
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="dropzone">
|
<div id="dropzone" class="dropzone">
|
||||||
<p>
|
<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="">
|
<input type="file" id="fileInput" value="" accept="image/*"><br />
|
||||||
|
<button type="button" id="take-photo" class="btn btn-primary btn-block btn-lg ">Take a Photo</button>
|
||||||
|
<video id="video" width="400" height="300" style="display:none"></video>
|
||||||
|
<a href="#" id="capture" style="display:none" class="btn btn-primary btn-md">Click Picture</a>
|
||||||
|
<a href="#" id="close" style="display:none" class="btn btn-default btn-md">Close</a>
|
||||||
|
<canvas id="canvas" width="400" height="300" style="display:none"></canvas>
|
||||||
</center>
|
</center>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section id="steps" class="row"></section>
|
<section id="steps" class="row">
|
||||||
|
<div id="load-image"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
<p class = "alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules.</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
<section id="addStep" class="panel panel-primary">
|
<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="text-align:center;">
|
<div style="display:flex; justify-content:center;">
|
||||||
<select class="form-control input-lg" id="selectStep">
|
|
||||||
<option value="none" disabled selected>Select a new step...</option>
|
|
||||||
</select>
|
|
||||||
<button class="btn btn-success btn-lg" name="add">Add Step</button>
|
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<p class="info">Select a new module to add to your sequence.</p>
|
||||||
<p class="info" style="padding:8px;">Select a new module to add to your sequence.</p>
|
<div class="row center-align radio-group">
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="resize">
|
||||||
|
<i class="fa fa-arrows-alt fa-4x i-over"></i>
|
||||||
|
</div>
|
||||||
|
<p>Resize</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="brightness">
|
||||||
|
<i class="fa fa-sun-o fa-4x i-over"></i>
|
||||||
|
</div>
|
||||||
|
<p>Brightness</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="contrast">
|
||||||
|
<i class="fa fa-adjust fa-4x i-over"></i>
|
||||||
|
</div>
|
||||||
|
<p>Contrast</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="saturation">
|
||||||
|
<i class="fa fa-tint fa-4x i-over i-small"></i>
|
||||||
|
</div>
|
||||||
|
<p>Saturation</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="rotate">
|
||||||
|
<i class="fa fa-rotate-right fa-4x i-over"></i>
|
||||||
|
</div>
|
||||||
|
<p>Rotate</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="radio" data-value="crop">
|
||||||
|
<i class="fa fa-crop fa-4x i-over"></i>
|
||||||
|
</div>
|
||||||
|
<p>Crop</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="center-align">
|
||||||
|
<select id="selectStep" >
|
||||||
|
<!-- The default null selection has been appended manually in demo.js
|
||||||
|
This is because the options in select are overritten when options are appended.-->
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button>
|
||||||
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<button class="btn btn-primary btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
|
||||||
|
|
||||||
|
<section id="sequence-actions" class="panel">
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<div class="row center-align">
|
||||||
|
<!--<button class="btn btn-primary btn-block btn-lg" name="save-sequence" id="save-seq">Save Sequence</button> -->
|
||||||
|
<!--<button class="btn btn-primary btn-block btn-lg" id="download-btn" name="download" style="display: block; margin: 0px 10px 0px 0px; width: 250px;">Download PNG</button> -->
|
||||||
|
<button class="btn btn-primary btn-block btn-lg js-view-as-gif" id="gif" style="margin: 0px 35px 0px 35px;width:100%;">View GIF</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="modal fade" id="js-download-gif-modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">Your gif is ready</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="js-download-modal-gif-container">
|
||||||
|
<!-- Gif should appear here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Done</button>
|
||||||
|
|
||||||
|
<button id="js-download-as-gif-button" class="btn btn-primary">Download</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<section id="dwnld" class="panel panel-primary">
|
||||||
|
<div class="form-inline">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div style="text-align:center;">
|
||||||
|
<h2 style="margin-top:20px">Save</h2>
|
||||||
|
<p>Or click ARROW to save the entire sequence as a workflow for future use.</p>
|
||||||
|
<select class="form-control input-md" id="selectSaveOption" style="margin-top:20px">
|
||||||
|
<option>Save as PNG</option>
|
||||||
|
<option>Save as GIF (all steps)</option>
|
||||||
|
<option>Save sequence</option>
|
||||||
|
<option>Save sequence string</option>
|
||||||
|
</select>
|
||||||
|
<button id="saveButton" class="btn btn-primary btn-lg" style="margin-top:20px; margin-bottom:0px;align:center; width:100%;">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<hr style="margin:20px;"><center><a class="color:grey;" id="clear-cache">Clear offline cache</a></center>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2>Need Help?</h2>
|
||||||
|
<p>
|
||||||
|
Post a link to this and ask help from other community members on <a href="https://github.com/publiclab/image-sequencer/issues/new">Github Issues</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-primary" href="https://gitter.im/publiclab/publiclab">Ask a question on Gitter</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2>Improve this tool</h2>
|
||||||
|
<p>
|
||||||
|
This is an open source toolkit which you can help add to and improve on <a href="https://github.com/publiclab/image-sequencer/">Github</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-primary" 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>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
var sequencer;
|
var sequencer;
|
||||||
@@ -93,4 +228,4 @@
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
39
examples/lib/cache.js
Normal file
39
examples/lib/cache.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
var setupCache = function() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||||
|
.then(function(registration) {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
|
installingWorker.onstatechange = () => {
|
||||||
|
console.log(installingWorker)
|
||||||
|
if (installingWorker.state === 'installed') {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('Registration successful, scope is:', registration.scope);
|
||||||
|
})
|
||||||
|
.catch(function(error) {
|
||||||
|
console.log('Service worker registration failed, error:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
caches.keys().then(function(cacheNames) {
|
||||||
|
cacheNames.forEach(function(cacheName) {
|
||||||
|
$("#clear-cache").append(" " + cacheName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#clear-cache").click(function() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
caches.keys().then(function(cacheNames) {
|
||||||
|
cacheNames.forEach(function(cacheName) {
|
||||||
|
caches.delete(cacheName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = setupCache;
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
var urlHash = require('./urlHash.js');
|
||||||
function DefaultHtmlSequencerUi(_sequencer, options) {
|
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@@ -7,32 +8,35 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
|||||||
|
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
importStepsFromUrlHash();
|
importStepsFromUrlHash();
|
||||||
if (!$('#selectStep').val())
|
if ($('#selectStep').val()==='none')
|
||||||
$(addStepSel + " button").prop("disabled", true);
|
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||||
|
handleSaveSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
// look up needed steps from Url Hash:
|
// look up needed steps from Url Hash:
|
||||||
function importStepsFromUrlHash() {
|
function importStepsFromUrlHash() {
|
||||||
var hash = 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 });
|
||||||
}
|
}
|
||||||
setUrlHashParameter("steps", sequencer.toString());
|
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNewStepUi() {
|
function selectNewStepUi() {
|
||||||
var m = $(addStepSel + " select").val();
|
var m = $(addStepSel + " select").val();
|
||||||
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||||
$(addStepSel + " button").prop("disabled", false);
|
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStepUi() {
|
function removeStepUi() {
|
||||||
var index = $(removeStepSel).index(this) + 1;
|
var index = $(removeStepSel).index(this) + 1;
|
||||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||||
// remove from URL hash too
|
// remove from URL hash too
|
||||||
setUrlHashParameter("steps", sequencer.toString());
|
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||||
|
//disable save-sequence button if all steps are removed
|
||||||
|
handleSaveSequence();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStepUi() {
|
function addStepUi() {
|
||||||
@@ -53,10 +57,23 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
|||||||
}
|
}
|
||||||
_sequencer
|
_sequencer
|
||||||
.addSteps(newStepName, options)
|
.addSteps(newStepName, options)
|
||||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
.run({ index: _sequencer.steps.length - sequenceLength - 1 });
|
||||||
|
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||||
|
$(addStepSel + " select").val("none");
|
||||||
|
|
||||||
|
//enable save-sequence button if disabled initially
|
||||||
|
handleSaveSequence();
|
||||||
|
|
||||||
// add to URL hash too
|
// add to URL hash too
|
||||||
setUrlHashParameter("steps", _sequencer.toString());
|
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSaveSequence(){
|
||||||
|
var stepCount=sequencer.steps.length;
|
||||||
|
if(stepCount<2)
|
||||||
|
$(" #save-seq").prop("disabled", true);
|
||||||
|
else
|
||||||
|
$(" #save-seq").prop("disabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -67,3 +84,6 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
|||||||
addStepUi: addStepUi
|
addStepUi: addStepUi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = DefaultHtmlSequencerUi;
|
||||||
|
|
||||||
|
|||||||
@@ -7,45 +7,63 @@
|
|||||||
// The variable 'step' stores useful data like input and
|
// The variable 'step' stores useful data like input and
|
||||||
// output values, step information.
|
// output values, step information.
|
||||||
// See documetation for more details.
|
// See documetation for more details.
|
||||||
function DefaultHtmlStepUi(_sequencer, options) {
|
|
||||||
|
|
||||||
|
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||||
|
var urlHash = require('./urlHash.js');
|
||||||
|
var _ = require('lodash');
|
||||||
|
var mapHtmlTypes = require('./mapHtmltypes');
|
||||||
|
|
||||||
|
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) {
|
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;
|
||||||
|
|
||||||
step.ui =
|
step.ui =
|
||||||
'\
|
'\
|
||||||
<div class="row step">\
|
<div class="container">\
|
||||||
<div class="col-md-4 details">\
|
<div class="row step" style="display:flex">\
|
||||||
<h3>' +
|
<form class="input-form">\
|
||||||
step.name +
|
<div class="col-md-4 details" style="flex:1">\
|
||||||
"</h3>\
|
<h3>\
|
||||||
<p><i>" +
|
<span class = "toggle">' +step.name + ' <i class="fa fa-caret-up toggleIcon" aria-hidden="true"></i></span>' +
|
||||||
|
'<span class="load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></span>' +
|
||||||
|
'</h3><div class="cal"><p><i>"'+
|
||||||
(step.description || "") +
|
(step.description || "") +
|
||||||
'</i></p>\
|
'</i></p></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<div class="col-md-8">\
|
</form>\
|
||||||
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
<div class="col-md-8 cal step-column">\
|
||||||
<a><img alt="" style="max-width=100%" class="img-thumbnail" /></a>\
|
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||||
|
<div class="step-image">\
|
||||||
|
<a><img alt="" class="img-thumbnail step-thumbnail"/></a>\
|
||||||
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
</div>\
|
</div>\
|
||||||
';
|
</div>\
|
||||||
|
</div>';
|
||||||
|
|
||||||
var tools =
|
var tools =
|
||||||
'<div class="tools btn-group">\
|
'<div class="cal"><div class="tools btn-group">\
|
||||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||||
<i class="fa fa-trash"></i>\
|
<i class="fa fa-trash"></i>\
|
||||||
</button>\
|
</button>\
|
||||||
|
<button class="btn insert-step" style="margin-left:10px;border-radius:6px;background-color:#fff;border:solid #bababa 1.1px;" >\
|
||||||
|
<i class="fa fa-plus"></i> Add\
|
||||||
|
</button>\
|
||||||
|
</div>\
|
||||||
</div>';
|
</div>';
|
||||||
|
|
||||||
|
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||||
|
|
||||||
var parser = new DOMParser();
|
var parser = new DOMParser();
|
||||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||||
step.ui = step.ui.querySelector("div.row");
|
step.ui = step.ui.querySelector("div.container");
|
||||||
step.linkElement = step.ui.querySelector("a");
|
step.linkElements = step.ui.querySelectorAll("a");
|
||||||
step.imgElement = step.ui.querySelector("a img");
|
step.imgElement = step.ui.querySelector("a img");
|
||||||
|
|
||||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||||
@@ -56,7 +74,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
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 ? 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") {
|
||||||
@@ -66,12 +84,28 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
}
|
}
|
||||||
html += "</select>";
|
html += "</select>";
|
||||||
} else {
|
} else {
|
||||||
|
let paramVal = step.options[paramName] || inputDesc.default;
|
||||||
html =
|
html =
|
||||||
'<input class="form-control target" type="' +
|
'<input class="form-control target" type="' +
|
||||||
inputDesc.type +
|
inputDesc.type +
|
||||||
'" name="' +
|
'" name="' +
|
||||||
paramName +
|
paramName +
|
||||||
'">';
|
'" value="' +
|
||||||
|
paramVal +
|
||||||
|
'" placeholder ="' +
|
||||||
|
(inputDesc.placeholder || "");
|
||||||
|
|
||||||
|
if (inputDesc.type.toLowerCase() == "range") {
|
||||||
|
html +=
|
||||||
|
'"min="' +
|
||||||
|
inputDesc.min +
|
||||||
|
'"max="' +
|
||||||
|
inputDesc.max +
|
||||||
|
'"step="' +
|
||||||
|
(inputDesc.step ? inputDesc.step : 1)+ '">' + '<span>' + paramVal + '</span>';
|
||||||
|
|
||||||
|
}
|
||||||
|
else html += '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
var div = document.createElement("div");
|
var div = document.createElement("div");
|
||||||
@@ -79,7 +113,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
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'>\
|
"<div class='det cal'>\
|
||||||
<label for='" +
|
<label for='" +
|
||||||
paramName +
|
paramName +
|
||||||
"'>" +
|
"'>" +
|
||||||
@@ -92,103 +126,216 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
|||||||
step.ui.querySelector("div.details").appendChild(div);
|
step.ui.querySelector("div.details").appendChild(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSaveButton(){
|
|
||||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled",false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$(step.ui.querySelector(".target")).change(toggleSaveButton);
|
|
||||||
|
|
||||||
$(step.ui.querySelector("div.details")).append(
|
$(step.ui.querySelector("div.details")).append(
|
||||||
"<p><button class='btn btn-default btn-save' disabled = 'true' >Save</button><span> Press save to see changes</span></p>"
|
'<div class="cal"><p><button type="submit" class="btn btn-default btn-save" disabled = "true" >Apply</button><span> Press apply to see changes</span></p></div>'
|
||||||
);
|
);
|
||||||
|
|
||||||
function saveOptions() {
|
|
||||||
$(step.ui.querySelector("div.details"))
|
|
||||||
.find("input,select")
|
|
||||||
.each(function(i, input) {
|
|
||||||
step.options[$(input).attr("name")] = input.value;
|
|
||||||
});
|
|
||||||
_sequencer.run({ index: step.index - 1 });
|
|
||||||
|
|
||||||
// modify the url hash
|
|
||||||
setUrlHashParameter("steps", _sequencer.toString());
|
|
||||||
// disable the save button
|
|
||||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled",true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// on clicking Save in the details pane of the step
|
|
||||||
$(step.ui.querySelector("div.details .btn-save")).click(saveOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step.name != "load-image")
|
if (step.name != "load-image") {
|
||||||
step.ui
|
step.ui
|
||||||
.querySelector("div.details")
|
.querySelector("div.details")
|
||||||
.appendChild(
|
.appendChild(
|
||||||
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')});
|
||||||
|
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||||
|
|
||||||
stepsEl.appendChild(step.ui);
|
// Insert the step's UI in the right place
|
||||||
|
if (stepOptions.index == _sequencer.steps.length) {
|
||||||
|
stepsEl.appendChild(step.ui);
|
||||||
|
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||||
|
if($("#steps .container:nth-last-child(2)"))
|
||||||
|
$("#steps .container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||||
|
} else {
|
||||||
|
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#load-image").append(step.ui);
|
||||||
|
}
|
||||||
|
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||||
|
$(step.ui.querySelector('.toggleIcon')).toggleClass('fa-caret-up').toggleClass('fa-caret-down');
|
||||||
|
$(step.ui.querySelectorAll(".cal")).toggleClass("collapse");
|
||||||
|
});
|
||||||
|
|
||||||
|
$(step.imgElement).on("mousemove", _.debounce(() => imageHover(step), 150));
|
||||||
|
|
||||||
|
function saveOptions(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (optionsChanged){
|
||||||
|
$(step.ui.querySelector("div.details"))
|
||||||
|
.find("input,select")
|
||||||
|
.each(function(i, input) {
|
||||||
|
$(input)
|
||||||
|
.data('initValue', $(input).val())
|
||||||
|
.data('hasChangedBefore', false);
|
||||||
|
step.options[$(input).attr("name")] = $(input).val();
|
||||||
|
});
|
||||||
|
_sequencer.run({ index: step.index - 1 });
|
||||||
|
|
||||||
|
// modify the url hash
|
||||||
|
urlHash.setUrlHashParameter("steps", _sequencer.toString())
|
||||||
|
// disable the save button
|
||||||
|
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||||
|
optionsChanged = false;
|
||||||
|
changedInputs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
||||||
|
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
||||||
|
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
||||||
|
optionsChanged = changedInputs > 0;
|
||||||
|
|
||||||
|
$(step.ui.querySelector('.btn-save')).prop('disabled', !optionsChanged);
|
||||||
|
return inputChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
var
|
||||||
|
changedInputs = 0,
|
||||||
|
optionsChanged = false;
|
||||||
|
$(step.ui.querySelector('.input-form')).on('submit', saveOptions);
|
||||||
|
$(step.ui.querySelectorAll('.target')).each(function(i, input) {
|
||||||
|
$(input)
|
||||||
|
.data('initValue', $(input).val())
|
||||||
|
.data('hasChangedBefore', false)
|
||||||
|
.on('input', function() {
|
||||||
|
$(this)
|
||||||
|
.focus()
|
||||||
|
.data('hasChangedBefore',
|
||||||
|
handleInputValueChange(
|
||||||
|
$(this).val(),
|
||||||
|
$(this).data('initValue'),
|
||||||
|
$(this).data('hasChangedBefore')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$('input[type="range"]').on('input', function() {
|
||||||
|
$(this).next().html($(this).val());
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onDraw(step) {
|
function onDraw(step) {
|
||||||
$(step.ui.querySelector(".load")).show();
|
$(step.ui.querySelector(".load")).show();
|
||||||
$(step.ui.querySelector("img")).hide();
|
$(step.ui.querySelector("img")).hide();
|
||||||
|
if( $(step.ui.querySelector(".toggleIcon")).hasClass("fa-caret-down") )
|
||||||
|
{
|
||||||
|
$(step.ui.querySelector(".load-spin")).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onComplete(step) {
|
function onComplete(step) {
|
||||||
$(step.ui.querySelector(".load")).hide();
|
$(step.ui.querySelector(".load")).hide();
|
||||||
$(step.ui.querySelector("img")).show();
|
$(step.ui.querySelector("img")).show();
|
||||||
|
$(step.ui.querySelector(".load-spin")).hide();
|
||||||
|
|
||||||
step.imgElement.src = step.output;
|
step.imgElement.src = (step.name == "load-image") ? step.output.src : step.output;
|
||||||
step.linkElement.href = step.output;
|
var imgthumbnail = step.ui.querySelector(".img-thumbnail");
|
||||||
|
for (let index = 0; index < step.linkElements.length; index++) {
|
||||||
|
if (step.linkElements[index].contains(imgthumbnail))
|
||||||
|
step.linkElements[index].href = step.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];
|
||||||
}
|
}
|
||||||
|
|
||||||
step.linkElement.download = step.name + "." + fileExtension(step.output);
|
for (let index = 0; index < step.linkElements.length; index++) {
|
||||||
step.linkElement.target = "_blank";
|
|
||||||
|
step.linkElements[index].download = step.name + "." + fileExtension(step.imgElement.src);
|
||||||
|
step.linkElements[index].target = "_blank";
|
||||||
|
}
|
||||||
|
|
||||||
// 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 (
|
if (step.options[i] !== undefined) {
|
||||||
step.options[i] !== undefined &&
|
if (inputs[i].type.toLowerCase() === "input")
|
||||||
inputs[i].type.toLowerCase() === "input"
|
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||||
)
|
.val(step.options[i])
|
||||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
.data('initValue', step.options[i]);
|
||||||
step.options[i];
|
if (inputs[i].type.toLowerCase() === "select")
|
||||||
if (
|
$(step.ui.querySelector('div[name="' + i + '"] select'))
|
||||||
step.options[i] !== undefined &&
|
.val(step.options[i])
|
||||||
inputs[i].type.toLowerCase() === "select"
|
.data('initValue', step.options[i]);
|
||||||
)
|
}
|
||||||
step.ui.querySelector('div[name="' + i + '"] select').value =
|
|
||||||
step.options[i];
|
|
||||||
}
|
}
|
||||||
for (var i in outputs) {
|
for (var i in outputs) {
|
||||||
if (step[i] !== undefined)
|
if (step[i] !== undefined)
|
||||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||||
step[i];
|
.val(step[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function imageHover(step){
|
||||||
|
|
||||||
|
var img = $(step.imgElement);
|
||||||
|
|
||||||
|
img.mousemove(function(e) {
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
canvas.width = img.width();
|
||||||
|
canvas.height = img.height();
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
context.drawImage(this,0,0);
|
||||||
|
|
||||||
|
var offset = $(this).offset();
|
||||||
|
var xPos = e.pageX - offset.left;
|
||||||
|
var yPos = e.pageY - offset.top;
|
||||||
|
var myData = context.getImageData(xPos, yPos, 1, 1);
|
||||||
|
img[0].title = "rgb: " +myData.data[0]+","+ myData.data[1]+","+myData.data[2];//+ rgbdata;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function onRemove(step) {
|
function onRemove(step) {
|
||||||
step.ui.remove();
|
step.ui.remove();
|
||||||
|
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||||
|
$('div[class*=imgareaselect-]').remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPreview() {
|
function getPreview() {
|
||||||
return step.imgElement;
|
return step.imgElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notify(msg,id){
|
||||||
|
if ($('#'+id).length == 0) {
|
||||||
|
var notification = document.createElement('span');
|
||||||
|
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
||||||
|
notification.id = id;
|
||||||
|
notification.classList.add("notification");
|
||||||
|
|
||||||
|
$('body').append(notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getPreview: getPreview,
|
getPreview: getPreview,
|
||||||
onSetup: onSetup,
|
onSetup: onSetup,
|
||||||
onComplete: onComplete,
|
onComplete: onComplete,
|
||||||
onRemove: onRemove,
|
onRemove: onRemove,
|
||||||
onDraw: onDraw
|
onDraw: onDraw,
|
||||||
|
notify: notify,
|
||||||
|
imageHover: imageHover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(typeof window === "undefined"){
|
||||||
|
module.exports={
|
||||||
|
DefaultHtmlStepUi: DefaultHtmlStepUi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DefaultHtmlStepUi;
|
||||||
|
|
||||||
|
|||||||
55
examples/lib/insertPreview.js
Normal file
55
examples/lib/insertPreview.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
function generatePreview(previewStepName, customValues, path, selector) {
|
||||||
|
|
||||||
|
var previewSequencer = ImageSequencer();
|
||||||
|
function insertPreview(src) {
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.classList.add('img-thumbnail')
|
||||||
|
img.classList.add('no-border');
|
||||||
|
img.src = src;
|
||||||
|
$(img).css("max-width", "200%");
|
||||||
|
$(img).css("transform", "translateX(-20%)");
|
||||||
|
var stepDiv = $('#'+selector+' .row').find('div').each(function() {
|
||||||
|
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||||
|
$(this).find('div').append(img);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPreview() {
|
||||||
|
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 = {
|
||||||
|
generatePreview : generatePreview,
|
||||||
|
updatePreviews : updatePreviews
|
||||||
|
}
|
||||||
135
examples/lib/intermediateHtmlStepUi.js
Normal file
135
examples/lib/intermediateHtmlStepUi.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
var urlHash = require('./urlHash.js'),
|
||||||
|
insertPreview = require('./insertPreview.js');
|
||||||
|
|
||||||
|
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||||
|
function stepUI() {
|
||||||
|
return '<div class="row insertDiv">\
|
||||||
|
<div class="col-md-6 col-md-offset-2" style="margin-top:5%">\
|
||||||
|
<section id="insertStep" class="panel panel-primary">\
|
||||||
|
<div class="form-inline">\
|
||||||
|
<div class="panel-body">\
|
||||||
|
<p class="info">Select a new module to add to your sequence.</p>\
|
||||||
|
<div class="row center-align radio-group">\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="resize">\
|
||||||
|
<i class="fa fa-arrows-alt fa-4x i-over"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Resize</p>\
|
||||||
|
</div>\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="brightness">\
|
||||||
|
<i class="fa fa-sun-o fa-4x i-over"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Brightness</p>\
|
||||||
|
</div>\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="contrast">\
|
||||||
|
<i class="fa fa-adjust fa-4x i-over"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Contrast</p>\
|
||||||
|
</div>\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="saturation">\
|
||||||
|
<i class="fa fa-tint fa-4x i-over i-small"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Saturation</p>\
|
||||||
|
</div>\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="rotate">\
|
||||||
|
<i class="fa fa-rotate-right fa-4x i-over"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Rotate</p>\
|
||||||
|
</div>\
|
||||||
|
<div>\
|
||||||
|
<div class="radio" data-value="crop">\
|
||||||
|
<i class="fa fa-crop fa-4x i-over"></i>\
|
||||||
|
</div>\
|
||||||
|
<p>Crop</p>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
<div class="center-align">\
|
||||||
|
<select class="form-control input-lg" id="selectStep">\
|
||||||
|
<!-- The default null selection has been appended manually in demo.js\
|
||||||
|
This is because the options in select are overritten when options are appended.-->\
|
||||||
|
</select>\
|
||||||
|
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
</section>\
|
||||||
|
</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function selectNewStepUi() {
|
||||||
|
var m = $("#insertStep select").val();
|
||||||
|
$("#insertStep .info").html(_sequencer.modulesInfo(m).description);
|
||||||
|
$("#insertStep #add-step-btn").prop("disabled", false);
|
||||||
|
}
|
||||||
|
insertStep = function (id) {
|
||||||
|
var modulesInfo = _sequencer.modulesInfo();
|
||||||
|
var parser = new DOMParser();
|
||||||
|
var addStepUI = stepUI();
|
||||||
|
addStepUI = parser.parseFromString(addStepUI, "text/html").querySelector("div")
|
||||||
|
step.ui
|
||||||
|
.querySelector("div.step")
|
||||||
|
.insertAdjacentElement('afterend',
|
||||||
|
addStepUI
|
||||||
|
);
|
||||||
|
insertPreview.updatePreviews(step.output,'insertStep');
|
||||||
|
var insertStepSelect = $("#insertStep select");
|
||||||
|
insertStepSelect.html("");
|
||||||
|
// Add modules to the insertStep dropdown
|
||||||
|
for (var m in modulesInfo) {
|
||||||
|
if (modulesInfo[m] !== undefined)
|
||||||
|
insertStepSelect.append(
|
||||||
|
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$('#insertStep #add-step-btn').selectize({
|
||||||
|
sortField: 'text'
|
||||||
|
});
|
||||||
|
$('#insertStep #add-step-btn').prop('disabled', true);
|
||||||
|
|
||||||
|
insertStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||||
|
$('#insertStep .radio-group .radio').on("click", function () {
|
||||||
|
$(this).parent().find('.radio').removeClass('selected');
|
||||||
|
$(this).addClass('selected');
|
||||||
|
newStep = $(this).attr('data-value');
|
||||||
|
insertStepSelect.val(newStep);
|
||||||
|
selectNewStepUi();
|
||||||
|
insert(id);
|
||||||
|
$(this).removeClass('selected');
|
||||||
|
});
|
||||||
|
$(step.ui.querySelector("#insertStep select")).on('change', selectNewStepUi);
|
||||||
|
$(step.ui.querySelector("#insertStep #add-step-btn")).on('click', function () { insert(id) });
|
||||||
|
}
|
||||||
|
|
||||||
|
function insert(id) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var insertStepSelect = $("#insertStep select");
|
||||||
|
if (insertStepSelect.val() == "none") return;
|
||||||
|
|
||||||
|
var newStepName = insertStepSelect.val()
|
||||||
|
$('div .insertDiv').remove();
|
||||||
|
var sequenceLength = 1;
|
||||||
|
if (sequencer.sequences[newStepName]) {
|
||||||
|
sequenceLength = sequencer.sequences[newStepName].length;
|
||||||
|
} else if (sequencer.modules[newStepName][1]["length"]) {
|
||||||
|
sequenceLength = sequencer.modules[newStepName][1]["length"];
|
||||||
|
}
|
||||||
|
_sequencer
|
||||||
|
.insertSteps(id + 1, newStepName).run({ index: id });
|
||||||
|
|
||||||
|
// add to URL hash too
|
||||||
|
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
insertStep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = IntermediateHtmlStepUi;
|
||||||
|
|
||||||
28
examples/lib/mapHtmltypes.js
Normal file
28
examples/lib/mapHtmltypes.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
function mapHtmlTypes(inputInfo){
|
||||||
|
var htmlType;
|
||||||
|
switch(inputInfo.type.toLowerCase()){
|
||||||
|
case 'integer':
|
||||||
|
htmlType = inputInfo.min != undefined ? 'range' : 'number';
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
htmlType = 'text';
|
||||||
|
break;
|
||||||
|
case 'select':
|
||||||
|
htmlType = 'select';
|
||||||
|
break;
|
||||||
|
case 'percentage':
|
||||||
|
htmlType = 'number';
|
||||||
|
break;
|
||||||
|
case 'float':
|
||||||
|
htmlType = inputInfo.min != undefined ? 'range' : 'text';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
htmlType = 'text';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var response = inputInfo;
|
||||||
|
response.type = htmlType;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mapHtmlTypes;
|
||||||
35
examples/lib/sw.js
Normal file
35
examples/lib/sw.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const staticCacheName = 'image-sequencer-static-v3';
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
console.log('Attempting to install service worker');
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', function(e) {
|
||||||
|
console.log('[ServiceWorker] Activate');
|
||||||
|
e.waitUntil(
|
||||||
|
caches.keys().then(function(cacheNames) {
|
||||||
|
return Promise.all(
|
||||||
|
cacheNames.filter(function(cacheName){
|
||||||
|
return cacheName.startsWith('image-sequencer-') &&
|
||||||
|
cacheName != staticCacheName;
|
||||||
|
}).map(function(cacheName){
|
||||||
|
return caches.delete(cacheName);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('fetch', function(event) {
|
||||||
|
event.respondWith(
|
||||||
|
caches.open(staticCacheName).then(function(cache) {
|
||||||
|
return cache.match(event.request).then(function (response) {
|
||||||
|
return response || fetch(event.request).then(function(response) {
|
||||||
|
if(event.request.method == "GET")
|
||||||
|
cache.put(event.request, response.clone());
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -40,3 +40,10 @@ function setUrlHashParameter(param, value) {
|
|||||||
setUrlHashParameters(params);
|
setUrlHashParameters(params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getUrlHashParameter: getUrlHashParameter,
|
||||||
|
setUrlHashParameter: setUrlHashParameter,
|
||||||
|
getUrlHashParameters: getUrlHashParameters,
|
||||||
|
setUrlHashParameters: setUrlHashParameters
|
||||||
|
}
|
||||||
|
|||||||
21
examples/manifest.json
Normal file
21
examples/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"short_name": "IS",
|
||||||
|
"name": "Image Sequencer",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "../icons/ic_192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/ic_512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": "/examples/#steps=",
|
||||||
|
"background_color": "#428bca",
|
||||||
|
"display": "standalone",
|
||||||
|
"scope": "/examples/",
|
||||||
|
"theme_color": "#428bca"
|
||||||
|
}
|
||||||
403
examples/selectize.default.css
Normal file
403
examples/selectize.default.css
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
/**
|
||||||
|
* selectize.default.css (v0.12.6) - Default Theme
|
||||||
|
* Copyright (c) 2013–2015 Brian Reavis & contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
|
||||||
|
* file except in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
||||||
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
||||||
|
* ANY KIND, either express or implied. See the License for the specific language
|
||||||
|
* governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
* @author Brian Reavis <brian@thirdroute.com>
|
||||||
|
*/
|
||||||
|
.selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder {
|
||||||
|
visibility: visible !important;
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
background: rgba(0, 0, 0, 0.06) !important;
|
||||||
|
border: 0 none !important;
|
||||||
|
-webkit-box-shadow: inset 0 0 12px 4px #fff;
|
||||||
|
box-shadow: inset 0 0 12px 4px #fff;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-drag_drop .ui-sortable-placeholder::after {
|
||||||
|
content: '!';
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-drag_drop .ui-sortable-helper {
|
||||||
|
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.selectize-dropdown-header {
|
||||||
|
position: relative;
|
||||||
|
padding: 5px 8px;
|
||||||
|
border-bottom: 1px solid #d0d0d0;
|
||||||
|
background: #f8f8f8;
|
||||||
|
-webkit-border-radius: 3px 3px 0 0;
|
||||||
|
-moz-border-radius: 3px 3px 0 0;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
}
|
||||||
|
.selectize-dropdown-header-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
color: #303030;
|
||||||
|
opacity: 0.4;
|
||||||
|
margin-top: -12px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 20px !important;
|
||||||
|
}
|
||||||
|
.selectize-dropdown-header-close:hover {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
.selectize-dropdown.plugin-optgroup_columns .optgroup {
|
||||||
|
border-right: 1px solid #f2f2f2;
|
||||||
|
border-top: 0 none;
|
||||||
|
float: left;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.selectize-dropdown.plugin-optgroup_columns .optgroup:last-child {
|
||||||
|
border-right: 0 none;
|
||||||
|
}
|
||||||
|
.selectize-dropdown.plugin-optgroup_columns .optgroup:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.selectize-dropdown.plugin-optgroup_columns .optgroup-header {
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button [data-value] {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 24px !important;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button [data-value] .remove {
|
||||||
|
z-index: 1;
|
||||||
|
/* fixes ie bug (see #392) */
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 17px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 0 0 0;
|
||||||
|
border-left: 1px solid #0073bb;
|
||||||
|
-webkit-border-radius: 0 2px 2px 0;
|
||||||
|
-moz-border-radius: 0 2px 2px 0;
|
||||||
|
border-radius: 0 2px 2px 0;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button [data-value] .remove:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button [data-value].active .remove {
|
||||||
|
border-left-color: #00578d;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button .disabled [data-value] .remove:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button .disabled [data-value] .remove {
|
||||||
|
border-left-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
.selectize-control.plugin-remove_button .remove-single {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
font-size: 23px;
|
||||||
|
}
|
||||||
|
.selectize-control {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.selectize-dropdown,
|
||||||
|
.selectize-input,
|
||||||
|
.selectize-input input {
|
||||||
|
color: #303030;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
-webkit-font-smoothing: inherit;
|
||||||
|
}
|
||||||
|
.selectize-input,
|
||||||
|
.selectize-control.single .selectize-input.input-active {
|
||||||
|
background: #fff;
|
||||||
|
cursor: text;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.selectize-input {
|
||||||
|
border: 1px solid #d0d0d0;
|
||||||
|
padding: 10px 0px;
|
||||||
|
display: inline-block;
|
||||||
|
width: 24vw;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.has-items {
|
||||||
|
padding: 5px 8px 2px;
|
||||||
|
}
|
||||||
|
.selectize-input.full {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.selectize-input.disabled,
|
||||||
|
.selectize-input.disabled * {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
.selectize-input.focus {
|
||||||
|
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||||
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
.selectize-input.dropdown-active {
|
||||||
|
-webkit-border-radius: 3px 3px 0 0;
|
||||||
|
-moz-border-radius: 3px 3px 0 0;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
}
|
||||||
|
.selectize-input > * {
|
||||||
|
vertical-align: baseline;
|
||||||
|
display: -moz-inline-stack;
|
||||||
|
display: inline-block;
|
||||||
|
zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input > div {
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0 3px 3px 0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
background: #1da7ee;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid #0073bb;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input > div.active {
|
||||||
|
background: #92c836;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid #00578d;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.disabled > div,
|
||||||
|
.selectize-control.multi .selectize-input.disabled > div.active {
|
||||||
|
color: #ffffff;
|
||||||
|
background: #d2d2d2;
|
||||||
|
border: 1px solid #aaaaaa;
|
||||||
|
}
|
||||||
|
.selectize-input > input {
|
||||||
|
display: inline-block !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
max-height: none !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
margin: 0 1px !important;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
border: 0 none !important;
|
||||||
|
background: none !important;
|
||||||
|
line-height: inherit !important;
|
||||||
|
-webkit-user-select: auto !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.selectize-input > input::-ms-clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.selectize-input > input:focus {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
.selectize-input::after {
|
||||||
|
content: ' ';
|
||||||
|
display: block;
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
.selectize-input.dropdown-active::before {
|
||||||
|
content: ' ';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
background: #f0f0f0;
|
||||||
|
height: 1px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.selectize-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
border: 1px solid #d0d0d0;
|
||||||
|
background: #fff;
|
||||||
|
margin: -1px 0 0 0;
|
||||||
|
border-top: 0 none;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-border-radius: 0 0 3px 3px;
|
||||||
|
-moz-border-radius: 0 0 3px 3px;
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
}
|
||||||
|
.selectize-dropdown [data-selectable] {
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.selectize-dropdown [data-selectable] .highlight {
|
||||||
|
background: rgba(125, 168, 208, 0.2);
|
||||||
|
-webkit-border-radius: 1px;
|
||||||
|
-moz-border-radius: 1px;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .option,
|
||||||
|
.selectize-dropdown .optgroup-header {
|
||||||
|
padding: 5px 8px;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .option,
|
||||||
|
.selectize-dropdown [data-disabled],
|
||||||
|
.selectize-dropdown [data-disabled] [data-selectable].option {
|
||||||
|
cursor: inherit;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.selectize-dropdown [data-selectable].option {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .optgroup:first-child .optgroup-header {
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .optgroup-header {
|
||||||
|
color: #303030;
|
||||||
|
background: #fff;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .active {
|
||||||
|
background-color: #f5fafd;
|
||||||
|
color: #495c68;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .active.create {
|
||||||
|
color: #495c68;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .create {
|
||||||
|
color: rgba(48, 48, 48, 0.5);
|
||||||
|
}
|
||||||
|
.selectize-dropdown-content {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
max-height: 200px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.selectize-control.single .selectize-input,
|
||||||
|
.selectize-control.single .selectize-input input {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.selectize-control.single .selectize-input.input-active,
|
||||||
|
.selectize-control.single .selectize-input.input-active input {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.selectize-control.single .selectize-input:after {
|
||||||
|
content: ' ';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 15px;
|
||||||
|
margin-top: -3px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 5px 5px 0 5px;
|
||||||
|
border-color: #808080 transparent transparent transparent;
|
||||||
|
}
|
||||||
|
.selectize-control.single .selectize-input.dropdown-active:after {
|
||||||
|
margin-top: -4px;
|
||||||
|
border-width: 0 5px 5px 5px;
|
||||||
|
border-color: transparent transparent #808080 transparent;
|
||||||
|
}
|
||||||
|
.selectize-control.rtl.single .selectize-input:after {
|
||||||
|
left: 15px;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
.selectize-control.rtl .selectize-input > input {
|
||||||
|
margin: 0 4px 0 -2px !important;
|
||||||
|
}
|
||||||
|
.selectize-control .selectize-input.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.has-items {
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.disabled [data-value] {
|
||||||
|
color: #999;
|
||||||
|
text-shadow: none;
|
||||||
|
background: none;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.disabled [data-value],
|
||||||
|
.selectize-control.multi .selectize-input.disabled [data-value] .remove {
|
||||||
|
border-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input.disabled [data-value] .remove {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input [data-value] {
|
||||||
|
text-shadow: 0 1px 0 rgba(0, 51, 83, 0.3);
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: #1b9dec;
|
||||||
|
background-image: -moz-linear-gradient(top, #1da7ee, #178ee9);
|
||||||
|
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#1da7ee), to(#178ee9));
|
||||||
|
background-image: -webkit-linear-gradient(top, #1da7ee, #178ee9);
|
||||||
|
background-image: -o-linear-gradient(top, #1da7ee, #178ee9);
|
||||||
|
background-image: linear-gradient(to bottom, #1da7ee, #178ee9);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1da7ee', endColorstr='#ff178ee9', GradientType=0);
|
||||||
|
-webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
|
||||||
|
box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
|
||||||
|
}
|
||||||
|
.selectize-control.multi .selectize-input [data-value].active {
|
||||||
|
background-color: #0085d4;
|
||||||
|
background-image: -moz-linear-gradient(top, #008fd8, #0075cf);
|
||||||
|
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#008fd8), to(#0075cf));
|
||||||
|
background-image: -webkit-linear-gradient(top, #008fd8, #0075cf);
|
||||||
|
background-image: -o-linear-gradient(top, #008fd8, #0075cf);
|
||||||
|
background-image: linear-gradient(to bottom, #008fd8, #0075cf);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff008fd8', endColorstr='#ff0075cf', GradientType=0);
|
||||||
|
}
|
||||||
|
.selectize-control.single .selectize-input {
|
||||||
|
-webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||||
|
box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
background-image: -moz-linear-gradient(top, #fefefe, #f2f2f2);
|
||||||
|
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fefefe), to(#f2f2f2));
|
||||||
|
background-image: -webkit-linear-gradient(top, #fefefe, #f2f2f2);
|
||||||
|
background-image: -o-linear-gradient(top, #fefefe, #f2f2f2);
|
||||||
|
background-image: linear-gradient(to bottom, #fefefe, #f2f2f2);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffefefe', endColorstr='#fff2f2f2', GradientType=0);
|
||||||
|
}
|
||||||
|
/* .selectize-control.single .selectize-input,
|
||||||
|
.selectize-dropdown.single {
|
||||||
|
border-color: #b8b8b8;
|
||||||
|
} */
|
||||||
|
.selectize-dropdown .optgroup-header {
|
||||||
|
padding-top: 7px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .optgroup {
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.selectize-dropdown .optgroup:first-child {
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
BIN
icons/ic_512.png
Normal file
BIN
icons/ic_512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
152
index.js
152
index.js
@@ -1,11 +1,14 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
require("./src/ImageSequencer");
|
require('./src/ImageSequencer');
|
||||||
sequencer = ImageSequencer({ ui: false });
|
sequencer = ImageSequencer({ ui: false });
|
||||||
var Spinner = require("ora");
|
var fs = require('fs')
|
||||||
|
var program = require('commander');
|
||||||
|
var utils = require('./src/CliUtils')
|
||||||
|
|
||||||
var program = require("commander");
|
var saveSequence = require('./src/cli/saveSequence.js')
|
||||||
var readlineSync = require("readline-sync");
|
var installModule = require('./src/cli/installModule.js')
|
||||||
|
var sequencerSteps = require('./src/cli/sequencerSteps.js')
|
||||||
|
|
||||||
function exit(message) {
|
function exit(message) {
|
||||||
console.error(message);
|
console.error(message);
|
||||||
@@ -23,17 +26,11 @@ program
|
|||||||
.option('--install-module [string]', "Module name space seaprated npm package name")
|
.option('--install-module [string]', "Module name space seaprated npm package name")
|
||||||
.parse(process.argv);
|
.parse(process.argv);
|
||||||
|
|
||||||
if (program.saveSequence) {
|
if (program.saveSequence) saveSequence(program, sequencer)
|
||||||
var params = program.saveSequence.split(' ');
|
|
||||||
sequencer.saveSequence(params[0], params[1]);
|
else if (program.installModule) installModule(program, sequencer)
|
||||||
} else if (program.installModule) {
|
|
||||||
var params = program.installModule.split(' ');
|
else {
|
||||||
var spinner = Spinner("Now Installing...").start();
|
|
||||||
require('child_process').execSync(`npm i ${params[1]}`)
|
|
||||||
sequencer.saveNewModule(params[0], params[1]);
|
|
||||||
sequencer.loadNewModule(params[0], require(params[1]));
|
|
||||||
spinner.stop();
|
|
||||||
} else {
|
|
||||||
// Parse step into an array to allow for multiple steps.
|
// Parse step into an array to allow for multiple steps.
|
||||||
if (!program.step) exit("No steps passed");
|
if (!program.step) exit("No steps passed");
|
||||||
program.step = program.step.split(" ");
|
program.step = program.step.split(" ");
|
||||||
@@ -42,12 +39,12 @@ if (program.saveSequence) {
|
|||||||
if (!program.image) exit("Can't read file.");
|
if (!program.image) exit("Can't read file.");
|
||||||
|
|
||||||
// User must input an image.
|
// User must input an image.
|
||||||
require("fs").access(program.image, function(err) {
|
fs.access(program.image, function(err) {
|
||||||
if (err) exit("Can't read file.");
|
if (err) exit("Can't read file.");
|
||||||
});
|
});
|
||||||
|
|
||||||
// User must input a step. If steps exist, check that every step is a valid step.
|
// User must input a step. If steps exist, check that every step is a valid step.
|
||||||
if (!program.step || !validateSteps(program.step))
|
if (!program.step || !(utils.validateSteps(program.step, sequencer)))
|
||||||
exit("Please ensure all steps are valid.");
|
exit("Please ensure all steps are valid.");
|
||||||
|
|
||||||
// If there's no user defined output directory, select a default directory.
|
// If there's no user defined output directory, select a default directory.
|
||||||
@@ -62,6 +59,9 @@ if (program.saveSequence) {
|
|||||||
for (var output in step.info.outputs) {
|
for (var output in step.info.outputs) {
|
||||||
console.log("[" + program.step + "]: " + output + " = " + step[output]);
|
console.log("[" + program.step + "]: " + output + " = " + step[output]);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
notify: function(msg) {
|
||||||
|
console.log('\x1b[36m%s\x1b[0m','🌟 '+msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,125 +81,9 @@ if (program.saveSequence) {
|
|||||||
else {
|
else {
|
||||||
outputFilename = null;
|
outputFilename = null;
|
||||||
}
|
}
|
||||||
require("./src/CliUtils").makedir(program.output, () => {
|
|
||||||
console.log('Files will be exported to "' + program.output + '"');
|
|
||||||
|
|
||||||
if (program.basic)
|
sequencerSteps(program, sequencer, outputFilename)
|
||||||
console.log("Basic mode is enabled, outputting only final image");
|
|
||||||
|
|
||||||
// Iterate through the steps and retrieve their inputs.
|
|
||||||
program.step.forEach(function(step) {
|
|
||||||
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
|
||||||
|
|
||||||
// If inputs exists, print to console.
|
|
||||||
if (Object.keys(options).length) {
|
|
||||||
console.log("[" + step + "]: Inputs");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If inputs exists, print them out with descriptions.
|
|
||||||
Object.keys(options).forEach(function(input) {
|
|
||||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
|
||||||
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
|
||||||
console.log(
|
|
||||||
new Array(step.length + 5).join(" ") +
|
|
||||||
input +
|
|
||||||
": " +
|
|
||||||
options[input].desc
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (program.config) {
|
|
||||||
try {
|
|
||||||
var config = JSON.parse(program.config);
|
|
||||||
console.log(`The parsed options object: `, config);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(
|
|
||||||
"\x1b[31m%s\x1b[0m",
|
|
||||||
`Options(Config) is not a not valid JSON Fallback activate`
|
|
||||||
);
|
|
||||||
program.config = false;
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (program.config && validateConfig(config, options)) {
|
|
||||||
console.log("Now using Options object");
|
|
||||||
Object.keys(options).forEach(function(input) {
|
|
||||||
options[input] = config[input];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// If inputs exist, iterate through them and prompt for values.
|
|
||||||
Object.keys(options).forEach(function(input) {
|
|
||||||
var value = readlineSync.question(
|
|
||||||
"[" +
|
|
||||||
step +
|
|
||||||
"]: Enter a value for " +
|
|
||||||
input +
|
|
||||||
" (" +
|
|
||||||
options[input].type +
|
|
||||||
", default: " +
|
|
||||||
options[input].default +
|
|
||||||
"): "
|
|
||||||
);
|
|
||||||
options[input] = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Add the step and its inputs to the sequencer.
|
|
||||||
sequencer.addSteps(step, options);
|
|
||||||
});
|
|
||||||
|
|
||||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
|
||||||
if (!process.env.TEST)
|
|
||||||
spinnerObj = Spinner("Your Image is being processed..").start();
|
|
||||||
|
|
||||||
// Run the sequencer.
|
|
||||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
|
||||||
// Export all images or final image as binary files.
|
|
||||||
sequencer.exportBin(program.output, program.basic, outputFilename);
|
|
||||||
|
|
||||||
//check if spinner was not overriden stop it
|
|
||||||
if (!spinnerObj.overrideFlag) {
|
|
||||||
spinnerObj.succeed();
|
|
||||||
console.log(`\nDone!!`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
|
||||||
function validateSteps(steps) {
|
|
||||||
// Assume all are valid in the beginning.
|
|
||||||
var valid = true;
|
|
||||||
steps.forEach(function(step) {
|
|
||||||
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
|
||||||
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
|
||||||
valid = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Takes config and options object and checks if all the keys exist in config
|
|
||||||
function validateConfig(config_, options_) {
|
|
||||||
options_ = Object.keys(options_);
|
|
||||||
if (
|
|
||||||
(function() {
|
|
||||||
for (var input in options_) {
|
|
||||||
if (!config_[options_[input]]) {
|
|
||||||
console.error(
|
|
||||||
"\x1b[31m%s\x1b[0m",
|
|
||||||
`Options Object does not have the required details "${
|
|
||||||
options_[input]
|
|
||||||
}" not specified. Fallback case activated`
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})() == false
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
else return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8340
package-lock.json
generated
8340
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "image-sequencer",
|
"name": "image-sequencer",
|
||||||
"version": "2.2.3",
|
"version": "3.0.0",
|
||||||
"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 tape test/**/*.js test/*.js | tap-spec; browserify test/modules/image-sequencer.js test/modules/chain.js test/modules/meta-modules.js test/modules/replace.js test/modules/import-export.js test/modules/run.js test/modules/dynamic-imports.js | tape-run --render=\"tap-spec\"",
|
"test": "TEST=true tape test/core/*.js test/core/ui/user-interface.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\"",
|
||||||
|
"test-ui": "jasmine test/spec/*.js",
|
||||||
|
"setup": "npm i && npm i -g grunt grunt-cli",
|
||||||
"start": "grunt serve"
|
"start": "grunt serve"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -22,40 +24,50 @@
|
|||||||
"url": "https://github.com/publiclab/image-sequencer/issues"
|
"url": "https://github.com/publiclab/image-sequencer/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bootstrap": "~3.2.0",
|
"bootstrap": "~3.4.0",
|
||||||
"buffer": "~5.0.2",
|
"buffer": "~5.2.1",
|
||||||
"commander": "^2.11.0",
|
"commander": "^2.11.0",
|
||||||
"data-uri-to-buffer": "^2.0.0",
|
"data-uri-to-buffer": "^2.0.0",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
"fisheyegl": "^0.1.2",
|
"fisheyegl": "^0.1.2",
|
||||||
"font-awesome": "~4.5.0",
|
"font-awesome": "~4.7.0",
|
||||||
"get-pixels": "~3.3.0",
|
"get-pixels": "~3.3.0",
|
||||||
|
"gifshot": "^0.4.5",
|
||||||
"image-sequencer-invert": "^1.0.0",
|
"image-sequencer-invert": "^1.0.0",
|
||||||
|
"imagejs": "0.0.9",
|
||||||
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
||||||
"jquery": "~2",
|
"jquery": "^3.3.1",
|
||||||
"jsqr": "^0.2.2",
|
"jsdom": "^13.1.0",
|
||||||
"lodash": "^4.17.5",
|
"jsqr": "^1.1.1",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
"ndarray-gaussian-filter": "^1.0.0",
|
"ndarray-gaussian-filter": "^1.0.0",
|
||||||
"ora": "^2.0.0",
|
"ora": "^3.0.0",
|
||||||
"pace": "0.0.4",
|
"pace": "0.0.4",
|
||||||
|
"qrcode": "^1.3.3",
|
||||||
"readline-sync": "^1.4.7",
|
"readline-sync": "^1.4.7",
|
||||||
"save-pixels": "~2.3.4",
|
"save-pixels": "~2.3.4",
|
||||||
"urify": "^2.1.0"
|
"selectize": "^0.12.6",
|
||||||
|
"urify": "^2.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "13.0.0",
|
"base64-img": "^1.0.4",
|
||||||
"grunt": "^0.4.5",
|
"browserify": "16.2.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": "^0.5.0",
|
"grunt-contrib-concat": "^1.0.1",
|
||||||
"grunt-contrib-uglify-es": "^3.3.0",
|
"grunt-contrib-uglify-es": "^3.3.0",
|
||||||
"grunt-contrib-watch": "^0.6.1",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"image-filter-core": "~1.0.0",
|
"image-filter-core": "~2.0.2",
|
||||||
"image-filter-threshold": "~1.0.0",
|
"image-filter-threshold": "~2.0.1",
|
||||||
"looks-same": "^3.2.1",
|
"jasmine-core": "^3.3.0",
|
||||||
"matchdep": "^0.3.0",
|
"jasmine-jquery": "^2.1.1",
|
||||||
"tap-spec": "^4.1.1",
|
"jasmine-spec-reporter": "^4.2.1",
|
||||||
"tape": ">=4.7.0",
|
"looks-same": "^7.0.0",
|
||||||
"tape-run": "^3.0.0",
|
"matchdep": "^2.0.0",
|
||||||
|
"tap-spec": "^5.0.0",
|
||||||
|
"tape": "^4.9.2",
|
||||||
|
"tape-run": "^5.0.0",
|
||||||
"uglify-es": "^3.3.7"
|
"uglify-es": "^3.3.7"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/publiclab/image-sequencer",
|
"homepage": "https://github.com/publiclab/image-sequencer",
|
||||||
|
|||||||
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')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
8
spec/helpers/reporter.js
Normal file
8
spec/helpers/reporter.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||||
|
|
||||||
|
jasmine.getEnv().clearReporters(); // remove default reporter logs
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter
|
||||||
|
spec: {
|
||||||
|
displayPending: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
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')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
19
spec/intermediateHtmlStepUi.spec.js
Normal file
19
spec/intermediateHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
describe('Intermediate step HTML', function() {
|
||||||
|
|
||||||
|
var IntermediateHtmlStepUi = require('../examples/lib/intermediateHtmlStepUi')
|
||||||
|
var sequencer = require('../src/ImageSequencer')()
|
||||||
|
var intermediateHtmlStepUi;
|
||||||
|
|
||||||
|
beforeEach(()=>{
|
||||||
|
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer)
|
||||||
|
|
||||||
|
spyOn(intermediateHtmlStepUi,'insertStep')
|
||||||
|
|
||||||
|
intermediateHtmlStepUi.insertStep()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('insert step ui', function() {
|
||||||
|
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
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
|
||||||
|
}
|
||||||
40
spec/urlHash.spec.js
Normal file
40
spec/urlHash.spec.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
describe('URL manipulation methods', function() {
|
||||||
|
|
||||||
|
var UrlHash = require('../examples/lib/urlHash')
|
||||||
|
var urlHash;
|
||||||
|
var params = {
|
||||||
|
module: 'brightness',
|
||||||
|
brightness: 50
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(()=>{
|
||||||
|
urlHash = UrlHash
|
||||||
|
|
||||||
|
spyOn(urlHash,'getUrlHashParameters')
|
||||||
|
spyOn(urlHash,'getUrlHashParameter')
|
||||||
|
spyOn(urlHash,'setUrlHashParameters')
|
||||||
|
spyOn(urlHash,'setUrlHashParameter')
|
||||||
|
|
||||||
|
urlHash.getUrlHashParameters()
|
||||||
|
urlHash.getUrlHashParameter('module')
|
||||||
|
urlHash.setUrlHashParameters(params)
|
||||||
|
urlHash.setUrlHashParameter('module','brightness')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('gets url hash params from window hash', function() {
|
||||||
|
expect(urlHash.getUrlHashParameters).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('gets url hash param from params object', function() {
|
||||||
|
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accepts param object and sets url hash params', function() {
|
||||||
|
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accepts param key-value pair and sets url hash params', function() {
|
||||||
|
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module','brightness')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// add steps to the sequencer
|
// add steps to the sequencer
|
||||||
function AddStep(_sequencer, image, name, o) {
|
function AddStep(_sequencer, name, o) {
|
||||||
return require('./InsertStep')(_sequencer,image,-1,name,o);
|
return require('./InsertStep')(_sequencer,-1,name,o);
|
||||||
}
|
}
|
||||||
module.exports = AddStep;
|
module.exports = AddStep;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
const 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
|
||||||
@@ -16,6 +14,45 @@ function makedir(path,callback){
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||||
|
function validateSteps(steps, sequencer) {
|
||||||
|
// Assume all are valid in the beginning.
|
||||||
|
var valid = true;
|
||||||
|
steps.forEach(function(step) {
|
||||||
|
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
||||||
|
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Takes config and options object and checks if all the keys exist in config
|
||||||
|
function validateConfig(config_, options_) {
|
||||||
|
options_ = Object.keys(options_);
|
||||||
|
if (
|
||||||
|
(function() {
|
||||||
|
for (var input in options_) {
|
||||||
|
if (!config_[options_[input]]) {
|
||||||
|
console.error(
|
||||||
|
"\x1b[31m%s\x1b[0m",
|
||||||
|
`Options Object does not have the required details "${
|
||||||
|
options_[input]
|
||||||
|
}" not specified. Fallback case activated`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})() == false
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = exports = {
|
module.exports = exports = {
|
||||||
makedir: makedir
|
makedir: makedir,
|
||||||
|
validateSteps: validateSteps,
|
||||||
|
validateConfig: validateConfig
|
||||||
}
|
}
|
||||||
@@ -32,13 +32,11 @@ module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
|||||||
if (err) console.error(err)
|
if (err) console.error(err)
|
||||||
});
|
});
|
||||||
if (filename && basic) {
|
if (filename && basic) {
|
||||||
for (var image in ref.images) {
|
var steps = ref.steps;
|
||||||
var steps = ref.images[image].steps;
|
|
||||||
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(dir + filename, buffer, function() { });
|
fs.writeFile(dir + filename, buffer, function() { });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getDirectories(dir, function(dirs) {
|
getDirectories(dir, function(dirs) {
|
||||||
@@ -50,8 +48,7 @@ module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
|||||||
}
|
}
|
||||||
fs.mkdir(dir + 'sequencer' + num, function() {
|
fs.mkdir(dir + 'sequencer' + num, function() {
|
||||||
var root = dir + 'sequencer' + num + '/';
|
var root = dir + 'sequencer' + num + '/';
|
||||||
for (var image in ref.images) {
|
var steps = ref.steps;
|
||||||
var steps = ref.images[image].steps;
|
|
||||||
if (basic) {
|
if (basic) {
|
||||||
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;
|
||||||
@@ -66,7 +63,6 @@ module.exports = function ExportBin(dir = "./output/", ref, basic, filename) {
|
|||||||
fs.writeFile(root + image + "_" + i + "." + ext, buffer, function() { });
|
fs.writeFile(root + image + "_" + i + "." + ext, buffer, function() { });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,42 +24,19 @@ function copy(a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatInput(args,format,images) {
|
function formatInput(args,format,images) {
|
||||||
images = [];
|
|
||||||
for (var image in this.images) {
|
|
||||||
images.push(image);
|
|
||||||
}
|
|
||||||
var json_q = {};
|
var json_q = {};
|
||||||
var format_i = format;
|
var format_i = format;
|
||||||
if (format == "+")
|
if (format == "+")
|
||||||
format = ['o_string_a', 'string_a', 'o_object'];
|
format = ['string_a', 'o_object'];
|
||||||
else if (format == "-")
|
else if (format == "-")
|
||||||
format = ['o_string_a', 'number_a'];
|
format = ['number_a'];
|
||||||
else if (format == "^")
|
else if (format == "^")
|
||||||
format = ['o_string_a', 'number', 'string', 'o_object'];
|
format = ['number', 'string', 'o_object'];
|
||||||
else if (format == "r")
|
else if (format == "r")
|
||||||
format = ['o_string_a', 'o_number'];
|
format = ['o_number'];
|
||||||
else if (format == "l")
|
else if (format == "l")
|
||||||
format = ['o_string','string','o_function'];
|
format = ['string','o_function'];
|
||||||
|
|
||||||
/*
|
|
||||||
formats:
|
|
||||||
addSteps :: o_image_a, name_a, o_o
|
|
||||||
o_string_a, string_a, o_object => { image: [{name,o}] }
|
|
||||||
removeSteps :: o_image_a, index_a
|
|
||||||
o_string_a, number_a => { image: [index] }
|
|
||||||
insertSteps :: o_image_a, index, name, o_o
|
|
||||||
o_string_a, number, string, o_object => { image: [{index,name,o}] }
|
|
||||||
run :: o_image_a, o_from
|
|
||||||
o_string_a, o_number => { image: index }
|
|
||||||
loadImages :: image, src, o_function
|
|
||||||
string, string, o_function => { images: [{image:src}], callback }
|
|
||||||
|
|
||||||
optionals:
|
|
||||||
image: o_string_a
|
|
||||||
options: o_object
|
|
||||||
from: o_number
|
|
||||||
callback: o_function
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(format[format.length-1] == "o_object") {
|
if(format[format.length-1] == "o_object") {
|
||||||
if(objTypeOf(args[args.length-1]) != "Object")
|
if(objTypeOf(args[args.length-1]) != "Object")
|
||||||
@@ -74,90 +51,56 @@ function formatInput(args,format,images) {
|
|||||||
args.push(function(){});
|
args.push(function(){});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(format[0] == "o_string_a") {
|
|
||||||
if(args.length == format.length - 1) {
|
|
||||||
var insert = false;
|
|
||||||
for (var i in args) {
|
|
||||||
if (format[parseInt(i)+1].includes( typeof(getPrimitive(args[i])) )){
|
|
||||||
insert = true;
|
|
||||||
}
|
|
||||||
else {insert = false; break;}
|
|
||||||
}
|
|
||||||
if(insert)
|
|
||||||
args.splice(0,0,copy(images));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (format[0] == "o_string" && format_i == "l" && args.length == 2) {
|
|
||||||
if (typeof(args[0]) == "string") {
|
|
||||||
var identifier = "image";
|
|
||||||
var number = 1;
|
|
||||||
while (this.images.hasOwnProperty(identifier+number)) number++;
|
|
||||||
args.splice(0,0,identifier+number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(args.length == format.length) {
|
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 ) {
|
||||||
json_q = copy(args[0]);
|
if(format_i == "r") json_q = {0:copy(args[0])};
|
||||||
if(!(format_i == "r" || format_i == "l")) {
|
else if(format_i == "-") {
|
||||||
for (var img in json_q)
|
json_q=[];
|
||||||
json_q[img] = makeArray(json_q[img]);
|
json_q= copy(args[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (format_i == "r") {
|
else if (format_i == "r" ) {
|
||||||
for (var img in args[0]) json_q[args[0][img]] = args[1];
|
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 = {
|
||||||
images: {},
|
image: args[0],
|
||||||
callback: args[2]
|
callback: args[1]
|
||||||
}
|
}
|
||||||
json_q.images[args[0]] = args[1];
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (var img in args[0]) {
|
json_q = [];
|
||||||
var image = args[0][img];
|
|
||||||
json_q[image] = [];
|
|
||||||
|
|
||||||
if(format_i == "+") {
|
if(format_i == "+") {
|
||||||
for(var s in args[1]) {
|
for(var s in args[0]) {
|
||||||
json_q[image].push({
|
json_q.push({
|
||||||
name: args[1][s],
|
name: args[0][s],
|
||||||
o: args[2]
|
o: args[1]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(format_i == "-") {
|
|
||||||
json_q[image] = args[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(format_i == "^") {
|
if(format_i == "^") {
|
||||||
var size = this.images[image].steps.length;
|
var size = this.steps.length;
|
||||||
var index = args[1];
|
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[image].push({
|
json_q.push({
|
||||||
index: index,
|
index: index,
|
||||||
name: args[2],
|
name: args[1],
|
||||||
o: args[3]
|
o: args[2]
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(format_i == "l") {
|
|
||||||
json_q.loadedimages = [];
|
|
||||||
for (var i in json_q.images) json_q.loadedimages.push(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return json_q;
|
return json_q;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
|
|
||||||
var sequencer = (this.name == "ImageSequencer") ? this : this.sequencer;
|
var sequencer = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.inBrowser = options.inBrowser || isBrowser;
|
options.inBrowser = options.inBrowser === undefined ? isBrowser : options.inBrowser;
|
||||||
options.sequencerCounter = 0;
|
options.sequencerCounter = 0;
|
||||||
|
|
||||||
function objTypeOf(object) {
|
function objTypeOf(object) {
|
||||||
@@ -24,7 +24,7 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
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]);
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,6 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
modules = require('./Modules'),
|
modules = require('./Modules'),
|
||||||
sequences = require('./SavedSequences.json'),
|
sequences = require('./SavedSequences.json'),
|
||||||
formatInput = require('./FormatInput'),
|
formatInput = require('./FormatInput'),
|
||||||
images = {},
|
|
||||||
inputlog = [],
|
inputlog = [],
|
||||||
events = require('./ui/UserInterface')(),
|
events = require('./ui/UserInterface')(),
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
@@ -66,94 +65,78 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
|
|
||||||
function addSteps() {
|
function addSteps() {
|
||||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
var args = [];
|
||||||
var json_q = {};
|
var json_q = {};
|
||||||
for (var arg in arguments) { args.push(copy(arguments[arg])); }
|
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 i in json_q)
|
require("./AddStep")(this_, json_q[j].name, json_q[j].o);
|
||||||
for (var j in json_q[i])
|
|
||||||
require("./AddStep")(this_, i, json_q[i][j].name, json_q[i][j].o);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStep(image, 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) {
|
||||||
thisStep = images[image].steps[index];
|
//var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
|
thisStep = ref.steps[index];
|
||||||
thisStep.UI.onRemove(thisStep.options.step);
|
thisStep.UI.onRemove(thisStep.options.step);
|
||||||
images[image].steps.splice(index, 1);
|
ref.steps.splice(index, 1);
|
||||||
}
|
}
|
||||||
//tell the UI a step has been removed
|
//tell the UI a step has been removed
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeSteps(image, index) {
|
function removeSteps(index) {
|
||||||
var run = {}, indices;
|
var indices;
|
||||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
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) });
|
||||||
|
|
||||||
for (var img in json_q) {
|
indices = json_q.sort(function(a, b) { return b - a });
|
||||||
indices = json_q[img].sort(function(a, b) { return b - a });
|
|
||||||
run[img] = indices[indices.length - 1];
|
|
||||||
for (var i in indices)
|
for (var i in indices)
|
||||||
removeStep(img, indices[i]);
|
removeStep(this_, indices[i]);
|
||||||
}
|
|
||||||
// this.run(run); // This is creating problems
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertSteps(image, index, name, o) {
|
function insertSteps(image, index, name, o) {
|
||||||
var run = {};
|
|
||||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
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) });
|
||||||
|
|
||||||
for (var img in json_q) {
|
var details = json_q;
|
||||||
var details = json_q[img];
|
|
||||||
details = details.sort(function(a, b) { return b.index - a.index });
|
details = details.sort(function(a, b) { return b.index - a.index });
|
||||||
for (var i in details)
|
for (var i in details)
|
||||||
require("./InsertStep")(this_, img, details[i].index, details[i].name, details[i].o);
|
require("./InsertStep")(this_, details[i].index, details[i].name, details[i].o);
|
||||||
run[img] = details[details.length - 1].index;
|
|
||||||
}
|
|
||||||
// this.run(run); // This is Creating issues
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is an object which contains the runtime configuration like progress bar
|
// Config is an object which contains the runtime configuration like progress bar
|
||||||
// information and index from which the sequencer should run
|
// information and index from which the sequencer should run
|
||||||
function run(config, t_image, t_from) {
|
function run(config, t_image, t_from) {
|
||||||
let 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 != 'test') {
|
|
||||||
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'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
arguments['0'] = config.mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
||||||
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
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 = args.splice(arg, 1)[0]; //callback is formed
|
||||||
|
|
||||||
var json_q = formatInput.call(this_, args, "r");
|
var json_q = formatInput.call(this_, args, "r");
|
||||||
|
|
||||||
@@ -164,13 +147,17 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
|
|
||||||
function loadImages() {
|
function loadImages() {
|
||||||
var args = [];
|
var args = [];
|
||||||
|
var prevSteps = this.getSteps().slice(1).map(step=>step.options.name)
|
||||||
var sequencer = this;
|
var sequencer = this;
|
||||||
|
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){
|
||||||
|
this.options.sequencerCounter = 0;
|
||||||
|
inputlog = [];
|
||||||
|
this.steps = [];
|
||||||
|
}
|
||||||
inputlog.push({ method: "loadImages", json_q: copy(json_q) });
|
inputlog.push({ method: "loadImages", json_q: copy(json_q) });
|
||||||
var loadedimages = this.copy(json_q.loadedimages);
|
|
||||||
|
|
||||||
var ret = {
|
var ret = {
|
||||||
name: "ImageSequencer Wrapper",
|
name: "ImageSequencer Wrapper",
|
||||||
sequencer: this,
|
sequencer: this,
|
||||||
@@ -179,22 +166,19 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
insertSteps: this.insertSteps,
|
insertSteps: this.insertSteps,
|
||||||
run: this.run,
|
run: this.run,
|
||||||
UI: this.UI,
|
UI: this.UI,
|
||||||
setUI: this.setUI,
|
setUI: this.setUI
|
||||||
images: loadedimages
|
|
||||||
};
|
};
|
||||||
|
function loadPrevSteps(ref){
|
||||||
function load(i) {
|
if(prevSteps.length!=0){
|
||||||
if (i == loadedimages.length) {
|
ref.addSteps(prevSteps)
|
||||||
json_q.callback.call(ret);
|
prevSteps=[];
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var img = loadedimages[i];
|
|
||||||
require('./ui/LoadImage')(sequencer, img, json_q.images[img], function() {
|
|
||||||
load(++i);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
require('./ui/LoadImage')(sequencer, "image", json_q.image, function() {
|
||||||
load(0);
|
loadPrevSteps(sequencer);
|
||||||
|
json_q.callback.call(ret);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceImage(selector, steps, options) {
|
function replaceImage(selector, steps, options) {
|
||||||
@@ -203,6 +187,11 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
return require('./ReplaceImage')(this, selector, steps, options);
|
return require('./ReplaceImage')(this, selector, steps, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//returns the steps added
|
||||||
|
function getSteps(){
|
||||||
|
return this.steps;
|
||||||
|
}
|
||||||
|
|
||||||
function setUI(UI) {
|
function setUI(UI) {
|
||||||
this.events = require('./ui/UserInterface')(UI);
|
this.events = require('./ui/UserInterface')(UI);
|
||||||
}
|
}
|
||||||
@@ -219,12 +208,13 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
modulesdata[modulename] = modules[modulename][1];
|
modulesdata[modulename] = modules[modulename][1];
|
||||||
}
|
}
|
||||||
for (var sequencename in this.sequences) {
|
for (var sequencename in this.sequences) {
|
||||||
modulesdata[sequencename] = { name: sequencename, steps: sequences[sequencename] };
|
modulesdata[sequencename] = { name: sequencename, steps: this.sequences[sequencename] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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'] };
|
||||||
}
|
}
|
||||||
@@ -235,9 +225,11 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
function toCliString() {
|
function toCliString() {
|
||||||
var cliStringSteps = `"`, cliOptions = {};
|
var cliStringSteps = `"`, cliOptions = {};
|
||||||
for (var step in this.steps) {
|
for (var step in this.steps) {
|
||||||
if (this.steps[step].options.name !== "load-image")
|
var name = (typeof this.steps[step].options !== "undefined")? this.steps[step].options.name : this.steps[step].name
|
||||||
cliStringSteps += `${this.steps[step].options.name} `;
|
if (name !== "load-image"){
|
||||||
for (var inp in modulesInfo(this.steps[step].options.name).inputs) {
|
cliStringSteps += `${name} `;
|
||||||
|
}
|
||||||
|
for (var inp in modulesInfo(name).inputs) {
|
||||||
cliOptions[inp] = this.steps[step].options[inp];
|
cliOptions[inp] = this.steps[step].options[inp];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,22 +242,26 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
if (step) {
|
if (step) {
|
||||||
return stepToString(step);
|
return stepToString(step);
|
||||||
} else {
|
} else {
|
||||||
return copy(this.images.image1.steps).map(stepToString).slice(1).join(',');
|
return copy(this.steps.map(stepToString).slice(1).join(','));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stringifies one step of the sequence
|
// Stringifies one step of the sequence
|
||||||
function stepToString(step) {
|
function stepToString(step) {
|
||||||
let inputs = copy(modulesInfo(step.options.name).inputs);
|
var arg = (step.name)?step.name:step.options.name;
|
||||||
inputs = inputs || {};
|
let inputs = modulesInfo(arg).inputs || {}, op = {};
|
||||||
|
|
||||||
for (let input in inputs) {
|
for (let input in inputs) {
|
||||||
inputs[input] = step.options[input] || inputs[input].default;
|
|
||||||
inputs[input] = encodeURIComponent(inputs[input]);
|
if (!!step.options[input] && step.options[input] != inputs[input].default) {
|
||||||
|
op[input] = step.options[input];
|
||||||
|
op[input] = encodeURIComponent(op[input]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var configurations = Object.keys(inputs).map(key => key + ':' + inputs[key]).join('|');
|
var configurations = Object.keys(op).map(key => key + ':' + op[key]).join('|');
|
||||||
return `${step.options.name}{${configurations}}`;
|
return `${arg}{${configurations}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// exports the current sequence as an array of JSON steps
|
// exports the current sequence as an array of JSON steps
|
||||||
@@ -379,19 +375,6 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
fs.writeFileSync('./src/Modules.js', mods);
|
fs.writeFileSync('./src/Modules.js', mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMetaModule(stepsCollection, info) {
|
|
||||||
var stepsArr = stepsCollection;
|
|
||||||
if (typeof stepsCollection === 'string')
|
|
||||||
stepsArr = stringToJSON(stepsCollection);
|
|
||||||
var metaMod = function() {
|
|
||||||
this.expandSteps(stepsArr);
|
|
||||||
return {
|
|
||||||
isMeta: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [metaMod, info];
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveSequence(name, sequenceString) {
|
function saveSequence(name, sequenceString) {
|
||||||
const sequence = stringToJSON(sequenceString);
|
const sequence = stringToJSON(sequenceString);
|
||||||
// Save the given sequence string as a module
|
// Save the given sequence string as a module
|
||||||
@@ -425,8 +408,9 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
inputlog: inputlog,
|
inputlog: inputlog,
|
||||||
modules: modules,
|
modules: modules,
|
||||||
sequences: sequences,
|
sequences: sequences,
|
||||||
images: images,
|
|
||||||
events: events,
|
events: events,
|
||||||
|
steps: steps,
|
||||||
|
image: image,
|
||||||
|
|
||||||
//user functions
|
//user functions
|
||||||
loadImages: loadImages,
|
loadImages: loadImages,
|
||||||
@@ -449,9 +433,10 @@ ImageSequencer = function ImageSequencer(options) {
|
|||||||
importJSON: importJSON,
|
importJSON: importJSON,
|
||||||
loadNewModule: loadNewModule,
|
loadNewModule: loadNewModule,
|
||||||
saveNewModule: saveNewModule,
|
saveNewModule: saveNewModule,
|
||||||
createMetaModule: createMetaModule,
|
createMetaModule: require('./util/createMetaModule'),
|
||||||
saveSequence: saveSequence,
|
saveSequence: saveSequence,
|
||||||
loadModules: loadModules,
|
loadModules: loadModules,
|
||||||
|
getSteps:getSteps,
|
||||||
|
|
||||||
//other functions
|
//other functions
|
||||||
log: log,
|
log: log,
|
||||||
|
|||||||
@@ -1,49 +1,53 @@
|
|||||||
const getStepUtils = require('./util/getStep.js');
|
const getStepUtils = require('./util/getStep.js');
|
||||||
|
|
||||||
// insert one or more steps at a given index in the sequencer
|
// insert one or more steps at a given index in the sequencer
|
||||||
function InsertStep(ref, image, index, name, o) {
|
function InsertStep(ref, index, name, o) {
|
||||||
if (ref.sequences[name]) {
|
if (ref.sequences[name]) {
|
||||||
return ref.importJSON(ref.sequences[name]);
|
return ref.importJSON(ref.sequences[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertStep(image, 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];
|
||||||
else {
|
else {
|
||||||
console.log('Module ' + name + ' not found.');
|
console.log('Module ' + name + ' not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var o = ref.copy(o_);
|
var o = ref.copy(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.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.image = image;
|
|
||||||
o.inBrowser = ref.options.inBrowser;
|
o.inBrowser = ref.options.inBrowser;
|
||||||
|
|
||||||
if (index == -1) index = ref.images[image].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,
|
||||||
ID: o.number,
|
ID: o.number,
|
||||||
imageName: o.image,
|
|
||||||
inBrowser: ref.options.inBrowser,
|
inBrowser: ref.options.inBrowser,
|
||||||
ui: ref.options.ui,
|
ui: ref.options.ui,
|
||||||
options: o
|
options: o
|
||||||
};
|
};
|
||||||
var UI = ref.events;
|
var UI = ref.events;
|
||||||
|
|
||||||
// Tell UI that a step has been set up.
|
// define the expandSteps function for sequencer
|
||||||
o = o || {};
|
|
||||||
ref.modules[name].expandSteps = function expandSteps(stepsArray) {
|
ref.modules[name].expandSteps = function expandSteps(stepsArray) {
|
||||||
for (var step of stepsArray) {
|
for (var i in stepsArray) {
|
||||||
ref.addSteps(step['name'], step['options']);
|
let step = stepsArray[i];
|
||||||
|
ref.insertSteps(index + Number.parseInt(i), step['name'], step['options']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell UI that a step has been set up.
|
||||||
|
o = o || {};
|
||||||
|
|
||||||
if (!ref.modules[name][1].length) {
|
if (!ref.modules[name][1].length) {
|
||||||
UI.onSetup(o.step);
|
UI.onSetup(o.step, { index: index });
|
||||||
ref.images[image].steps.splice(index, 0, ref.modules[name][0](o, UI));
|
ref.steps.splice(index, 0, ref.modules[name][0](o, UI));
|
||||||
} else {
|
} else {
|
||||||
ref.modules[name][0](o, UI);
|
ref.modules[name][0](o, UI);
|
||||||
}
|
}
|
||||||
@@ -51,8 +55,8 @@ function InsertStep(ref, image, index, name, o) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertStep(image, index, name, o);
|
insertStep(index, name, o);
|
||||||
ref.steps = ref.images[image].steps;
|
ref.steps = ref.steps;
|
||||||
|
|
||||||
}
|
}
|
||||||
module.exports = InsertStep;
|
module.exports = InsertStep;
|
||||||
|
|||||||
@@ -2,23 +2,38 @@
|
|||||||
* Core modules and their info files
|
* Core modules and their info files
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'channel': require('./modules/Channel'),
|
'add-qr': require('./modules/AddQR'),
|
||||||
'brightness': require('./modules/Brightness'),
|
|
||||||
'edge-detect': require('./modules/EdgeDetect'),
|
|
||||||
'ndvi': require('./modules/Ndvi'),
|
|
||||||
'crop': require('./modules/Crop'),
|
|
||||||
'colormap': require('./modules/Colormap'),
|
|
||||||
'decode-qr': require('./modules/DecodeQr'),
|
|
||||||
'fisheye-gl': require('./modules/FisheyeGl'),
|
|
||||||
'dynamic': require('./modules/Dynamic'),
|
|
||||||
'blur': require('./modules/Blur'),
|
|
||||||
'saturation': require('./modules/Saturation'),
|
|
||||||
'average': require('./modules/Average'),
|
'average': require('./modules/Average'),
|
||||||
'blend': require('./modules/Blend'),
|
'blend': require('./modules/Blend'),
|
||||||
'import-image': require('./modules/ImportImage'),
|
'blur': require('./modules/Blur'),
|
||||||
'overlay': require('./modules/Overlay'),
|
'brightness': require('./modules/Brightness'),
|
||||||
'gradient': require('./modules/Gradient'),
|
'channel': require('./modules/Channel'),
|
||||||
'invert': require('image-sequencer-invert'),
|
|
||||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
|
||||||
'colorbar': require('./modules/Colorbar'),
|
'colorbar': require('./modules/Colorbar'),
|
||||||
|
'colormap': require('./modules/Colormap'),
|
||||||
|
'contrast': require('./modules/Contrast'),
|
||||||
|
'convolution': require('./modules/Convolution'),
|
||||||
|
'crop': require('./modules/Crop'),
|
||||||
|
'decode-qr': require('./modules/DecodeQr'),
|
||||||
|
'dither': require('./modules/Dither'),
|
||||||
|
'draw-rectangle': require('./modules/DrawRectangle'),
|
||||||
|
'dynamic': require('./modules/Dynamic'),
|
||||||
|
'edge-detect': require('./modules/EdgeDetect'),
|
||||||
|
'flip-image': require('./modules/FlipImage'),
|
||||||
|
'fisheye-gl': require('./modules/FisheyeGl'),
|
||||||
|
'histogram': require('./modules/Histogram'),
|
||||||
|
'gamma-correction': require('./modules/GammaCorrection'),
|
||||||
|
'gradient': require('./modules/Gradient'),
|
||||||
|
'import-image': require('./modules/ImportImage'),
|
||||||
|
'invert': require('image-sequencer-invert'),
|
||||||
|
'ndvi': require('./modules/Ndvi'),
|
||||||
|
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||||
|
'paint-bucket': require('./modules/PaintBucket'),
|
||||||
|
'overlay': require('./modules/Overlay'),
|
||||||
|
'replace-color':require('./modules/ReplaceColor'),
|
||||||
|
'resize': require('./modules/Resize'),
|
||||||
|
'rotate': require('./modules/Rotate'),
|
||||||
|
'saturation': require('./modules/Saturation'),
|
||||||
|
'threshold': require('./modules/Threshold'),
|
||||||
|
'tint': require('./modules/Tint'),
|
||||||
|
'white-balance': require('./modules/WhiteBalance')
|
||||||
}
|
}
|
||||||
60
src/Run.js
60
src/Run.js
@@ -5,9 +5,8 @@ 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) {
|
||||||
var image = drawarray[pos - 1].image;
|
if (ref.objTypeOf(callback) == "Function" && ref.steps.slice(-1)[0].output) {
|
||||||
if (ref.objTypeOf(callback) == "Function" && ref.images[image].steps.slice(-1)[0].output) {
|
var steps = ref.steps;
|
||||||
var steps = ref.images[image].steps;
|
|
||||||
var out = steps[steps.length - 1].output.src;
|
var out = steps[steps.length - 1].output.src;
|
||||||
callback(out);
|
callback(out);
|
||||||
return true;
|
return true;
|
||||||
@@ -16,39 +15,39 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
|
|
||||||
// so we don't run on the loadImage module:
|
// so we don't run on the loadImage module:
|
||||||
if (drawarray[pos] !== undefined) {
|
if (drawarray[pos] !== undefined) {
|
||||||
var image = drawarray[pos].image;
|
|
||||||
var i = drawarray[pos].i;
|
var i = drawarray[pos].i;
|
||||||
var input = ref.images[image].steps[i - 1].output;
|
var input = ref.steps[i - 1].output;
|
||||||
|
var step = ref.steps[i];
|
||||||
|
|
||||||
ref.images[image].steps[i].getStep = function getStep(offset) {
|
step.getStep = function getStep(offset) {
|
||||||
if (i + offset >= ref.images[image].steps.length) return { options: { name: undefined } };
|
if (i + offset >= ref.steps.length) return { options: { name: undefined } };
|
||||||
else return ref.images[image].steps.slice(i + offset)[0];
|
else return ref.steps.slice(i + offset)[0];
|
||||||
};
|
};
|
||||||
ref.images[image].steps[i].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)) {
|
||||||
ref.images[image].steps[i][util] = getStepUtils[util];
|
step[util] = getStepUtils[util];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell UI that a step is being drawn.
|
// Tell UI that a step is being drawn.
|
||||||
ref.images[image].steps[i].UI.onDraw(ref.images[image].steps[i].options.step);
|
step.UI.onDraw(step.options.step);
|
||||||
|
|
||||||
// provides a set of standard tools for each step
|
// provides a set of standard tools for each step
|
||||||
var inputForNextStep = require('./RunToolkit')(ref.copy(input));
|
var inputForNextStep = require('./RunToolkit')(ref.copy(input));
|
||||||
|
|
||||||
ref.images[image].steps[i].draw(
|
step.draw(
|
||||||
inputForNextStep,
|
inputForNextStep,
|
||||||
function onEachStep() {
|
function onEachStep() {
|
||||||
|
|
||||||
// This output is accessible by UI
|
// This output is accessible by UI
|
||||||
ref.images[image].steps[i].options.step.output = ref.images[image].steps[i].output.src;
|
ref.steps[i].options.step.output = ref.steps[i].output.src;
|
||||||
|
|
||||||
// Tell UI that step has been drawn.
|
// Tell UI that step has been drawn.
|
||||||
ref.images[image].steps[i].UI.onComplete(ref.images[image].steps[i].options.step);
|
ref.steps[i].UI.onComplete(ref.steps[i].options.step);
|
||||||
|
|
||||||
drawStep(drawarray, ++pos);
|
drawStep(drawarray, ++pos);
|
||||||
},
|
},
|
||||||
@@ -58,36 +57,33 @@ function Run(ref, json_q, callback, ind, progressObj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function drawSteps(json_q) {
|
function drawSteps(json_q) {
|
||||||
var drawarray = [];
|
var drawarray = [],
|
||||||
for (var image in json_q) {
|
no_steps = ref.steps.length,
|
||||||
var no_steps = ref.images[image].steps.length;
|
init = json_q[0];
|
||||||
var init = json_q[image];
|
|
||||||
for (var i = 0; i < no_steps - init; i++) {
|
for (var i = 0; i < no_steps - init; i++) {
|
||||||
drawarray.push({ image: image, i: init + i });
|
drawarray.push({i: init + i });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
drawStep(drawarray, ind);
|
drawStep(drawarray, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(json_q) {
|
function filter(json_q) {
|
||||||
for (var image in json_q) {
|
|
||||||
if (json_q[image] == 0 && ref.images[image].steps.length == 1)
|
if (json_q[0] == 0 && ref.steps.length == 1)
|
||||||
delete json_q[image];
|
delete json_q[0];
|
||||||
else if (json_q[image] == 0) json_q[image]++;
|
else if (json_q[0] == 0) json_q[0]++;
|
||||||
}
|
var prevstep = ref.steps[json_q[0] - 1];
|
||||||
for (var image in json_q) {
|
|
||||||
var prevstep = ref.images[image].steps[json_q[image] - 1];
|
|
||||||
while (
|
while (
|
||||||
typeof prevstep == "undefined" ||
|
typeof prevstep == "undefined" ||
|
||||||
typeof prevstep.output == "undefined"
|
typeof prevstep.output == "undefined"
|
||||||
) {
|
) {
|
||||||
prevstep = ref.images[image].steps[--json_q[image] - 1];
|
prevstep = ref.steps[--json_q[0] - 1];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return json_q;
|
return json_q;
|
||||||
}
|
}
|
||||||
|
|
||||||
var json_q = filter(json_q);
|
var json_q = filter(json_q);
|
||||||
|
|
||||||
return drawSteps(json_q);
|
return drawSteps(json_q);
|
||||||
}
|
}
|
||||||
module.exports = Run;
|
module.exports = Run;
|
||||||
|
|||||||
17
src/cli/installModule.js
Normal file
17
src/cli/installModule.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
var childProcess = require('child_process')
|
||||||
|
var Spinner = require('ora');
|
||||||
|
|
||||||
|
module.exports = function (program, sequencer) {
|
||||||
|
console.log(
|
||||||
|
"\x1b[33m%s\x1b[0m",
|
||||||
|
"Please wait while your Module is being Installed...\nThis may take a while!"
|
||||||
|
);
|
||||||
|
|
||||||
|
var params = program.installModule.split(' ');
|
||||||
|
var spinner = Spinner("Now Installing...").start();
|
||||||
|
childProcess.execSync(`npm i ${params[1]}`)
|
||||||
|
sequencer.saveNewModule(params[0], params[1]);
|
||||||
|
sequencer.loadNewModule(params[0], require(params[1]));
|
||||||
|
spinner.stop();
|
||||||
|
console.log("\x1b[32m%s\x1b[0m", "Your module was installed successfully!!");
|
||||||
|
}
|
||||||
7
src/cli/saveSequence.js
Normal file
7
src/cli/saveSequence.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = function (program, sequencer) {
|
||||||
|
|
||||||
|
var params = program.saveSequence.split(' ');
|
||||||
|
sequencer.saveSequence(params[0], params[1]);
|
||||||
|
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||||
|
|
||||||
|
}
|
||||||
88
src/cli/sequencerSteps.js
Normal file
88
src/cli/sequencerSteps.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
var Spinner = require('ora');
|
||||||
|
var readlineSync = require('readline-sync');
|
||||||
|
var utils = require('../CliUtils')
|
||||||
|
|
||||||
|
module.exports = function (program, sequencer, outputFilename) {
|
||||||
|
utils.makedir(program.output, () => {
|
||||||
|
console.log('Files will be exported to "' + program.output + '"');
|
||||||
|
|
||||||
|
if (program.basic)
|
||||||
|
console.log("Basic mode is enabled, outputting only final image");
|
||||||
|
|
||||||
|
// Iterate through the steps and retrieve their inputs.
|
||||||
|
program.step.forEach(function(step) {
|
||||||
|
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
||||||
|
|
||||||
|
// If inputs exists, print to console.
|
||||||
|
if (Object.keys(options).length) {
|
||||||
|
console.log("[" + step + "]: Inputs");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If inputs exists, print them out with descriptions.
|
||||||
|
Object.keys(options).forEach(function(input) {
|
||||||
|
// The array below creates a variable number of spaces. This is done with (length + 1).
|
||||||
|
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||||
|
console.log(
|
||||||
|
new Array(step.length + 5).join(" ") +
|
||||||
|
input +
|
||||||
|
": " +
|
||||||
|
options[input].desc
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (program.config) {
|
||||||
|
try {
|
||||||
|
var config = JSON.parse(program.config);
|
||||||
|
console.log(`The parsed options object: `, config);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
"\x1b[31m%s\x1b[0m",
|
||||||
|
`Options(Config) is not a not valid JSON Fallback activate`
|
||||||
|
);
|
||||||
|
program.config = false;
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (program.config && utils.validateConfig(config, options)) {
|
||||||
|
console.log("Now using Options object");
|
||||||
|
Object.keys(options).forEach(function(input) {
|
||||||
|
options[input] = config[input];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If inputs exist, iterate through them and prompt for values.
|
||||||
|
Object.keys(options).forEach(function(input) {
|
||||||
|
var value = readlineSync.question(
|
||||||
|
"[" +
|
||||||
|
step +
|
||||||
|
"]: Enter a value for " +
|
||||||
|
input +
|
||||||
|
" (" +
|
||||||
|
options[input].type +
|
||||||
|
", default: " +
|
||||||
|
options[input].default +
|
||||||
|
"): "
|
||||||
|
);
|
||||||
|
options[input] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Add the step and its inputs to the sequencer.
|
||||||
|
sequencer.addSteps(step, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||||
|
if (!process.env.TEST)
|
||||||
|
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||||
|
|
||||||
|
// Run the sequencer.
|
||||||
|
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||||
|
// Export all images or final image as binary files.
|
||||||
|
sequencer.exportBin(program.output, program.basic, outputFilename);
|
||||||
|
|
||||||
|
//check if spinner was not overriden stop it
|
||||||
|
if (!spinnerObj.overrideFlag) {
|
||||||
|
spinnerObj.succeed();
|
||||||
|
console.log(`\nDone!!`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
51
src/modules/AddQR/Module.js
Normal file
51
src/modules/AddQR/Module.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
module.exports = function AddQR(options, UI) {
|
||||||
|
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
options.size = options.size || defaults.size;
|
||||||
|
options.qrCodeString = options.qrCodeString || "https://github.com/publiclab/image-sequencer";
|
||||||
|
var output;
|
||||||
|
getPixels = require('get-pixels');
|
||||||
|
|
||||||
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
|
||||||
|
return getPixels(input.src, function (err, oldPixels) {
|
||||||
|
function changePixel(r, g, b, a) {
|
||||||
|
return [r, g, b, a];
|
||||||
|
}
|
||||||
|
|
||||||
|
function extraManipulation(pixels,generateOutput) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
require('./QR')(options, pixels, oldPixels, generateOutput);
|
||||||
|
}
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
changePixel: changePixel,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
inBrowser: options.inBrowser,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/modules/AddQR/QR.js
Normal file
48
src/modules/AddQR/QR.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
module.exports = exports = function (options, pixels, oldPixels, callback) {
|
||||||
|
var QRCode = require('qrcode')
|
||||||
|
QRCode.toDataURL(options.qrCodeString, function (err, url) {
|
||||||
|
var getPixels = require("get-pixels");
|
||||||
|
getPixels(url, function (err, qrPixels) {
|
||||||
|
if (err) {
|
||||||
|
console.log("Bad image path", image);
|
||||||
|
}
|
||||||
|
|
||||||
|
var imagejs = require('imagejs');
|
||||||
|
var bitmap = new imagejs.Bitmap({ width: qrPixels.shape[0], height: qrPixels.shape[1] });
|
||||||
|
bitmap._data.data = qrPixels.data;
|
||||||
|
var resized = bitmap.resize({
|
||||||
|
width: options.size, height: options.size,
|
||||||
|
algorithm: "bicubicInterpolation"
|
||||||
|
});
|
||||||
|
|
||||||
|
qrPixels.data = resized._data.data;
|
||||||
|
qrPixels.shape = [options.size, options.size, 4];
|
||||||
|
qrPixels.stride[1] = 4 * options.size;
|
||||||
|
|
||||||
|
var width = oldPixels.shape[0],
|
||||||
|
height = oldPixels.shape[1];
|
||||||
|
var xe = width - options.size,
|
||||||
|
ye = height - options.size;
|
||||||
|
for (var m = 0; m < width; m++) {
|
||||||
|
for (var n = 0; n < height; n++) {
|
||||||
|
if (m >= xe && n >= ye) {
|
||||||
|
pixels.set(m, n, 0, qrPixels.get(m - xe, n - ye, 0))
|
||||||
|
pixels.set(m, n, 1, qrPixels.get(m - xe, n - ye, 1))
|
||||||
|
pixels.set(m, n, 2, qrPixels.get(m - xe, n - ye, 2))
|
||||||
|
pixels.set(m, n, 3, qrPixels.get(m - xe, n - ye, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
pixels.set(m, n, 0, oldPixels.get(m, n, 0))
|
||||||
|
pixels.set(m, n, 1, oldPixels.get(m, n, 1))
|
||||||
|
pixels.set(m, n, 2, oldPixels.get(m, n, 2))
|
||||||
|
pixels.set(m, n, 3, oldPixels.get(m, n, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
4
src/modules/AddQR/index.js
Normal file
4
src/modules/AddQR/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
require('./info.json')
|
||||||
|
]
|
||||||
19
src/modules/AddQR/info.json
Normal file
19
src/modules/AddQR/info.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "Add QR",
|
||||||
|
"description": "Adds QR corresponding to the given string",
|
||||||
|
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||||
|
"inputs": {
|
||||||
|
"size": {
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "size of QR code in pixels",
|
||||||
|
"default": 200
|
||||||
|
},
|
||||||
|
"qrCodeString":{
|
||||||
|
"type": "string",
|
||||||
|
"desc": "input string to generate QR code",
|
||||||
|
"default": "https://github.com/publiclab/image-sequencer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#add-qr-module"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,65 +1,63 @@
|
|||||||
/*
|
/*
|
||||||
* Average all pixel colors
|
* Average all pixel colors
|
||||||
*/
|
*/
|
||||||
module.exports = function Average(options, UI){
|
module.exports = function Average(options, UI) {
|
||||||
|
|
||||||
options.blur = options.blur || 2
|
|
||||||
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;
|
||||||
|
|
||||||
function changePixel(r, g, b, a){
|
|
||||||
return [r,g,b,a]
|
|
||||||
}
|
|
||||||
|
|
||||||
// do the averaging
|
// do the averaging
|
||||||
function extraManipulation(pixels){
|
function extraManipulation(pixels) {
|
||||||
var sum = [0,0,0,0];
|
var i = 0, sum = [0, 0, 0, 0];
|
||||||
for (var i = 0; i < pixels.data.length; i += 4) {
|
while (i < pixels.data.length) {
|
||||||
sum[0] += pixels.data[i + 0];
|
sum[0] += pixels.data[i++];
|
||||||
sum[1] += pixels.data[i + 1];
|
sum[1] += pixels.data[i++];
|
||||||
sum[2] += pixels.data[i + 2];
|
sum[2] += pixels.data[i++];
|
||||||
sum[3] += pixels.data[i + 3];
|
sum[3] += pixels.data[i++];
|
||||||
}
|
}
|
||||||
|
|
||||||
sum[0] = parseInt(sum[0] / (pixels.data.length / 4));
|
let divisor = pixels.data.length / 4;
|
||||||
sum[1] = parseInt(sum[1] / (pixels.data.length / 4));
|
|
||||||
sum[2] = parseInt(sum[2] / (pixels.data.length / 4));
|
|
||||||
sum[3] = parseInt(sum[3] / (pixels.data.length / 4));
|
|
||||||
|
|
||||||
for (var i = 0; i < pixels.data.length; i += 4) {
|
sum[0] = Math.floor(sum[0] / divisor);
|
||||||
pixels.data[i + 0] = sum[0];
|
sum[1] = Math.floor(sum[1] / divisor);
|
||||||
pixels.data[i + 1] = sum[1];
|
sum[2] = Math.floor(sum[2] / divisor);
|
||||||
pixels.data[i + 2] = sum[2];
|
sum[3] = Math.floor(sum[3] / divisor);
|
||||||
pixels.data[i + 3] = sum[3];
|
|
||||||
|
i = 0
|
||||||
|
while (i < pixels.data.length) {
|
||||||
|
pixels.data[i++] = sum[0];
|
||||||
|
pixels.data[i++] = sum[1];
|
||||||
|
pixels.data[i++] = sum[2];
|
||||||
|
pixels.data[i++] = sum[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
// report back and store average in metadata:
|
// report back and store average in metadata:
|
||||||
options.step.metadata.averages = sum;
|
options.step.metadata.averages = sum;
|
||||||
console.log("average: ", sum);
|
|
||||||
// TODO: refactor into a new "display()" method as per https://github.com/publiclab/image-sequencer/issues/242
|
// 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>");
|
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;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image, datauri, mimetype){
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
// This output is accessible by Image Sequencer
|
// This output is accessible by Image Sequencer
|
||||||
step.output = {
|
step.output = {
|
||||||
src: datauri,
|
src: datauri,
|
||||||
format: mimetype
|
format: mimetype
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
output: output,
|
output: output,
|
||||||
changePixel: changePixel,
|
|
||||||
extraManipulation: extraManipulation,
|
extraManipulation: extraManipulation,
|
||||||
format: input.format,
|
format: input.format,
|
||||||
image: options.image,
|
image: options.image,
|
||||||
@@ -69,7 +67,7 @@ module.exports = function Average(options, UI){
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
options: options,
|
options: options,
|
||||||
draw: draw,
|
draw: draw,
|
||||||
output: output,
|
output: output,
|
||||||
UI: UI
|
UI: UI
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
"name": "Average",
|
"name": "Average",
|
||||||
"description": "Average all pixel color",
|
"description": "Average all pixel color",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#average-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,75 @@
|
|||||||
module.exports = function Dynamic(options, UI, util) {
|
module.exports = function Dynamic(options, UI, util) {
|
||||||
|
|
||||||
options.func = options.func || "function(r1, g1, b1, a1, r2, g2, b2, a2) { return [ r1, g2, b2, a2 ] }";
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
|
||||||
var output;
|
options.func = options.func || defaults.blend;
|
||||||
|
options.offset = options.offset || defaults.offset;
|
||||||
|
|
||||||
// This function is called on every draw.
|
var output;
|
||||||
function draw(input, callback, progressObj) {
|
|
||||||
|
|
||||||
progressObj.stop(true);
|
// This function is called on every draw.
|
||||||
progressObj.overrideFlag = true;
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
var step = this;
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
// convert to runnable code:
|
var step = this;
|
||||||
if (typeof options.func === "string") eval('options.func = ' + options.func);
|
|
||||||
|
|
||||||
var getPixels = require('get-pixels');
|
// convert to runnable code:
|
||||||
|
if (typeof options.func === "string") eval('options.func = ' + options.func);
|
||||||
|
|
||||||
// save first image's pixels
|
var getPixels = require('get-pixels');
|
||||||
var priorStep = this.getStep(-2);
|
|
||||||
|
|
||||||
getPixels(priorStep.output.src, function(err, pixels) {
|
// convert offset as string to int
|
||||||
options.firstImagePixels = pixels;
|
if (typeof options.offset === "string") options.offset = parseInt(options.offset);
|
||||||
|
|
||||||
function changePixel(r2, g2, b2, a2, x, y) {
|
// save first image's pixels
|
||||||
// blend!
|
var priorStep = this.getStep(options.offset);
|
||||||
var p = options.firstImagePixels;
|
|
||||||
return options.func(
|
|
||||||
r2, g2, b2, a2,
|
|
||||||
p.get(x, y, 0),
|
|
||||||
p.get(x, y, 1),
|
|
||||||
p.get(x, y, 2),
|
|
||||||
p.get(x, y, 3)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function output(image, datauri, mimetype) {
|
if (priorStep.output === undefined) {
|
||||||
|
this.output = input;
|
||||||
|
UI.notify('Offset Unavailable', 'offset-notification');
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
// This output is accessible by Image Sequencer
|
getPixels(priorStep.output.src, function(err, pixels) {
|
||||||
step.output = { src: datauri, format: mimetype };
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// run PixelManipulatin on second image's pixels
|
function output(image, datauri, mimetype) {
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
|
||||||
|
// 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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
output: output,
|
output: output,
|
||||||
changePixel: changePixel,
|
UI: UI
|
||||||
format: input.format,
|
}
|
||||||
image: options.image,
|
|
||||||
inBrowser: options.inBrowser,
|
|
||||||
callback: callback
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
options: options,
|
|
||||||
draw: draw,
|
|
||||||
output: output,
|
|
||||||
UI: UI
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "Blend",
|
"name": "Blend",
|
||||||
"description": "Blend the past two image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
|
"description": "Blend two chosen image steps with the given function. Defaults to using the red channel from image 1 and the green and blue and alpha channels of image 2. Easier to use interfaces coming soon!",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"offset": {
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "Choose which image to blend the current image with. Two steps back is -2, three steps back is -3 etc.",
|
||||||
|
"default": -2
|
||||||
|
},
|
||||||
"blend": {
|
"blend": {
|
||||||
"type": "input",
|
"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) { return [ r1, 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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
module.exports = exports = function(pixels, blur) {
|
module.exports = exports = function(pixels, blur) {
|
||||||
let kernel = kernelGenerator(blur, 1), oldpix = pixels;
|
let kernel = kernelGenerator(blur, 1), oldpix = require('lodash').cloneDeep(pixels);
|
||||||
kernel = flipKernel(kernel);
|
kernel = flipKernel(kernel);
|
||||||
|
|
||||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function Blur(options, UI) {
|
module.exports = function Blur(options, UI) {
|
||||||
|
|
||||||
options.blur = options.blur || 2
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
options.blur = options.blur || defaults.blur;
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
function draw(input, callback, progressObj) {
|
function draw(input, callback, progressObj) {
|
||||||
@@ -13,13 +14,9 @@ module.exports = function Blur(options, UI) {
|
|||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
function changePixel(r, g, b, a) {
|
|
||||||
return [r, g, b, a]
|
|
||||||
}
|
|
||||||
|
|
||||||
function extraManipulation(pixels) {
|
function extraManipulation(pixels) {
|
||||||
pixels = require('./Blur')(pixels, options.blur)
|
pixels = require('./Blur')(pixels, options.blur);
|
||||||
return pixels
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image, datauri, mimetype) {
|
function output(image, datauri, mimetype) {
|
||||||
@@ -31,7 +28,6 @@ module.exports = function Blur(options, UI) {
|
|||||||
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
output: output,
|
output: output,
|
||||||
changePixel: changePixel,
|
|
||||||
extraManipulation: extraManipulation,
|
extraManipulation: extraManipulation,
|
||||||
format: input.format,
|
format: input.format,
|
||||||
image: options.image,
|
image: options.image,
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "Blur",
|
"name": "Blur",
|
||||||
"description": "Gaussian blur an image by a given value, typically 0-5",
|
"description": "Applies a Gaussian blur given by the intensity value",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"blur": {
|
"blur": {
|
||||||
"type": "integer",
|
"type": "float",
|
||||||
"desc": "amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||||
"default": 2
|
"default": 2,
|
||||||
|
"min": 0,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.25
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#blur-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Changes the Image Brightness
|
* Changes the Image Brightness
|
||||||
*/
|
*/
|
||||||
|
module.exports = function Brightness(options, UI) {
|
||||||
|
|
||||||
module.exports = function Brightness(options,UI){
|
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;
|
||||||
|
|
||||||
progressObj.stop(true);
|
progressObj.stop(true);
|
||||||
progressObj.overrideFlag = true;
|
progressObj.overrideFlag = true;
|
||||||
@@ -17,21 +21,20 @@ module.exports = function Brightness(options,UI){
|
|||||||
For eg. progressObj = new SomeProgressModule()
|
For eg. progressObj = new SomeProgressModule()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var step = this;
|
var step = this, val = (options.brightness) / 100.0;;
|
||||||
|
|
||||||
function changePixel(r, g, b, a){
|
function changePixel(r, g, b, a) {
|
||||||
var val = (options.brightness)/100.0
|
|
||||||
|
|
||||||
r = val*r<255?val*r:255
|
r = Math.min(val * r, 255);
|
||||||
g = val*g<255?val*g:255
|
g = Math.min(val * g, 255);
|
||||||
b = val*b<255?val*b:255
|
b = Math.min(val * b, 255);
|
||||||
return [r , g, b, a]
|
return [r, g, b, a];
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image,datauri,mimetype){
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
// This output is accessible by Image Sequencer
|
// This output is accessible by Image Sequencer
|
||||||
step.output = {src:datauri,format:mimetype};
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +50,7 @@ module.exports = function Brightness(options,UI){
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
options: options,
|
options: options,
|
||||||
draw: draw,
|
draw: draw,
|
||||||
output: output,
|
output: output,
|
||||||
UI: UI
|
UI: UI
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"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": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"desc": "% brightness for the new image",
|
"desc": "% brightness for the new image",
|
||||||
"default": 0
|
"default": "175",
|
||||||
}
|
"min": "0",
|
||||||
}
|
"max": "200"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#brightness-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
module.exports = function Channel(options, UI) {
|
module.exports = function Channel(options, UI) {
|
||||||
|
|
||||||
options.channel = options.channel || "green";
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
|
||||||
|
options.channel = options.channel || defaults.channel;
|
||||||
|
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
@@ -15,9 +17,9 @@ 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) {
|
function output(image, datauri, mimetype) {
|
||||||
|
|||||||
@@ -8,5 +8,6 @@
|
|||||||
"default": "green",
|
"default": "green",
|
||||||
"values": ["red", "green", "blue"]
|
"values": ["red", "green", "blue"]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#channel-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
module.exports = function NdviColormapfunction(options, UI) {
|
module.exports = require('../../util/createMetaModule.js')(
|
||||||
|
function mapFunction(options) {
|
||||||
|
|
||||||
options.x = options.x || 0;
|
// return steps with options:
|
||||||
options.y = options.y || 0;
|
return [
|
||||||
options.colormap = options.colormap || "default";
|
{ 'name': 'gradient', 'options': {} },
|
||||||
options.h = options.h || 10;
|
{ 'name': 'colormap', 'options': { colormap: options.colormap } },
|
||||||
this.expandSteps([
|
{ 'name': 'crop', 'options': { 'y': 0, 'h': options.h } },
|
||||||
{ 'name': 'gradient', 'options': {} },
|
{ 'name': 'overlay', 'options': { 'x': options.x, 'y': options.y, 'offset': -4 } }
|
||||||
{ 'name': 'colormap', 'options': { colormap: options.colormap } },
|
];
|
||||||
{ 'name': 'crop', 'options': { 'y': 0, 'h': options.h } },
|
}, {
|
||||||
{ 'name': 'overlay', 'options': { 'x': options.x, 'y': options.y, 'offset': -4 } }
|
infoJson: require('./info.json')
|
||||||
]);
|
}
|
||||||
return {
|
)[0];
|
||||||
isMeta: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,10 +24,10 @@
|
|||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
"h": {
|
"h": {
|
||||||
"type": "iinteger",
|
"type": "integer",
|
||||||
"desc": "height of the colorbar",
|
"desc": "height of the colorbar",
|
||||||
"default": 10
|
"default": 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"length": 4
|
"docs-link": "https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#colorbar-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,32 +56,142 @@ var colormaps = {
|
|||||||
[0, [0, 0, 0], [255, 255, 255] ],
|
[0, [0, 0, 0], [255, 255, 255] ],
|
||||||
[1, [255, 255, 255], [255, 255, 255] ]
|
[1, [255, 255, 255], [255, 255, 255] ]
|
||||||
]),
|
]),
|
||||||
default: colormap([
|
|
||||||
[0, [0, 0, 255], [0, 255, 0] ],
|
bluwhtgrngis: colormap([
|
||||||
[0.25, [0, 255, 0], [255, 255, 0] ],
|
[0, [6,23,86], [6,25, 84] ],
|
||||||
[0.50, [0, 255, 255], [255, 255, 0] ],
|
[0.0625, [6,25,84], [6,25, 84] ],//1
|
||||||
[0.75, [255, 255, 0], [255, 0, 0] ]
|
[0.125, [6,25,84], [6,25, 84] ],//2
|
||||||
|
[0.1875, [6,25,84], [6,25, 84] ],
|
||||||
|
[0.25, [6,25,84], [6,25,84] ],
|
||||||
|
[0.3125, [6,25,84], [9,24, 84] ],//5
|
||||||
|
[0.3438, [9,24, 84], [119,120,162] ],//5
|
||||||
|
[0.375, [119,129,162],[249,250,251] ], //6
|
||||||
|
[0.406, [249,250,251],[255,255,255] ], //6.5
|
||||||
|
[0.4375, [255,255,255],[255,255,255] ], //7 white
|
||||||
|
[0.50, [255,255,255],[214,205,191] ],//8
|
||||||
|
[0.52, [214,205,191],[178,175,96] ],//8.2
|
||||||
|
[0.5625, [178,175,96], [151,176,53] ],//9
|
||||||
|
[0.593, [151,176,53], [146,188,12] ],//9.5
|
||||||
|
[0.625, [146,188,12], [96,161,1] ], //10
|
||||||
|
[0.6875, [96,161,1], [30,127,3] ],//11
|
||||||
|
[0.75, [30,127,3], [0,99,1] ],//12
|
||||||
|
[0.8125, [0,99,1], [0,74,1] ],//13
|
||||||
|
[0.875, [0,74,1], [0,52, 0] ],//14
|
||||||
|
[0.9375, [0,52, 0], [0,34,0] ], //15
|
||||||
|
[0.968, [0,34,0], [68,70,67] ] //16
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
brntogrn: colormap([
|
||||||
|
[0, [110,12,3], [118,6,1] ],
|
||||||
|
[0.0625, [118,6,1], [141,19,6] ],
|
||||||
|
[0.125, [141,19,6], [165,35,13] ],
|
||||||
|
[0.1875, [165,35,13], [177,59,25] ],
|
||||||
|
[0.2188, [177,59,25], [192,91,36] ],
|
||||||
|
[0.25, [192,91,36], [214, 145, 76] ],
|
||||||
|
[0.3125, [214,145,76], [230,183,134] ],
|
||||||
|
[0.375, [230,183,134],[243, 224, 194]],
|
||||||
|
[0.4375, [243,224,194],[250,252,229] ],
|
||||||
|
[0.50, [250,252,229],[217,235,185] ],
|
||||||
|
[0.5625, [217,235,185],[184,218,143] ],
|
||||||
|
[0.625, [184,218,143],[141,202,89] ],
|
||||||
|
[0.6875, [141,202,89], [80,176,61] ],
|
||||||
|
[0.75, [80,176,61], [0, 147, 32] ],
|
||||||
|
[0.8125, [0,147,32], [1, 122, 22] ],
|
||||||
|
[0.875, [1,122,22], [0, 114, 19] ],
|
||||||
|
[0.90, [0,114,19], [0,105,18] ],
|
||||||
|
[0.9375, [0,105,18], [7,70,14] ]
|
||||||
|
|
||||||
]),
|
]),
|
||||||
ndvi: colormap([
|
|
||||||
[0, [0, 0, 255], [38, 195, 195] ],
|
|
||||||
[0.5, [0, 150, 0], [255, 255, 0] ],
|
blutoredjet: colormap([
|
||||||
[0.75, [255, 255, 0], [255, 50, 50] ]
|
[0, [0,0,140], [1,1,186] ],
|
||||||
|
[0.0625, [1,1,186], [0,1,248] ],
|
||||||
|
[0.125, [0,1,248], [0,70,254] ],
|
||||||
|
[0.1875, [0,70,254], [0,130,255] ],
|
||||||
|
[0.25, [0,130,255], [2,160,255] ],
|
||||||
|
[0.2813, [2,160,255], [0,187,255] ], //inset
|
||||||
|
[0.3125, [0,187,255], [6,250,255] ],
|
||||||
|
// [0.348, [0,218,255], [8,252,251] ],//inset
|
||||||
|
[0.375, [8,252,251], [27,254,228] ],
|
||||||
|
[0.406, [27,254,228], [70,255,187] ], //insert
|
||||||
|
[0.4375, [70,255,187], [104,254,151]],
|
||||||
|
[0.47, [104,254,151],[132,255,19] ],//insert
|
||||||
|
[0.50, [132,255,19], [195,255,60] ],
|
||||||
|
[0.5625, [195,255,60], [231,254,25] ],
|
||||||
|
[0.5976, [231,254,25], [253,246,1] ],//insert
|
||||||
|
[0.625, [253,246,1], [252,210,1] ], //yellow
|
||||||
|
[0.657, [252,210,1], [255,183,0] ],//insert
|
||||||
|
[0.6875, [255,183,0], [255,125,2] ],
|
||||||
|
[0.75, [255,125,2], [255,65, 1] ],
|
||||||
|
[0.8125, [255,65, 1], [247, 1, 1] ],
|
||||||
|
[0.875, [247,1,1], [200, 1, 3] ],
|
||||||
|
[0.9375, [200,1,3], [122, 3, 2] ]
|
||||||
|
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
colors16: colormap([
|
||||||
|
[0, [0,0,0], [0,0,0] ],
|
||||||
|
[0.0625, [3,1,172], [3,1,172] ],
|
||||||
|
[0.125, [3,1,222], [3,1, 222] ],
|
||||||
|
[0.1875, [0,111,255], [0,111,255] ],
|
||||||
|
[0.25, [3,172,255], [3,172,255] ],
|
||||||
|
[0.3125, [1,226,255], [1,226,255] ],
|
||||||
|
[0.375, [2,255,0], [2,255,0] ],
|
||||||
|
[0.4375, [198,254,0], [190,254,0] ],
|
||||||
|
[0.50, [252,255,0], [252,255,0] ],
|
||||||
|
[0.5625, [255,223,3], [255,223,3] ],
|
||||||
|
[0.625, [255,143,3], [255,143,3] ],
|
||||||
|
[0.6875, [255,95,3], [255,95,3] ],
|
||||||
|
[0.75, [242,0,1], [242,0,1] ],
|
||||||
|
[0.8125, [245,0,170], [245,0,170] ],
|
||||||
|
[0.875, [223,180,225], [223,180,225] ],
|
||||||
|
[0.9375, [255,255,255], [255,255, 255]]
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
default: colormap([
|
||||||
|
[0, [45,1,121], [25,1,137] ],
|
||||||
|
[0.125, [25,1,137], [0,6,156] ],
|
||||||
|
[0.1875, [0,6,156], [7,41,172] ],
|
||||||
|
[0.25, [7,41,172], [22,84,187] ],
|
||||||
|
[0.3125, [22,84,187], [25,125,194] ],
|
||||||
|
[0.375, [25,125,194], [26,177,197] ],
|
||||||
|
[0.4375, [26,177,197], [23,199,193] ],
|
||||||
|
[0.47, [23,199,193], [25, 200,170] ],
|
||||||
|
[0.50, [25, 200,170], [21,209,27] ],
|
||||||
|
[0.5625, [21,209,27], [108,215,18] ],
|
||||||
|
[0.625, [108,215,18], [166,218,19] ],
|
||||||
|
[0.6875, [166,218,19], [206,221,20] ],
|
||||||
|
[0.75, [206,221,20], [222,213,19 ] ],
|
||||||
|
[0.7813, [222,213,19], [222, 191, 19]],
|
||||||
|
[0.8125, [222, 191, 19], [227,133,17] ],
|
||||||
|
[0.875, [227,133,17], [231,83,16] ],
|
||||||
|
[0.9375, [231,83,16], [220,61,48] ]
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
fastie: colormap([
|
||||||
|
[0, [255, 255, 255], [0, 0, 0] ],
|
||||||
|
[0.167, [0, 0, 0], [255, 255, 255] ],
|
||||||
|
[0.33, [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] ]
|
||||||
|
]),
|
||||||
|
|
||||||
|
|
||||||
stretched: colormap([
|
stretched: colormap([
|
||||||
[0, [0, 0, 255], [0, 0, 255] ],
|
[0, [0, 0, 255], [0, 0, 255] ],
|
||||||
[0.1, [0, 0, 255], [38, 195, 195] ],
|
[0.1, [0, 0, 255], [38, 195, 195] ],
|
||||||
[0.5, [0, 150, 0], [255, 255, 0] ],
|
[0.5, [0, 150, 0], [255, 255, 0] ],
|
||||||
[0.7, [255, 255, 0], [255, 50, 50] ],
|
[0.7, [255, 255, 0], [255, 50, 50] ],
|
||||||
[0.9, [255, 50, 50], [255, 50, 50] ]
|
[0.9, [255, 50, 50], [255, 50, 50] ]
|
||||||
]),
|
|
||||||
fastie: colormap([
|
|
||||||
[0, [255, 255, 255], [0, 0, 0] ],
|
|
||||||
[0.167, [0, 0, 0], [255, 255, 255] ],
|
|
||||||
[0.33, [255, 255, 255], [0, 0, 0] ],
|
|
||||||
[0.5, [0, 0, 0], [140, 140, 255] ],
|
|
||||||
[0.55, [140, 140, 255], [0, 255, 0] ],
|
|
||||||
[0.63, [0, 255, 0], [255, 255, 0] ],
|
|
||||||
[0.75, [255, 255, 0], [255, 0, 0] ],
|
|
||||||
[0.95, [255, 0, 0], [255, 0, 255] ]
|
|
||||||
])
|
])
|
||||||
}
|
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
module.exports = function Colormap(options,UI) {
|
module.exports = function Colormap(options, UI) {
|
||||||
|
|
||||||
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;
|
||||||
@@ -16,7 +16,7 @@ module.exports = function Colormap(options,UI) {
|
|||||||
return [res[0], res[1], res[2], 255];
|
return [res[0], res[1], res[2], 255];
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image,datauri,mimetype){
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
// This output is accessible by Image Sequencer
|
// This output is accessible by Image Sequencer
|
||||||
step.output = { src: datauri, format: mimetype };
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"type": "select",
|
"type": "select",
|
||||||
"desc": "Name of the Colormap",
|
"desc": "Name of the Colormap",
|
||||||
"default": "default",
|
"default": "default",
|
||||||
"values": ["default","greyscale","stretched","fastie"]
|
"values": ["default","greyscale","bluwhtgrngis","stretched","fastie","brntogrn","blutoredjet","colors16"]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#colormap-module"
|
||||||
}
|
}
|
||||||
|
|||||||
47
src/modules/Contrast/Contrast.js
Normal file
47
src/modules/Contrast/Contrast.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
module.exports = exports = function(pixels, contrast) {
|
||||||
|
let oldpix = _.cloneDeep(pixels);
|
||||||
|
contrast = Number(contrast)
|
||||||
|
if (contrast < -100) contrast = -100;
|
||||||
|
if (contrast > 100) contrast = 100;
|
||||||
|
contrast = (100.0 + contrast) / 100.0;
|
||||||
|
contrast *= contrast;
|
||||||
|
|
||||||
|
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||||
|
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||||
|
var r = oldpix.get(i, j, 0) / 255.0;
|
||||||
|
r -= 0.5;
|
||||||
|
r *= contrast;
|
||||||
|
r += 0.5;
|
||||||
|
r *= 255;
|
||||||
|
if (r < 0) r = 0;
|
||||||
|
if (r > 255) r = 255;
|
||||||
|
|
||||||
|
|
||||||
|
var g = oldpix.get(i, j, 1) / 255.0;
|
||||||
|
g -= 0.5;
|
||||||
|
g *= contrast;
|
||||||
|
g += 0.5;
|
||||||
|
g *= 255;
|
||||||
|
if (g < 0) g = 0;
|
||||||
|
if (g > 255) g = 255;
|
||||||
|
|
||||||
|
|
||||||
|
var b = oldpix.get(i, j, 2) / 255.0;
|
||||||
|
b -= 0.5;
|
||||||
|
b *= contrast;
|
||||||
|
b += 0.5;
|
||||||
|
b *= 255;
|
||||||
|
if (b < 0) b = 0;
|
||||||
|
if (b > 255) b = 255;
|
||||||
|
|
||||||
|
|
||||||
|
pixels.set(i, j, 0, r);
|
||||||
|
pixels.set(i, j, 1, g);
|
||||||
|
pixels.set(i, j, 2, b);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
45
src/modules/Contrast/Module.js
Normal file
45
src/modules/Contrast/Module.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// /*
|
||||||
|
// * Changes the Image Contrast
|
||||||
|
// */
|
||||||
|
|
||||||
|
module.exports = function Contrast(options, UI) {
|
||||||
|
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
options.contrast = options.contrast || defaults.contrast;
|
||||||
|
var output;
|
||||||
|
|
||||||
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('./Contrast')(pixels, options.contrast)
|
||||||
|
return pixels
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
|
// This output is accessible by Image Sequencer
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/modules/Contrast/index.js
Normal file
4
src/modules/Contrast/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
require('./info.json')
|
||||||
|
]
|
||||||
14
src/modules/Contrast/info.json
Normal file
14
src/modules/Contrast/info.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Contrast",
|
||||||
|
"description": "Change the contrast of the image by given value",
|
||||||
|
"inputs": {
|
||||||
|
"contrast": {
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "contrast for the new image, typically -100 to 100",
|
||||||
|
"default": 70,
|
||||||
|
"min": -100,
|
||||||
|
"max": 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#contrast-module"
|
||||||
|
}
|
||||||
71
src/modules/Convolution/Convolution.js
Normal file
71
src/modules/Convolution/Convolution.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
var _ = require('lodash');
|
||||||
|
module.exports = exports = function(pixels, constantFactor, kernelValues) {
|
||||||
|
let kernel = kernelGenerator(constantFactor, kernelValues), oldpix = _.cloneDeep(pixels);
|
||||||
|
kernel = flipKernel(kernel);
|
||||||
|
|
||||||
|
for (let i = 0; i < pixels.shape[0]; i++) {
|
||||||
|
for (let j = 0; j < pixels.shape[1]; j++) {
|
||||||
|
let neighboutPos = getNeighbouringPixelPositions([i, j]);
|
||||||
|
let acc = [0.0, 0.0, 0.0, 0.0];
|
||||||
|
for (let a = 0; a < kernel.length; a++) {
|
||||||
|
for (let b = 0; b < kernel.length; b++) {
|
||||||
|
acc[0] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 0) * kernel[a][b]);
|
||||||
|
acc[1] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 1) * kernel[a][b]);
|
||||||
|
acc[2] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 2) * kernel[a][b]);
|
||||||
|
acc[3] += (oldpix.get(neighboutPos[a][b][0], neighboutPos[a][b][1], 3) * kernel[a][b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc[0] = Math.min(acc[0], 255);
|
||||||
|
acc[1] = Math.min(acc[1], 255);
|
||||||
|
acc[2] = Math.min(acc[2], 255);
|
||||||
|
pixels.set(i, j, 0, acc[0]);
|
||||||
|
pixels.set(i, j, 1, acc[1]);
|
||||||
|
pixels.set(i, j, 2, acc[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pixels;
|
||||||
|
|
||||||
|
|
||||||
|
function kernelGenerator(constantFactor, kernelValues) {
|
||||||
|
kernelValues = kernelValues.split(" ");
|
||||||
|
for (i = 0; i < 9; i++) {
|
||||||
|
kernelValues[i] = Number(kernelValues[i]) * constantFactor;
|
||||||
|
}
|
||||||
|
let k = 0;
|
||||||
|
let arr = [];
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
let columns = [];
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
columns.push(kernelValues[k]);
|
||||||
|
k += 1;
|
||||||
|
}
|
||||||
|
arr.push(columns);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNeighbouringPixelPositions(pixelPosition) {
|
||||||
|
let x = pixelPosition[0], y = pixelPosition[1], result = [];
|
||||||
|
|
||||||
|
for (let i = -1; i <= 1; i++) {
|
||||||
|
let arr = [];
|
||||||
|
for (let j = -1; j <= 1; j++)
|
||||||
|
arr.push([x + i, y + j]);
|
||||||
|
|
||||||
|
result.push(arr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flipKernel(kernel) {
|
||||||
|
let result = [];
|
||||||
|
for (let i = kernel.length - 1; i >= 0; i--) {
|
||||||
|
let arr = [];
|
||||||
|
for (let j = kernel[i].length - 1; j >= 0; j--) {
|
||||||
|
arr.push(kernel[i][j]);
|
||||||
|
}
|
||||||
|
result.push(arr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/modules/Convolution/Module.js
Normal file
42
src/modules/Convolution/Module.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
module.exports = function Convolution(options, UI) {
|
||||||
|
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
|
||||||
|
options.kernelValues = options.kernelValues || defaults.kernelValues;
|
||||||
|
options.constantFactor = options.constantFactor || defaults.constantFactor;
|
||||||
|
var output;
|
||||||
|
|
||||||
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('./Convolution')(pixels, options.constantFactor, options.kernelValues);
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/modules/Convolution/index.js
Normal file
4
src/modules/Convolution/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
require('./info.json')
|
||||||
|
]
|
||||||
20
src/modules/Convolution/info.json
Normal file
20
src/modules/Convolution/info.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "Convolution",
|
||||||
|
"description": "Image Convolution using a given 3x3 kernel matrix <a href='https://en.wikipedia.org/wiki/Kernel_(image_processing)'>Read more</a>",
|
||||||
|
"inputs": {
|
||||||
|
"constantFactor":{
|
||||||
|
"type": "float",
|
||||||
|
"desc": "a constant factor, multiplies all the kernel values by that factor",
|
||||||
|
"default": 0.1111,
|
||||||
|
"placeholder": 0.1111
|
||||||
|
},
|
||||||
|
|
||||||
|
"kernelValues": {
|
||||||
|
"type": "string",
|
||||||
|
"desc": "nine space separated numbers representing the kernel values in left to right and top to bottom format.",
|
||||||
|
"default": "1 1 1 1 1 1 1 1 1",
|
||||||
|
"placeholder": "1 1 1 1 1 1 1 1 1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#convolution-module"
|
||||||
|
}
|
||||||
@@ -1,22 +1,33 @@
|
|||||||
module.exports = function Crop(input,options,callback) {
|
module.exports = function Crop(input,options,callback) {
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
var getPixels = require('get-pixels'),
|
var getPixels = require('get-pixels'),
|
||||||
savePixels = require('save-pixels');
|
savePixels = require('save-pixels');
|
||||||
|
|
||||||
options.x = parseInt(options.x) || 0;
|
options.x = parseInt(options.x) || defaults.x;
|
||||||
options.y = parseInt(options.y) || 0;
|
options.y = parseInt(options.y) || defaults.y;
|
||||||
|
|
||||||
getPixels(input.src,function(err,pixels){
|
getPixels(input.src,function(err,pixels){
|
||||||
options.w = parseInt(options.w) || Math.floor(pixels.shape[0]);
|
options.w = parseInt(options.w) || Math.floor(pixels.shape[0]);
|
||||||
options.h = parseInt(options.h) || Math.floor(pixels.shape[1]);
|
options.h = parseInt(options.h) || Math.floor(pixels.shape[1]);
|
||||||
|
options.backgroundColor = options.backgroundColor || defaults.backgroundColor;
|
||||||
var ox = options.x;
|
var ox = options.x;
|
||||||
var oy = options.y;
|
var oy = options.y;
|
||||||
var w = options.w;
|
var w = options.w;
|
||||||
var h = options.h;
|
var h = options.h;
|
||||||
var iw = pixels.shape[0]; //Width of Original Image
|
var iw = pixels.shape[0]; //Width of Original Image
|
||||||
|
var ih = pixels.shape[1]; //Height of Original Image
|
||||||
|
var backgroundArray = [];
|
||||||
|
backgroundColor = options.backgroundColor.split(" ");
|
||||||
|
for(var i = 0; i < w ; i++){
|
||||||
|
backgroundArray = backgroundArray.concat([backgroundColor[0],backgroundColor[1],backgroundColor[2],backgroundColor[3]]);
|
||||||
|
}
|
||||||
var newarray = new Uint8Array(4*w*h);
|
var newarray = new Uint8Array(4*w*h);
|
||||||
for (var n = oy; n < oy + h; n++) {
|
for (var n = oy; n < oy + h; n++) {
|
||||||
|
if(n<ih){
|
||||||
newarray.set(pixels.data.slice(n*4*iw + ox, n*4*iw + ox + 4*w),4*w*(n-oy));
|
newarray.set(pixels.data.slice(n*4*iw + ox, n*4*iw + ox + 4*w),4*w*(n-oy));
|
||||||
|
} else {
|
||||||
|
newarray.set(backgroundArray,4*w*(n-oy));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pixels.data = newarray;
|
pixels.data = newarray;
|
||||||
pixels.shape = [w,h,4];
|
pixels.shape = [w,h,4];
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ module.exports = function CropModule(options, UI) {
|
|||||||
|
|
||||||
// we should get UI to return the image thumbnail so we can attach our own UI extensions
|
// we should get UI to return the image thumbnail so we can attach our own UI extensions
|
||||||
// add our custom in-module html ui:
|
// add our custom in-module html ui:
|
||||||
if (options.step.inBrowser) var ui = require('./Ui.js')(options.step, UI);
|
if (options.step.inBrowser && !options.noUI) var ui = require('./Ui.js')(options.step, UI);
|
||||||
var output,
|
var output,
|
||||||
setupComplete = false;
|
setupComplete = false;
|
||||||
|
|
||||||
// This function is caled everytime the step has to be redrawn
|
// This function is caled everytime the step has to be redrawn
|
||||||
function draw(input,callback) {
|
function draw(input,callback) {
|
||||||
@@ -29,8 +29,23 @@ module.exports = function CropModule(options, UI) {
|
|||||||
// save the input image;
|
// save the input image;
|
||||||
// TODO: this should be moved to module API to persist the input image
|
// TODO: this should be moved to module API to persist the input image
|
||||||
options.step.input = input.src;
|
options.step.input = input.src;
|
||||||
|
var parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
|
||||||
|
|
||||||
require('./Crop')(input, options, function(out, format){
|
//parse the inputs
|
||||||
|
parseCornerCoordinateInputs(options,{
|
||||||
|
src: input.src,
|
||||||
|
x: { valInp: options.x, type: 'horizontal' },
|
||||||
|
y: { valInp: options.y, type: 'vertical' },
|
||||||
|
w: { valInp: options.w, type: 'horizontal' },
|
||||||
|
h: { valInp: options.h, type: 'vertical' },
|
||||||
|
}, function (options, coord) {
|
||||||
|
options.x = parseInt(coord.x.valInp);
|
||||||
|
options.y = parseInt(coord.y.valInp);
|
||||||
|
options.w = coord.w.valInp;
|
||||||
|
options.h = coord.h.valInp;
|
||||||
|
});
|
||||||
|
|
||||||
|
require('./Crop')(input, options, function (out, format) {
|
||||||
|
|
||||||
// This output is accessible to Image Sequencer
|
// This output is accessible to Image Sequencer
|
||||||
step.output = {
|
step.output = {
|
||||||
@@ -49,7 +64,7 @@ module.exports = function CropModule(options, UI) {
|
|||||||
|
|
||||||
// start custom UI setup (draggable UI)
|
// start custom UI setup (draggable UI)
|
||||||
// only once we have an input image
|
// only once we have an input image
|
||||||
if (setupComplete === false && options.step.inBrowser) {
|
if (setupComplete === false && options.step.inBrowser && !options.noUI) {
|
||||||
setupComplete = true;
|
setupComplete = true;
|
||||||
ui.setup();
|
ui.setup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Crop",
|
"name": "Crop",
|
||||||
"description": "Crop image to given x, y, w, h in pixels, measured from top left",
|
"description": "Crop image to given x, y, w, h in pixels or % , measured from top left",
|
||||||
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"x": {
|
"x": {
|
||||||
@@ -16,12 +16,19 @@
|
|||||||
"w": {
|
"w": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"desc": "Width of crop",
|
"desc": "Width of crop",
|
||||||
"default": "(100%)"
|
"default": "(50%)"
|
||||||
},
|
},
|
||||||
"h": {
|
"h": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"desc": "Height of crop",
|
"desc": "Height of crop",
|
||||||
"default": "(100%)"
|
"default": "(50%)"
|
||||||
|
},
|
||||||
|
"backgroundColor": {
|
||||||
|
"type": "string",
|
||||||
|
"desc": "Background Color (Four space separated RGBA values)",
|
||||||
|
"default": "255 255 255 255",
|
||||||
|
"placeholder": "255 255 255 255"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#crop-module"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ module.exports = function DoNothing(options,UI) {
|
|||||||
var getPixels = require('get-pixels');
|
var getPixels = require('get-pixels');
|
||||||
|
|
||||||
// This function is called everytime a step has to be redrawn
|
// This function is called everytime a step has to be redrawn
|
||||||
function draw(input,callback) {
|
function draw(input,callback,progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
@@ -18,16 +21,25 @@ module.exports = function DoNothing(options,UI) {
|
|||||||
|
|
||||||
var w = pixels.shape[0];
|
var w = pixels.shape[0];
|
||||||
var h = pixels.shape[1];
|
var h = pixels.shape[1];
|
||||||
var decoded = jsQR.decodeQRFromImage(pixels.data,w,h);
|
var decoded = jsQR(pixels.data,w,h);
|
||||||
|
|
||||||
// This output is accessible to Image Sequencer
|
|
||||||
step.output = input;
|
|
||||||
step.output.data = decoded;
|
|
||||||
|
|
||||||
// Tell Image Sequencer that this step is complete
|
// Tell Image Sequencer that this step is complete
|
||||||
callback();
|
options.step.qrval = (decoded)?decoded.data:"undefined";
|
||||||
options.step.qrval = decoded;
|
});
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype){
|
||||||
|
// This output is accessible by Image Sequencer
|
||||||
|
step.output = {
|
||||||
|
src: datauri,
|
||||||
|
format: mimetype
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
callback: callback
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
},
|
},
|
||||||
"outputs": {
|
"outputs": {
|
||||||
"qrval": {
|
"qrval": {
|
||||||
"type": "text"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#decodeqr-module"
|
||||||
}
|
}
|
||||||
|
|||||||
76
src/modules/Dither/Dither.js
Normal file
76
src/modules/Dither/Dither.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
module.exports = function Dither(pixels, type) {
|
||||||
|
type = type;
|
||||||
|
let bayerThresholdMap = [
|
||||||
|
[15, 135, 45, 165],
|
||||||
|
[195, 75, 225, 105],
|
||||||
|
[60, 180, 30, 150],
|
||||||
|
[240, 120, 210, 90]
|
||||||
|
];
|
||||||
|
|
||||||
|
let lumR = [];
|
||||||
|
let lumG = [];
|
||||||
|
let lumB = [];
|
||||||
|
for (let i = 0; i < 256; i++) {
|
||||||
|
lumR[i] = i * 0.299;
|
||||||
|
lumG[i] = i * 0.587;
|
||||||
|
lumB[i] = i * 0.114;
|
||||||
|
}
|
||||||
|
let threshold = 129;
|
||||||
|
let imageDataLength = pixels.data.length; //imageData.data.length;
|
||||||
|
|
||||||
|
// Greyscale luminance (sets r pixels to luminance of rgb)
|
||||||
|
for (let i = 0; i <= imageDataLength; i++) {
|
||||||
|
pixels.data[i] = Math.floor(lumR[pixels.data[i++]] + lumG[pixels.data[i++]] + lumB[pixels.data[i++]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let w = pixels.shape[0];
|
||||||
|
let newPixel, err;
|
||||||
|
|
||||||
|
for (let currentPixel = 0; currentPixel <= imageDataLength; currentPixel += 4) {
|
||||||
|
|
||||||
|
if (type === "none") {
|
||||||
|
// No dithering
|
||||||
|
pixels.data[currentPixel] = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||||
|
|
||||||
|
} else if (type === "bayer") {
|
||||||
|
|
||||||
|
// 4x4 Bayer ordered dithering algorithm
|
||||||
|
let x = currentPixel / 4 % w;
|
||||||
|
let y = Math.floor(currentPixel / 4 / w);
|
||||||
|
let map = Math.floor((pixels.data[currentPixel] + bayerThresholdMap[x % 4][y % 4]) / 2);
|
||||||
|
pixels.data[currentPixel] = (map < threshold) ? 0 : 255;
|
||||||
|
|
||||||
|
} else if (type === "floydsteinberg") {
|
||||||
|
|
||||||
|
// Floyd–Steinberg dithering algorithm
|
||||||
|
newPixel = pixels.data[currentPixel] < 129 ? 0 : 255;
|
||||||
|
err = Math.floor((pixels.data[currentPixel] - newPixel) / 16);
|
||||||
|
pixels.data[currentPixel] = newPixel;
|
||||||
|
|
||||||
|
pixels.data[currentPixel + 4] += err * 7;
|
||||||
|
pixels.data[currentPixel + 4 * w - 4] += err * 3;
|
||||||
|
pixels.data[currentPixel + 4 * w] += err * 5;
|
||||||
|
pixels.data[currentPixel + 4 * w + 4] += err * 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Bill Atkinson's dithering algorithm
|
||||||
|
newPixel = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||||
|
err = Math.floor((pixels.data[currentPixel] - newPixel) / 8);
|
||||||
|
pixels.data[currentPixel] = newPixel;
|
||||||
|
|
||||||
|
pixels.data[currentPixel + 4] += err;
|
||||||
|
pixels.data[currentPixel + 8] += err;
|
||||||
|
pixels.data[currentPixel + 4 * w - 4] += err;
|
||||||
|
pixels.data[currentPixel + 4 * w] += err;
|
||||||
|
pixels.data[currentPixel + 4 * w + 4] += err;
|
||||||
|
pixels.data[currentPixel + 8 * w] += err;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set g and b pixels equal to r
|
||||||
|
pixels.data[currentPixel + 1] = pixels.data[currentPixel + 2] = pixels.data[currentPixel];
|
||||||
|
}
|
||||||
|
return pixels;
|
||||||
|
|
||||||
|
}
|
||||||
38
src/modules/Dither/Module.js
Normal file
38
src/modules/Dither/Module.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
module.exports = function Dither(options, UI){
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
var output;
|
||||||
|
|
||||||
|
function draw(input,callback,progressObj){
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
options.dither = options.dither || defaults.dither;
|
||||||
|
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('./Dither')(pixels, options.dither)
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/modules/Dither/index.js
Normal file
4
src/modules/Dither/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
require('./info.json')
|
||||||
|
]
|
||||||
14
src/modules/Dither/info.json
Normal file
14
src/modules/Dither/info.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "Dither",
|
||||||
|
"description": "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.<a href='https://en.wikipedia.org/wiki/Dither'>Read more</a>",
|
||||||
|
"inputs": {
|
||||||
|
"dither": {
|
||||||
|
"type": "select",
|
||||||
|
"desc": "Name of the Dithering Algorithm",
|
||||||
|
"default": "none",
|
||||||
|
"values": ["none","floydsteinberg","bayer","Atkinson"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#dither-module"
|
||||||
|
}
|
||||||
|
|
||||||
32
src/modules/DrawRectangle/DrawRectangle.js
Normal file
32
src/modules/DrawRectangle/DrawRectangle.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
module.exports = exports = function(pixels, options){
|
||||||
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
|
|
||||||
|
options.startingX = options.startingX || defaults.startingX;
|
||||||
|
options.startingY = options.startingY || defaults.startingY;
|
||||||
|
var ox = Number(options.startingX),
|
||||||
|
oy = Number(options.startingY),
|
||||||
|
iw = pixels.shape[0],
|
||||||
|
ih = pixels.shape[1],
|
||||||
|
thickness = Number(options.thickness) || defaults.thickness,
|
||||||
|
ex = options.endX = Number(options.endX) - thickness || iw - 1,
|
||||||
|
ey = options.endY = Number(options.endY) -thickness || ih - 1,
|
||||||
|
color = options.color || defaults.color;
|
||||||
|
color = color.split(" ");
|
||||||
|
|
||||||
|
var drawSide = function(startX, startY, endX, endY){
|
||||||
|
for (var n=startX; n <= endX+thickness; n++){
|
||||||
|
for (var k=startY; k <= endY+thickness; k++){
|
||||||
|
pixels.set(n, k, 0, color[0]);
|
||||||
|
pixels.set(n, k, 1, color[1]);
|
||||||
|
pixels.set(n, k, 2, color[2]);
|
||||||
|
pixels.set(n, k, 3, color[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawSide(ox, oy, ox, ey); // Left
|
||||||
|
drawSide(ex, oy, ex, ey); // Right
|
||||||
|
drawSide(ox, oy, ex, oy); // Top
|
||||||
|
drawSide(ox, ey, ex, ey); // Bottom
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
44
src/modules/DrawRectangle/Module.js
Normal file
44
src/modules/DrawRectangle/Module.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
module.exports = function DrawRectangle(options, UI) {
|
||||||
|
|
||||||
|
|
||||||
|
var output;
|
||||||
|
|
||||||
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
|
||||||
|
function changePixel(r, g, b, a) {
|
||||||
|
return [r, g, b, a]
|
||||||
|
}
|
||||||
|
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('./DrawRectangle')(pixels, options)
|
||||||
|
return pixels
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
changePixel: changePixel,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/modules/DrawRectangle/index.js
Normal file
4
src/modules/DrawRectangle/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
require('./info.json')
|
||||||
|
]
|
||||||
42
src/modules/DrawRectangle/info.json
Normal file
42
src/modules/DrawRectangle/info.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "Draw Rectangle",
|
||||||
|
"description": "It draws a rectangle on the image",
|
||||||
|
"inputs": {
|
||||||
|
"startingX":{
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "starting x position of the rectangle",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
|
||||||
|
"startingY": {
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "starting y position of the rectangle",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
|
||||||
|
"endX":{
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "last x position of the rectangle",
|
||||||
|
"default": "width"
|
||||||
|
},
|
||||||
|
|
||||||
|
"endY":{
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "last y position of the rectangle",
|
||||||
|
"default": "height"
|
||||||
|
},
|
||||||
|
|
||||||
|
"thickness":{
|
||||||
|
"type": "integer",
|
||||||
|
"desc": "thickness of border",
|
||||||
|
"default": 1
|
||||||
|
},
|
||||||
|
|
||||||
|
"color":{
|
||||||
|
"type": "string",
|
||||||
|
"desc": "RGBA values separated by a space",
|
||||||
|
"default": "0 0 0 255"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#draw-rectangle-module"
|
||||||
|
}
|
||||||
@@ -54,6 +54,22 @@ module.exports = function Dynamic(options,UI) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// via P5js: https://github.com/processing/p5.js/blob/2920492842aae9a8bf1a779916893ac19d65cd38/src/math/calculation.js#L461-L472
|
||||||
|
function map(n, start1, stop1, start2, stop2, withinBounds) {
|
||||||
|
var newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
|
||||||
|
if (!withinBounds) {
|
||||||
|
return newval;
|
||||||
|
}
|
||||||
|
// also via P5js: https://github.com/processing/p5.js/blob/2920492842aae9a8bf1a779916893ac19d65cd38/src/math/calculation.js#L116-L119
|
||||||
|
function constrain(n, low, high) {
|
||||||
|
return Math.max(Math.min(n, high), low);
|
||||||
|
};
|
||||||
|
if (start2 < stop2) {
|
||||||
|
return constrain(newval, start2, stop2);
|
||||||
|
} else {
|
||||||
|
return constrain(newval, stop2, start2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function output(image,datauri,mimetype){
|
function output(image,datauri,mimetype){
|
||||||
|
|
||||||
|
|||||||
@@ -3,24 +3,25 @@
|
|||||||
"description": "A module which accepts JavaScript math expressions to produce each color channel based on the original image's color. See <a href='https://publiclab.org/wiki/infragram-sandbox'>Infragrammar</a>.",
|
"description": "A module which accepts JavaScript math expressions to produce each color channel based on the original image's color. See <a href='https://publiclab.org/wiki/infragram-sandbox'>Infragrammar</a>.",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"red": {
|
"red": {
|
||||||
"type": "input",
|
"type": "string",
|
||||||
"desc": "Expression to return for red channel with R, G, B, and A inputs",
|
"desc": "Expression to return for red channel with R, G, B, and A inputs",
|
||||||
"default": "r"
|
"default": "r"
|
||||||
},
|
},
|
||||||
"green": {
|
"green": {
|
||||||
"type": "input",
|
"type": "string",
|
||||||
"desc": "Expression to return for green channel with R, G, B, and A inputs",
|
"desc": "Expression to return for green channel with R, G, B, and A inputs",
|
||||||
"default": "g"
|
"default": "g"
|
||||||
},
|
},
|
||||||
"blue": {
|
"blue": {
|
||||||
"type": "input",
|
"type": "string",
|
||||||
"desc": "Expression to return for blue channel with R, G, B, and A inputs",
|
"desc": "Expression to return for blue channel with R, G, B, and A inputs",
|
||||||
"default": "b"
|
"default": "b"
|
||||||
},
|
},
|
||||||
"monochrome (fallback)": {
|
"monochrome (fallback)": {
|
||||||
"type": "input",
|
"type": "string",
|
||||||
"desc": "Expression to return with R, G, B, and A inputs; fallback for other channels if none provided",
|
"desc": "Expression to return with R, G, B, and A inputs; fallback for other channels if none provided",
|
||||||
"default": "r + g + b"
|
"default": "r + g + b"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#dynamic-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,177 +1,201 @@
|
|||||||
const _ = require('lodash')
|
// Define kernels for the sobel filter
|
||||||
|
const kernelx = [
|
||||||
|
[-1, 0, 1],
|
||||||
|
[-2, 0, 2],
|
||||||
|
[-1, 0, 1]
|
||||||
|
],
|
||||||
|
kernely = [
|
||||||
|
[-1,-2,-1],
|
||||||
|
[ 0, 0, 0],
|
||||||
|
[ 1, 2, 1]
|
||||||
|
];
|
||||||
|
|
||||||
//define kernels for the sobel filter
|
let pixelsToBeSupressed = [];
|
||||||
const kernelx = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
|
|
||||||
kernely = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];
|
|
||||||
|
|
||||||
let angles = [], mags = [], strongEdgePixels = [], weakEdgePixels = [], notInUI;
|
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, hysteresis) {
|
||||||
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, inBrowser) {
|
let angles = [], grads = [], strongEdgePixels = [], weakEdgePixels = [];
|
||||||
notInUI = !inBrowser;
|
for (var x = 0; x < pixels.shape[0]; x++) {
|
||||||
for (var x = 0; x < pixels.shape[0]; x++) {
|
grads.push([]);
|
||||||
angles.push([]);
|
angles.push([]);
|
||||||
mags.push([]);
|
for (var y = 0; y < pixels.shape[1]; y++) {
|
||||||
for (var y = 0; y < pixels.shape[1]; y++) {
|
var result = sobelFilter(
|
||||||
var result = changePixel(
|
pixels,
|
||||||
pixels,
|
x,
|
||||||
pixels.get(x, y, 0),
|
y
|
||||||
pixels.get(x, y, 3),
|
);
|
||||||
x,
|
let pixel = result.pixel;
|
||||||
y
|
|
||||||
);
|
|
||||||
let pixel = result.pixel;
|
|
||||||
|
|
||||||
pixels.set(x, y, 0, pixel[0]);
|
grads.slice(-1)[0].push(pixel[3]);
|
||||||
pixels.set(x, y, 1, pixel[1]);
|
angles.slice(-1)[0].push(result.angle);
|
||||||
pixels.set(x, y, 2, pixel[2]);
|
|
||||||
pixels.set(x, y, 3, pixel[3]);
|
|
||||||
|
|
||||||
mags.slice(-1)[0].push(pixel[3]);
|
|
||||||
angles.slice(-1)[0].push(result.angle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
nonMaxSupress(pixels, grads, angles);
|
||||||
|
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels);
|
||||||
|
if(hysteresis.toLowerCase() == 'true') hysteresis(strongEdgePixels, weakEdgePixels);
|
||||||
|
|
||||||
return doubleThreshold(nonMaxSupress(pixels), highThresholdRatio, lowThresholdRatio);
|
strongEdgePixels.forEach(pixel => preserve(pixels, pixel));
|
||||||
|
weakEdgePixels.forEach(pixel => supress(pixels, pixel));
|
||||||
|
pixelsToBeSupressed.forEach(pixel => supress(pixels, pixel));
|
||||||
|
|
||||||
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
//changepixel function that convolutes every pixel (sobel filter)
|
|
||||||
function changePixel(pixels, val, a, x, y) {
|
|
||||||
let magX = 0.0;
|
|
||||||
for (let a = 0; a < 3; a++) {
|
|
||||||
for (let b = 0; b < 3; b++) {
|
|
||||||
|
|
||||||
let xn = x + a - 1;
|
function supress(pixels, pixel) {
|
||||||
let yn = y + b - 1;
|
pixels.set(pixel[0], pixel[1], 0, 0);
|
||||||
|
pixels.set(pixel[0], pixel[1], 1, 0);
|
||||||
magX += pixels.get(xn, yn, 0) * kernelx[a][b];
|
pixels.set(pixel[0], pixel[1], 2, 0);
|
||||||
}
|
pixels.set(pixel[0], pixel[1], 3, 255);
|
||||||
}
|
|
||||||
let magY = 0.0;
|
|
||||||
for (let a = 0; a < 3; a++) {
|
|
||||||
for (let b = 0; b < 3; b++) {
|
|
||||||
|
|
||||||
let xn = x + a - 1;
|
|
||||||
let yn = y + b - 1;
|
|
||||||
|
|
||||||
magY += pixels.get(xn, yn, 0) * kernely[a][b];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mag = Math.sqrt(Math.pow(magX, 2) + Math.pow(magY, 2));
|
|
||||||
let angle = Math.atan2(magY, magX);
|
|
||||||
return {
|
|
||||||
pixel:
|
|
||||||
[val, val, val, mag],
|
|
||||||
angle: angle
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Non Maximum Supression without interpolation
|
function preserve(pixels, pixel) {
|
||||||
function nonMaxSupress(pixels) {
|
pixels.set(pixel[0], pixel[1], 0, 255);
|
||||||
|
pixels.set(pixel[0], pixel[1], 1, 255);
|
||||||
angles = angles.map((arr) => arr.map(convertToDegrees));
|
pixels.set(pixel[0], pixel[1], 2, 255);
|
||||||
|
pixels.set(pixel[0], pixel[1], 3, 255);
|
||||||
for (let i = 1; i < pixels.shape[0] - 1; i++) {
|
|
||||||
for (let j = 1; j < pixels.shape[1] - 1; j++) {
|
|
||||||
|
|
||||||
let angle = angles[i][j];
|
|
||||||
let pixel = pixels.get(i, j);
|
|
||||||
|
|
||||||
if ((angle >= -22.5 && angle <= 22.5) ||
|
|
||||||
(angle < -157.5 && angle >= -180))
|
|
||||||
|
|
||||||
if ((mags[i][j] >= mags[i][j + 1]) &&
|
|
||||||
(mags[i][j] >= mags[i][j - 1]))
|
|
||||||
pixels.set(i, j, 3, mags[i][j]);
|
|
||||||
else
|
|
||||||
pixels.set(i, j, 3, 0);
|
|
||||||
|
|
||||||
else if ((angle >= 22.5 && angle <= 67.5) ||
|
|
||||||
(angle < -112.5 && angle >= -157.5))
|
|
||||||
|
|
||||||
if ((mags[i][j] >= mags[i + 1][j + 1]) &&
|
|
||||||
(mags[i][j] >= mags[i - 1][j - 1]))
|
|
||||||
pixels.set(i, j, 3, mags[i][j]);
|
|
||||||
else
|
|
||||||
pixels.set(i, j, 3, 0);
|
|
||||||
|
|
||||||
else if ((angle >= 67.5 && angle <= 112.5) ||
|
|
||||||
(angle < -67.5 && angle >= -112.5))
|
|
||||||
|
|
||||||
if ((mags[i][i] >= mags[i + 1][j]) &&
|
|
||||||
(mags[i][j] >= mags[i][j]))
|
|
||||||
pixels.set(i, j, 3, mags[i][j]);
|
|
||||||
else
|
|
||||||
pixels.set(i, j, 3, 0);
|
|
||||||
|
|
||||||
else if ((angle >= 112.5 && angle <= 157.5) ||
|
|
||||||
(angle < -22.5 && angle >= -67.5))
|
|
||||||
|
|
||||||
if ((mags[i][j] >= mags[i + 1][j - 1]) &&
|
|
||||||
(mags[i][j] >= mags[i - 1][j + 1]))
|
|
||||||
pixels.set(i, j, 3, mags[i][j]);
|
|
||||||
else
|
|
||||||
pixels.set(i, j, 3, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pixels;
|
|
||||||
}
|
}
|
||||||
//Converts radians to degrees
|
|
||||||
|
// sobelFilter function that convolves sobel kernel over every pixel
|
||||||
|
function sobelFilter(pixels, x, y) {
|
||||||
|
let val = pixels.get(x, y, 0),
|
||||||
|
gradX = 0.0,
|
||||||
|
gradY = 0.0;
|
||||||
|
|
||||||
|
for (let a = 0; a < 3; a++) {
|
||||||
|
for (let b = 0; b < 3; b++) {
|
||||||
|
|
||||||
|
let xn = x + a - 1,
|
||||||
|
yn = y + b - 1;
|
||||||
|
|
||||||
|
if (isOutOfBounds(pixels, xn, yn)) {
|
||||||
|
gradX += pixels.get(xn+1, yn+1, 0) * kernelx[a][b];
|
||||||
|
gradY += pixels.get(xn+1, yn+1, 0) * kernely[a][b];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gradX += pixels.get(xn, yn, 0) * kernelx[a][b];
|
||||||
|
gradY += pixels.get(xn, yn, 0) * kernely[a][b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const grad = Math.sqrt(Math.pow(gradX, 2) + Math.pow(gradY, 2)),
|
||||||
|
angle = Math.atan2(gradY, gradX);
|
||||||
|
return {
|
||||||
|
pixel: [val, val, val, grad],
|
||||||
|
angle: angle
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function categorizeAngle(angle){
|
||||||
|
if ((angle >= -22.5 && angle <= 22.5) || (angle < -157.5 && angle >= -180)) return 1;
|
||||||
|
else if ((angle >= 22.5 && angle <= 67.5) || (angle < -112.5 && angle >= -157.5)) return 2;
|
||||||
|
else if ((angle >= 67.5 && angle <= 112.5) || (angle < -67.5 && angle >= -112.5)) return 3;
|
||||||
|
else if ((angle >= 112.5 && angle <= 157.5) || (angle < -22.5 && angle >= -67.5)) return 4;
|
||||||
|
|
||||||
|
/* Category Map
|
||||||
|
* 1 => E-W
|
||||||
|
* 2 => NE-SW
|
||||||
|
* 3 => N-S
|
||||||
|
* 4 => NW-SE
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOutOfBounds(pixels, x, y){
|
||||||
|
return ((x < 0) || (y < 0) || (x >= pixels.shape[0]) || (y >= pixels.shape[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeElem = (arr = [], elem) => {
|
||||||
|
return arr = arr.filter((arrelem) => {
|
||||||
|
return arrelem !== elem;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non Maximum Supression without interpolation
|
||||||
|
function nonMaxSupress(pixels, grads, angles) {
|
||||||
|
angles = angles.map((arr) => arr.map(convertToDegrees));
|
||||||
|
|
||||||
|
for (let x = 0; x < pixels.shape[0]; x++) {
|
||||||
|
for (let y = 0; y < pixels.shape[1]; y++) {
|
||||||
|
|
||||||
|
let angleCategory = categorizeAngle(angles[x][y]);
|
||||||
|
|
||||||
|
if (!isOutOfBounds(pixels, x - 1, y - 1) && !isOutOfBounds(pixels, x+1, y+1)){
|
||||||
|
switch (angleCategory){
|
||||||
|
case 1:
|
||||||
|
if (!((grads[x][y] >= grads[x][y + 1]) && (grads[x][y] >= grads[x][y - 1]))) {
|
||||||
|
pixelsToBeSupressed.push([x, y]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if (!((grads[x][y] >= grads[x + 1][y + 1]) && (grads[x][y] >= grads[x - 1][y - 1]))){
|
||||||
|
pixelsToBeSupressed.push([x, y]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
if (!((grads[x][y] >= grads[x + 1][y]) && (grads[x][y] >= grads[x - 1][y]))) {
|
||||||
|
pixelsToBeSupressed.push([x, y]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
if (!((grads[x][y] >= grads[x + 1][y - 1]) && (grads[x][y] >= grads[x - 1][y + 1]))) {
|
||||||
|
pixelsToBeSupressed.push([x, y]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Converts radians to degrees
|
||||||
var convertToDegrees = radians => (radians * 180) / Math.PI;
|
var convertToDegrees = radians => (radians * 180) / Math.PI;
|
||||||
|
|
||||||
//Finds the max value in a 2d array like mags
|
// Finds the max value in a 2d array like grads
|
||||||
var findMaxInMatrix = arr => Math.max(...arr.map(el => el.map(val => !!val ? val : 0)).map(el => Math.max(...el)));
|
var findMaxInMatrix = arr => Math.max(...arr.map(el => el.map(val => !!val ? val : 0)).map(el => Math.max(...el)));
|
||||||
|
|
||||||
//Applies the double threshold to the image
|
// Applies the double threshold to the image
|
||||||
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio) {
|
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels) {
|
||||||
|
|
||||||
const highThreshold = findMaxInMatrix(mags) * 0.2;
|
const highThreshold = findMaxInMatrix(grads) * highThresholdRatio,
|
||||||
const lowThreshold = highThreshold * lowThresholdRatio;
|
lowThreshold = highThreshold * lowThresholdRatio;
|
||||||
|
|
||||||
for (let i = 0; i < pixels.shape[0]; i++) {
|
for (let x = 0; x < pixels.shape[0]; x++) {
|
||||||
for (let j = 0; j < pixels.shape[1]; j++) {
|
for (let y = 0; y < pixels.shape[1]; y++) {
|
||||||
let pixelPos = [i, j];
|
let pixelPos = [x, y];
|
||||||
|
|
||||||
mags[i][j] > lowThreshold
|
if (grads[x][y] > lowThreshold){
|
||||||
? mags[i][j] > highThreshold
|
if (grads[x][y] > highThreshold) {
|
||||||
? strongEdgePixels.push(pixelPos)
|
strongEdgePixels.push(pixelPos);
|
||||||
: weakEdgePixels.push(pixelPos)
|
|
||||||
: pixels.set(i, j, 3, 0);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
weakEdgePixels.push(pixelPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pixelsToBeSupressed.push(pixelPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
strongEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 255));
|
|
||||||
|
|
||||||
return pixels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hysteresis edge tracking algorithm -- not working as of now
|
function hysteresis(strongEdgePixels, weakEdgePixels){
|
||||||
/* function hysteresis(pixels) {
|
strongEdgePixels.forEach(pixel => {
|
||||||
function getNeighbouringPixelPositions(pixelPosition) {
|
let x = pixel[0],
|
||||||
let x = pixelPosition[0], y = pixelPosition[1]
|
y = pixel[1];
|
||||||
return [[x + 1, y + 1],
|
|
||||||
[x + 1, y],
|
if (weakEdgePixels.includes([x+1, y])) {
|
||||||
[x + 1, y - 1],
|
removeElem(weakEdgePixels, [x+1, y]);
|
||||||
[x, y + 1],
|
}
|
||||||
[x, y - 1],
|
else if (weakEdgePixels.includes([x-1, y])) {
|
||||||
[x - 1, y + 1],
|
removeElem(weakEdgePixels, [x-1, y]);
|
||||||
[x - 1, y],
|
|
||||||
[x - 1, y - 1]]
|
|
||||||
}
|
}
|
||||||
|
else if (weakEdgePixels.includes([x, y+1])) {
|
||||||
//This can potentially be improved see https://en.wikipedia.org/wiki/Connected-component_labeling
|
removeElem(weakEdgePixels, [x, y+1]);
|
||||||
for (weakPixel in weakEdgePixels) {
|
}
|
||||||
let neighbourPixels = getNeighbouringPixelPositions(weakEdgePixels[weakPixel])
|
else if(weakEdgePixels.includes([x, y-1])) {
|
||||||
for (pixel in neighbourPixels) {
|
removeElem(weakEdgePixels, [x, y-1]);
|
||||||
if (strongEdgePixels.find(el => _.isEqual(el, neighbourPixels[pixel]))) {
|
}
|
||||||
pixels.set(weakPixel[0], weakPixel[1], 3, 255)
|
})
|
||||||
weakEdgePixels.splice(weakPixel, weakPixel)
|
}
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
weakEdgePixels.forEach(pix => pixels.set(pix[0], pix[1], 3, 0))
|
|
||||||
return pixels
|
|
||||||
} */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* Detect Edges in an Image
|
* Detect Edges in an Image
|
||||||
*/
|
*/
|
||||||
module.exports = function edgeDetect(options,UI) {
|
module.exports = function edgeDetect(options, UI) {
|
||||||
|
|
||||||
options.blur = options.blur || 2;
|
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
|
||||||
options.highThresholdRatio = options.highThresholdRatio||0.2;
|
options.blur = options.blur || defaults.blur;
|
||||||
options.lowThresholdRatio = options.lowThresholdRatio||0.15;
|
options.highThresholdRatio = options.highThresholdRatio || defaults.highThresholdRatio;
|
||||||
|
options.lowThresholdRatio = options.lowThresholdRatio || defaults.lowThresholdRatio;
|
||||||
|
options.hystereis = options.hysteresis || defaults.hysteresis;
|
||||||
|
|
||||||
var output;
|
var output;
|
||||||
|
|
||||||
// The function which is called on every draw.
|
// The function which 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;
|
||||||
@@ -18,21 +20,19 @@ module.exports = function edgeDetect(options,UI) {
|
|||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
|
|
||||||
// Extra Manipulation function used as an enveloper for applying gaussian blur and Convolution
|
// Extra Manipulation function used as an enveloper for applying gaussian blur and Convolution
|
||||||
function extraManipulation(pixels){
|
|
||||||
pixels = require('ndarray-gaussian-filter')(pixels,options.blur);
|
|
||||||
return require('./EdgeUtils')(pixels,options.highThresholdRatio,options.lowThresholdRatio,options.inBrowser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function changePixel(r, g, b, a) {
|
function changePixel(r, g, b, a) {
|
||||||
return [(r+g+b)/3, (r+g+b)/3, (r+g+b)/3, a];
|
return [(r + g + b) / 3, (r + g + b) / 3, (r + g + b) / 3, a];
|
||||||
}
|
}
|
||||||
|
|
||||||
function output(image,datauri,mimetype){
|
function extraManipulation(pixels) {
|
||||||
|
pixels = require('ndarray-gaussian-filter')(pixels, options.blur);
|
||||||
// This output is accessible by Image Sequencer
|
pixels = require('./EdgeUtils')(pixels, options.highThresholdRatio, options.lowThresholdRatio, options.hystereis);
|
||||||
step.output = {src:datauri,format:mimetype};
|
return pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
@@ -44,12 +44,11 @@ module.exports = function edgeDetect(options,UI) {
|
|||||||
inBrowser: options.inBrowser,
|
inBrowser: options.inBrowser,
|
||||||
callback: callback
|
callback: callback
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options: options,
|
options: options,
|
||||||
draw: draw,
|
draw: draw,
|
||||||
output: output,
|
output: output,
|
||||||
UI: UI
|
UI: UI
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "Detect Edges",
|
"name": "Detect Edges",
|
||||||
"description": "this module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge. Read more at: https://en.wikipedia.org/wiki/Canny_edge_detector",
|
"description": "This module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge.<a href='https://en.wikipedia.org/wiki/Canny_edge_detector'> Read more. </a>",
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"blur": {
|
"blur": {
|
||||||
"type": "integer",
|
"type": "float",
|
||||||
"desc": "amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||||
"default": 2
|
"default": 2,
|
||||||
|
"min": 0,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.25
|
||||||
},
|
},
|
||||||
"highThresholdRatio":{
|
"highThresholdRatio":{
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"desc": "The high threshold ratio for the image",
|
"desc": "The high threshold ratio for the image",
|
||||||
"default": 0.2
|
"default": 0.2,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.25
|
||||||
},
|
},
|
||||||
"lowThresholdRatio": {
|
"lowThresholdRatio": {
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"desc": "The low threshold value for the image",
|
"desc": "The low threshold value for the image",
|
||||||
"default": 0.15
|
"default": 0.15,
|
||||||
}
|
"min": 0,
|
||||||
}
|
"max": 1,
|
||||||
|
"step": 0.05
|
||||||
|
},
|
||||||
|
"hysteresis": {
|
||||||
|
"type": "select",
|
||||||
|
"desc": "Toggle Hysteresis",
|
||||||
|
"values": ["false", "true"],
|
||||||
|
"default": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#edge-detect-module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,13 +54,14 @@
|
|||||||
},
|
},
|
||||||
"fragmentSrc": {
|
"fragmentSrc": {
|
||||||
"type": "PATH",
|
"type": "PATH",
|
||||||
"desc": "Patht to a WebGL fragment shader file",
|
"desc": "Path to a WebGL fragment shader file",
|
||||||
"default": "(inbuilt)"
|
"default": "(inbuilt)"
|
||||||
},
|
},
|
||||||
"vertexSrc": {
|
"vertexSrc": {
|
||||||
"type": "PATH",
|
"type": "PATH",
|
||||||
"desc": "Patht to a WebGL vertex shader file",
|
"desc": "Path to a WebGL vertex shader file",
|
||||||
"default": "(inbuilt)"
|
"default": "(inbuilt)"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#fisheyegl-module"
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/modules/FlipImage/Module.js
Normal file
51
src/modules/FlipImage/Module.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Flip the image on vertical/horizontal axis.
|
||||||
|
*/
|
||||||
|
module.exports = function FlipImage(options, UI) {
|
||||||
|
options.Axis = options.Axis || require('./info.json').inputs.Axis.default;
|
||||||
|
|
||||||
|
var output,
|
||||||
|
getPixels = require('get-pixels');
|
||||||
|
|
||||||
|
function draw(input, callback, progressObj) {
|
||||||
|
|
||||||
|
progressObj.stop(true);
|
||||||
|
progressObj.overrideFlag = true;
|
||||||
|
|
||||||
|
var step = this;
|
||||||
|
|
||||||
|
return getPixels(input.src, function(err, oldPixels){
|
||||||
|
function changePixel(r, g, b, a) {
|
||||||
|
return [r, g, b, a];
|
||||||
|
}
|
||||||
|
function extraManipulation(pixels) {
|
||||||
|
if (err){
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return require('./flipImage')(oldPixels, pixels, options.Axis);
|
||||||
|
}
|
||||||
|
function output(image, datauri, mimetype) {
|
||||||
|
step.output = { src: datauri, format: mimetype };
|
||||||
|
}
|
||||||
|
|
||||||
|
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||||
|
output: output,
|
||||||
|
changePixel: changePixel,
|
||||||
|
extraManipulation: extraManipulation,
|
||||||
|
format: input.format,
|
||||||
|
image: options.image,
|
||||||
|
inBrowser: options.inBrowser,
|
||||||
|
callback: callback
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options: options,
|
||||||
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/modules/FlipImage/flipImage.js
Normal file
31
src/modules/FlipImage/flipImage.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module.exports = function flipImage(oldPixels, pixels, axis) {
|
||||||
|
var width = oldPixels.shape[0],
|
||||||
|
height = oldPixels.shape[1];
|
||||||
|
|
||||||
|
function copyPixel(x1, y1, x2, y2){
|
||||||
|
pixels.set(x1, y1, 0, oldPixels.get(x2, y2, 0))
|
||||||
|
pixels.set(x1, y1, 1, oldPixels.get(x2, y2, 1))
|
||||||
|
pixels.set(x1, y1, 2, oldPixels.get(x2, y2, 2))
|
||||||
|
pixels.set(x1, y1, 3, oldPixels.get(x2, y2, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
function flip(){
|
||||||
|
if(axis.toLowerCase() == 'vertical'){
|
||||||
|
for (var n=0; n < width; n++){
|
||||||
|
for (var m=0; m < height; m++){
|
||||||
|
copyPixel(n, m, n, height - m - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var n=0; n < width; n++){
|
||||||
|
for (var m=0; m < height; m++){
|
||||||
|
copyPixel(n, m, width - n - 1, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flip();
|
||||||
|
return pixels;
|
||||||
|
}
|
||||||
4
src/modules/FlipImage/index.js
Normal file
4
src/modules/FlipImage/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = [
|
||||||
|
require('./Module'),
|
||||||
|
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