mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-11 10:49:59 +01:00
469 lines
14 KiB
JavaScript
469 lines
14 KiB
JavaScript
if (typeof window !== 'undefined') { isBrowser = true }
|
|
else { var isBrowser = false }
|
|
require('./util/getStep.js');
|
|
|
|
ImageSequencer = function ImageSequencer(options) {
|
|
|
|
var sequencer = (this.name == "ImageSequencer") ? this : this.sequencer;
|
|
options = options || {};
|
|
options.inBrowser = options.inBrowser || isBrowser;
|
|
options.sequencerCounter = 0;
|
|
|
|
function objTypeOf(object) {
|
|
return Object.prototype.toString.call(object).split(" ")[1].slice(0, -1)
|
|
}
|
|
|
|
function log(color, msg) {
|
|
if (options.ui != "none") {
|
|
if (arguments.length == 1) console.log(arguments[0]);
|
|
else if (arguments.length == 2) console.log(color, msg);
|
|
}
|
|
}
|
|
|
|
function copy(a) {
|
|
if (!typeof (a) == "object") return a;
|
|
if (objTypeOf(a) == "Array") return a.slice();
|
|
if (objTypeOf(a) == "Object") {
|
|
var b = {};
|
|
for (var v in a) {
|
|
b[v] = copy(a[v]);
|
|
}
|
|
return b;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
function makeArray(input) {
|
|
return (objTypeOf(input) == "Array") ? input : [input];
|
|
}
|
|
|
|
var image,
|
|
steps = [],
|
|
modules = require('./Modules'),
|
|
sequences = require('./SavedSequences.json'),
|
|
formatInput = require('./FormatInput'),
|
|
images = {},
|
|
inputlog = [],
|
|
events = require('./ui/UserInterface')(),
|
|
fs = require('fs');
|
|
|
|
|
|
|
|
if (options.inBrowser) {
|
|
for (o in sequencer) {
|
|
modules[o] = sequencer[o];
|
|
}
|
|
sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
|
if (!sequences) {
|
|
sequences = {};
|
|
window.localStorage.setItem('sequences', JSON.stringify(sequences));
|
|
}
|
|
}
|
|
|
|
// if in browser, prompt for an image
|
|
// if (options.imageSelect || options.inBrowser) addStep('image-select');
|
|
// else if (options.imageUrl) loadImage(imageUrl);
|
|
|
|
function addSteps() {
|
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
|
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
|
var json_q = {};
|
|
for (var arg in arguments) { args.push(copy(arguments[arg])); }
|
|
json_q = formatInput.call(this_, args, "+");
|
|
|
|
inputlog.push({ method: "addSteps", json_q: copy(json_q) });
|
|
|
|
for (var i in json_q)
|
|
for (var j in json_q[i])
|
|
require("./AddStep")(this_, i, json_q[i][j].name, json_q[i][j].o);
|
|
|
|
return this;
|
|
}
|
|
|
|
function removeStep(image, index) {
|
|
//remove the step from images[image].steps and redraw remaining images
|
|
if (index > 0) {
|
|
thisStep = images[image].steps[index];
|
|
thisStep.UI.onRemove(thisStep.options.step);
|
|
images[image].steps.splice(index, 1);
|
|
}
|
|
//tell the UI a step has been removed
|
|
}
|
|
|
|
function removeSteps(image, index) {
|
|
var run = {}, indices;
|
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
|
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
|
|
|
var json_q = formatInput.call(this_, args, "-");
|
|
inputlog.push({ method: "removeSteps", json_q: copy(json_q) });
|
|
|
|
for (var img in json_q) {
|
|
indices = json_q[img].sort(function(a, b) { return b - a });
|
|
run[img] = indices[indices.length - 1];
|
|
for (var i in indices)
|
|
removeStep(img, indices[i]);
|
|
}
|
|
// this.run(run); // This is creating problems
|
|
return this;
|
|
}
|
|
|
|
function insertSteps(image, index, name, o) {
|
|
var run = {};
|
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
|
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
|
for (var arg in arguments) args.push(arguments[arg]);
|
|
|
|
var json_q = formatInput.call(this_, args, "^");
|
|
inputlog.push({ method: "insertSteps", json_q: copy(json_q) });
|
|
|
|
for (var img in json_q) {
|
|
var details = json_q[img];
|
|
details = details.sort(function(a, b) { return b.index - a.index });
|
|
for (var i in details)
|
|
require("./InsertStep")(this_, img, details[i].index, details[i].name, details[i].o);
|
|
run[img] = details[details.length - 1].index;
|
|
}
|
|
// this.run(run); // This is Creating issues
|
|
return this;
|
|
}
|
|
|
|
// Config is an object which contains the runtime configuration like progress bar
|
|
// information and index from which the sequencer should run
|
|
function run(config, t_image, t_from) {
|
|
let progressObj, index = 0;
|
|
config = config || { mode: 'no-arg' };
|
|
if (config.index) index = config.index;
|
|
|
|
if (config.mode != 'test') {
|
|
if (config.mode != "no-arg" && typeof config != 'function') {
|
|
if (config.progressObj) progressObj = config.progressObj;
|
|
delete arguments['0'];
|
|
}
|
|
}
|
|
else {
|
|
arguments['0'] = config.mode;
|
|
}
|
|
|
|
var this_ = (this.name == "ImageSequencer") ? this : this.sequencer;
|
|
var args = (this.name == "ImageSequencer") ? [] : [this.images];
|
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
|
|
|
var callback = function() { };
|
|
for (var arg in args)
|
|
if (objTypeOf(args[arg]) == "Function")
|
|
callback = args.splice(arg, 1)[0];
|
|
|
|
var json_q = formatInput.call(this_, args, "r");
|
|
|
|
require('./Run')(this_, json_q, callback, index, progressObj);
|
|
|
|
return true;
|
|
}
|
|
|
|
function loadImages() {
|
|
var args = [];
|
|
var sequencer = this;
|
|
for (var arg in arguments) args.push(copy(arguments[arg]));
|
|
var json_q = formatInput.call(this, args, "l");
|
|
|
|
inputlog.push({ method: "loadImages", json_q: copy(json_q) });
|
|
var loadedimages = this.copy(json_q.loadedimages);
|
|
|
|
var ret = {
|
|
name: "ImageSequencer Wrapper",
|
|
sequencer: this,
|
|
addSteps: this.addSteps,
|
|
removeSteps: this.removeSteps,
|
|
insertSteps: this.insertSteps,
|
|
run: this.run,
|
|
UI: this.UI,
|
|
setUI: this.setUI,
|
|
images: loadedimages
|
|
};
|
|
|
|
function load(i) {
|
|
if (i == loadedimages.length) {
|
|
json_q.callback.call(ret);
|
|
return;
|
|
}
|
|
var img = loadedimages[i];
|
|
require('./ui/LoadImage')(sequencer, img, json_q.images[img], function() {
|
|
load(++i);
|
|
});
|
|
}
|
|
|
|
load(0);
|
|
}
|
|
|
|
function replaceImage(selector, steps, options) {
|
|
options = options || {};
|
|
options.callback = options.callback || function() { };
|
|
return require('./ReplaceImage')(this, selector, steps, options);
|
|
}
|
|
|
|
function setUI(UI) {
|
|
this.events = require('./ui/UserInterface')(UI);
|
|
}
|
|
|
|
var exportBin = function(dir, basic, filename) {
|
|
return require('./ExportBin')(dir, this, basic, filename);
|
|
}
|
|
|
|
function modulesInfo(name) {
|
|
var modulesdata = {}
|
|
if (name == "load-image") return {};
|
|
if (arguments.length == 0) {
|
|
for (var modulename in this.modules) {
|
|
modulesdata[modulename] = modules[modulename][1];
|
|
}
|
|
for (var sequencename in this.sequences) {
|
|
modulesdata[sequencename] = { name: sequencename, steps: this.sequences[sequencename] };
|
|
}
|
|
}
|
|
else {
|
|
if (modules[name])
|
|
modulesdata = modules[name][1];
|
|
else
|
|
modulesdata = { 'inputs': sequences[name]['options'] };
|
|
}
|
|
return modulesdata;
|
|
}
|
|
|
|
// Genates a CLI string for the current sequence
|
|
function toCliString() {
|
|
var cliStringSteps = `"`, cliOptions = {};
|
|
for (var step in this.steps) {
|
|
if (this.steps[step].options.name !== "load-image")
|
|
cliStringSteps += `${this.steps[step].options.name} `;
|
|
for (var inp in modulesInfo(this.steps[step].options.name).inputs) {
|
|
cliOptions[inp] = this.steps[step].options[inp];
|
|
}
|
|
}
|
|
cliStringSteps = cliStringSteps.substr(0, cliStringSteps.length - 1) + `"`;
|
|
return `sequencer -i [PATH] -s ${cliStringSteps} -d '${JSON.stringify(cliOptions)}'`
|
|
}
|
|
|
|
// Strigifies the current sequence
|
|
function toString(step) {
|
|
if (step) {
|
|
return stepToString(step);
|
|
} else {
|
|
return copy(this.images.image1.steps).map(stepToString).slice(1).join(',');
|
|
}
|
|
}
|
|
|
|
// Stringifies one step of the sequence
|
|
function stepToString(step) {
|
|
let inputs = modulesInfo(step.options.name).inputs || {}, op = {};
|
|
|
|
for (let input in inputs) {
|
|
|
|
if (!!step.options[input] && step.options[input] != inputs[input].default) {
|
|
op[input] = step.options[input];
|
|
op[input] = encodeURIComponent(op[input]);
|
|
}
|
|
|
|
}
|
|
|
|
var configurations = Object.keys(op).map(key => key + ':' + op[key]).join('|');
|
|
return `${step.options.name}{${configurations}}`;
|
|
}
|
|
|
|
// exports the current sequence as an array of JSON steps
|
|
function toJSON() {
|
|
return this.stringToJSON(this.toString());
|
|
}
|
|
|
|
// Coverts stringified sequence into an array of JSON steps
|
|
function stringToJSON(str) {
|
|
let steps;
|
|
if (str.includes(','))
|
|
steps = str.split(',');
|
|
else
|
|
steps = [str];
|
|
return steps.map(stringToJSONstep);
|
|
}
|
|
|
|
// Converts one stringified step into JSON
|
|
function stringToJSONstep(str) {
|
|
var bracesStrings;
|
|
if (str.includes('{'))
|
|
if (str.includes('(') && str.indexOf('(') < str.indexOf('{'))
|
|
bracesStrings = ['(', ')'];
|
|
else
|
|
bracesStrings = ['{', '}'];
|
|
else
|
|
bracesStrings = ['(', ')'];
|
|
|
|
if (str.indexOf(bracesStrings[0]) === -1) { // if there are no settings specified
|
|
var moduleName = str.substr(0);
|
|
stepSettings = "";
|
|
} else {
|
|
var moduleName = str.substr(0, str.indexOf(bracesStrings[0]));
|
|
stepSettings = str.slice(str.indexOf(bracesStrings[0]) + 1, -1);
|
|
}
|
|
|
|
stepSettings = stepSettings.split('|').reduce(function formatSettings(accumulator, current, i) {
|
|
var settingName = current.substr(0, current.indexOf(':')),
|
|
settingValue = current.substr(current.indexOf(':') + 1);
|
|
settingValue = settingValue.replace(/^\(/, '').replace(/\)$/, ''); // strip () at start/end
|
|
settingValue = settingValue.replace(/^\{/, '').replace(/\}$/, ''); // strip {} at start/end
|
|
settingValue = decodeURIComponent(settingValue);
|
|
current = [
|
|
settingName,
|
|
settingValue
|
|
];
|
|
if (!!settingName) accumulator[settingName] = settingValue;
|
|
return accumulator;
|
|
}, {});
|
|
|
|
return {
|
|
name: moduleName,
|
|
options: stepSettings
|
|
}
|
|
}
|
|
|
|
// imports a string into the sequencer steps
|
|
function importString(str) {
|
|
let sequencer = this;
|
|
if (this.name != "ImageSequencer")
|
|
sequencer = this.sequencer;
|
|
var stepsFromString = stringToJSON(str);
|
|
stepsFromString.forEach(function eachStep(stepObj) {
|
|
sequencer.addSteps(stepObj.name, stepObj.options);
|
|
});
|
|
}
|
|
|
|
// imports a array of JSON steps into the sequencer steps
|
|
function importJSON(obj) {
|
|
let sequencer = this;
|
|
if (this.name != "ImageSequencer")
|
|
sequencer = this.sequencer;
|
|
obj.forEach(function eachStep(stepObj) {
|
|
sequencer.addSteps(stepObj.name, stepObj.options);
|
|
});
|
|
}
|
|
|
|
function loadNewModule(name, options) {
|
|
|
|
if (!options) {
|
|
return this;
|
|
|
|
} else if (Array.isArray(options)) {
|
|
// contains the array of module and info
|
|
this.modules[name] = options;
|
|
|
|
} else if (options.func && options.info) {
|
|
// passed in options object
|
|
this.modules[name] = [
|
|
options.func, options.info
|
|
];
|
|
|
|
} else if (options.path && !this.inBrowser) {
|
|
// load from path(only in node)
|
|
const module = [
|
|
require(`${options.path}/Module.js`),
|
|
require(`${options.path}/info.json`)
|
|
];
|
|
this.modules[name] = module;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
function saveNewModule(name, path) {
|
|
if (options.inBrowser) {
|
|
// Not for browser context
|
|
return;
|
|
}
|
|
var mods = fs.readFileSync('./src/Modules.js').toString();
|
|
mods = mods.substr(0, mods.length - 1) + " '" + name + "': require('" + path + "'),\n}";
|
|
fs.writeFileSync('./src/Modules.js', mods);
|
|
}
|
|
|
|
function createMetaModule(stepsCollection, info) {
|
|
var stepsArr = stepsCollection;
|
|
if (typeof stepsCollection === 'string')
|
|
stepsArr = stringToJSON(stepsCollection);
|
|
var metaMod = function() {
|
|
this.expandSteps(stepsArr);
|
|
return {
|
|
isMeta: true
|
|
}
|
|
}
|
|
return [metaMod, info];
|
|
}
|
|
|
|
function saveSequence(name, sequenceString) {
|
|
const sequence = stringToJSON(sequenceString);
|
|
// Save the given sequence string as a module
|
|
if (options.inBrowser) {
|
|
// Inside the browser we save the meta-modules using the Web Storage API
|
|
var sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
|
sequences[name] = sequence;
|
|
window.localStorage.setItem('sequences', JSON.stringify(sequences));
|
|
}
|
|
else {
|
|
// In node we save the sequences in the json file SavedSequences.json
|
|
var sequences = require('./SavedSequences.json');
|
|
sequences[name] = sequence;
|
|
fs.writeFileSync('./src/SavedSequences.json', JSON.stringify(sequences));
|
|
}
|
|
}
|
|
|
|
function loadModules() {
|
|
// This function loads the modules and saved sequences
|
|
this.modules = require('./Modules');
|
|
if (options.inBrowser)
|
|
this.sequences = JSON.parse(window.localStorage.getItem('sequences'));
|
|
else
|
|
this.sequences = require('./SavedSequences.json');
|
|
}
|
|
|
|
return {
|
|
//literals and objects
|
|
name: "ImageSequencer",
|
|
options: options,
|
|
inputlog: inputlog,
|
|
modules: modules,
|
|
sequences: sequences,
|
|
images: images,
|
|
events: events,
|
|
|
|
//user functions
|
|
loadImages: loadImages,
|
|
loadImage: loadImages,
|
|
addSteps: addSteps,
|
|
removeSteps: removeSteps,
|
|
insertSteps: insertSteps,
|
|
replaceImage: replaceImage,
|
|
run: run,
|
|
setUI: setUI,
|
|
exportBin: exportBin,
|
|
modulesInfo: modulesInfo,
|
|
toCliString: toCliString,
|
|
toString: toString,
|
|
stepToString: stepToString,
|
|
toJSON: toJSON,
|
|
stringToJSON: stringToJSON,
|
|
stringToJSONstep: stringToJSONstep,
|
|
importString: importString,
|
|
importJSON: importJSON,
|
|
loadNewModule: loadNewModule,
|
|
saveNewModule: saveNewModule,
|
|
createMetaModule: createMetaModule,
|
|
saveSequence: saveSequence,
|
|
loadModules: loadModules,
|
|
|
|
//other functions
|
|
log: log,
|
|
objTypeOf: objTypeOf,
|
|
copy: copy,
|
|
|
|
setInputStep: require('./ui/SetInputStep')(sequencer)
|
|
}
|
|
|
|
}
|
|
module.exports = ImageSequencer;
|