Add option to use Processing with a server as a capture method triggered by the camera.

Enter a url into the Settings panel in the Processing URL input box and select the radio button.
This commit is contained in:
Matt McWilliams 2022-04-30 15:58:17 -04:00
parent 467a5c06d6
commit bbfe6fc657
17 changed files with 283 additions and 15 deletions

View File

@ -419,6 +419,10 @@
<input type="text" id="intval" name="intval" placeholder="INTVAL3 URL"/>
<input type="radio" id="camera_type_intval" name="camera_type" value="intval" onclick="devices.intval();" />
</div>
<div class="spacer">
<input type="text" id="processing" name="processing" placeholder="PROCESSING URL" />
<input type="radio" id="camera_type_processing" name="camera_type" value="processing" onclick="devices.processing();" />
</div>
<div>
<h4>Light</h4>
<select id="light_device">

View File

@ -1,6 +1,7 @@
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const intval_1 = require("intval");
const processing_1 = require("processing");
/** class representing camera functions **/
class Camera {
/**
@ -13,6 +14,7 @@ class Camera {
};
this.arduino = null;
this.intval = null;
this.processing = null;
this.id = 'camera';
this.arduino = arduino;
this.cfg = cfg;
@ -37,6 +39,7 @@ class Camera {
listen() {
this.ipc.on(this.id, this.listener.bind(this));
this.ipc.on('intval', this.connectIntval.bind(this));
this.ipc.on('processing', this.connectProcessing.bind(this));
}
/**
*
@ -51,7 +54,15 @@ class Camera {
cmd = this.cfg.arduino.cmd[`${this.id}_backward`];
}
this.state.dir = dir;
if (this.intval) {
if (this.processing) {
try {
ms = await this.processing.setDir(dir);
}
catch (err) {
this.log.error(err);
}
}
else if (this.intval) {
try {
ms = await this.intval.setDir(dir);
}
@ -78,7 +89,15 @@ class Camera {
if (this.filmout.state.enabled) {
await this.filmout.start();
}
if (this.intval) {
if (this.processing) {
try {
ms = await this.processing.move();
}
catch (err) {
this.log.error(err);
}
}
else if (this.intval) {
try {
ms = await this.intval.move();
}
@ -129,6 +148,7 @@ class Camera {
return new Promise((resolve, reject) => {
if (arg.connect) {
this.intval = new intval_1.Intval(arg.url);
this.processing = null;
this.intval.connect((err, ms, state) => {
if (err) {
this.ui.send('intval', { connected: false });
@ -148,6 +168,17 @@ class Camera {
}
});
}
/**
*
**/
async connectProcessing(event, arg) {
return new Promise((resolve, reject) => {
this.processing = new processing_1.Processing(arg.url);
this.intval = null;
this.ui.send('processing', { connected: true, url: arg.url });
return resolve(true);
});
}
/**
*
**/

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const exec_1 = require("exec");
class Processing {
constructor(url) {
this._baseUrl = (url.indexOf('http') === -1 && url.indexOf('://') === -1) ? `http://${url}` : url;
}
async move() {
return new Promise(async (resolve, reject) => {
const timeStart = +new Date();
const url = `${this._baseUrl}`;
const cmd = `curl --http0.9 ${url}`;
let res;
let ms;
//console.log(url)
try {
res = await exec_1.exec(cmd);
}
catch (err) {
return reject(err);
}
ms = (+new Date()) - timeStart;
return resolve(ms);
});
}
async setDir(dir) {
return new Promise((resolve, reject) => {
return resolve(0);
});
}
}
module.exports.Processing = Processing;
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/processing/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,+BAA4B;AAE5B,MAAM,UAAU;IAEf,YAAa,GAAY;QACxB,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;IAClG,CAAC;IAEM,KAAK,CAAC,IAAI;QAChB,OAAO,IAAI,OAAO,CAAE,KAAK,EAAE,OAAa,EAAE,MAAY,EAAE,EAAE;YACzD,MAAM,SAAS,GAAY,CAAC,IAAI,IAAI,EAAE,CAAA;YACtC,MAAM,GAAG,GAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;YACvC,MAAM,GAAG,GAAY,kBAAkB,GAAG,EAAE,CAAA;YAC5C,IAAI,GAAY,CAAA;YAChB,IAAI,EAAW,CAAA;YACf,kBAAkB;YAClB,IAAI;gBACH,GAAG,GAAG,MAAM,WAAI,CAAC,GAAG,CAAC,CAAA;aACrB;YAAC,OAAO,GAAG,EAAE;gBACb,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;aAClB;YACD,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;YAC9B,OAAO,OAAO,CAAC,EAAE,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACH,CAAC;IACM,KAAK,CAAC,MAAM,CAAE,GAAa;QACjC,OAAO,IAAI,OAAO,CAAE,CAAC,OAAa,EAAE,MAAY,EAAE,EAAE;YACnD,OAAO,OAAO,CAAC,CAAC,CAAC,CAAA;QAClB,CAAC,CAAC,CAAA;IACH,CAAC;CACD;AAED,MAAM,CAAC,OAAO,CAAC,UAAU,GAAG,UAAU,CAAA"}

View File

@ -23,6 +23,7 @@ class Devices {
listen() {
ipcRenderer.on('ready', this.ready.bind(this));
ipcRenderer.on('intval', this.intvalCb.bind(this));
ipcRenderer.on('processing', this.processingCb.bind(this));
ipcRenderer.on('error_state', this.errorState.bind(this));
}
ready(event, arg) {
@ -136,13 +137,13 @@ class Devices {
let proceed = false;
let obj = {
connect: true,
url: url
url
};
if (url !== '' && typeof url !== 'undefined') {
proceed = confirm(`Are you sure you want to connect to INTVAL3 @ ${url}?`);
}
else {
alert('Cannot connect to INTVAL3 url as entered.');
alert('Cannot connect to INTVAL3 URL as entered.');
}
if (proceed) {
gui.overlay(true);
@ -174,6 +175,32 @@ class Devices {
$('#intval').removeClass('active');
}
}
processing() {
const url = $('#processing').val();
let proceed = false;
let obj = {
url
};
if (url !== '' && typeof url !== 'undefined') {
proceed = confirm(`Are you sure you want to connect to Processing @ ${url}?`);
}
else {
alert('Cannot connect to Processing URL as entered.');
}
if (proceed) {
gui.overlay(true);
gui.spinner(true, `Connecting to Processing @ ${url}`);
ipcRenderer.send('processing', obj);
}
else {
$('#camera_type_arduino').prop('checked', 'checked');
$('#processing').removeClass('active');
}
}
processingCb() {
gui.spinner(false);
gui.overlay(false);
}
errorState() {
gui.spinner(false);
gui.overlay(false);

File diff suppressed because one or more lines are too long

9
app/package-lock.json generated
View File

@ -35,6 +35,7 @@
"moment": "^2.29.1",
"mscript": "file:lib/mscript",
"node-notifier": "^9.0.0",
"processing": "file:lib/processing",
"proj": "file:lib/proj",
"request": "^2.88.2",
"sequencer": "file:lib/sequencer",
@ -134,6 +135,7 @@
"version": "1.0.0",
"license": "ISC"
},
"lib/processing": {},
"lib/proj": {
"version": "1.0.0",
"license": "ISC"
@ -9136,6 +9138,10 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"node_modules/processing": {
"resolved": "lib/processing",
"link": true
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@ -18757,6 +18763,9 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"processing": {
"version": "file:lib/processing"
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "mcopy-app",
"version": "1.6.9",
"version": "1.7.0",
"description": "GUI for the mcopy small gauge film optical printer platform",
"main": "main.js",
"scripts": {
@ -76,6 +76,7 @@
"mscript": "file:lib/mscript",
"node-notifier": "^9.0.0",
"proj": "file:lib/proj",
"processing": "file:lib/processing",
"request": "^2.88.2",
"sequencer": "file:lib/sequencer",
"serialport": "^9.0.7",

View File

@ -19,6 +19,7 @@ class Devices {
listen () {
ipcRenderer.on('ready', this.ready.bind(this));
ipcRenderer.on('intval', this.intvalCb.bind(this));
ipcRenderer.on('processing', this.processingCb.bind(this));
ipcRenderer.on('error_state', this.errorState.bind(this));
}
@ -135,13 +136,13 @@ class Devices {
let proceed : boolean = false;
let obj : any = {
connect: true,
url : url
url
};
if ( url !== '' && typeof url !== 'undefined') {
proceed = confirm(`Are you sure you want to connect to INTVAL3 @ ${url}?`);
} else {
alert('Cannot connect to INTVAL3 url as entered.');
alert('Cannot connect to INTVAL3 URL as entered.');
}
if (proceed) {
@ -154,6 +155,7 @@ class Devices {
}
}
intvalCb (evt : any, args : any) {
let state : any;
gui.spinner(false);
@ -174,6 +176,34 @@ class Devices {
}
}
processing () {
const url : string = $('#processing').val() as string;
let proceed : boolean = false;
let obj : any = {
url
};
if ( url !== '' && typeof url !== 'undefined') {
proceed = confirm(`Are you sure you want to connect to Processing @ ${url}?`);
} else {
alert('Cannot connect to Processing URL as entered.');
}
if (proceed) {
gui.overlay(true);
gui.spinner(true, `Connecting to Processing @ ${url}`);
ipcRenderer.send('processing', obj);
} else {
$('#camera_type_arduino').prop('checked', 'checked');
$('#processing').removeClass('active');
}
}
processingCb () {
gui.spinner(false);
gui.overlay(false);
}
errorState () {
gui.spinner(false);
gui.overlay(false);

View File

@ -1,5 +1,5 @@
{
"version": "1.6.9",
"version": "1.7.0",
"ext_port": 1111,
"profiles": {
"mcopy": {

4
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "mcopy",
"version": "1.6.9",
"version": "1.7.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.6.9",
"version": "1.7.0",
"license": "MIT",
"dependencies": {
"arduino": "file:app/lib/arduino",

View File

@ -1,6 +1,6 @@
{
"name": "mcopy",
"version": "1.6.9",
"version": "1.7.0",
"description": "Small gauge film optical printer platform",
"main": "build.js",
"directories": {
@ -48,6 +48,7 @@
"log": "file:app/lib/log",
"mscript": "file:app/lib/mscript",
"proj": "file:app/lib/proj",
"processing": "file:app/lib/processing",
"sequencer": "file:app/lib/sequencer",
"settings": "file:app/lib/settings",
"system": "file:app/lib/system"

View File

@ -0,0 +1,67 @@
import processing.net.*;
import codeanticode.syphon.*;
Server server;
PImage img;
SyphonClient syphon;
int frameCounter = 0;
int port = 5204;
void setup() {
size(1920, 1080, P3D);
syphon = new SyphonClient(this);
server = new Server(this, port);
println("Server listening on port " + port);
}
void draw() {
Client client = server.available();
JSONObject json;
String req;
String res;
String frameNumber;
background(0);
if (syphon.newFrame()) {
img = syphon.getImage(img);
}
if (img != null) {
image(img, 0, 0, width, height);
}
if (client != null) {
req = client.readString();
if (req != null) {
json = new JSONObject();
json.setInt("frame", frameCounter);
//format number to 000001 for filesystem sorting
frameNumber = nf(frameCounter, 6);
//debug request
//println(client.ip() + "\t" + req);
println("Capturing frame " + frameNumber + "...");
/////////
// Place single frame capture code here
/////////
delay(100);
save("frame_" + frameNumber + ".tif");
delay(100);
println("Captured frame " + frameNumber);
json.setBoolean("success", true);
res = json.toString();
//debug response
//println("res " + res);
client.write(res + "\n");
server.disconnect(client);
frameCounter++;
}
}
}

View File

@ -1,6 +1,7 @@
'use strict';
import { Intval } from 'intval';
import { Processing } from 'processing';
import { delay } from 'delay';
/** class representing camera functions **/
@ -12,6 +13,7 @@ class Camera {
};
private arduino : Arduino = null;
private intval : any = null;
private processing : any = null;
private log : any;
private cfg : any;
private filmout : any;
@ -46,6 +48,7 @@ class Camera {
private listen () {
this.ipc.on(this.id, this.listener.bind(this));
this.ipc.on('intval', this.connectIntval.bind(this));
this.ipc.on('processing', this.connectProcessing.bind(this));
}
/**
@ -62,7 +65,13 @@ class Camera {
}
this.state.dir = dir;
if (this.intval) {
if (this.processing) {
try {
ms = await this.processing.setDir(dir);
} catch (err) {
this.log.error(err);
}
} else if (this.intval) {
try {
ms = await this.intval.setDir(dir);
} catch (err) {
@ -87,7 +96,13 @@ class Camera {
if (this.filmout.state.enabled) {
await this.filmout.start()
}
if (this.intval) {
if (this.processing) {
try {
ms = await this.processing.move();
} catch (err) {
this.log.error(err);
}
} else if (this.intval) {
try {
ms = await this.intval.move();
} catch (err) {
@ -137,6 +152,7 @@ class Camera {
return new Promise((resolve, reject) => {
if (arg.connect) {
this.intval = new Intval(arg.url)
this.processing = null
this.intval.connect((err : any, ms : number, state : boolean) => {
if (err) {
this.ui.send('intval', { connected : false })
@ -155,6 +171,18 @@ class Camera {
})
}
/**
*
**/
private async connectProcessing (event : any, arg : any) {
return new Promise((resolve, reject) => {
this.processing = new Processing(arg.url)
this.intval = null
this.ui.send('processing', { connected : true, url : arg.url })
return resolve(true)
})
}
/**
*
**/

1
src/globals.d.ts vendored
View File

@ -1,6 +1,7 @@
declare module 'delay';
declare module 'log';
declare module 'intval';
declare module 'processing';
declare module 'electron';
declare module 'fs-extra';
declare module 'uuid';

35
src/processing/index.ts Normal file
View File

@ -0,0 +1,35 @@
'use strict'
import { exec } from 'exec';
class Processing {
private _baseUrl : string
constructor (url : string) {
this._baseUrl = (url.indexOf('http') === -1 && url.indexOf('://') === -1) ? `http://${url}` : url
}
public async move () {
return new Promise (async (resolve : any, reject : any) => {
const timeStart : number = +new Date()
const url : string = `${this._baseUrl}`
const cmd : string = `curl --http0.9 ${url}`
let res : string
let ms : number
//console.log(url)
try {
res = await exec(cmd)
} catch (err) {
return reject(err)
}
ms = (+new Date()) - timeStart
return resolve(ms)
})
}
public async setDir (dir : boolean) {
return new Promise ((resolve : any, reject : any) => {
return resolve(0)
})
}
}
module.exports.Processing = Processing