Compare commits

..

5 Commits

Author SHA1 Message Date
Jeffrey Warren
3bbe6fa6dc Merge branch 'main' into HarshKhandeparkar-patch-3 2020-01-28 13:03:47 -05:00
Rishabh Shukla
ceff43a502 Merge branch 'main' into HarshKhandeparkar-patch-3 2020-01-28 22:32:27 +05:30
Harsh Khandeparkar
bb4e3162f9 Merge branch 'main' into HarshKhandeparkar-patch-3 2020-01-28 21:32:06 +05:30
Harsh Khandeparkar
64c23bee31 Update package.json 2020-01-28 21:31:24 +05:30
Harsh Khandeparkar
de4a2cb50f Fix typo 2020-01-28 21:25:37 +05:30
62 changed files with 4419 additions and 7807 deletions

75
.github/CODEOWNERS vendored
View File

@@ -1,75 +0,0 @@
# <-- DOCS FOR THIS FILE -->
# This is a comment.
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @global-owner1 and @global-owner2 will be requested for
# review when someone opens a pull request.
# * @global-owner1 @global-owner2
# Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.
# *.js @js-owner
# You can also use email addresses if you prefer. They'll be
# used to look up users just like we do for commit author
# emails.
# *.go docs@example.com
# In this example, @doctocat owns any files in the build/logs
# directory at the root of the repository and any of its
# subdirectories.
# /build/logs/ @doctocat
# The `docs/*` pattern will match files like
# `docs/getting-started.md` but not further nested files like
# `docs/build-app/troubleshooting.md`.
# docs/* docs@example.com
# In this example, @octocat owns any file in an apps directory
# anywhere in your repository.
# apps/ @octocat
# In this example, @doctocat owns any file in the `/docs`
# directory in the root of your repository.
# /docs/ @doctocat
# <-- /DOCS FOR THIS FILE -->
# <-- COMMON TO ALL MAINTAINERS -->
/*.json @publiclab/is-maintainers
/*.md @publiclab/is-maintainers
/*.lock @ubliclab/is-maintainers
/Gruntfile.js @publiclab/is-maintainers
/.github/ @publiclab/is-maintainers
/scripts/ @publiclab/is-maintainers
# <-- /COMMON TO ALL MAINTAINERS -->
# <-- SPECIFIC MAINTAINERS -->
/index.js @publiclab/is-cli-maintainers
/src/cli/ @publiclab/is-cli-maintainers
/src/CliUtils.js @publiclab/is-cli-maintainers
/src/*.js @publiclab/is-core-maintainers
/src/*.json @publiclab/is-core-maintainers
/src/util/ @publiclab/is-core-maintainers
/test/core/* @publiclab/is-core-maintainers
/src/modules/ @publiclab/is-module-maintainers
/docs/ @publiclab/is-module-maintainers
/test/ @publiclab/is-tests-maintainers
/jest* @publiclab/is-tests-maintainers
/eslint* @publiclab/is-tests-maintainers
/travis* @publiclab/is-tests-maintainers
.travis.yml @publiclab/is-tests-maintainers
.gitpod* @publiclab/is-tests-maintainers
/gitpod* @publiclab/is-tests-maintainers
/examples/ @publiclab/is-ui-maintainers
/icons/ @publiclab/is-ui-maintainers
/test/ui-2/test/* @publiclab/is-ui-maintainers
/test/ui/spec/* @publiclab/is-ui-maintainers
# <-- /SPECIFIC MAINTAINERS -->

View File

@@ -1,10 +1,3 @@
---
name: Bug report 🐞
about: Help us identify and fix a bug!
title: ''
labels: bug
---
### Please describe the problem (or idea)
> What happened just before the problem occurred? Or what problem could this idea solve?
@@ -17,13 +10,13 @@ labels: bug
### Please show us where to look
Paste in a full URL, starting with:
https://beta.sequencer.publiclab.org
> https://beta.sequencer.publiclab.org/
If you can share a screenshot or a GIF that is EXTRA helpful! 💖
### What's your PublicLab.org username?
> This can help us diagnose the issue:
If you can see a version number in the upper right, please note that!
### Browser, version, and operating system

View File

@@ -1,39 +0,0 @@
---
name: New release checklist ✅
about: Coordinate steps to publish a new release
title: 'Checklist and coordination for v0.0.0 major/minor/patch release'
labels: release
assignees: '@publiclab/is-maintainers'
---
This template guides us through the steps of creating a new release, based on conversation and testing in [#1692](https://github.com/publiclab/image-sequencer/issues/1692).
Discuss with @publiclab/is-maintainers if anything is ambiguous!
<!-- NOTE: Change v0.0.0 to the appropriate release version -->
* [x] open an issue using the "release" template with this checklist with title `Checklist and coordination for v0.0.0 major/minor/patch release` (see [semantic versioning](https://docs.npmjs.com/about-semantic-versioning/))
* [ ] create a release [project](https://github.com/publiclab/image-sequencer/projects) from [this template](https://github.com/publiclab/image-sequencer/projects/5). You can copy a project from its menu.
* [ ] compile release notes below from corresponding [release project](https://github.com/publiclab/image-sequencer/projects).
* [ ] update version number in `examples/sw.js` (ex #1734) and `package.json` (ex #1695)
* [ ] finalize and merge to `main` branch (freeze merges to `main` branch until next step)
* [ ] merge, build and publish `/dist/` files to `stable` (merges to `main` branch can resume for next release)
* [ ] create a release on GitHub and use features description + release notes from below
* [ ] tag version number branch (i.e. `v0.0.0`)
* [ ] publish tagged branch to `npm`
* [ ] publish to live Github pages [demo](https://sequencer.publiclab.org) (with [bash script](https://github.com/publiclab/image-sequencer/pull/1703) from `/scripts/update-demo`) (from within GitPod works well)
* [ ] move anything necessary to next release project, i.e. <!-- Update this link -->https://github.com/publiclab/image-sequencer/projects/[insert project number]
* [ ] close this issue!
Noting we're now in this process in https://github.com/publiclab/image-sequencer/pull/1695 for `v3.6.0`.
****
### Release notes
Compile and edit release notes below, to be copied into the release description.
#### Added
#### Fixed
#### Changed

17
.github/config.yml vendored
View File

@@ -4,27 +4,22 @@
# Comment to be posted to on first time issues
newIssueWelcomeComment: |
Thanks for opening your first issue here! This space is [protected by our Code of Conduct](https://publiclab.org/conduct) - and we're here to help.
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!
Don't forget to join our [PublicLab Gitter channel](https://gitter.im/publiclab/publiclab) and our [ImageSequencer Gitter Channel](https://gitter.im/publiclab/image-sequencer) for some brainstorming discussions.
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! This space is [protected by our Code of Conduct](https://publiclab.org/conduct).
Thanks for opening this pull request!
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
Also please refer (https://github.com/publiclab/image-sequencer/blob/main/README.md) for installation help.
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
# Comment to be posted to on pull requests merged by a first time user
firstPRMergeComment: |
Congrats on merging your first pull request! 🙌🎉⚡️
Your code will be published to https://beta.sequencer.publiclab.org in a day or two. Please test out your work on this testing server and report back with a comment that all has gone well!
In the meantime, can you tell us your Twitter handle so we can thank you properly also do join our weekly check-in to share your this week goal and the awesome work you did 😃.
Please find the link **pinned in the issue section**
Now that you've completed this, you can help someone else take their first step! Try looking at this list of `first-timers-only` issues, and see if someone else is waiting for feedback, or even stuck! 😕
People often get stuck at the same steps, so you might be able to help someone get unstuck, or help lead them to some documentation that'd help. Reach out and be encouraging and friendly! 😄 🎉
Your code will be published to https://beta.sequencer.publiclab.org in a day or two.
In the meantime, can you tell us your Twitter handle so we can thank you properly?
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

View File

@@ -1,7 +0,0 @@
FROM gitpod/workspace-full
USER root
RUN sudo apt-get update && apt-get install -y apt-transport-https \
&& sudo apt-get install -y \
xserver-xorg-dev libxext-dev libxi-dev build-essential libxi-dev libglu1-mesa-dev libglew-dev pkg-config libglu1-mesa-dev freeglut3-dev mesa-common-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*

View File

@@ -1,18 +0,0 @@
image:
file: .gitpod.dockerfile
tasks:
- init: npm run setup
command: npm start
ports:
- port: 3000
onOpen: open-preview
github:
prebuilds:
branches: true
pullRequests: true
pullRequestsFromForks: true
addCheck: true
addComment: true
addBadge: false
addLabel: false

View File

@@ -1,8 +1,8 @@
sudo: required
language: node_js
node_js:
- '8'
- '10'
- '12'
env:
- CXX=g++-4.8
before_script:
@@ -10,24 +10,15 @@ before_script:
- 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
jobs:
include:
- name: "Base istanbul/tape node tests"
script: npm test
- name: "Benchmark tests"
script: npm run benchmark
- name: "Gif tests"
script: npm run gif-test
- name: "Browserify core tests and run"
script: grunt tests && npm run core-tests
- name: "Jasmine UI tests (mocked browser env)"
script: npm run test-ui
- name: "jest-puppeteer UI tests (full browser env)"
script: npm run test-ui-2
- name: "CLI tests"
script: npm run test-cli
- name: "Grunt build test of dev environment"
script: grunt build
script:
- npm test
- npm run benchmark
- npm run gif-test
- grunt tests
- npm run core-tests
- npm run test-ui
- npm run test-ui-2
- grunt build
after_success:
- bash <(curl -s https://codecov.io/bash)
after_script:

View File

@@ -17,7 +17,6 @@ Most contribution (we imagine) would be in the form of API-compatible modules, w
* [Ideas](#Contribution-ideas)
* [Grunt Tasks](#grunt-tasks)
* [UI Helper Methods](#ui-helper-methods)
* [Scripts](#scripts)
****
@@ -375,7 +374,7 @@ module.exports =
We are now using `eslint` and `husky` to help lint and format our code each time we commit. Eslint defines coding standards and helps in cleaning up the code. To run eslint for checking errors globally or within a specific file run:
```
npx eslint .
npx eslint .
npx eslint <file path>
```
@@ -413,15 +412,15 @@ The following command is used for running the tasks: `grunt [task-name]`. Here `
The method returns a scoped `jQuery` object which only searches for elements inside a given scope (a DOM element).
To use the method,
To use the method,
* import the `scopeSelector` and `scopeSelectorAll` methods from `lib/scopeQuery.js`
* call the methods with scope as a parameter
```js
var scopeQuery = require('./scopeQuery');
var $step = scopeQuery.scopeSelector(scope),
$stepAll = scopeQuery.scopeSelectorAll(scope);
$stepAll = scopeQuery.scopeSelectorAll(scope);
```
This will return an object with a constructor which returns a `jQuery` object (from inside the scope) but with new `elem` and `elemAll` methods.
@@ -434,7 +433,7 @@ This will return an object with a constructor which returns a `jQuery` object (f
#### Example
```js
//The scope is a div element with id=“container“ and there are three divs in it
//The scope is a div element with id=“container“ and there are three divs in it
//with ids „1“, „2“, and „3“, and all of them have a „child“ class attribute
var $step = require('./scopeQuery').scopeSelector(document.getElementById('container'));
@@ -459,23 +458,3 @@ The following code can be used
$step('query').show().hide();
$stepAll('q2').show().hide();
```
## Scripts
The following shell scripts are present in the `scripts/` directory.
- `update-gh-pages`: This script can be used to update the `gh-pages` branch of this repo or a fork.
This script is not meant to be used directly as it runs in the current working directory.
If you run it on your primary local clone, it can **delete** the local changes. This script is made to be used in a github action
or in a temporary directory via another script, such as `update-demo`.
Arguments:
1. Repo(to use as upstream) url in the form username/repo (default: publiclab/image-sequencer) NOTE: Github only
2. Branch to pull from eg: main or stable (default: stable)
3. CNAME URL (default: none)
4. Set the fourth argument to anything to bypass the warning. You will have to set this argument if you want to run this script in another script without needing
user interaction, such as in a github action.
- `update-demo`: A safe, interactive script that can be used to update the `gh-pages` branch of any image-sequencer fork.
This script is safe to use directly because it separately clones the repo in a temporary directory.
Arguments: None since it is a an *interactive* script, ie it asks the user for input.

View File

@@ -44,14 +44,7 @@ module.exports = function(grunt) {
dest: 'dist/image-sequencer-ui.brow.js'
},
tests: {
src: ['test/core/sequencer/meta-modules.js',
'test/core/sequencer/image-sequencer.js',
'test/core/sequencer/chain.js',
'test/core/sequencer/replace.js',
'test/core/sequencer/import-export.js',
'test/core/sequencer/run.js',
'test/core/sequencer/dynamic-imports.js',
'test/core/util/*.js'],
src: ['test/core/sequencer/meta-modules.js', 'test/core/sequencer/image-sequencer.js', 'test/core/sequencer/chain.js', 'test/core/sequencer/replace.js', 'test/core/sequencer/import-export.js', 'test/core/sequencer/run.js', 'test/core/sequencer/dynamic-imports.js', 'test/core/util/*.js'],
dest: './output/core-tests.js'
}
},

View File

@@ -2,18 +2,12 @@ Image Sequencer
====
[![Code of Conduct](https://img.shields.io/badge/code-of%20conduct-green.svg)](https://publiclab.org/conduct)
[![npm version](https://badge.fury.io/js/image-sequencer.svg)](https://badge.fury.io/js/image-sequencer)
[![Build Status](https://travis-ci.org/publiclab/image-sequencer.svg?branch=master)](https://travis-ci.org/publiclab/image-sequencer) [![Maintainability](https://api.codeclimate.com/v1/badges/5906996dd2e90aca6398/maintainability)](https://codeclimate.com/github/publiclab/image-sequencer/maintainability) [![Codecov](https://img.shields.io/codecov/c/github/publiclab/image-sequencer.svg?logo=codecov)](https://codecov.io/gh/publiclab/image-sequencer)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/publiclab/image-sequencer/)
- **Latest Stable Demo**: https://sequencer.publiclab.org
- **Latest Beta Demo**: https://beta.sequencer.publiclab.org
- **Stable Branch**: https://github.com/publiclab/image-sequencer/tree/stable/
Begin running (and contributing to) this codebase immediately with [GitPod](https://gitpod.io) (this also opens the latest `main` branch code):
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/publiclab/image-sequencer)
## Why
Image Sequencer is different from other image processing systems because it's _non-destructive_: instead of modifying the original image, it **creates a new image at each step in a sequence**. This is because it:
@@ -77,12 +71,6 @@ In case of a port conflict please run the following
npm i -g http-server ; http-server -p 3000
```
### Online one-click setup for contributing
Contribute to ImageSequencer using a fully featured online development environment that will automatically: clone the repo, install the dependencies and start the webserver.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/)
### Browser
Just include [image-sequencer.min.js](https://github.com/publiclab/image-sequencer/blob/stable/dist/image-sequencer.min.js) in the Head section of your web page. See the [demo here](https://sequencer.publiclab.org)!
@@ -620,7 +608,8 @@ The final frames are then converted back to a GIF but in the process, the time d
Modules that do not work:
1. ColorBar (Will get fixed upon fixing overlay as this is a meta module which uses overlay)
2. FisheyeGL
3. Overlay
4. Blend
5. Histogram
6. WebGL Distort
4. Overlay
5. Text Overlay (Almost fixed)
6. Blend
7. Histogram
8. WebGL Distort

View File

@@ -1,8 +1,12 @@
/* https://github.com/theleagueof/league-spartan */
@font-face {
font-family: 'League Spartan';
src: url('https://cdn.jsdelivr.net/npm/fontsource-league-spartan@3/files/league-spartan-latin-600-normal.woff2') format('woff2'),
url('https://cdn.jsdelivr.net/npm/fontsource-league-spartan@3/files/league-spartan-latin-600-normal.woff') format('woff');
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot');
src: url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.eot?#iefix') format('embedded-opentype'),
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff2') format('woff2'),
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.woff') format('woff'),
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.ttf') format('truetype'),
url('https://raw.githubusercontent.com/theleagueof/league-spartan/master/_webfonts/leaguespartan-bold.svg#league_spartanbold') format('svg');
font-weight: bold;
font-style: normal;
}
@@ -40,6 +44,7 @@ body > .container-fluid {
.panel {
margin-left: 20px;
margin-right: 20px;
min-width:400px;
}
.mouse {
@@ -61,6 +66,7 @@ body > .container-fluid {
border-radius: 8px;
text-align: center;
color: #444;
min-width:300px;
}
.dropzone input {
@@ -150,13 +156,6 @@ body > .container-fluid {
margin: 0px 0px 0px 10px;
width: 250px;
}
@media(max-width: 768px) {
#dropzone {
margin: 0 0% 30px;
}
}
#dwnld {
max-width: 500px;
margin: 20px auto;
@@ -325,7 +324,7 @@ a.name-header{
position: fixed;
right: 2%;
top: 5%;
color: gray;
color: lightgray;
}
/* Non float rightward alignment*/
.right {

View File

@@ -340,7 +340,6 @@ window.onload = function () {
else
step.imgElement.src = url;
insertPreview.updatePreviews(url, document.querySelector('#addStep'));
DefaultHtmlStepUi(sequencer).updateDimensions(step);
}
});

View File

@@ -60,13 +60,13 @@
<div class="container-fluid">
<header class="text-center">
<header class="text-center" style="min-width: 450px">
<h1><a href="/" target='_blank' class="name-header">Image Sequencer</a></h1>
<p>
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original
image, it
creates a new image at each step in a sequence.
<a href="https://publiclab.org/image-sequencer">Learn more</a>
<a href="https://github.com/publiclab/image-sequencer/blob/main/README.md">Learn more</a>
</p>
<p>
Open Source
@@ -218,7 +218,7 @@
<h2>Need Help?</h2>
<p>
<a class="btn btn-default" href="https://github.com/publiclab/image-sequencer/issues">Ask a question</a>
<a class="btn btn-default" href="https://gitter.im/publiclab/image-sequencer" target="_blank">Ask in our chatroom </a>
<a class="btn btn-default" href="https://publiclab.org/chat">Ask in our chatroom</a>
</p>
</div>
<div class="col-md-6">

View File

@@ -1,5 +1,4 @@
var urlHash = require('./urlHash.js');
insertPreview = require('./insertPreview.js');
function DefaultHtmlSequencerUi(_sequencer, options) {
options = options || {};
@@ -28,17 +27,12 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
function selectNewStepUi() {
var m = $(addStepSel + ' select').val();
if(!m) m = arguments[0];
else $(addStepSel + ' .info').html(_sequencer.modulesInfo(m).description);
$(addStepSel + ' .info').html(_sequencer.modulesInfo(m).description);
$(addStepSel + ' #add-step-btn').prop('disabled', false);
}
function removeStepUi() {
var index = $(removeStepSel).index(this) + 1;
// If last step is removed.
if(sequencer.steps.length==index+1){
console.log("inside")
insertPreview.updatePreviews(sequencer.steps[index-1].output.src, document.querySelector('#addStep'));
}
sequencer.removeSteps(index).run({ index: index - 1 });
// remove from URL hash too
urlHash.setUrlHashParameter('steps', sequencer.toString());

View File

@@ -11,7 +11,6 @@
const intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js'),
urlHash = require('./urlHash.js'),
_ = require('lodash'),
insertPreview = require('./insertPreview.js');
mapHtmlTypes = require('./mapHtmltypes'),
scopeQuery = require('./scopeQuery'),
isGIF = require('../../src/util/isGif');
@@ -136,7 +135,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
'"max="' +
inputDesc.max +
'"step="' +
inputDesc.step + '">' + '<span>' + paramVal + '</span>';
(inputDesc.step ? inputDesc.step : 1) + '">' + '<span>' + paramVal + '</span>';
}
else html += '">';
@@ -366,9 +365,6 @@ function DefaultHtmlStepUi(_sequencer, options) {
updateDimensions(step);
});
if (step.name === 'load-image') insertPreview.updatePreviews(step.output.src, document.querySelector('#addStep'));
else insertPreview.updatePreviews(step.output, document.querySelector('#addStep'));
// Handle the wasm bolt display
if (step.useWasm) {

View File

@@ -10,7 +10,6 @@ function generatePreview(previewStepName, customValues, path, DomNode) {
$(img).css('transform', 'translateX(-20%)');
$(DomNode.querySelector('.radio-group')).find('.radio').each(function() {
if ($(this).attr('data-value') === previewStepName) {
$(this).find('img').remove();
$(this).append(img);
}
});

View File

@@ -7,7 +7,6 @@ function mapHtmlTypes(inputInfo){
switch(inputInfo.type.toLowerCase()){
case 'integer':
htmlType = inputInfo.min != undefined ? 'range' : 'number';
if (htmlType === 'range') inputInfo.step = inputInfo.step || 1; // default range step size for integer
break;
case 'string':
htmlType = 'text';
@@ -20,7 +19,6 @@ function mapHtmlTypes(inputInfo){
break;
case 'float':
htmlType = inputInfo.min != undefined ? 'range' : 'text';
if (htmlType === 'range') inputInfo.step = inputInfo.step || 0.1; // default range step size for float
break;
default:
htmlType = 'text';

View File

@@ -1,4 +1,4 @@
const staticCacheName = 'image-sequencer-static-v3.6.0';
const staticCacheName = 'image-sequencer-static-v3.5.1';
self.addEventListener('install', event => {
console.log('Attempting to install service worker');
});

6741
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,19 @@
{
"name": "image-sequencer",
"version": "3.6.0",
"version": "3.5.1",
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
"main": "src/ImageSequencer.js",
"scripts": {
"debug": "TEST=true node ./index.js -i ./examples/images/monarch.png -s invert",
"test": "TEST=true istanbul cover tape test/core/*.js test/core/ui/user-interface.js test/core/modules/*.js | tap-spec;",
"benchmark": "node test/core/sequencer/benchmark.js | tap-spec;",
"gif-test": "node test/core/gifs/gif-test.js | tap-spec;",
"core-tests": "cat ./output/core-tests.js | tape-run --render=\"tap-spec\"",
"benchmark" : "node test/core/sequencer/benchmark.js | tap-spec;",
"gif-test" : "node test/core/gifs/gif-test.js | tap-spec;",
"core-tests" : "cat ./output/core-tests.js | tape-run --render=\"tap-spec\"",
"test-all": "npm run test && npm run benchmark && npm run gif-test && grunt tests && npm run core-tests",
"test-ui": "node node_modules/jasmine/bin/jasmine test/ui/spec/*.js",
"test-ui-2": "node ./node_modules/.bin/jest",
"test-cli": "node test/cli/*.js | tap-spec",
"setup": "npm i && npm i -g grunt grunt-cli && npm rebuild --build-from-source && grunt build",
"start": "grunt serve"
"start": "grunt serve"
},
"lint-staged": {
"*.js": [
@@ -40,8 +39,8 @@
"base64-img": "^1.0.4",
"bootstrap": "^3.4.1",
"bootstrap-colorpicker": "^2.5.3",
"buffer": "~6.0.2",
"commander": "^6.2.0",
"buffer": "~5.4.0",
"commander": "^4.0.1",
"compressorjs": "^1.0.5",
"data-uri-to-buffer": "^3.0.0",
"downloadjs": "^1.4.7",
@@ -56,22 +55,22 @@
"image-sequencer-invert": "^1.0.0",
"imagejs": "0.0.9",
"imagemin": "^7.0.1",
"imagemin-jpegtran": "^7.0.0",
"imagemin-pngquant": "^9.0.1",
"imagemin-jpegtran": "^6.0.0",
"imagemin-pngquant": "^8.0.0",
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
"istanbul": "^0.4.5",
"jasmine": "^3.4.0",
"jpegtran-bin": "^5.0.2",
"jpegtran-bin": "^4.0.0",
"jquery": "^3.3.1",
"jsdom": "^16.3.0",
"jspdf": "^2.1.1",
"jsdom": "^15.0.0",
"jspdf": "^1.5.3",
"jsqr": "^1.1.1",
"lodash": "^4.17.11",
"ndarray": "^1.0.18",
"opencv.js": "^1.2.1",
"ora": "^5.1.0",
"ora": "^4.0.3",
"pace": "0.0.4",
"pngquant-bin": "^6.0.0",
"pngquant-bin": "^5.0.2",
"puppeteer": "^1.14.0",
"qrcode": "^1.3.3",
"readline-sync": "^1.4.7",
@@ -86,7 +85,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.4.3",
"@babel/plugin-syntax-object-rest-spread": "^7.2.0",
"babelify": "^10.0.0",
"browserify": "17.0.0",
"browserify": "16.5.0",
"eslint": "^6.1.0",
"grunt": "^1.0.3",
"grunt-browser-sync": "^2.2.0",
@@ -100,15 +99,15 @@
"image-filter-threshold": "~2.0.1",
"jasmine-core": "^3.3.0",
"jasmine-jquery": "^2.1.1",
"jasmine-spec-reporter": "^6.0.0",
"jest": "^26.1.0",
"jasmine-spec-reporter": "^4.2.1",
"jest": "^25.1.0",
"jest-puppeteer": "^4.3.0",
"lint-staged": "^10.0.3",
"looks-same": "^7.0.0",
"matchdep": "^2.0.0",
"tap-spec": "^5.0.0",
"tape": "^4.9.2",
"tape-run": "^8.0.0",
"tape-run": "^6.0.0",
"uglify-es": "^3.3.7"
},
"husky": {
@@ -120,4 +119,4 @@
"bin": {
"sequencer": "./index.js"
}
}
}

View File

@@ -1,26 +0,0 @@
#!/bin/bash
scriptsDir=$(realpath $(dirname $0))
echo -ne "Enter the repo to push to in the form username/repo (required): "
read -e pushRepo
echo -ne "Enter repo URL to pull from (upstream) in the form username/repo (default: publiclab/image-sequencer): "
read -e repoInput
echo -ne "Enter branch name (default: stable): "
read -e branchInput
echo -ne "Enter CNAME URL(default: none): "
read -e cnameUrlInput
tempDir=$(mktemp -d)
pushd $tempDir > /dev/null
git clone https://github.com/$pushRepo
pushd image-sequencer > /dev/null
$scriptsDir/update-gh-pages "$repoInput" "$branchInput" "$cnameUrlInput" "no warn"
popd > /dev/null
popd > /dev/null

View File

@@ -1,117 +0,0 @@
#!/bin/bash
set -e # So that nothing wrong is published
warn() {
echo -e "\033[1;31m
------IMPORTANT------
THIS SCRIPT IS NOT MEANT TO BE USED DIRECTLY, PLEASE NEWLY CLONE THE REPO IN A SEPARATE DIRECTORY AND USE THE SCRIPT THERE.
USING THIS SCRIPT IN YOUR MAIN CLONE MAY DELETE YOUR LOCAL CHANGES.
This script is made to be reusable: If you want to manually update the demo, \
use the interactive script \`update-demo\`. This script can also be used in a github action.
You can set the 4th argument to anything to bypass this warning. \
Setting the 4th argument means that the first 3 arguments are also set which means that you know what you are doing (I assume).
------IMPORTANT------
\033[0m"
echo -ne "Do you still want to continue? [Y/n]: "
read -e yN
case $yN in
[yY][eE][sS] | [yY])
;;
*)
exit 0
;;
esac
}
# --- Constants ---
deps="jquery bootstrap imgareaselect gifshot downloadjs selectize font-awesome bootstrap-colorpicker jspdf opencv.js/opencv.js" # A list of node_module dependencies to force commit
# --- Constants ---
# --- Arguments ---
# $1: Repo(to use as upstream) url in the form username/repo (default: publiclab/image-sequencer) NOTE: Github only
# $2: Branch to pull from eg: main or stable (default: stable)
# $3: CNAME URL (default: none)
# $4: Set the fourth argument to anything to bypass the warning.
if [[ "$1" != "" ]];
then
repo=$1
else
repo="publiclab/image-sequencer"
fi
if [[ "$2" != "" ]];
then
branch=$2
else
branch="stable"
fi
if [[ "$3" != "" ]];
then
CNAMEURL=$3
else
CNAMEURL=""
fi
# --- Arguments ---
# --- Main Script ---
if [[ "$4" == "" ]]; # Set a 4th argument to anything to bypass this warning.
then
warn
fi
git checkout gh-pages
git remote add upstream https://github.com/$repo
git fetch upstream
git reset --hard upstream/$branch
echo -e "Running setup script."
npm run setup
echo -e "Building dist files."
grunt production
if [ ! -f CNAME ];
then
echo -e "Creating CNAME"
touch CNAME
fi
echo $CNAMEURL > CNAME
echo -e "Removing unnecessary files."
rm -R docs/
rm -R test/
rm CONTRIBUTING.md
rm index.js
echo -e "Copying important files from src/"
cp src/ui/prepareDynamic.js prepareDynamic.js
echo "Removing src/"
rm -R src/
mkdir -p src/ui/
mv prepareDynamic.js src/ui/prepareDynamic.js
echo -e "git add dist and node_modules dependencies."
git add .
for dep in $deps; # Force add node_modules dependencies
do
git add -f node_modules/$dep
done
git add -f dist/image-sequencer.js
git add -f dist/image-sequencer-ui.js
echo -e "committing and pusing."
git commit --no-verify -m "update"
git push -f
exit 0
# --- Main Script ---

View File

@@ -11,7 +11,6 @@ module.exports = {
'canvas-resize': require('./modules/CanvasResize'),
'channel': require('./modules/Channel'),
'colorbar': require('./modules/Colorbar'),
'color-halftone': require('./modules/ColorHalftone'),
'color-temperature': require('./modules/ColorTemperature'),
'colormap': require('./modules/Colormap'),
'constrained-crop': require('./modules/ConstrainedCrop'),
@@ -31,7 +30,6 @@ module.exports = {
'gradient': require('./modules/Gradient'),
'grid-overlay': require('./modules/GridOverlay'),
'import-image': require('./modules/ImportImage'),
'mask': require('./modules/Mask'),
'minify-image': require('./modules/MinifyImage'),
// 'invert': require('image-sequencer-invert'),
'invert': require('./modules/Invert'),
@@ -44,7 +42,6 @@ module.exports = {
'resize': require('./modules/Resize'),
'rotate': require('./modules/Rotate'),
'saturation': require('./modules/Saturation'),
'shadow': require('./modules/Shadow'),
'text-overlay': require('./modules/TextOverlay'),
'threshold': require('./modules/Threshold'),
'tint': require('./modules/Tint'),

View File

@@ -1,135 +0,0 @@
/*
* Generate halftone versions of CMYK channels and blend them with varying rotations as in analog print color separation processes.
* Simulates a CMYK halftone rendering of the image by multiplying pixel values with a four rotated 2D sine wave patterns, one each for cyan, magenta, yellow, and black.
* http://evanw.github.io/glfx.js/docs/#colorHalftone
*/
module.exports = function ColorHalftone(options, UI) {
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
var output;
var fx = require('glfx');
var dataURItoBlob = function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString });
};
var canvasToBlobUrl = function canvasToBlobUrl(canvas) {
var blob = dataURItoBlob(canvas.toDataURL('image/png'));
return window.URL.createObjectURL(blob);
};
var colorHalftone = function colorHalftone(id, options, download) {
// try to create a WebGL canvas (will fail if WebGL isn't supported)
try {
var canvas = fx.canvas(1500, 1500);
} catch (e) {
alert(e);
return;
}
// convert the image to a texture
var imageEl = document.getElementById(id);
var image = new Image();
image.onload = function() {
var texture = canvas.texture(image);
canvas.draw(texture,
image.width, // * ratio,
image.height// * ratio
);
canvas.colorHalftone(
image.width / 2,
image.height / 2,
parseFloat(options.angle),
parseFloat(options.size)
).update();
var burl = canvasToBlobUrl(canvas);
if (download) {
window.open(burl);
} else { // replace the image
// keep non-blob version in case we have to fall back:
// image.src = canvas.toDataURL('image/png');
// window.location = canvas.toDataURL('image/png');
imageEl.src = burl;
}
};
$(image).hide();
image.src = imageEl.src;
};
function draw(input, callback) {
var step = this;
options.angle = options.angle || defaults.angle;
options.size = options.size || defaults.size;
if (!options.inBrowser) {
// this.output = input;
// callback();
require('../_nomodule/gl-context')(input, callback, step, options);
}
else {
var image = document.createElement('img');
image.onload = () => {
colorHalftone(
'img',
options
);
image.onload = () => {
var canvas = document.createElement('canvas');
canvas.width = image.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = image.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(image, 0, 0);
step.output = { src: canvas.toDataURL('image/png'), format: 'png' };
image.remove();
callback();
};
};
image.src = input.src;
image.id = 'img';
document.body.appendChild(image);
}
}
return {
options: options,
draw: draw,
output: output,
UI: UI
};
};

View File

@@ -1,4 +0,0 @@
module.exports = [
require('./Module'),
require('./info.json')
];

View File

@@ -1,22 +0,0 @@
{
"name": "color-halftone",
"requires": ["webgl"],
"description": "Generate halftone versions of CMYK channels and blend them with varying rotations as in analog print color separation processes.",
"inputs": {
"angle": {
"type": "float",
"desc": "angle of rotation of the halftone patterns in radians",
"default": "0.25",
"min": "0",
"max": "1.57"
},
"size": {
"type": "integer",
"desc": "the diameter of a dot in pixels",
"default": "4",
"min": "3",
"max": "20"
}
},
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#color-halftone-module"
}

View File

@@ -6,7 +6,7 @@ module.exports = require('../../util/createMetaModule.js')(
{ 'name': 'gradient', 'options': {} },
{ 'name': 'colormap', 'options': { colormap: options.colormap || defaults.colormap } },
{ 'name': 'crop', 'options': { 'y': 0, 'w': '100%', 'h': options.h || defaults.h } },
{ 'name': 'overlay', 'options': { 'x': options.x || defaults.x, 'y': options.y || defaults.y, 'offset': -4 } }
{ 'name': 'overlay', 'options': { 'x': options.x || defaults.h, 'y': options.y || defaults.y, 'offset': -4 } }
];
}, {
infoJson: require('./info.json')

View File

@@ -29,13 +29,11 @@ module.exports = function CropModule(options, UI) {
options.step.input = input.src;
// We should do this via event/listener:
if (ui && ui.hide) ui.hide();
function extraManipulation(pixels) {
const newPixels = require('./Crop')(pixels, options, function() {
// We should do this via event/listener:
if (ui && ui.hide) ui.hide();
// Start custom UI setup (draggable UI)
// Only once we have an input image
if (setupComplete === false && options.step.inBrowser && !options.noUI) {

View File

@@ -14,9 +14,11 @@ const kernelx = [
[ 1, 2, 1]
];
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, useHysteresis) {
let angles = [], grads = [], strongEdgePixels = [], weakEdgePixels = [], pixelsToBeSupressed = [];
let pixelsToBeSupressed = [];
module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, useHysteresis) {
let angles = [], grads = [], strongEdgePixels = [], weakEdgePixels = [];
for (var x = 0; x < pixels.shape[0]; x++) {
grads.push([]);
angles.push([]);
@@ -32,8 +34,8 @@ module.exports = function(pixels, highThresholdRatio, lowThresholdRatio, useHyst
angles.slice(-1)[0].push(result.angle);
}
}
nonMaxSupress(pixels, grads, angles, pixelsToBeSupressed); // Non Maximum Suppression: Filter fine edges.
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels, pixelsToBeSupressed); // Double Threshold: Categorizes edges into strong and weak edges based on two thresholds.
nonMaxSupress(pixels, grads, angles); // Non Maximum Suppression: Filter fine edges.
doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels); // Double Threshold: Categorizes edges into strong and weak edges based on two thresholds.
if(useHysteresis.toLowerCase() == 'true') hysteresis(strongEdgePixels, weakEdgePixels); // Optional Hysteresis (very slow) to minimize edges generated due to noise.
strongEdgePixels.forEach(pixel => preserve(pixels, pixel)); // Makes the strong edges White.
@@ -110,13 +112,10 @@ function sobelFilter(pixels, x, y) {
* @returns {Number} Category number of the given angle
*/
function categorizeAngle(angle){
const pi = Math.PI;
angle = angle > 0 ? angle : pi - Math.abs(angle); // Diagonally flip the angle if it is negative (since edge remains the same)
if (angle <= pi / 8 || angle > 7 * pi / 8) return 1;
else if (angle > pi / 8 && angle <= 3 * pi / 8) return 2;
else if (angle > 3 * pi / 8 && angle <= 5 * pi / 8) return 3;
else if (angle > 5 * pi / 8 && angle <= 7 * pi / 8) return 4;
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
@@ -145,7 +144,9 @@ const removeElem = (arr = [], elem) => { // Removes the specified element from t
};
// Non Maximum Supression without interpolation.
function nonMaxSupress(pixels, grads, angles, pixelsToBeSupressed) {
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++) {
@@ -158,7 +159,7 @@ function nonMaxSupress(pixels, grads, angles, pixelsToBeSupressed) {
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]);
@@ -182,11 +183,20 @@ function nonMaxSupress(pixels, grads, angles, pixelsToBeSupressed) {
}
}
/**
* @method convertToDegrees
* @description Converts the given angle(in radians) to degrees.
* @param {Number} radians Angle in radians
* @returns {Number} Angle in degrees
*/
var convertToDegrees = radians => (radians * 180) / Math.PI;
// 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)));
// Applies the double threshold to the image.
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels, pixelsToBeSupressed) {
function doubleThreshold(pixels, highThresholdRatio, lowThresholdRatio, grads, strongEdgePixels, weakEdgePixels) {
const highThreshold = findMaxInMatrix(grads) * highThresholdRatio, // High Threshold relative to the strongest edge
lowThreshold = highThreshold * lowThresholdRatio; // Low threshold relative to high threshold

View File

@@ -16,6 +16,7 @@ module.exports = function edgeDetect(options, UI) {
// The function which is called on every draw.
function draw(input, callback, progressObj) {
progressObj.stop(true);
progressObj.overrideFlag = true;

View File

@@ -3,9 +3,6 @@ const pixelSetter = require('../../util/pixelSetter.js'),
module.exports = function Gradient(options, UI) {
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
options.gradientType = options.gradientType || defaults.gradientType;
var output;
// The function which is called on every draw.
@@ -18,24 +15,11 @@ module.exports = function Gradient(options, UI) {
function extraManipulation(pixels) {
const [w, h] = pixels.shape;
if (options.gradientType === 'linear') {
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
let val = (i / w) * 255;
pixelSetter(i, j, [val, val, val, 255], pixels);
}
}
}
else {
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
var distX = Math.abs(w / 2 - i);
var distY = Math.abs(h / 2 - j);
var distance = Math.sqrt(Math.pow(distX, 2) + Math.pow(distY, 2));
val = 255 * (distance / pixels.shape[0]);
pixelSetter(i, j, [val, val, val, 255], pixels);
}
for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) {
let val = (i / w) * 255;
pixelSetter(i, j, [val, val, val, 255], pixels);
}
}

View File

@@ -1,13 +1,6 @@
{
"name": "gradient",
"description": "Gives a gradient of the image",
"inputs": {
"gradientType": {
"type": "select",
"desc": "Choose between linear or circular gradient",
"default": "linear",
"values": ["linear", "circular"]
}
},
"inputs": {},
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#gradient-module"
}

View File

@@ -1,82 +0,0 @@
module.exports = function Mask(options, UI, util) {
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
options.offset = options.offset || defaults.offset;
options.resize = options.resize || defaults.resize;
var output;
// This function is called on every draw.
function draw(input, callback, progressObj) {
progressObj.stop(true);
progressObj.overrideFlag = true;
var step = this;
var getPixels = require('get-pixels');
// convert offset as string to int
if (typeof options.offset === 'string')
options.offset = parseInt(options.offset);
// save first image's pixels
var priorStep = this.getStep(options.offset);
if (priorStep.output === undefined) {
this.output = input;
UI.notify('Offset Unavailable', 'offset-notification');
callback();
}
const alpha_masking = function(c, a) {
return (a * c + (255 - a) * c) / 255;
};
const internalSequencer = ImageSequencer({ inBrowser: false, ui: false });
internalSequencer.loadImage(priorStep.output.src, function() {
internalSequencer.importJSON([{ 'name': 'resize', 'options': { resize: options.resize } }]);
internalSequencer.run(function onCallback(internalOutput) {
getPixels(internalOutput, function(err, pixels) {
options.firstImagePixels = pixels;
function changePixel(r2, g2, b2, a2, x, y) {
let p = options.firstImagePixels;
let r1 = p.get(x, y, 0),
g1 = p.get(x, y, 1),
b1 = p.get(x, y, 2),
a1 = p.get(x, y, 3);
return [alpha_masking(r1, a2), alpha_masking(g1, a2), alpha_masking(b1, a2)];
}
function output(image, datauri, mimetype, wasmSuccess) {
step.output = {
src: datauri,
format: mimetype,
wasmSuccess,
useWasm: options.useWasm
};
}
// run PixelManipulatin on second image's pixels
return require('../_nomodule/PixelManipulation.js')(input, {
output: output,
ui: options.step.ui,
changePixel: changePixel,
format: input.format,
image: options.image,
inBrowser: options.inBrowser,
callback: callback,
useWasm: options.useWasm
});
});
});
});
}
return {
options: options,
draw: draw,
output: output,
UI: UI
};
};

View File

@@ -1,4 +0,0 @@
module.exports = [
require('./Module'),
require('./info.json')
];

View File

@@ -1,18 +0,0 @@
{
"name": "mask",
"description": "Masks two images according to their Alpha values",
"inputs": {
"offset": {
"type": "integer",
"desc": "Choose which image to mask the current image with. Two steps back is -2, three steps back is -3 etc.",
"default": -2
},
"resize": {
"type": "string",
"desc": "Percentage value by which first image is to be resized",
"default": "125%"
}
},
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
}

View File

@@ -1,17 +1,15 @@
module.exports = function Dynamic(options, UI, util) {
const defaults = require('./../../util/getDefaults.js')(require('./info.json'));
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
options.x = options.x || defaults.x;
options.y = options.y || defaults.y;
if(options.step.inBrowser && !options.noUI && sequencer.getSteps().length < 2)
options.offset = -1;
let ui;
if (options.step.inBrowser && !options.noUI) var ui = require('./Ui.js')(options.step, UI);
if (options.step.inBrowser && !options.noUI) ui = require('./Ui.js')(options.step, UI);
let output;
var output;
// This function is called on every draw.
function draw(input, callback, progressObj) {
@@ -21,15 +19,15 @@ module.exports = function Dynamic(options, UI, util) {
progressObj.stop(true);
progressObj.overrideFlag = true;
const step = this;
var step = this;
const parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
var parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
// save the pixels of the base image
const baseStepImage = this.getStep(options.offset).image;
const baseStepOutput = this.getOutput(options.offset);
var baseStepImage = this.getStep(options.offset).image;
var baseStepOutput = this.getOutput(options.offset);
const getPixels = require('get-pixels');
var getPixels = require('get-pixels');
getPixels(input.src, function(err, pixels) {
// parse the inputs
@@ -49,29 +47,20 @@ module.exports = function Dynamic(options, UI, util) {
function changePixel(r1, g1, b1, a1, x, y) {
const firstImagePixels = [r1, g1, b1, a1];
// overlay
const p = options.secondImagePixels;
var p = options.secondImagePixels;
if (x >= options.x
&& x - options.x < p.shape[0]
&& y >= options.y
&& y - options.y < p.shape[1]){
const secondImagePixels = [
&& y - options.y < p.shape[1])
return [
p.get(x - options.x, y - options.y, 0),
p.get(x - options.x, y - options.y, 1),
p.get(x - options.x, y - options.y, 2),
p.get(x - options.x, y - options.y, 3)
];
if(secondImagePixels[3] === 0)
return firstImagePixels;
else
return secondImagePixels;
}
else
return firstImagePixels;
return [r1, g1, b1, a1];
}
function output(image, datauri, mimetype, wasmSuccess) {

View File

@@ -1,3 +1,6 @@
const imagejs = require('imagejs'),
pixelSetter = require('../../util/pixelSetter'),
ndarray = require('ndarray');
/*
* Resize the image by given percentage value
*/
@@ -16,7 +19,44 @@ module.exports = function Resize(options, UI) {
const step = this;
function extraManipulation(pixels) {
return require('./Resize')(pixels, options);
// Value above 100% scales up, and below 100% scales down
const resize_value = parseInt(options.resize.slice(0, -1));
if (resize_value == 100) return pixels;
const new_width = Math.round(pixels.shape[0] * (resize_value / 100)),
new_height = Math.round(pixels.shape[1] * (resize_value / 100));
const bitmap = new imagejs.Bitmap({ width: pixels.shape[0], height: pixels.shape[1] });
for (let x = 0; x < pixels.shape[0]; x++) {
for (let y = 0; y < pixels.shape[1]; y++) {
let r = pixels.get(x, y, 0),
g = pixels.get(x, y, 1),
b = pixels.get(x, y, 2),
a = pixels.get(x, y, 3);
bitmap.setPixel(x, y, r, g, b, a);
}
}
const resized = bitmap.resize({
width: new_width,
height: new_height,
algorithm: 'bicubicInterpolation'
});
const newPix = new ndarray([], [new_width, new_height, 4]);
for (let x = 0; x < new_width; x++) {
for (let y = 0; y < new_height; y++) {
const {r, g, b, a} = resized.getPixel(x, y);
pixelSetter(x, y, [r, g, b, a], newPix);
}
}
return newPix;
}
function output(image, datauri, mimetype, wasmSuccess) {

View File

@@ -1,44 +0,0 @@
const imagejs = require('imagejs'),
pixelSetter = require('../../util/pixelSetter'),
ndarray = require('ndarray');
module.exports = function Resize(pixels, options) {
const resize_value = parseFloat(options.resize);
if (resize_value == 100) return pixels;
const new_width = Math.round(pixels.shape[0] * (resize_value / 100)),
new_height = Math.round(pixels.shape[1] * (resize_value / 100));
const bitmap = new imagejs.Bitmap({
width: pixels.shape[0],
height: pixels.shape[1]
});
for (let x = 0; x < pixels.shape[0]; x++) {
for (let y = 0; y < pixels.shape[1]; y++) {
let r = pixels.get(x, y, 0),
g = pixels.get(x, y, 1),
b = pixels.get(x, y, 2),
a = pixels.get(x, y, 3);
bitmap.setPixel(x, y, r, g, b, a);
}
}
const resized = bitmap.resize({
width: new_width,
height: new_height,
algorithm: 'bicubicInterpolation'
});
const newPix = new ndarray([], [new_width, new_height, 4]);
for (let x = 0; x < new_width; x++) {
for (let y = 0; y < new_height; y++) {
const { r, g, b, a } = resized.getPixel(x, y);
pixelSetter(x, y, [r, g, b, a], newPix);
}
}
return newPix;
};

View File

@@ -1,146 +0,0 @@
/*
* Create Shadow
*/
module.exports = function canvasResize(options, UI) {
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
const pixelSetter = require('../../util/pixelSetter.js');
var output;
function draw(input, callback, progressObj) {
options.X_value = parseInt(options.X_value || defaults.X_value);
options.Y_value = parseInt(options.Y_value || defaults.Y_value);
progressObj.stop(true);
progressObj.overrideFlag = true;
var step = this;
function extraManipulation(pixels) {
let [w, h] = pixels.shape;
let newPixels = require('ndarray')(new Uint8Array(4 * (w + Math.abs(options.X_value)) * (h + Math.abs(options.Y_value))).fill(0), [(w + Math.abs(options.X_value)), (h + Math.abs(options.Y_value)), 4]);
let iMax = w,
jMax = h;
if (options.X_value < 0 && options.Y_value < 0) {
for (var k = 0; k < Math.abs(options.X_value); k++) {
for (var l = 0; l < (h + Math.abs(options.Y_value)); l++) {
let val = 255 - ((k / Math.abs(options.X_value)) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (var k = 0; k < (w + Math.abs(options.X_value)); k++) {
for (var l = 0; l < Math.abs(options.Y_value); l++) {
if (k < Math.abs(options.X_value) && k < l) {
continue;
}
let val = 255 - ((l / Math.abs(options.Y_value)) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (let i = 0; i < iMax && i < w; i++) {
for (let j = 0; j < jMax && j < h; j++) {
let x = i + Math.abs(options.X_value), y = j + Math.abs(options.Y_value);
pixelSetter(x, y, [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2), pixels.get(i, j, 3)], newPixels);
}
}
}
else if (options.X_value >= 0 && options.Y_value >= 0) {
for (var k = w; k < (w + options.X_value); k++) {
for (var l = 0; l < (h + options.Y_value); l++) {
let val = (((k - w) / options.X_value) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (var k = 0; k < (w + options.X_value); k++) {
for (var l = h; l < (h + options.Y_value); l++) {
if (k >= w && l >= h && ((k - w) >= (l - h))) {
continue;
}
let val = ((l - h) / options.Y_value * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (let i = 0; i < iMax && i < w; i++) {
for (let j = 0; j < jMax && j < h; j++) {
let x = i, y = j;
pixelSetter(x, y, [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2), pixels.get(i, j, 3)], newPixels);
}
}
}
else if (options.X_value < 0 && options.Y_value >= 0) {
for (var k = 0; k < (w + Math.abs(options.X_value)); k++) {
for (var l = h; l < (h + options.Y_value); l++) {
let val = ((l - h) / options.Y_value * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (var k = 0; k < Math.abs(options.X_value); k++) {
for (var l = 0; l < (h + options.Y_value); l++) {
if (l + (k * (options.Y_value / Math.abs(options.X_value))) - (options.Y_value + h) > 0 && l >= h) {
continue;
}
let val = 255 - ((k / Math.abs(options.X_value)) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (let i = 0; i < iMax && i < w; i++) {
for (let j = 0; j < jMax && j < h; j++) {
let x = i + Math.abs(options.X_value), y = j;
pixelSetter(x, y, [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2), pixels.get(i, j, 3)], newPixels);
}
}
}
else if (options.X_value >= 0 && options.Y_value < 0) {
for (var k = w; k < (w + options.X_value); k++) {
for (var l = 0; l < (h + Math.abs(options.Y_value)); l++) {
let val = (((k - w) / options.X_value) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (var k = 0; k < (w + options.X_value); k++) {
for (var l = 0; l < Math.abs(options.Y_value); l++) {
if (l >= ((options.X_value / Math.abs(options.Y_value)) * (w + options.X_value - k)) && k >= w) {
continue;
}
let val = 255 - (l / Math.abs(options.Y_value) * 255);
pixelSetter(k, l, [val, val, val, 255], newPixels);
}
}
for (let i = 0; i < iMax && i < w; i++) {
for (let j = 0; j < jMax && j < h; j++) {
let x = i, y = j + Math.abs(options.Y_value);
pixelSetter(x, y, [pixels.get(i, j, 0), pixels.get(i, j, 1), pixels.get(i, j, 2), pixels.get(i, j, 3)], newPixels);
}
}
}
return newPixels;
}
function output(image, datauri, mimetype, wasmSuccess) {
step.output = { src: datauri, format: mimetype, wasmSuccess, useWasm: options.useWasm };
}
return require('../_nomodule/PixelManipulation.js')(input, {
output: output,
ui: options.step.ui,
extraManipulation: extraManipulation,
format: input.format,
image: options.image,
inBrowser: options.inBrowser,
callback: callback,
useWasm:options.useWasm
});
}
return {
options: options,
draw: draw,
output: output,
UI: UI
};
};

View File

@@ -1,4 +0,0 @@
module.exports = [
require('./Module'),
require('./info.json')
];

View File

@@ -1,17 +0,0 @@
{
"name": "shadow",
"description": "Creates a two sided shadow.",
"inputs": {
"X_value": {
"type": "integer",
"desc": "X-value",
"default": 20
},
"Y_value": {
"type": "integer",
"desc": "Y-value",
"default": 20
}
},
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md#shadow-module"
}

View File

@@ -6,7 +6,7 @@ module.exports = function DoNothing(options, UI) {
var defaults = require('./../../util/getDefaults.js')(require('./info.json'));
var output;
var fx = require('glfx');
var fx = require('./glfx');
var dataURItoBlob = function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string

View File

@@ -0,0 +1,152 @@
/*
* glfx.js
* http://evanw.github.com/glfx.js/
*
* Copyright 2011 Evan Wallace
* Released under the MIT license
*/
module.exports = function() {
function q(a, d, c) { return Math.max(a, Math.min(d, c)); } function w(b) { return { _: b, loadContentsOf: function(b) { a = this._.gl; this._.loadContentsOf(b); }, destroy: function() { a = this._.gl; this._.destroy(); } }; } function A(a) { return w(r.fromElement(a)); } function B(b, d) {
var c = a.UNSIGNED_BYTE; if (a.getExtension('OES_texture_float') && a.getExtension('OES_texture_float_linear')) { var e = new r(100, 100, a.RGBA, a.FLOAT); try { e.drawTo(function() { c = a.FLOAT; }); } catch (g) { } e.destroy(); } this._.texture && this._.texture.destroy();
this._.spareTexture && this._.spareTexture.destroy(); this.width = b; this.height = d; this._.texture = new r(b, d, a.RGBA, c); this._.spareTexture = new r(b, d, a.RGBA, c); this._.extraTexture = this._.extraTexture || new r(0, 0, a.RGBA, c); this._.flippedShader = this._.flippedShader || new h(null, 'uniform sampler2D texture;varying vec2 texCoord;void main(){gl_FragColor=texture2D(texture,vec2(texCoord.x,1.0-texCoord.y));}'); this._.isInitialized = !0;
} function C(a, d, c) {
this._.isInitialized &&
a._.width == this.width && a._.height == this.height || B.call(this, d ? d : a._.width, c ? c : a._.height); a._.use(); this._.texture.drawTo(function() { h.getDefaultShader().drawRect(); }); return this;
} function D() { this._.texture.use(); this._.flippedShader.drawRect(); return this; } function f(a, d, c, e) { (c || this._.texture).use(); this._.spareTexture.drawTo(function() { a.uniforms(d).drawRect(); }); this._.spareTexture.swapWith(e || this._.texture); } function E(a) { a.parentNode.insertBefore(this, a); a.parentNode.removeChild(a); return this; }
function F() { var b = new r(this._.texture.width, this._.texture.height, a.RGBA, a.UNSIGNED_BYTE); this._.texture.use(); b.drawTo(function() { h.getDefaultShader().drawRect(); }); return w(b); } function G() { var b = this._.texture.width, d = this._.texture.height, c = new Uint8Array(4 * b * d); this._.texture.drawTo(function() { a.readPixels(0, 0, b, d, a.RGBA, a.UNSIGNED_BYTE, c); }); return c; } function k(b) { return function() { a = this._.gl; return b.apply(this, arguments); }; } function x(a, d, c, e, g, l, n, p) {
var m = c - g, h = e - l, f = n - g, k = p - l; g = a - c + g - n; l =
d - e + l - p; var q = m * k - f * h, f = (g * k - f * l) / q, m = (m * l - g * h) / q; return [c - a + f * c, e - d + f * e, f, n - a + m * n, p - d + m * p, m, a, d, 1];
} function y(a) { var d = a[0], c = a[1], e = a[2], g = a[3], l = a[4], n = a[5], p = a[6], m = a[7]; a = a[8]; var f = d * l * a - d * n * m - c * g * a + c * n * p + e * g * m - e * l * p; return [(l * a - n * m) / f, (e * m - c * a) / f, (c * n - e * l) / f, (n * p - g * a) / f, (d * a - e * p) / f, (e * g - d * n) / f, (g * m - l * p) / f, (c * p - d * m) / f, (d * l - c * g) / f]; } function z(a) {
var d = a.length; this.xa = []; this.ya = []; this.u = []; this.y2 = []; a.sort(function(a, b) { return a[0] - b[0]; }); for (var c = 0; c < d; c++)this.xa.push(a[c][0]), this.ya.push(a[c][1]);
this.u[0] = 0; this.y2[0] = 0; for (c = 1; c < d - 1; ++c) { a = this.xa[c + 1] - this.xa[c - 1]; var e = (this.xa[c] - this.xa[c - 1]) / a, g = e * this.y2[c - 1] + 2; this.y2[c] = (e - 1) / g; this.u[c] = (6 * ((this.ya[c + 1] - this.ya[c]) / (this.xa[c + 1] - this.xa[c]) - (this.ya[c] - this.ya[c - 1]) / (this.xa[c] - this.xa[c - 1])) / a - e * this.u[c - 1]) / g; } this.y2[d - 1] = 0; for (c = d - 2; 0 <= c; --c)this.y2[c] = this.y2[c] * this.y2[c + 1] + this.u[c];
} function u(a, d) {
return new h(null, a + 'uniform sampler2D texture;uniform vec2 texSize;varying vec2 texCoord;void main(){vec2 coord=texCoord*texSize;' +
d + 'gl_FragColor=texture2D(texture,coord/texSize);vec2 clampedCoord=clamp(coord,vec2(0.0),texSize);if(coord!=clampedCoord){gl_FragColor.a*=max(0.0,1.0-length(coord-clampedCoord));}}');
} function H(b, d) {
a.brightnessContrast = a.brightnessContrast || new h(null, 'uniform sampler2D texture;uniform float brightness;uniform float contrast;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);color.rgb+=brightness;if(contrast>0.0){color.rgb=(color.rgb-0.5)/(1.0-contrast)+0.5;}else{color.rgb=(color.rgb-0.5)*(1.0+contrast)+0.5;}gl_FragColor=color;}');
f.call(this, a.brightnessContrast, { brightness: q(-1, b, 1), contrast: q(-1, d, 1) }); return this;
} function t(a) { a = new z(a); for (var d = [], c = 0; 256 > c; c++)d.push(q(0, Math.floor(256 * a.interpolate(c / 255)), 255)); return d; } function I(b, d, c) {
b = t(b); 1 == arguments.length ? d = c = b : (d = t(d), c = t(c)); for (var e = [], g = 0; 256 > g; g++)e.splice(e.length, 0, b[g], d[g], c[g], 255); this._.extraTexture.initFromBytes(256, 1, e); this._.extraTexture.use(1); a.curves = a.curves || new h(null, 'uniform sampler2D texture;uniform sampler2D map;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);color.r=texture2D(map,vec2(color.r)).r;color.g=texture2D(map,vec2(color.g)).g;color.b=texture2D(map,vec2(color.b)).b;gl_FragColor=color;}');
a.curves.textures({ map: 1 }); f.call(this, a.curves, {}); return this;
} function J(b) {
a.denoise = a.denoise || new h(null, 'uniform sampler2D texture;uniform float exponent;uniform float strength;uniform vec2 texSize;varying vec2 texCoord;void main(){vec4 center=texture2D(texture,texCoord);vec4 color=vec4(0.0);float total=0.0;for(float x=-4.0;x<=4.0;x+=1.0){for(float y=-4.0;y<=4.0;y+=1.0){vec4 sample=texture2D(texture,texCoord+vec2(x,y)/texSize);float weight=1.0-abs(dot(sample.rgb-center.rgb,vec3(0.25)));weight=pow(weight,exponent);color+=sample*weight;total+=weight;}}gl_FragColor=color/total;}');
for (var d = 0; 2 > d; d++)f.call(this, a.denoise, { exponent: Math.max(0, b), texSize: [this.width, this.height] }); return this;
} function K(b, d) {
a.hueSaturation = a.hueSaturation || new h(null, 'uniform sampler2D texture;uniform float hue;uniform float saturation;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float angle=hue*3.14159265;float s=sin(angle),c=cos(angle);vec3 weights=(vec3(2.0*c,-sqrt(3.0)*s-c,sqrt(3.0)*s-c)+1.0)/3.0;float len=length(color.rgb);color.rgb=vec3(dot(color.rgb,weights.xyz),dot(color.rgb,weights.zxy),dot(color.rgb,weights.yzx));float average=(color.r+color.g+color.b)/3.0;if(saturation>0.0){color.rgb+=(average-color.rgb)*(1.0-1.0/(1.001-saturation));}else{color.rgb+=(average-color.rgb)*(-saturation);}gl_FragColor=color;}');
f.call(this, a.hueSaturation, { hue: q(-1, b, 1), saturation: q(-1, d, 1) }); return this;
} function L(b) {
a.noise = a.noise || new h(null, 'uniform sampler2D texture;uniform float amount;varying vec2 texCoord;float rand(vec2 co){return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);}void main(){vec4 color=texture2D(texture,texCoord);float diff=(rand(texCoord)-0.5)*amount;color.r+=diff;color.g+=diff;color.b+=diff;gl_FragColor=color;}');
f.call(this, a.noise, { amount: q(0, b, 1) }); return this;
} function M(b) {
a.sepia = a.sepia || new h(null, 'uniform sampler2D texture;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float r=color.r;float g=color.g;float b=color.b;color.r=min(1.0,(r*(1.0-(0.607*amount)))+(g*(0.769*amount))+(b*(0.189*amount)));color.g=min(1.0,(r*0.349*amount)+(g*(1.0-(0.314*amount)))+(b*0.168*amount));color.b=min(1.0,(r*0.272*amount)+(g*0.534*amount)+(b*(1.0-(0.869*amount))));gl_FragColor=color;}');
f.call(this, a.sepia, { amount: q(0, b, 1) }); return this;
} function N(b, d) {
a.unsharpMask = a.unsharpMask || new h(null, 'uniform sampler2D blurredTexture;uniform sampler2D originalTexture;uniform float strength;uniform float threshold;varying vec2 texCoord;void main(){vec4 blurred=texture2D(blurredTexture,texCoord);vec4 original=texture2D(originalTexture,texCoord);gl_FragColor=mix(blurred,original,1.0+strength);}');
this._.extraTexture.ensureFormat(this._.texture); this._.texture.use(); this._.extraTexture.drawTo(function() { h.getDefaultShader().drawRect(); }); this._.extraTexture.use(1); this.triangleBlur(b); a.unsharpMask.textures({ originalTexture: 1 }); f.call(this, a.unsharpMask, { strength: d }); this._.extraTexture.unuse(1); return this;
} function O(b) {
a.vibrance = a.vibrance || new h(null, 'uniform sampler2D texture;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float average=(color.r+color.g+color.b)/3.0;float mx=max(color.r,max(color.g,color.b));float amt=(mx-average)*(-amount*3.0);color.rgb=mix(color.rgb,vec3(mx),amt);gl_FragColor=color;}');
f.call(this, a.vibrance, { amount: q(-1, b, 1) }); return this;
} function P(b, d) {
a.vignette = a.vignette || new h(null, 'uniform sampler2D texture;uniform float size;uniform float amount;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);float dist=distance(texCoord,vec2(0.5,0.5));color.rgb*=smoothstep(0.8,size*0.799,dist*(amount+size));gl_FragColor=color;}');
f.call(this, a.vignette, { size: q(0, b, 1), amount: q(0, d, 1) }); return this;
} function Q(b, d, c) {
a.lensBlurPrePass = a.lensBlurPrePass || new h(null, 'uniform sampler2D texture;uniform float power;varying vec2 texCoord;void main(){vec4 color=texture2D(texture,texCoord);color=pow(color,vec4(power));gl_FragColor=vec4(color);}'); var e = 'uniform sampler2D texture0;uniform sampler2D texture1;uniform vec2 delta0;uniform vec2 delta1;uniform float power;varying vec2 texCoord;' +
s + 'vec4 sample(vec2 delta){float offset=random(vec3(delta,151.7182),0.0);vec4 color=vec4(0.0);float total=0.0;for(float t=0.0;t<=30.0;t++){float percent=(t+offset)/30.0;color+=texture2D(texture0,texCoord+delta*percent);total+=1.0;}return color/total;}';
a.lensBlur0 = a.lensBlur0 || new h(null, e + 'void main(){gl_FragColor=sample(delta0);}'); a.lensBlur1 = a.lensBlur1 || new h(null, e + 'void main(){gl_FragColor=(sample(delta0)+sample(delta1))*0.5;}'); a.lensBlur2 = a.lensBlur2 || (new h(null, e + 'void main(){vec4 color=(sample(delta0)+2.0*texture2D(texture1,texCoord))/3.0;gl_FragColor=pow(color,vec4(power));}')).textures({ texture1: 1 }); for (var e =
[], g = 0; 3 > g; g++) { var l = c + 2 * g * Math.PI / 3; e.push([b * Math.sin(l) / this.width, b * Math.cos(l) / this.height]); } b = Math.pow(10, q(-1, d, 1)); f.call(this, a.lensBlurPrePass, { power: b }); this._.extraTexture.ensureFormat(this._.texture); f.call(this, a.lensBlur0, { delta0: e[0] }, this._.texture, this._.extraTexture); f.call(this, a.lensBlur1, { delta0: e[1], delta1: e[2] }, this._.extraTexture, this._.extraTexture); f.call(this, a.lensBlur0, { delta0: e[1] }); this._.extraTexture.use(1); f.call(this, a.lensBlur2, { power: 1 / b, delta0: e[2] }); return this;
}
function R(b, d, c, e, g, l) {
a.tiltShift = a.tiltShift || new h(null, 'uniform sampler2D texture;uniform float blurRadius;uniform float gradientRadius;uniform vec2 start;uniform vec2 end;uniform vec2 delta;uniform vec2 texSize;varying vec2 texCoord;' + s + 'void main(){vec4 color=vec4(0.0);float total=0.0;float offset=random(vec3(12.9898,78.233,151.7182),0.0);vec2 normal=normalize(vec2(start.y-end.y,end.x-start.x));float radius=smoothstep(0.0,1.0,abs(dot(texCoord*texSize-start,normal))/gradientRadius)*blurRadius;for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec4 sample=texture2D(texture,texCoord+delta/texSize*percent*radius);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}');
var n = c - b, p = e - d, m = Math.sqrt(n * n + p * p); f.call(this, a.tiltShift, { blurRadius: g, gradientRadius: l, start: [b, d], end: [c, e], delta: [n / m, p / m], texSize: [this.width, this.height] }); f.call(this, a.tiltShift, { blurRadius: g, gradientRadius: l, start: [b, d], end: [c, e], delta: [-p / m, n / m], texSize: [this.width, this.height] }); return this;
} function S(b) {
a.triangleBlur = a.triangleBlur || new h(null, 'uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;' + s + 'void main(){vec4 color=vec4(0.0);float total=0.0;float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec4 sample=texture2D(texture,texCoord+delta*percent);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}');
f.call(this, a.triangleBlur, { delta: [b / this.width, 0] }); f.call(this, a.triangleBlur, { delta: [0, b / this.height] }); return this;
} function T(b, d, c) {
a.zoomBlur = a.zoomBlur || new h(null, 'uniform sampler2D texture;uniform vec2 center;uniform float strength;uniform vec2 texSize;varying vec2 texCoord;' + s + 'void main(){vec4 color=vec4(0.0);float total=0.0;vec2 toCenter=center-texCoord*texSize;float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=0.0;t<=40.0;t++){float percent=(t+offset)/40.0;float weight=4.0*(percent-percent*percent);vec4 sample=texture2D(texture,texCoord+toCenter*percent*strength/texSize);sample.rgb*=sample.a;color+=sample*weight;total+=weight;}gl_FragColor=color/total;gl_FragColor.rgb/=gl_FragColor.a+0.00001;}');
f.call(this, a.zoomBlur, { center: [b, d], strength: c, texSize: [this.width, this.height] }); return this;
} function U(b, d, c, e) {
a.colorHalftone = a.colorHalftone || new h(null, 'uniform sampler2D texture;uniform vec2 center;uniform float angle;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;float pattern(float angle){float s=sin(angle),c=cos(angle);vec2 tex=texCoord*texSize-center;vec2 point=vec2(c*tex.x-s*tex.y,s*tex.x+c*tex.y)*scale;return(sin(point.x)*sin(point.y))*4.0;}void main(){vec4 color=texture2D(texture,texCoord);vec3 cmy=1.0-color.rgb;float k=min(cmy.x,min(cmy.y,cmy.z));cmy=(cmy-k)/(1.0-k);cmy=clamp(cmy*10.0-3.0+vec3(pattern(angle+0.26179),pattern(angle+1.30899),pattern(angle)),0.0,1.0);k=clamp(k*10.0-5.0+pattern(angle+0.78539),0.0,1.0);gl_FragColor=vec4(1.0-cmy-k,color.a);}');
f.call(this, a.colorHalftone, { center: [b, d], angle: c, scale: Math.PI / e, texSize: [this.width, this.height] }); return this;
} function V(b, d, c, e) {
a.dotScreen = a.dotScreen || new h(null, 'uniform sampler2D texture;uniform vec2 center;uniform float angle;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;float pattern(){float s=sin(angle),c=cos(angle);vec2 tex=texCoord*texSize-center;vec2 point=vec2(c*tex.x-s*tex.y,s*tex.x+c*tex.y)*scale;return(sin(point.x)*sin(point.y))*4.0;}void main(){vec4 color=texture2D(texture,texCoord);float average=(color.r+color.g+color.b)/3.0;gl_FragColor=vec4(vec3(average*10.0-5.0+pattern()),color.a);}');
f.call(this, a.dotScreen, { center: [b, d], angle: c, scale: Math.PI / e, texSize: [this.width, this.height] }); return this;
} function W(b) {
a.edgeWork1 = a.edgeWork1 || new h(null, 'uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;' + s + 'void main(){vec2 color=vec2(0.0);vec2 total=vec2(0.0);float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec3 sample=texture2D(texture,texCoord+delta*percent).rgb;float average=(sample.r+sample.g+sample.b)/3.0;color.x+=average*weight;total.x+=weight;if(abs(t)<15.0){weight=weight*2.0-1.0;color.y+=average*weight;total.y+=weight;}}gl_FragColor=vec4(color/total,0.0,1.0);}');
a.edgeWork2 = a.edgeWork2 || new h(null, 'uniform sampler2D texture;uniform vec2 delta;varying vec2 texCoord;' + s + 'void main(){vec2 color=vec2(0.0);vec2 total=vec2(0.0);float offset=random(vec3(12.9898,78.233,151.7182),0.0);for(float t=-30.0;t<=30.0;t++){float percent=(t+offset-0.5)/30.0;float weight=1.0-abs(percent);vec2 sample=texture2D(texture,texCoord+delta*percent).xy;color.x+=sample.x*weight;total.x+=weight;if(abs(t)<15.0){weight=weight*2.0-1.0;color.y+=sample.y*weight;total.y+=weight;}}float c=clamp(10000.0*(color.y/total.y-color.x/total.x)+0.5,0.0,1.0);gl_FragColor=vec4(c,c,c,1.0);}');
f.call(this, a.edgeWork1, { delta: [b / this.width, 0] }); f.call(this, a.edgeWork2, { delta: [0, b / this.height] }); return this;
} function X(b, d, c) {
a.hexagonalPixelate = a.hexagonalPixelate || new h(null, 'uniform sampler2D texture;uniform vec2 center;uniform float scale;uniform vec2 texSize;varying vec2 texCoord;void main(){vec2 tex=(texCoord*texSize-center)/scale;tex.y/=0.866025404;tex.x-=tex.y*0.5;vec2 a;if(tex.x+tex.y-floor(tex.x)-floor(tex.y)<1.0)a=vec2(floor(tex.x),floor(tex.y));else a=vec2(ceil(tex.x),ceil(tex.y));vec2 b=vec2(ceil(tex.x),floor(tex.y));vec2 c=vec2(floor(tex.x),ceil(tex.y));vec3 TEX=vec3(tex.x,tex.y,1.0-tex.x-tex.y);vec3 A=vec3(a.x,a.y,1.0-a.x-a.y);vec3 B=vec3(b.x,b.y,1.0-b.x-b.y);vec3 C=vec3(c.x,c.y,1.0-c.x-c.y);float alen=length(TEX-A);float blen=length(TEX-B);float clen=length(TEX-C);vec2 choice;if(alen<blen){if(alen<clen)choice=a;else choice=c;}else{if(blen<clen)choice=b;else choice=c;}choice.x+=choice.y*0.5;choice.y*=0.866025404;choice*=scale/texSize;gl_FragColor=texture2D(texture,choice+center/texSize);}');
f.call(this, a.hexagonalPixelate, { center: [b, d], scale: c, texSize: [this.width, this.height] }); return this;
} function Y(b) {
a.ink = a.ink || new h(null, 'uniform sampler2D texture;uniform float strength;uniform vec2 texSize;varying vec2 texCoord;void main(){vec2 dx=vec2(1.0/texSize.x,0.0);vec2 dy=vec2(0.0,1.0/texSize.y);vec4 color=texture2D(texture,texCoord);float bigTotal=0.0;float smallTotal=0.0;vec3 bigAverage=vec3(0.0);vec3 smallAverage=vec3(0.0);for(float x=-2.0;x<=2.0;x+=1.0){for(float y=-2.0;y<=2.0;y+=1.0){vec3 sample=texture2D(texture,texCoord+dx*x+dy*y).rgb;bigAverage+=sample;bigTotal+=1.0;if(abs(x)+abs(y)<2.0){smallAverage+=sample;smallTotal+=1.0;}}}vec3 edge=max(vec3(0.0),bigAverage/bigTotal-smallAverage/smallTotal);gl_FragColor=vec4(color.rgb-dot(edge,edge)*strength*100000.0,color.a);}');
f.call(this, a.ink, { strength: b * b * b * b * b, texSize: [this.width, this.height] }); return this;
} function Z(b, d, c, e) {
a.bulgePinch = a.bulgePinch || u('uniform float radius;uniform float strength;uniform vec2 center;', 'coord-=center;float distance=length(coord);if(distance<radius){float percent=distance/radius;if(strength>0.0){coord*=mix(1.0,smoothstep(0.0,radius/distance,percent),strength*0.75);}else{coord*=mix(1.0,pow(percent,1.0+strength*0.75)*radius/distance,1.0-percent);}}coord+=center;');
f.call(this, a.bulgePinch, { radius: c, strength: q(-1, e, 1), center: [b, d], texSize: [this.width, this.height] }); return this;
} function $(b, d, c) {
a.matrixWarp = a.matrixWarp || u('uniform mat3 matrix;uniform bool useTextureSpace;', 'if(useTextureSpace)coord=coord/texSize*2.0-1.0;vec3 warp=matrix*vec3(coord,1.0);coord=warp.xy/warp.z;if(useTextureSpace)coord=(coord*0.5+0.5)*texSize;'); b = Array.prototype.concat.apply([], b); if (4 == b.length) b =
[b[0], b[1], 0, b[2], b[3], 0, 0, 0, 1]; else if (9 != b.length) throw 'can only warp with 2x2 or 3x3 matrix'; f.call(this, a.matrixWarp, { matrix: d ? y(b) : b, texSize: [this.width, this.height], useTextureSpace: c | 0 }); return this;
} function aa(a, d) {
var c = x.apply(null, d), e = x.apply(null, a), c = y(c); return this.matrixWarp([c[0] * e[0] + c[1] * e[3] + c[2] * e[6], c[0] * e[1] + c[1] * e[4] + c[2] * e[7], c[0] * e[2] + c[1] * e[5] + c[2] * e[8], c[3] * e[0] + c[4] * e[3] + c[5] * e[6], c[3] * e[1] + c[4] * e[4] + c[5] * e[7], c[3] * e[2] + c[4] * e[5] + c[5] * e[8], c[6] * e[0] + c[7] * e[3] + c[8] * e[6],
c[6] * e[1] + c[7] * e[4] + c[8] * e[7], c[6] * e[2] + c[7] * e[5] + c[8] * e[8]]);
} function ba(b, d, c, e) {
a.swirl = a.swirl || u('uniform float radius;uniform float angle;uniform vec2 center;', 'coord-=center;float distance=length(coord);if(distance<radius){float percent=(radius-distance)/radius;float theta=percent*percent*angle;float s=sin(theta);float c=cos(theta);coord=vec2(coord.x*c-coord.y*s,coord.x*s+coord.y*c);}coord+=center;');
f.call(this, a.swirl, { radius: c, center: [b, d], angle: e, texSize: [this.width, this.height] }); return this;
} var v = {}; (function() {
function a(b) {
if (!b.getExtension('OES_texture_float')) return !1; var c = b.createFramebuffer(), e = b.createTexture(); b.bindTexture(b.TEXTURE_2D, e); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_MAG_FILTER, b.NEAREST); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_MIN_FILTER, b.NEAREST); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_WRAP_S, b.CLAMP_TO_EDGE); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_WRAP_T, b.CLAMP_TO_EDGE);
b.texImage2D(b.TEXTURE_2D, 0, b.RGBA, 1, 1, 0, b.RGBA, b.UNSIGNED_BYTE, null); b.bindFramebuffer(b.FRAMEBUFFER, c); b.framebufferTexture2D(b.FRAMEBUFFER, b.COLOR_ATTACHMENT0, b.TEXTURE_2D, e, 0); c = b.createTexture(); b.bindTexture(b.TEXTURE_2D, c); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_MAG_FILTER, b.LINEAR); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_MIN_FILTER, b.LINEAR); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_WRAP_S, b.CLAMP_TO_EDGE); b.texParameteri(b.TEXTURE_2D, b.TEXTURE_WRAP_T, b.CLAMP_TO_EDGE); b.texImage2D(b.TEXTURE_2D,
0, b.RGBA, 2, 2, 0, b.RGBA, b.FLOAT, new Float32Array([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); var e = b.createProgram(), d = b.createShader(b.VERTEX_SHADER), g = b.createShader(b.FRAGMENT_SHADER); b.shaderSource(d, 'attribute vec2 vertex;void main(){gl_Position=vec4(vertex,0.0,1.0);}'); b.shaderSource(g, 'uniform sampler2D texture;void main(){gl_FragColor=texture2D(texture,vec2(0.5));}'); b.compileShader(d); b.compileShader(g); b.attachShader(e, d); b.attachShader(e,
g); b.linkProgram(e); d = b.createBuffer(); b.bindBuffer(b.ARRAY_BUFFER, d); b.bufferData(b.ARRAY_BUFFER, new Float32Array([0, 0]), b.STREAM_DRAW); b.enableVertexAttribArray(0); b.vertexAttribPointer(0, 2, b.FLOAT, !1, 0, 0); d = new Uint8Array(4); b.useProgram(e); b.viewport(0, 0, 1, 1); b.bindTexture(b.TEXTURE_2D, c); b.drawArrays(b.POINTS, 0, 1); b.readPixels(0, 0, 1, 1, b.RGBA, b.UNSIGNED_BYTE, d); return 127 === d[0] || 128 === d[0];
} function d() { } function c(a) {
'OES_texture_float_linear' === a ? (void 0 === this.$OES_texture_float_linear$ && Object.defineProperty(this,
'$OES_texture_float_linear$', { enumerable: !1, configurable: !1, writable: !1, value: new d }), a = this.$OES_texture_float_linear$) : a = n.call(this, a); return a;
} function e() { var a = f.call(this); -1 === a.indexOf('OES_texture_float_linear') && a.push('OES_texture_float_linear'); return a; } try { var g = document.createElement('canvas').getContext('experimental-webgl'); } catch (l) { } if (g && -1 === g.getSupportedExtensions().indexOf('OES_texture_float_linear') && a(g)) {
var n = WebGLRenderingContext.prototype.getExtension, f = WebGLRenderingContext.prototype.getSupportedExtensions;
WebGLRenderingContext.prototype.getExtension = c; WebGLRenderingContext.prototype.getSupportedExtensions = e;
}
})(); var a; v.canvas = function() {
var b = document.createElement('canvas'); try { a = b.getContext('experimental-webgl', { premultipliedAlpha: !1 }); } catch (d) { a = null; } if (!a) throw 'This browser does not support WebGL'; b._ = { gl: a, isInitialized: !1, texture: null, spareTexture: null, flippedShader: null }; b.texture = k(A); b.draw = k(C); b.update = k(D); b.replace = k(E); b.contents = k(F); b.getPixelArray = k(G); b.brightnessContrast = k(H);
b.hexagonalPixelate = k(X); b.hueSaturation = k(K); b.colorHalftone = k(U); b.triangleBlur = k(S); b.unsharpMask = k(N); b.perspective = k(aa); b.matrixWarp = k($); b.bulgePinch = k(Z); b.tiltShift = k(R); b.dotScreen = k(V); b.edgeWork = k(W); b.lensBlur = k(Q); b.zoomBlur = k(T); b.noise = k(L); b.denoise = k(J); b.curves = k(I); b.swirl = k(ba); b.ink = k(Y); b.vignette = k(P); b.vibrance = k(O); b.sepia = k(M); return b;
}; v.splineInterpolate = t; var h = function() {
function b(b, c) {
var e = a.createShader(b); a.shaderSource(e, c); a.compileShader(e); if (!a.getShaderParameter(e,
a.COMPILE_STATUS)) throw 'compile error: ' + a.getShaderInfoLog(e); return e;
} function d(d, l) { this.texCoordAttribute = this.vertexAttribute = null; this.program = a.createProgram(); d = d || c; l = l || e; l = 'precision highp float;' + l; a.attachShader(this.program, b(a.VERTEX_SHADER, d)); a.attachShader(this.program, b(a.FRAGMENT_SHADER, l)); a.linkProgram(this.program); if (!a.getProgramParameter(this.program, a.LINK_STATUS)) throw 'link error: ' + a.getProgramInfoLog(this.program); } var c = 'attribute vec2 vertex;attribute vec2 _texCoord;varying vec2 texCoord;void main(){texCoord=_texCoord;gl_Position=vec4(vertex*2.0-1.0,0.0,1.0);}',
e = 'uniform sampler2D texture;varying vec2 texCoord;void main(){gl_FragColor=texture2D(texture,texCoord);}'; d.prototype.destroy = function() { a.deleteProgram(this.program); this.program = null; }; d.prototype.uniforms = function(b) {
a.useProgram(this.program); for (var e in b) if (b.hasOwnProperty(e)) {
var c = a.getUniformLocation(this.program, e); if (null !== c) {
var d = b[e]; if ('[object Array]' == Object.prototype.toString.call(d)) switch (d.length) {
case 1: a.uniform1fv(c, new Float32Array(d)); break;
case 2: a.uniform2fv(c, new Float32Array(d)); break; case 3: a.uniform3fv(c, new Float32Array(d)); break; case 4: a.uniform4fv(c, new Float32Array(d)); break; case 9: a.uniformMatrix3fv(c, !1, new Float32Array(d)); break; case 16: a.uniformMatrix4fv(c, !1, new Float32Array(d)); break; default: throw 'dont\'t know how to load uniform "' + e + '" of length ' + d.length;
} else if ('[object Number]' == Object.prototype.toString.call(d)) a.uniform1f(c, d); else throw 'attempted to set uniform "' + e + '" to invalid value ' + (d || 'undefined').toString();
}
} return this;
}; d.prototype.textures = function(b) { a.useProgram(this.program); for (var c in b) b.hasOwnProperty(c) && a.uniform1i(a.getUniformLocation(this.program, c), b[c]); return this; }; d.prototype.drawRect = function(b, c, e, d) {
var f = a.getParameter(a.VIEWPORT); c = void 0 !== c ? (c - f[1]) / f[3] : 0; b = void 0 !== b ? (b - f[0]) / f[2] : 0; e = void 0 !== e ? (e - f[0]) / f[2] : 1; d = void 0 !== d ? (d - f[1]) / f[3] : 1; null == a.vertexBuffer && (a.vertexBuffer = a.createBuffer()); a.bindBuffer(a.ARRAY_BUFFER, a.vertexBuffer); a.bufferData(a.ARRAY_BUFFER, new Float32Array([b,
c, b, d, e, c, e, d]), a.STATIC_DRAW); null == a.texCoordBuffer && (a.texCoordBuffer = a.createBuffer(), a.bindBuffer(a.ARRAY_BUFFER, a.texCoordBuffer), a.bufferData(a.ARRAY_BUFFER, new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]), a.STATIC_DRAW)); null == this.vertexAttribute && (this.vertexAttribute = a.getAttribLocation(this.program, 'vertex'), a.enableVertexAttribArray(this.vertexAttribute)); null == this.texCoordAttribute && (this.texCoordAttribute = a.getAttribLocation(this.program, '_texCoord'), a.enableVertexAttribArray(this.texCoordAttribute));
a.useProgram(this.program); a.bindBuffer(a.ARRAY_BUFFER, a.vertexBuffer); a.vertexAttribPointer(this.vertexAttribute, 2, a.FLOAT, !1, 0, 0); a.bindBuffer(a.ARRAY_BUFFER, a.texCoordBuffer); a.vertexAttribPointer(this.texCoordAttribute, 2, a.FLOAT, !1, 0, 0); a.drawArrays(a.TRIANGLE_STRIP, 0, 4);
}; d.getDefaultShader = function() { a.defaultShader = a.defaultShader || new d; return a.defaultShader; }; return d;
}(); z.prototype.interpolate = function(a) {
for (var d = 0, c = this.ya.length - 1; 1 < c - d;) { var e = c + d >> 1; this.xa[e] > a ? c = e : d = e; } var e = this.xa[c] -
this.xa[d], g = (this.xa[c] - a) / e; a = (a - this.xa[d]) / e; return g * this.ya[d] + a * this.ya[c] + ((g * g * g - g) * this.y2[d] + (a * a * a - a) * this.y2[c]) * e * e / 6;
}; var r = function() {
function b(b, c, d, f) {
this.gl = a; this.id = a.createTexture(); this.width = b; this.height = c; this.format = d; this.type = f; a.bindTexture(a.TEXTURE_2D, this.id); a.texParameteri(a.TEXTURE_2D, a.TEXTURE_MAG_FILTER, a.LINEAR); a.texParameteri(a.TEXTURE_2D, a.TEXTURE_MIN_FILTER, a.LINEAR); a.texParameteri(a.TEXTURE_2D, a.TEXTURE_WRAP_S, a.CLAMP_TO_EDGE); a.texParameteri(a.TEXTURE_2D,
a.TEXTURE_WRAP_T, a.CLAMP_TO_EDGE); b && c && a.texImage2D(a.TEXTURE_2D, 0, this.format, b, c, 0, this.format, this.type, null);
} function d(a) { null == c && (c = document.createElement('canvas')); c.width = a.width; c.height = a.height; a = c.getContext('2d'); a.clearRect(0, 0, c.width, c.height); return a; } b.fromElement = function(c) { var d = new b(0, 0, a.RGBA, a.UNSIGNED_BYTE); d.loadContentsOf(c); return d; }; b.prototype.loadContentsOf = function(b) {
this.width = b.width || b.videoWidth; this.height = b.height || b.videoHeight; a.bindTexture(a.TEXTURE_2D,
this.id); a.texImage2D(a.TEXTURE_2D, 0, this.format, this.format, this.type, b);
}; b.prototype.initFromBytes = function(b, c, d) { this.width = b; this.height = c; this.format = a.RGBA; this.type = a.UNSIGNED_BYTE; a.bindTexture(a.TEXTURE_2D, this.id); a.texImage2D(a.TEXTURE_2D, 0, a.RGBA, b, c, 0, a.RGBA, this.type, new Uint8Array(d)); }; b.prototype.destroy = function() { a.deleteTexture(this.id); this.id = null; }; b.prototype.use = function(b) { a.activeTexture(a.TEXTURE0 + (b || 0)); a.bindTexture(a.TEXTURE_2D, this.id); }; b.prototype.unuse = function(b) {
a.activeTexture(a.TEXTURE0 +
(b || 0)); a.bindTexture(a.TEXTURE_2D, null);
}; b.prototype.ensureFormat = function(b, c, d, f) { if (1 == arguments.length) { var h = arguments[0]; b = h.width; c = h.height; d = h.format; f = h.type; } if (b != this.width || c != this.height || d != this.format || f != this.type) this.width = b, this.height = c, this.format = d, this.type = f, a.bindTexture(a.TEXTURE_2D, this.id), a.texImage2D(a.TEXTURE_2D, 0, this.format, b, c, 0, this.format, this.type, null); }; b.prototype.drawTo = function(b) {
a.framebuffer = a.framebuffer || a.createFramebuffer(); a.bindFramebuffer(a.FRAMEBUFFER,
a.framebuffer); a.framebufferTexture2D(a.FRAMEBUFFER, a.COLOR_ATTACHMENT0, a.TEXTURE_2D, this.id, 0); if (a.checkFramebufferStatus(a.FRAMEBUFFER) !== a.FRAMEBUFFER_COMPLETE) throw Error('incomplete framebuffer'); a.viewport(0, 0, this.width, this.height); b(); a.bindFramebuffer(a.FRAMEBUFFER, null);
}; var c = null; b.prototype.fillUsingCanvas = function(b) { b(d(this)); this.format = a.RGBA; this.type = a.UNSIGNED_BYTE; a.bindTexture(a.TEXTURE_2D, this.id); a.texImage2D(a.TEXTURE_2D, 0, a.RGBA, a.RGBA, a.UNSIGNED_BYTE, c); return this; };
b.prototype.toImage = function(b) { this.use(); h.getDefaultShader().drawRect(); var f = 4 * this.width * this.height, k = new Uint8Array(f), n = d(this), p = n.createImageData(this.width, this.height); a.readPixels(0, 0, this.width, this.height, a.RGBA, a.UNSIGNED_BYTE, k); for (var m = 0; m < f; m++)p.data[m] = k[m]; n.putImageData(p, 0, 0); b.src = c.toDataURL(); }; b.prototype.swapWith = function(a) {
var b; b = a.id; a.id = this.id; this.id = b; b = a.width; a.width = this.width; this.width = b; b = a.height; a.height = this.height; this.height = b; b = a.format; a.format =
this.format; this.format = b;
}; return b;
}(), s = 'float random(vec3 scale,float seed){return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}'; return v;
}();

View File

@@ -1,38 +0,0 @@
require('../../src/ImageSequencer');
sequencer = ImageSequencer({ ui: true });
const saveSequence = require('../../src/cli/saveSequence.js');
const test = require('tape');
const { Command } = require('commander');
test('testing save sequence function', function (t) {
try {
let program = new Command();
program
.option('--save-sequence [string]', 'Name space separated with Stringified sequence');
program.parse(['node', 'test', '--save-sequence', '"invert brightness"']);
if (program.saveSequence)
saveSequence(program, sequencer);
t.true(1, 'creation success');
} catch (error) {
t.true(!error, 'creation fail');
}
try {
let program = new Command();
program
.option('--save-sequence [string]', 'Name space separated with Stringified sequence');
program.parse(['node', 'test', '--save-sequence']);
if (program.saveSequence)
saveSequence(program, sequencer);
t.true(0, 'creation success');
} catch (error) {
t.true(1, 'creation fail');
}
t.end();
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -30,7 +30,7 @@ test('blend module loads with correct options', t => {
});
test('blend module works correctly', t => {
sequencer.run(() => {
sequencer.run({mode: 'test'}, () => {
let result = sequencer.steps[2].output.src;

View File

@@ -23,7 +23,7 @@ test('Check Options', function(t) {
// Test 3 to check brightness module works as expected
test('canvas-resize module works correctly', function(t) {
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
var result = sequencer.steps[1].output.src;
require('get-pixels')(result, (err, pix) => {
t.equal(pix.shape[0], 500);

View File

@@ -1,8 +0,0 @@
const testModule = require('../templates/module-test'),
options = {
angle: '0.5',
size: '5'
},
benchmark = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAp0lEQVQ4T62SsQ3CMBBF3y/YgDUYAQE9IzACEvS0LAAZgRGoYQZGAXpzKFISWYmxzsCV1v/vnnTWCwy4CRaCO4WjBtDVBFvBwcsZAKJibTUXPHKwHMBl5QL0rGaCZ/tWCoitNoLj14CfDf4HqEkGS4Oz9/ZxTv1SgJNg5YUNAG3RYGpwAUbZj+TZFKASrFPZjwapsMHE4AqMuyt4DFKZAHvBrsggBXoDQmQp9u/Xo6IAAAAASUVORK5CYII=';
//testModule('webgl-distort', options, benchmark);

View File

@@ -14,7 +14,7 @@ test('Load Decode-Qr module', function(t) {
});
test('Decode-qr module works correctly', function(t) {
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
var result = sequencer.steps[1].options.step.qrval;
t.equal(result, 'http://github.com/publiclab/image-sequencer', 'should be equal');
t.end();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -28,7 +28,7 @@ test('Load invert module', function(t) {
});
test('Inverted image isn\'t identical', function(t) {
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
var input = sequencer.steps[0].output.src;
var output = sequencer.steps[1].output.src;
input = DataURItoBuffer(input);
@@ -40,7 +40,7 @@ test('Inverted image isn\'t identical', function(t) {
// test("Twice inverted image is identical to original image", function(t) {
// sequencer.addSteps('test','invert');
// sequencer.run(function(out) {
// sequencer.run({ mode: 'test' }, function(out) {
// var input = sequencer.steps[0].output.src
// var output = sequencer.steps[2].output.src
// base64Img.imgSync(input, target, 'input')
@@ -56,7 +56,7 @@ test('Inverted image isn\'t identical', function(t) {
// });
test('Invert module produces correct output', function(t) {
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
var result = sequencer.steps[1].output.src;
var benchmark = invert;
base64Img.imgSync(result, target, 'result');

File diff suppressed because one or more lines are too long

View File

@@ -1,21 +1,4 @@
const testModule = require('../templates/module-test'),
benchmark = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAklEQVR4AewaftIAAAAzSURBVLXBAQEAMAiAME7/zN4Ssr2BzzEJSEACEpCABCQgAQlIQAISkIAEJCABCUhAAhJYclMCJyy7k2QAAAAASUVORK5CYII=',
benchmark = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAklEQVR4AewaftIAAAAzSURBVLXBAQEAMAiAME7/zN4Ssr2BzzEJSEACEpCABCQgAQlIQAISkIAEJCABCUhAAhJYclMCJyy7k2QAAAAASUVORK5CYII=';
benchmark1 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAAklEQVR4AewaftIAAAAkSURBVJXBAQEAMAiAME7/zN4Ksr2Bz5EEEkgggQQSSCCBBBIs6poCE8Zr7KAAAAAASUVORK5CYII=',
benchmark2 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAklEQVR4AewaftIAAAAiSURBVI3BAQEAAAiAIPP/5uqCMAtHIJFEEkkkkUQSSSTRAzwDAhGkYPRhAAAAAElFTkSuQmCC',
benchmark3 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAAklEQVR4AewaftIAAAAdSURBVHXBAQEAMAiAME7/zN4Csr2Bz0GCBAkSJCwpbQIJAvmJUgAAAABJRU5ErkJggg==',
options1 = {
resize: '70.85%'
},
options2 = {
resize: '60 %'
},
options3 = {
resize: '40'
};
testModule('resize', {resize: '129%'}, benchmark);
require('../templates/options-test')('resize', [options1, options2, options3], [benchmark1, benchmark2, benchmark3]);
testModule('resize', {resize: '129%'}, benchmark);

File diff suppressed because one or more lines are too long

View File

@@ -25,7 +25,7 @@ test('Check Options', function(t) {
// Test 3 to check Text Overlay module works as expected.
// test('Text Overlay module works correctly', function(t) {
// sequencer.run(function(out) {
// sequencer.run({ mode: 'test' }, function(out) {
// // The test runs in node , and the text overlay is a browser only module,
// // thus it there is no image processing and output is same as input.
// var result = sequencer.steps[1].output.src;

View File

@@ -175,7 +175,7 @@ test('getSteps() returns correct array of steps', function(t){
});
test('run() runs the sequencer and returns output to callback', function(t) {
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
t.equal(typeof (sequencer.steps[sequencer.steps.length - 1].output), 'object', 'Output is Generated');
t.equal(out, sequencer.steps[sequencer.steps.length - 1].output.src, 'Output callback works');
t.end();
@@ -185,7 +185,7 @@ test('run() runs the sequencer and returns output to callback', function(t) {
test('getStep(offset) returns the step at offset distance relative to current step', function(t) {
sequencer.addSteps('invert', {});
sequencer.addSteps('blend', {});
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
t.equal(!!out, true, 'Blend generates output');
t.end();
});
@@ -202,7 +202,7 @@ test('blend returns different output depending on the set offset', function(t) {
sequencer.addSteps('blend', {});
// because we've added blend before, so instead of -3 we set it to -4
sequencer.addSteps('blend', {'offset': -4});
sequencer.run(function(out) {
sequencer.run({ mode: 'test' }, function(out) {
t.notStrictEqual(out, sequencer.steps[sequencer.steps.length - 2].output.src, 'different offsets give different output');
t.end();
});

View File

@@ -25,7 +25,7 @@ module.exports = (moduleName, options, benchmark, input) => {
// Add the step.
sequencer.addSteps(moduleName, options[0]);
// Run the ImageSequencer with initial option.
sequencer.run(() => {
sequencer.run({ mode: 'test' }, () => {
let result = sequencer.steps[1].output.src;
base64Img.imgSync(result, target, 'result');
@@ -42,7 +42,7 @@ module.exports = (moduleName, options, benchmark, input) => {
// Change the option of the given module.
sequencer.steps[1].setOptions(options[1]);
// Run the ImageSequencer witch changed option.
sequencer.run(() => {
sequencer.run({ mode: 'test' }, () => {
let newResult = sequencer.steps[1].output.src;
base64Img.imgSync(newResult, target, 'newResult');

View File

@@ -1,35 +0,0 @@
const timeout = process.env.SLOWMO ? 30000 : 10000;
const fs = require('fs');
beforeAll(async () => {
path = fs.realpathSync('file://../examples/index.html');
await page.goto('file://' + path, {waitUntil: 'domcontentloaded'});
});
describe('Apply Button Works', () => {
test('Apply Button is clicked', async () => {
await page.waitForSelector('.step');
await page.click('[data-value=\'resize\']');
const Length1 = await page.evaluate(() => document.querySelectorAll('.step').length);
//Lets change the default value
expect(Length1).toBe(2);
// Let's check the source of the image output by the default values
const src1 = await page.evaluate(() => document.querySelectorAll('.step img')[1].src);
//Lets change the default value
await page.evaluate(() => document.querySelector('div[name="resize"] input').value = '');
await page.type('div[name="resize"] input', '50%');
//Wait for the apply button to get enabled then click
await page.waitForFunction('document.querySelector(".btn-save").disabled == false');
await page.$eval('.btn-save', elem => elem.click());
//Wait for the image to process with the new value
await page.waitForSelector('.load', {visible: false});
//Let's check the source of the image output by the new values
const src2 = await page.evaluate(() => document.querySelectorAll('.step img')[1].src);
//Expect default and new image to be changed
expect(src1).not.toEqual(src2);
}, timeout);
});

View File

@@ -6,12 +6,10 @@ describe('HTML Types Mapping Function', function() {
expect(mapHtmlTypes({type: 'percentage'})).toEqual({type: 'number'});
expect(mapHtmlTypes({type: 'integer'})).toEqual({type: 'number'});
expect(mapHtmlTypes({type: 'integer', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100, step: 1});
expect(mapHtmlTypes({type: 'float', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100, step: 0.1}); // should default to step = 1
expect(mapHtmlTypes({type: 'integer', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100});
expect(mapHtmlTypes({type: 'float'})).toEqual({type: 'text'});
expect(mapHtmlTypes({type: 'float', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100, step: 0.1});
expect(mapHtmlTypes({type: 'float', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100, step: 0.1}); // should default to step = 0.1
expect(mapHtmlTypes({type: 'float', min: 20, max: 100})).toEqual({type: 'range', min: 20, max: 100});
});
it('maps text type', function() {
@@ -23,4 +21,4 @@ describe('HTML Types Mapping Function', function() {
expect(mapHtmlTypes({type: 'select'})).toEqual({type: 'select'});
});
});
});

4003
yarn.lock

File diff suppressed because it is too large Load Diff