mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-20 15:20:02 +01:00
Compare commits
1 Commits
dependabot
...
rebase-ass
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
415c62d9dc |
@@ -17,6 +17,7 @@ module.exports = function(grunt) {
|
|||||||
files: [
|
files: [
|
||||||
'src/*.js',
|
'src/*.js',
|
||||||
'src/*/*.js',
|
'src/*/*.js',
|
||||||
|
'src/*/*/*.js',
|
||||||
'Gruntfile.js'
|
'Gruntfile.js'
|
||||||
],
|
],
|
||||||
tasks: [ 'build:js' ]
|
tasks: [ 'build:js' ]
|
||||||
|
|||||||
204
examples/demo.js
204
examples/demo.js
@@ -1,208 +1,28 @@
|
|||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
|
|
||||||
sequencer = ImageSequencer();
|
sequencer = ImageSequencer();
|
||||||
|
|
||||||
// Load information of all modules (Name, Inputs, Outputs)
|
// Load information of all modules (Name, Inputs, Outputs)
|
||||||
var modulesInfo = sequencer.modulesInfo();
|
var modulesInfo = sequencer.modulesInfo();
|
||||||
|
|
||||||
// Add modules to the addStep dropdown
|
// Add modules to the addStep dropdown
|
||||||
for(var m in modulesInfo) {
|
for (var m in modulesInfo) {
|
||||||
$('#addStep select').append(
|
$("#addStep select").append(
|
||||||
'<option value="'+m+'">'+modulesInfo[m].name+'</option>'
|
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial definitions
|
// UI for each step:
|
||||||
var steps = document.querySelector('#steps');
|
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||||
var parser = new DOMParser();
|
|
||||||
var reader = new FileReader();
|
|
||||||
|
|
||||||
// Set the UI in sequencer. This Will generate HTML based on
|
// UI for the overall demo:
|
||||||
// Image Sequencer events :
|
var ui = DefaultHtmlSequencerUi(sequencer);
|
||||||
// onSetup : Called every time a step is added
|
|
||||||
// onDraw : Called every time a step starts draw
|
|
||||||
// onComplete : Called every time a step finishes drawing
|
|
||||||
// onRemove : Called everytime a step is removed
|
|
||||||
// The variable 'step' stores useful data like input and
|
|
||||||
// output values, step information.
|
|
||||||
// See documetation for more details.
|
|
||||||
sequencer.setUI({
|
|
||||||
|
|
||||||
onSetup: function(step) {
|
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||||
|
|
||||||
if (step.options && step.options.description) step.description = step.options.description
|
|
||||||
|
|
||||||
step.ui = '\
|
|
||||||
<div class="row step">\
|
|
||||||
<div class="col-md-4 details">\
|
|
||||||
<h3>'+step.name+'</h3>\
|
|
||||||
<p><i>'+(step.description || '')+'</i></p>\
|
|
||||||
</div>\
|
|
||||||
<div class="col-md-8">\
|
|
||||||
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
|
||||||
<a><img alt="" class=“img-thumbnail” /></a>\
|
|
||||||
</div>\
|
|
||||||
</div>\
|
|
||||||
';
|
|
||||||
|
|
||||||
var tools =
|
|
||||||
'<div class="tools btn-group">\
|
|
||||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
|
||||||
<i class="fa fa-trash"></i>\
|
|
||||||
</button>\
|
|
||||||
</div>';
|
|
||||||
|
|
||||||
step.ui = parser.parseFromString(step.ui,'text/html');
|
|
||||||
step.ui = step.ui.querySelector('div.row');
|
|
||||||
step.linkElement = step.ui.querySelector('a');
|
|
||||||
step.imgElement = step.ui.querySelector('a img');
|
|
||||||
|
|
||||||
if(sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
|
||||||
var inputs = sequencer.modulesInfo(step.name).inputs;
|
|
||||||
var outputs = sequencer.modulesInfo(step.name).outputs;
|
|
||||||
var merged = Object.assign(inputs, outputs); // combine outputs w inputs
|
|
||||||
for (var paramName in merged) {
|
|
||||||
var isInput = inputs.hasOwnProperty(paramName);
|
|
||||||
var html = "";
|
|
||||||
var inputDesc = (isInput)?inputs[paramName]:{};
|
|
||||||
if (!isInput) {
|
|
||||||
html += "<span class=\"output\"></span>";
|
|
||||||
} else if (inputDesc.type.toLowerCase() == "select") {
|
|
||||||
html += "<select class=\"form-control\" name=\""+paramName+"\">";
|
|
||||||
for (var option in inputDesc.values) {
|
|
||||||
html += "<option>"+inputDesc.values[option]+"</option>";
|
|
||||||
}
|
|
||||||
html += "</select>";
|
|
||||||
} else {
|
|
||||||
html = "<input class=\"form-control\" type=\""+inputDesc.type+"\" name=\""+paramName+"\">";
|
|
||||||
}
|
|
||||||
var div = document.createElement('div');
|
|
||||||
div.className = "row";
|
|
||||||
div.setAttribute('name', paramName);
|
|
||||||
var description = inputs[paramName].desc || paramName;
|
|
||||||
div.innerHTML = "<div class='det'>\
|
|
||||||
<label for='" + paramName + "'>" + description + "</label>\
|
|
||||||
"+html+"\
|
|
||||||
</div>";
|
|
||||||
step.ui.querySelector('div.details').appendChild(div);
|
|
||||||
}
|
|
||||||
$(step.ui.querySelector('div.details')).append("<p><button class='btn btn-default btn-save'>Save</button></p>");
|
|
||||||
|
|
||||||
function saveOptions() {
|
|
||||||
$(step.ui.querySelector('div.details')).find('input,select').each(function(i, input) {
|
|
||||||
step.options[$(input).attr('name')] = input.value;
|
|
||||||
});
|
|
||||||
sequencer.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// on clicking Save in the details pane of the step
|
|
||||||
$(step.ui.querySelector('div.details .btn-save')).click(saveOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(step.name != "load-image")
|
|
||||||
step.ui.querySelector('div.details').appendChild(
|
|
||||||
parser.parseFromString(tools,'text/html')
|
|
||||||
.querySelector('div')
|
|
||||||
);
|
|
||||||
|
|
||||||
steps.appendChild(step.ui);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDraw: function(step) {
|
|
||||||
$(step.ui.querySelector('.load')).show();
|
|
||||||
$(step.ui.querySelector('img')).hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
onComplete: function(step) {
|
|
||||||
$(step.ui.querySelector('.load')).hide();
|
|
||||||
$(step.ui.querySelector('img')).show();
|
|
||||||
|
|
||||||
step.imgElement.src = step.output;
|
|
||||||
step.linkElement.href = step.output;
|
|
||||||
|
|
||||||
function fileExtension(output) {
|
|
||||||
return output.split('/')[1].split(';')[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
step.linkElement.download = step.name + "." + fileExtension(step.output);
|
|
||||||
step.linkElement.target = "_blank";
|
|
||||||
|
|
||||||
if(sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
|
||||||
var inputs = sequencer.modulesInfo(step.name).inputs;
|
|
||||||
var outputs = sequencer.modulesInfo(step.name).outputs;
|
|
||||||
for (var i in inputs) {
|
|
||||||
if (step.options[i] !== undefined &&
|
|
||||||
inputs[i].type.toLowerCase() === "input") step.ui.querySelector('div[name="' + i + '"] input')
|
|
||||||
.value = step.options[i];
|
|
||||||
if (step.options[i] !== undefined &&
|
|
||||||
inputs[i].type.toLowerCase() === "select") step.ui.querySelector('div[name="' + i + '"] select')
|
|
||||||
.value = step.options[i];
|
|
||||||
}
|
|
||||||
for (var i in outputs) {
|
|
||||||
if (step[i] !== undefined) step.ui.querySelector('div[name="'+i+'"] input')
|
|
||||||
.value = step[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemove: function(step) {
|
|
||||||
step.ui.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
sequencer.loadImage('images/tulips.png', function loadImageUI() {
|
|
||||||
|
|
||||||
// look up needed steps from Url Hash:
|
|
||||||
var hash = getUrlHashParameter('steps');
|
|
||||||
|
|
||||||
if (hash) {
|
|
||||||
var stepsFromHash = hash.split(',');
|
|
||||||
stepsFromHash.forEach(function eachStep(step) {
|
|
||||||
sequencer.addSteps(step);
|
|
||||||
});
|
|
||||||
sequencer.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#addStep select').on('change', selectNewStepUI);
|
|
||||||
|
|
||||||
function selectNewStepUI() {
|
|
||||||
var m = $('#addStep select').val();
|
|
||||||
$('#addStep .info').html(sequencer.modulesInfo(m).description);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addStepUI() {
|
|
||||||
var options = {};
|
|
||||||
var inputs = $('#options input, #options select');
|
|
||||||
$.each(inputs, function() {
|
|
||||||
options[this.name] = $(this).val();
|
|
||||||
});
|
|
||||||
if($('#addStep select').val() == "none") return;
|
|
||||||
// add to URL hash too
|
|
||||||
var hash = getUrlHashParameter('steps') || '';
|
|
||||||
if (hash != '') hash += ',';
|
|
||||||
setUrlHashParameter('steps', hash + $('#addStep select').val())
|
|
||||||
sequencer.addSteps($('#addStep select').val(),options).run();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#addStep button').on('click', addStepUI);
|
|
||||||
|
|
||||||
|
|
||||||
function removeStepUI(){
|
|
||||||
var index = $('button.remove').index(this) + 1;
|
|
||||||
sequencer.removeSteps(index).run();
|
|
||||||
// remove from URL hash too
|
|
||||||
var urlHash = getUrlHashParameter('steps').split(',');
|
|
||||||
urlHash.splice(index - 1, 1);
|
|
||||||
setUrlHashParameter("steps", urlHash.join(','));
|
|
||||||
}
|
|
||||||
|
|
||||||
$('body').on('click','button.remove', removeStepUI);
|
|
||||||
|
|
||||||
|
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||||
|
$("#addStep button").on("click", ui.addStepUi);
|
||||||
|
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||||
|
|
||||||
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
||||||
setupFileHandling(sequencer);
|
setupFileHandling(sequencer);
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,76 +3,93 @@
|
|||||||
<html>
|
<html>
|
||||||
|
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
<meta http-equiv="content-type" content="text/html; charset=UTF8">
|
||||||
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
<link rel="icon" sizes="192x192" href="../icons/ic_192.png">
|
||||||
|
|
||||||
|
|
||||||
<title>Image Sequencer</title>
|
<title>Image Sequencer</title>
|
||||||
|
|
||||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||||
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||||
<script src="../dist/image-sequencer.js" charset="utf-8"></script>
|
<script src="../dist/image-sequencer.js" charset="utf-8"></script>
|
||||||
<script src="lib/urlHash.js" charset="utf-8"></script>
|
<script src="lib/urlHash.js" charset="utf-8"></script>
|
||||||
<script src="lib/imageSelection.js" charset="utf-8"></script>
|
<script src="lib/imageSelection.js" charset="utf-8"></script>
|
||||||
<script src="demo.js" charset="utf-8"></script>
|
<script src="lib/defaultHtmlStepUi.js" charset="utf-8"></script>
|
||||||
|
<script src="lib/defaultHtmlSequencerUi.js" charset="utf-8"></script>
|
||||||
|
<script src="demo.js" charset="utf-8"></script>
|
||||||
|
<!-- for crop module: -->
|
||||||
|
<script src="../node_modules/imgareaselect/jquery.imgareaselect.dev.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="demo.css">
|
<link href="../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="../node_modules/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||||
|
<!-- for crop module: -->
|
||||||
|
<link href="../node_modules/imgareaselect/distfiles/css/imgareaselect-default.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="demo.css">
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
<header class="text-center">
|
<header class="text-center">
|
||||||
<h1>Image Sequencer</h1>
|
<h1>Image Sequencer</h1>
|
||||||
<p>
|
<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 pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it
|
||||||
<a href="https://publiclab.org/image-sequencer">Learn more</a>
|
creates a new image at each step in a sequence.
|
||||||
</p>
|
<a href="https://publiclab.org/image-sequencer">Learn more</a>
|
||||||
<p>
|
</p>
|
||||||
Open Source <a href="https://github.com/publiclab/image-sequencer"><i class="fa fa-github"></i></a> by <a href="https://publiclab.org">Public Lab</a>
|
<p>
|
||||||
</p>
|
Open Source
|
||||||
</header>
|
<a href="https://github.com/publiclab/image-sequencer">
|
||||||
|
<i class="fa fa-github"></i>
|
||||||
<div id="dropzone">
|
</a> by
|
||||||
<p><i>Select or drag in an image to start!</i></p>
|
<a href="https://publiclab.org">Public Lab</a>
|
||||||
<center><input type="file" id="fileInput" value=""></center>
|
</p>
|
||||||
</div>
|
</header>
|
||||||
|
|
||||||
<section id="steps" class="row"></section>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<section id="addStep" class="panel panel-primary">
|
|
||||||
<div class="form-inline">
|
|
||||||
<div class="panel-body">
|
|
||||||
<div style="text-align:center;">
|
|
||||||
<select class="form-control input-lg">
|
|
||||||
<option value="none" disabled selected>Select a new step...</option>
|
|
||||||
</select>
|
|
||||||
<button class="btn btn-success btn-lg" name="add">Add Step</button>
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<p class="info" style="padding:8px;">Select a new module to add to your sequence.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
<div id="dropzone">
|
||||||
|
<p>
|
||||||
|
<i>Select or drag in an image to start!</i>
|
||||||
|
</p>
|
||||||
|
<center>
|
||||||
|
<input type="file" id="fileInput" value="">
|
||||||
|
</center>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<section id="steps" class="row"></section>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<section id="addStep" class="panel panel-primary">
|
||||||
|
<div class="form-inline">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div style="text-align:center;">
|
||||||
|
<select class="form-control input-lg" id="selectStep">
|
||||||
|
<option value="none" disabled selected>Select a new step...</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-success btn-lg" name="add">Add Step</button>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<p class="info" style="padding:8px;">Select a new module to add to your sequence.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
var sequencer;
|
var sequencer;
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
</script>
|
</body>
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
60
examples/lib/defaultHtmlSequencerUi.js
Normal file
60
examples/lib/defaultHtmlSequencerUi.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var addStepSel = options.addStepSel = options.addStepSel || "#addStep";
|
||||||
|
var removeStepSel = options.removeStepSel = options.removeStepSel || "button.remove";
|
||||||
|
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||||
|
|
||||||
|
function onLoad() {
|
||||||
|
importStepsFromUrlHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
// look up needed steps from Url Hash:
|
||||||
|
function importStepsFromUrlHash() {
|
||||||
|
var hash = getUrlHashParameter("steps");
|
||||||
|
|
||||||
|
if (hash) {
|
||||||
|
var stepsFromHash = hash.split(",");
|
||||||
|
stepsFromHash.forEach(function eachStep(step) {
|
||||||
|
_sequencer.addSteps(step);
|
||||||
|
});
|
||||||
|
_sequencer.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectNewStepUi() {
|
||||||
|
var m = $(addStepSel + " select").val();
|
||||||
|
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeStepUi() {
|
||||||
|
var index = $(removeStepSel).index(this) + 1;
|
||||||
|
sequencer.removeSteps(index).run();
|
||||||
|
// remove from URL hash too
|
||||||
|
var urlHash = getUrlHashParameter("steps").split(",");
|
||||||
|
urlHash.splice(index - 1, 1);
|
||||||
|
setUrlHashParameter("steps", urlHash.join(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStepUi() {
|
||||||
|
if ($(addStepSel + " select").val() == "none") return;
|
||||||
|
|
||||||
|
// add to URL hash too
|
||||||
|
var hash = getUrlHashParameter("steps") || "";
|
||||||
|
if (hash != "") hash += ",";
|
||||||
|
setUrlHashParameter("steps", hash + $(addStepSel + " select").val());
|
||||||
|
|
||||||
|
var newStepName = $(addStepSel + " select").val();
|
||||||
|
_sequencer
|
||||||
|
.addSteps(newStepName, options)
|
||||||
|
.run(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
onLoad: onLoad,
|
||||||
|
importStepsFromUrlHash: importStepsFromUrlHash,
|
||||||
|
selectNewStepUi: selectNewStepUi,
|
||||||
|
removeStepUi: removeStepUi,
|
||||||
|
addStepUi: addStepUi
|
||||||
|
}
|
||||||
|
}
|
||||||
190
examples/lib/defaultHtmlStepUi.js
Normal file
190
examples/lib/defaultHtmlStepUi.js
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
// Set the UI in sequencer. This Will generate HTML based on
|
||||||
|
// Image Sequencer events :
|
||||||
|
// onSetup : Called every time a step is added
|
||||||
|
// onDraw : Called every time a step starts draw
|
||||||
|
// onComplete : Called every time a step finishes drawing
|
||||||
|
// onRemove : Called everytime a step is removed
|
||||||
|
// The variable 'step' stores useful data like input and
|
||||||
|
// output values, step information.
|
||||||
|
// See documetation for more details.
|
||||||
|
function DefaultHtmlStepUi(_sequencer, options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||||
|
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||||
|
|
||||||
|
function onSetup(step) {
|
||||||
|
if (step.options && step.options.description)
|
||||||
|
step.description = step.options.description;
|
||||||
|
|
||||||
|
step.ui =
|
||||||
|
'\
|
||||||
|
<div class="row step">\
|
||||||
|
<div class="col-md-4 details">\
|
||||||
|
<h3>' +
|
||||||
|
step.name +
|
||||||
|
"</h3>\
|
||||||
|
<p><i>" +
|
||||||
|
(step.description || "") +
|
||||||
|
'</i></p>\
|
||||||
|
</div>\
|
||||||
|
<div class="col-md-8">\
|
||||||
|
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||||
|
<a><img alt="" style="max-width=100%" class="img-thumbnail" /></a>\
|
||||||
|
</div>\
|
||||||
|
</div>\
|
||||||
|
';
|
||||||
|
|
||||||
|
var tools =
|
||||||
|
'<div class="tools btn-group">\
|
||||||
|
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||||
|
<i class="fa fa-trash"></i>\
|
||||||
|
</button>\
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
var parser = new DOMParser();
|
||||||
|
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||||
|
step.ui = step.ui.querySelector("div.row");
|
||||||
|
step.linkElement = step.ui.querySelector("a");
|
||||||
|
step.imgElement = step.ui.querySelector("a img");
|
||||||
|
|
||||||
|
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||||
|
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||||
|
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||||
|
var merged = Object.assign(inputs, outputs); // combine outputs w inputs
|
||||||
|
for (var paramName in merged) {
|
||||||
|
var isInput = inputs.hasOwnProperty(paramName);
|
||||||
|
var html = "";
|
||||||
|
var inputDesc = isInput ? inputs[paramName] : {};
|
||||||
|
if (!isInput) {
|
||||||
|
html += '<span class="output"></span>';
|
||||||
|
} else if (inputDesc.type.toLowerCase() == "select") {
|
||||||
|
html += '<select class="form-control" name="' + paramName + '">';
|
||||||
|
for (var option in inputDesc.values) {
|
||||||
|
html += "<option>" + inputDesc.values[option] + "</option>";
|
||||||
|
}
|
||||||
|
html += "</select>";
|
||||||
|
} else {
|
||||||
|
html =
|
||||||
|
'<input class="form-control" type="' +
|
||||||
|
inputDesc.type +
|
||||||
|
'" name="' +
|
||||||
|
paramName +
|
||||||
|
'">';
|
||||||
|
}
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.className = "row";
|
||||||
|
div.setAttribute("name", paramName);
|
||||||
|
var description = inputs[paramName].desc || paramName;
|
||||||
|
div.innerHTML =
|
||||||
|
"<div class='det'>\
|
||||||
|
<label for='" +
|
||||||
|
paramName +
|
||||||
|
"'>" +
|
||||||
|
description +
|
||||||
|
"</label>\
|
||||||
|
" +
|
||||||
|
html +
|
||||||
|
"\
|
||||||
|
</div>";
|
||||||
|
step.ui.querySelector("div.details").appendChild(div);
|
||||||
|
}
|
||||||
|
$(step.ui.querySelector("div.details")).append(
|
||||||
|
"<p><button class='btn btn-default btn-save'>Save</button></p>"
|
||||||
|
);
|
||||||
|
|
||||||
|
function saveOptions() {
|
||||||
|
$(step.ui.querySelector("div.details"))
|
||||||
|
.find("input,select")
|
||||||
|
.each(function(i, input) {
|
||||||
|
step.options[$(input).attr("name")] = input.value;
|
||||||
|
});
|
||||||
|
_sequencer.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveOptions();
|
||||||
|
|
||||||
|
// on clicking Save in the details pane of the step
|
||||||
|
$(step.ui.querySelector("div.details .btn-save")).click(
|
||||||
|
function saveOptions() {
|
||||||
|
$(step.ui.querySelector("div.details"))
|
||||||
|
.find("input,select")
|
||||||
|
.each(function(i, input) {
|
||||||
|
step.options[$(input).attr("name")] = input.value;
|
||||||
|
});
|
||||||
|
_sequencer.run();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.name != "load-image")
|
||||||
|
step.ui
|
||||||
|
.querySelector("div.details")
|
||||||
|
.appendChild(
|
||||||
|
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||||
|
);
|
||||||
|
|
||||||
|
stepsEl.appendChild(step.ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDraw(step) {
|
||||||
|
$(step.ui.querySelector(".load")).show();
|
||||||
|
$(step.ui.querySelector("img")).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onComplete(step) {
|
||||||
|
$(step.ui.querySelector(".load")).hide();
|
||||||
|
$(step.ui.querySelector("img")).show();
|
||||||
|
|
||||||
|
step.imgElement.src = step.output;
|
||||||
|
step.linkElement.href = step.output;
|
||||||
|
|
||||||
|
function fileExtension(output) {
|
||||||
|
return output.split("/")[1].split(";")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
step.linkElement.download = step.name + "." + fileExtension(step.output);
|
||||||
|
step.linkElement.target = "_blank";
|
||||||
|
|
||||||
|
// fill inputs with stored step options
|
||||||
|
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||||
|
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||||
|
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||||
|
for (var i in inputs) {
|
||||||
|
if (
|
||||||
|
step.options[i] !== undefined &&
|
||||||
|
inputs[i].type.toLowerCase() === "input"
|
||||||
|
)
|
||||||
|
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||||
|
step.options[i];
|
||||||
|
if (
|
||||||
|
step.options[i] !== undefined &&
|
||||||
|
inputs[i].type.toLowerCase() === "select"
|
||||||
|
)
|
||||||
|
step.ui.querySelector('div[name="' + i + '"] select').value =
|
||||||
|
step.options[i];
|
||||||
|
}
|
||||||
|
for (var i in outputs) {
|
||||||
|
if (step[i] !== undefined)
|
||||||
|
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||||
|
step[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRemove(step) {
|
||||||
|
step.ui.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPreview() {
|
||||||
|
return step.imgElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getPreview: getPreview,
|
||||||
|
onSetup: onSetup,
|
||||||
|
onComplete: onComplete,
|
||||||
|
onRemove: onRemove,
|
||||||
|
onDraw: onDraw
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,8 @@
|
|||||||
"pace": "0.0.4",
|
"pace": "0.0.4",
|
||||||
"readline-sync": "^1.4.7",
|
"readline-sync": "^1.4.7",
|
||||||
"save-pixels": "~2.3.4",
|
"save-pixels": "~2.3.4",
|
||||||
"urify": "^2.1.0"
|
"urify": "^2.1.0",
|
||||||
|
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "13.0.0",
|
"browserify": "13.0.0",
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
// add steps to the sequencer
|
// add steps to the sequencer
|
||||||
function AddStep(ref, image, name, o) {
|
function AddStep(_sequencer, image, name, o) {
|
||||||
|
|
||||||
function addStep(image, name, o_) {
|
function addStep(image, name, o_) {
|
||||||
var moduleInfo = ref.modules[name][1];
|
var moduleInfo = _sequencer.modules[name][1];
|
||||||
|
|
||||||
var o = ref.copy(o_);
|
var o = _sequencer.copy(o_);
|
||||||
o.number = ref.options.sequencerCounter++; // gives a unique ID to each step
|
o.number = _sequencer.options.sequencerCounter++; // gives a unique ID to each step
|
||||||
o.name = o_.name || name || moduleInfo.name;
|
o.name = o_.name || name || moduleInfo.name;
|
||||||
o.description = o_.description || moduleInfo.description;
|
o.description = o_.description || moduleInfo.description;
|
||||||
o.selector = o_.selector || 'ismod-' + name;
|
o.selector = o_.selector || 'ismod-' + name;
|
||||||
o.container = o_.container || ref.options.selector;
|
o.container = o_.container || _sequencer.options.selector;
|
||||||
o.image = image;
|
o.image = image;
|
||||||
o.inBrowser = ref.options.inBrowser;
|
o.inBrowser = _sequencer.options.inBrowser;
|
||||||
|
|
||||||
o.step = {
|
o.step = {
|
||||||
name: o.name,
|
name: o.name,
|
||||||
description: o.description,
|
description: o.description,
|
||||||
ID: o.number,
|
ID: o.number,
|
||||||
imageName: o.image,
|
imageName: o.image,
|
||||||
inBrowser: ref.options.inBrowser,
|
inBrowser: _sequencer.options.inBrowser,
|
||||||
ui: ref.options.ui,
|
ui: _sequencer.options.ui,
|
||||||
options: o
|
options: o
|
||||||
};
|
};
|
||||||
var UI = ref.events;
|
var UI = _sequencer.events;
|
||||||
var module = ref.modules[name][0](o,UI);
|
var module = _sequencer.modules[name][0](o,UI);
|
||||||
ref.images[image].steps.push(module);
|
_sequencer.images[image].steps.push(module);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,47 +13,61 @@
|
|||||||
* y = options.y
|
* y = options.y
|
||||||
* y = options.y + options.h
|
* y = options.y + options.h
|
||||||
*/
|
*/
|
||||||
module.exports = function CropModule(options,UI) {
|
module.exports = function CropModule(options, UI) {
|
||||||
|
|
||||||
// TODO: we could also set this to {} if nil in AddModule.js to avoid this line:
|
// TODO: we could also set this to {} if nil in AddModule.js to avoid this line:
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
// Tell the UI that a step has been added
|
// Tell the UI that a step has been added
|
||||||
UI.onSetup(options.step);
|
UI.onSetup(options.step); // we should get UI to return the image thumbnail so we can attach our own UI extensions
|
||||||
var output;
|
// add our custom in-module html ui:
|
||||||
|
var ui = require('./Ui.js')(options.step, UI);
|
||||||
|
var output,
|
||||||
|
setupComplete = false;
|
||||||
|
|
||||||
// This function is caled everytime the step has to be redrawn
|
// This function is caled everytime the step has to be redrawn
|
||||||
function draw(input,callback) {
|
function draw(input,callback) {
|
||||||
|
|
||||||
// Tell the UI that the step has been triggered
|
// Tell the UI that the step has been triggered
|
||||||
UI.onDraw(options.step);
|
UI.onDraw(options.step);
|
||||||
var step = this;
|
var step = this;
|
||||||
|
|
||||||
require('./Crop')(input,options,function(out,format){
|
// save the input image;
|
||||||
|
// TODO: this should be moved to module API to persist the input image
|
||||||
|
options.step.input = input.src;
|
||||||
|
|
||||||
// This output is accessible to Image Sequencer
|
require('./Crop')(input, options, function(out, format){
|
||||||
step.output = {
|
|
||||||
src: out,
|
|
||||||
format: format
|
|
||||||
}
|
|
||||||
|
|
||||||
// This output is accessible to the UI
|
// This output is accessible to Image Sequencer
|
||||||
options.step.output = out;
|
step.output = {
|
||||||
|
src: out,
|
||||||
|
format: format
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the UI that the step has been drawn
|
// This output is accessible to the UI
|
||||||
UI.onComplete(options.step);
|
options.step.output = out;
|
||||||
|
|
||||||
// Tell Image Sequencer that step has been drawn
|
// Tell the UI that the step has been drawn
|
||||||
callback();
|
UI.onComplete(options.step);
|
||||||
|
|
||||||
});
|
// start custom UI setup (draggable UI)
|
||||||
|
// only once we have an input image
|
||||||
|
if (setupComplete === false && options.step.inBrowser) {
|
||||||
|
setupComplete = true;
|
||||||
|
ui.setup();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
// Tell Image Sequencer that step has been drawn
|
||||||
|
callback();
|
||||||
|
|
||||||
return {
|
});
|
||||||
options: options,
|
|
||||||
draw: draw,
|
}
|
||||||
output: output,
|
|
||||||
UI: UI
|
return {
|
||||||
}
|
options: options,
|
||||||
}
|
draw: draw,
|
||||||
|
output: output,
|
||||||
|
UI: UI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
68
src/modules/Crop/Ui.js
Normal file
68
src/modules/Crop/Ui.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
module.exports = function CropModuleUi(step, ui) {
|
||||||
|
|
||||||
|
// The problem is we don't have input image dimensions at the
|
||||||
|
// time of setting up the UI; that comes when draw() is triggered...
|
||||||
|
// so we're triggering setup only on first run of draw()
|
||||||
|
function setup() {
|
||||||
|
// display original input image on initial setup
|
||||||
|
showOriginal()
|
||||||
|
let width = Math.floor(imgEl.width),
|
||||||
|
height = Math.floor(imgEl.height),
|
||||||
|
x1 = 0,
|
||||||
|
y1 = 0,
|
||||||
|
x2 = width / 2,
|
||||||
|
y2 = height / 2;
|
||||||
|
|
||||||
|
// display with 50%/50% default crop:
|
||||||
|
setOptions(
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
x2 - x1,
|
||||||
|
y2 - y1
|
||||||
|
)
|
||||||
|
|
||||||
|
$(imgEl()).imgAreaSelect({
|
||||||
|
handles: true,
|
||||||
|
x1: x1,
|
||||||
|
y1: y1,
|
||||||
|
x2: x2,
|
||||||
|
y2: y2,
|
||||||
|
// when selection is complete
|
||||||
|
onSelectEnd: function onSelectEnd(img, selection) {
|
||||||
|
// assign crop values to module UI form inputs:
|
||||||
|
setOptions(
|
||||||
|
selection.x1,
|
||||||
|
selection.y1,
|
||||||
|
selection.x2 - selection.x1,
|
||||||
|
selection.y2 - selection.y1
|
||||||
|
)
|
||||||
|
// then hide the draggable UI
|
||||||
|
$(imgEl()).imgAreaSelect({
|
||||||
|
hide: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// step.imgSelector is not defined, imgElement is:
|
||||||
|
function imgEl() {
|
||||||
|
return step.imgElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOptions(x1,y1,x2,y2) {
|
||||||
|
let options = $($(imgEl()).parents()[2]).find("input");
|
||||||
|
options[0].value = x1;
|
||||||
|
options[1].value = y1;
|
||||||
|
options[2].value = x2 - x1;
|
||||||
|
options[3].value = y2 - y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaces currently displayed output thumbnail with the input image, for ui dragging purposes
|
||||||
|
function showOriginal() {
|
||||||
|
step.imgElement.src = step.input;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setup: setup
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,14 +5,12 @@
|
|||||||
module.exports = function UserInterface(events = {}) {
|
module.exports = function UserInterface(events = {}) {
|
||||||
|
|
||||||
events.onSetup = events.onSetup || function(step) {
|
events.onSetup = events.onSetup || function(step) {
|
||||||
if(step.ui == false) {
|
if (step.ui == false) {
|
||||||
// No UI
|
// No UI
|
||||||
}
|
} else if(step.inBrowser) {
|
||||||
else if(step.inBrowser) {
|
|
||||||
// Create and append an HTML Element
|
// Create and append an HTML Element
|
||||||
console.log("Added Step \""+step.name+"\" to \""+step.imageName+"\".");
|
console.log("Added Step \""+step.name+"\" to \""+step.imageName+"\".");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Create a NodeJS Object
|
// Create a NodeJS Object
|
||||||
console.log('\x1b[36m%s\x1b[0m',"Added Step \""+step.name+"\" to \""+step.imageName+"\".");
|
console.log('\x1b[36m%s\x1b[0m',"Added Step \""+step.name+"\" to \""+step.imageName+"\".");
|
||||||
}
|
}
|
||||||
@@ -21,12 +19,10 @@ module.exports = function UserInterface(events = {}) {
|
|||||||
events.onDraw = events.onDraw || function(step) {
|
events.onDraw = events.onDraw || function(step) {
|
||||||
if (step.ui == false) {
|
if (step.ui == false) {
|
||||||
// No UI
|
// No UI
|
||||||
}
|
} else if(step.inBrowser) {
|
||||||
else if(step.inBrowser) {
|
|
||||||
// Overlay a loading spinner
|
// Overlay a loading spinner
|
||||||
console.log("Drawing Step \""+step.name+"\" on \""+step.imageName+"\".");
|
console.log("Drawing Step \""+step.name+"\" on \""+step.imageName+"\".");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Don't do anything
|
// Don't do anything
|
||||||
console.log('\x1b[33m%s\x1b[0m',"Drawing Step \""+step.name+"\" on \""+step.imageName+"\".");
|
console.log('\x1b[33m%s\x1b[0m',"Drawing Step \""+step.name+"\" on \""+step.imageName+"\".");
|
||||||
}
|
}
|
||||||
@@ -35,27 +31,23 @@ module.exports = function UserInterface(events = {}) {
|
|||||||
events.onComplete = events.onComplete || function(step) {
|
events.onComplete = events.onComplete || function(step) {
|
||||||
if (step.ui == false) {
|
if (step.ui == false) {
|
||||||
// No UI
|
// No UI
|
||||||
}
|
} else if(step.inBrowser) {
|
||||||
else if(step.inBrowser) {
|
|
||||||
// Update the DIV Element
|
// Update the DIV Element
|
||||||
// Hide the laoding spinner
|
// Hide the laoding spinner
|
||||||
console.log("Drawn Step \""+step.name+"\" on \""+step.imageName+"\".");
|
console.log("Drawn Step \""+step.name+"\" on \""+step.imageName+"\".");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Update the NodeJS Object
|
// Update the NodeJS Object
|
||||||
console.log('\x1b[32m%s\x1b[0m',"Drawn Step \""+step.name+"\" on \""+step.imageName+"\".");
|
console.log('\x1b[32m%s\x1b[0m',"Drawn Step \""+step.name+"\" on \""+step.imageName+"\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
events.onRemove = events.onRemove || function(step) {
|
events.onRemove = events.onRemove || function(step) {
|
||||||
if(step.ui == false){
|
if (step.ui == false){
|
||||||
// No UI
|
// No UI
|
||||||
}
|
} else if(step.inBrowser) {
|
||||||
else if(step.inBrowser) {
|
|
||||||
// Remove the DIV Element
|
// Remove the DIV Element
|
||||||
console.log("Removing Step \""+step.name+"\" of \""+step.imageName+"\".");
|
console.log("Removing Step \""+step.name+"\" of \""+step.imageName+"\".");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Delete the NodeJS Object
|
// Delete the NodeJS Object
|
||||||
console.log('\x1b[31m%s\x1b[0m',"Removing Step \""+step.name+"\" of \""+step.imageName+"\".");
|
console.log('\x1b[31m%s\x1b[0m',"Removing Step \""+step.name+"\" of \""+step.imageName+"\".");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user