All uncommited features, attempting to simplify features in fd

This commit is contained in:
Matt McWilliams 2025-12-31 00:00:33 -08:00
parent e4c109543b
commit b8bc954aed
25 changed files with 349 additions and 57 deletions

View File

@ -139,13 +139,21 @@ class Display {
}
public setFraming () {
this.framing= true;
this.framing = true;
}
public unsetFraming () {
this.framing = false;
}
public blank () {
this.unsetFocus();
this.unsetFraming();
this.updateSize();
this.clear();
this.updateScreen();
}
private onResize (event : any) {
this.updateSize();
this.clear();
@ -513,6 +521,10 @@ class Client {
this.display.updateImage();
}
private receiveBlank (msg : Message) {
this.display.blank();
}
public sendOffset (x : number, y : number) {
this.client.send(JSON.stringify({ cmd : 'offset', x, y }));
}
@ -525,6 +537,10 @@ class Client {
this.client.send(JSON.stringify({ cmd : 'scale', scale }));
}
public sendBlank () {
this.client.send(JSON.stringify({ cmd : 'blank' }));
}
/**
* HELPERS
**/

8
dist/cli/index.d.ts vendored
View File

@ -1,8 +1,10 @@
import 'dotenv/config';
import type { Logger } from 'winston';
import { FD } from '../fd';
export declare class CLI {
private log;
log: Logger;
private args;
private fd;
fd: FD;
private camera;
private display;
private bin;
@ -19,5 +21,5 @@ export declare class CLI {
private parseLine;
private parse;
private execute;
private frame;
private expose;
}

64
dist/cli/index.js vendored
View File

@ -12,17 +12,21 @@ const display_1 = require("../display");
const files_1 = require("../files");
const delay_1 = require("../delay");
const camera_1 = require("../camera");
let cli;
var Actions;
(function (Actions) {
Actions[Actions["LOAD"] = 0] = "LOAD";
Actions[Actions["DISPLAY"] = 1] = "DISPLAY";
Actions[Actions["DELAY"] = 2] = "DELAY";
Actions[Actions["EXPOSE"] = 0] = "EXPOSE";
Actions[Actions["DELAY"] = 1] = "DELAY";
Actions[Actions["FORWARD"] = 2] = "FORWARD";
Actions[Actions["BACKWARD"] = 3] = "BACKWARD";
Actions[Actions["GOTO"] = 4] = "GOTO";
})(Actions || (Actions = {}));
class CLI {
constructor() {
this.mock = true;
this.mock = false;
this.log = (0, log_1.createLog)('fm');
this.settings();
this.args = {};
this.display = new display_1.Display(this.width, this.height);
this.fd = new fd_1.FD(this.bin, this.width, this.height, this.host, this.port, this.displayStr, this.mock);
this.camera = new camera_1.Camera(this.mock);
@ -35,7 +39,9 @@ class CLI {
await this.parse(this.args.input);
await (0, delay_1.delay)(2000);
}
await (0, delay_1.delay)(5000);
this.fd.exit();
process.exit(0);
}
settings() {
//parse args
@ -47,9 +53,26 @@ class CLI {
}
parseLine(line) {
let parts;
let cmd = {};
let cmdChar;
if (line.trim() === '') {
return null;
}
parts = line.split(',');
if (parts.length > 0) {
cmdChar = parts[0].trim().toUpperCase()[0];
switch (cmdChar) {
case 'E':
cmd.action = Actions.EXPOSE;
break;
case 'D':
cmd.action = Actions.DELAY;
cmd.time = 1000;
break;
default:
return null;
}
}
return null;
}
async parse(filePath) {
@ -81,18 +104,18 @@ class CLI {
case Actions.DELAY:
await (0, delay_1.delay)(cmd.time);
break;
case Actions.DISPLAY:
await this.frame(cmd);
case Actions.EXPOSE:
await this.expose(cmd);
break;
default:
break;
}
// await this.load(img, 100, 200, 640, 640);
//await this.load(img, 100, 200, 640, 640);
//await delay(2000);
//await this.display(img, [ 4000 ] );
//await delay(8000);
}
async frame(cmd) {
async expose(cmd) {
const start = Date.now();
let load;
let open;
@ -120,6 +143,29 @@ class CLI {
}
exports.CLI = CLI;
if (require.main === module) {
new CLI();
cli = new CLI();
}
async function exitHandler(options, exitCode) {
if (options.cleanup) {
cli.log.info(`Cleaning up...`);
try {
await cli.fd.exit();
}
catch (err) {
cli.log.error('Error cleanly exiting filmout_display (fd) executable', err);
}
}
exitCode == 'SIGINT' ? cli.log.info(`exit: ${exitCode}`) : cli.log.error(`exit: ${exitCode}`, new Error(`Exited with non-zero code: "${exitCode}"`));
if (options.exit)
process.exit();
}
// do something when app is closing
process.on('exit', exitHandler.bind(null, { cleanup: true }));
// catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, { exit: true }));
// catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null, { exit: true }));
process.on('SIGUSR2', exitHandler.bind(null, { exit: true }));
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, { exit: true }));
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

6
dist/exposure/index.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export type ExposureSingle = [number];
export type ExposureChannels = [number, number, number];
export declare class Exposure {
constructor();
static map(value: number, start1: number, stop1: number, start2: number, stop2: number): number;
}

21
dist/exposure/index.js vendored Normal file
View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Exposure = void 0;
class Exposure {
constructor() {
}
static map(value, start1, stop1, start2, stop2) {
if (value < start1) {
value = start1;
}
else if (value > stop1) {
value = stop1;
}
const ratio = (value - start1) / (stop1 - start1);
const mappedValue = start2 + (stop2 - start2) * ratio;
return mappedValue;
}
}
exports.Exposure = Exposure;
module.exports = { Exposure };
//# sourceMappingURL=index.js.map

1
dist/exposure/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exposure/index.ts"],"names":[],"mappings":";;;AAIA,MAAa,QAAQ;IACpB;IAEA,CAAC;IAEM,MAAM,CAAC,GAAG,CAAE,KAAc,EAAE,MAAe,EAAE,KAAc,EAAE,MAAe,EAAE,KAAc;QAClG,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YACpB,KAAK,GAAG,MAAM,CAAC;QAChB,CAAC;aAAM,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;YAC1B,KAAK,GAAG,KAAK,CAAC;QACf,CAAC;QAEA,MAAM,KAAK,GAAY,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAY,MAAM,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC;QAE/D,OAAO,WAAW,CAAC;IAErB,CAAC;CACD;AAlBD,4BAkBC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,QAAQ,EAAE,CAAC"}

8
dist/fd/index.d.ts vendored
View File

@ -1,10 +1,10 @@
declare enum Action {
export declare enum Action {
NONE = 0,
LOAD = 1,
DISPLAY = 2,
STOP = 3
}
declare enum Mode {
export declare enum Mode {
RGB = 0,
BW = 1,
INVERT = 2,
@ -51,6 +51,7 @@ export declare class FD {
private socketConnected;
private waiting;
private mock;
private mode;
constructor(bin: string, width: number, height: number, host: string, port: number, display?: string, mock?: boolean);
private startDisplay;
private startClient;
@ -64,5 +65,6 @@ export declare class FD {
isConnected(): boolean;
private test;
exit(): Promise<void>;
setMode(mode: Mode): void;
}
export type { Action, Mode, fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
export type { fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };

17
dist/fd/index.js vendored
View File

@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FD = void 0;
exports.FD = exports.Mode = exports.Action = void 0;
const net_1 = __importDefault(require("net"));
const log_1 = require("../log");
const shell_1 = require("../shell");
@ -14,7 +14,7 @@ var Action;
Action[Action["LOAD"] = 1] = "LOAD";
Action[Action["DISPLAY"] = 2] = "DISPLAY";
Action[Action["STOP"] = 3] = "STOP";
})(Action || (Action = {}));
})(Action || (exports.Action = Action = {}));
var Mode;
(function (Mode) {
Mode[Mode["RGB"] = 0] = "RGB";
@ -23,7 +23,7 @@ var Mode;
Mode[Mode["BW_INVERT"] = 3] = "BW_INVERT";
Mode[Mode["RGB_CHANNELS"] = 4] = "RGB_CHANNELS";
Mode[Mode["INVERT_CHANNELS"] = 5] = "INVERT_CHANNELS";
})(Mode || (Mode = {}));
})(Mode || (exports.Mode = Mode = {}));
class FD {
constructor(bin, width, height, host, port, display = null, mock = false) {
this.env = null;
@ -33,6 +33,7 @@ class FD {
this.socketConnected = false;
this.waiting = null;
this.mock = false;
this.mode = Mode.RGB;
this.bin = bin;
this.width = width;
this.height = height;
@ -127,6 +128,7 @@ class FD {
async load(image, x, y, w, h) {
const msg = {
action: Action.LOAD,
mode: this.mode,
image,
position: {
x,
@ -166,6 +168,7 @@ class FD {
async display(image, exposure = []) {
const msg = {
action: Action.DISPLAY,
mode: this.mode,
image,
exposure
};
@ -258,7 +261,13 @@ class FD {
if (this.shell !== null)
this.shell.kill();
}
setMode(mode) {
if (mode !== this.mode) {
this.log.info(`Set mode to: ${mode}`);
}
this.mode = mode;
}
}
exports.FD = FD;
module.exports = { FD };
module.exports = { FD, Action, Mode, };
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

14
dist/index.js vendored
View File

@ -246,6 +246,9 @@ async function cmd(msg) {
case 'framing':
await framing();
break;
case 'blank':
await blank();
break;
case 'offset':
offset(msg);
break;
@ -307,6 +310,15 @@ async function start() {
function stop() {
sequence.stop();
}
async function blank() {
if (focusImage !== null) {
await stopFocus();
}
if (framingImage !== null) {
await stopFraming();
}
await send({ cmd: 'blank' });
}
async function send(msg) {
const msgStr = JSON.stringify(msg);
wss.clients.forEach((client) => {
@ -344,6 +356,7 @@ async function focus() {
};
}
focusImage = await testimage_1.TestImage.Focus(pos.w, pos.h);
fd.setMode(fd_1.Mode.RGB);
await fd.load(focusImage, pos.x, pos.y, pos.w, pos.h);
await fd.display(focusImage);
send({ cmd: 'focus' });
@ -381,6 +394,7 @@ async function framing() {
};
}
framingImage = await testimage_1.TestImage.Frame(pos.w, pos.h);
fd.setMode(fd_1.Mode.RGB);
await fd.load(framingImage, pos.x, pos.y, pos.w, pos.h);
await fd.display(framingImage);
send({ cmd: 'framing' });

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

12
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"body-parser": "^1.20.2",
"dotenv": "^16.4.5",
"express": "^4.19.2",
@ -1063,6 +1064,12 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
@ -4145,6 +4152,11 @@
"readable-stream": "^3.6.0"
}
},
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",

View File

@ -22,6 +22,7 @@
"typescript": "^5.4.5"
},
"dependencies": {
"argparse": "^2.0.1",
"body-parser": "^1.20.2",
"dotenv": "^16.4.5",
"express": "^4.19.2",

View File

@ -3,29 +3,35 @@ import { readFile, lstat} from 'fs/promises';
import type { Stats } from 'fs';
import { tmpdir, EOL } from 'os';
import { join, basename } from 'path';
import { ArgumentParser } from 'argparse';
import type { Logger } from 'winston';
import { createLog } from '../log';
import { envInt, envString} from '../env';
import { FD } from '../fd';
import type { fdOutgoingPosition, fdResult } from '../fd';
import { FD, Mode, Action } from '../fd';
import type { fdOutgoingPosition, fdResult} from '../fd';
import { Display, Dimensions } from '../display';
import { Files } from '../files';
import type { ImageObject } from '../files';
import { delay } from '../delay';
import { Camera } from '../camera';
import { TestImage } from '../testimage';
let cli : CLI;
enum Actions {
LOAD,
DISPLAY,
DELAY
EXPOSE,
DELAY,
FORWARD,
BACKWARD,
GOTO
}
interface Args {
input? : string;
width? : number;
height? : number;
mock: boolean;
mock?: boolean;
}
interface CMD {
@ -35,9 +41,9 @@ interface CMD {
}
export class CLI {
private log : Logger;
public log : Logger;
private args : Args;
private fd : FD;
public fd : FD;
private camera : Camera;
private display: Display;
@ -46,7 +52,7 @@ export class CLI {
private height : number;
private host : string;
private port : number;
private mock : boolean = true;
private mock : boolean = false;
private displayStr : string | null;
private lastImage : string | null;
@ -54,6 +60,7 @@ export class CLI {
constructor () {
this.log = createLog('fm');
this.settings();
this.args = this.getArgs();
this.display = new Display(this.width, this.height);
this.fd = new FD(this.bin, this.width, this.height, this.host, this.port, this.displayStr, this.mock);
this.camera = new Camera(this.mock);
@ -67,7 +74,9 @@ export class CLI {
await this.parse(this.args.input);
await delay(2000)
}
await delay(5000);
this.fd.exit();
process.exit(0);
}
private settings () {
@ -80,12 +89,23 @@ export class CLI {
this.port = envInt('FD_PORT', 8082);
}
private parseLine (line : string) : CMD {
let parts : string[];
if (line.trim() === '') {
return null;
}
return null;
private getArgs () {
const parser = new ArgumentParser({
description: 'Filmout manager CLI application',
});
/*
parser.addArgument(['-f', '--file'], {
help: 'Path to a file',
type: String, // Explicitly define type
required: true,
});
parser.addArgument(['-v', '--verbose'], {
help: 'Enable verbose output',
action: 'storeTrue', // Boolean flag
});
*/
return parser.parseArgs();
}
private async parse (filePath : string) {
@ -112,26 +132,56 @@ export class CLI {
}
}
private parseLine (line : string) : CMD {
let parts : string[];
let cmd : CMD = {} as CMD;
let cmdChar : string;
if (line.trim() === '') {
return null;
}
this.log.info(`LINE: ${line.trim()}`);
parts = line.split(',');
if (parts.length > 0) {
cmdChar = parts[0].trim().toUpperCase()[0];
switch (cmdChar) {
case 'E' :
cmd.action = Actions.EXPOSE;
break;
case 'D':
cmd.action = Actions.DELAY;
cmd.time = 1000;
break;
default :
return null;
}
}
return null;
}
private async execute (cmd : CMD) {
if (cmd === null) return;
switch (cmd.action) {
case Actions.DELAY:
await delay(cmd.time);
break;
case Actions.DISPLAY :
await this.frame(cmd);
case Actions.EXPOSE :
await this.expose(cmd);
break;
default :
break;
}
// await this.load(img, 100, 200, 640, 640);
//await this.load(img, 100, 200, 640, 640);
//await delay(2000);
//await this.display(img, [ 4000 ] );
//await delay(8000);
}
private async frame (cmd : CMD) {
private async expose (cmd : CMD) {
const start : number = Date.now();
let load : number;
let open : number;
@ -160,5 +210,31 @@ export class CLI {
}
if (require.main === module) {
new CLI();
}
cli = new CLI();
}
async function exitHandler(options : any, exitCode : string) {
if (options.cleanup) {
cli.log.info(`Cleaning up...`);
try {
await cli.fd.exit();
} catch (err) {
cli.log.error('Error cleanly exiting filmout_display (fd) executable', err);
}
}
exitCode == 'SIGINT' ? cli.log.info(`exit: ${exitCode}`) : cli.log.error(`exit: ${exitCode}`, new Error(`Exited with non-zero code: "${exitCode}"`));
if (options.exit) process.exit();
}
// do something when app is closing
process.on('exit', exitHandler.bind(null,{cleanup:true}));
// catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
// catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));

25
src/exposure/index.ts Normal file
View File

@ -0,0 +1,25 @@
export type ExposureSingle = [ number ];
export type ExposureChannels = [number, number, number];
export class Exposure {
constructor () {
}
public static map (value : number, start1 : number, stop1 : number, start2 : number, stop2 : number) : number {
if (value < start1) {
value = start1;
} else if (value > stop1) {
value = stop1;
}
const ratio : number = (value - start1) / (stop1 - start1);
const mappedValue : number = start2 + (stop2 - start2) * ratio;
return mappedValue;
}
}
module.exports = { Exposure };

View File

@ -5,20 +5,15 @@ import { createLog } from '../log'
import { Shell } from '../shell';
import { delay } from '../delay';
enum Action {
export enum Action {
NONE,
LOAD,
DISPLAY,
STOP
}
enum Mode {
RGB,
BW,
INVERT,
BW_INVERT,
RGB_CHANNELS,
INVERT_CHANNELS
export enum Mode {
RGB
}
interface fdOutgoingPosition {
@ -66,6 +61,8 @@ export class FD {
private waiting : Function = null;
private mock : boolean = false;
private mode : Mode = Mode.RGB;
constructor (bin: string, width : number, height : number, host : string, port : number, display : string = null, mock : boolean = false) {
this.bin = bin;
this.width = width;
@ -167,6 +164,7 @@ export class FD {
public async load (image : string, x : number, y : number, w : number, h : number) : Promise<fdResult> {
const msg : fdOutgoingMessage = {
action : Action.LOAD,
mode : this.mode,
image,
position : {
x,
@ -206,6 +204,7 @@ export class FD {
public async display (image : string, exposure : number[] = []) : Promise<fdResult> {
const msg : fdOutgoingMessage = {
action : Action.DISPLAY,
mode : this.mode,
image,
exposure
};
@ -304,8 +303,15 @@ export class FD {
if (this.client !== null) this.client.end();
if (this.shell !== null) this.shell.kill();
}
public setMode (mode : Mode) {
if (mode !== this.mode) {
this.log.info(`Set mode to: ${mode}`);
}
this.mode = mode;
}
}
module.exports = { FD };
module.exports = { FD, Action, Mode,};
export type { Action, Mode, fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
export type { fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };

View File

@ -21,7 +21,7 @@ import { Files } from './files';
import type { SequenceObject, VideoObject, ImageObject } from './files';
import { delay } from './delay';
import { TestImage } from './testimage';
import { FD } from './fd';
import { FD, Mode, Action} from './fd';
import type { fdOutgoingPosition } from './fd';
import { Display, Dimensions } from './display';
import { FFMPEG } from './ffmpeg';
@ -234,6 +234,9 @@ async function cmd (msg : Message) {
case 'framing' :
await framing();
break;
case 'blank' :
await blank();
break;
case 'offset' :
offset(msg);
break;
@ -305,6 +308,16 @@ function stop () {
sequence.stop();
}
async function blank () {
if (focusImage !== null) {
await stopFocus();
}
if (framingImage !== null) {
await stopFraming();
}
await send({ cmd : 'blank' });
}
async function send (msg : Message) {
const msgStr : string = JSON.stringify(msg);
wss.clients.forEach((client : WebSocket ) => {
@ -343,6 +356,7 @@ async function focus () {
}
}
focusImage = await TestImage.Focus(pos.w, pos.h);
fd.setMode(Mode.RGB);
await fd.load (focusImage, pos.x, pos.y, pos.w, pos.h);
await fd.display(focusImage);
send({ cmd : 'focus' });
@ -381,6 +395,7 @@ async function framing () {
}
}
framingImage = await TestImage.Frame(pos.w, pos.h);
fd.setMode(Mode.RGB);
await fd.load (framingImage, pos.x, pos.y, pos.w, pos.h);
await fd.display(framingImage);
send({ cmd : 'framing' });

View File

@ -32,6 +32,24 @@ html, body{
display: none;
}
#overlayWrapper {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#overlayMessage{
display: inline-block;
color: #fff;
background: rgba(125, 125, 125, 0.5);
border-radius: 8px;
padding: 10px 20px;
margin: 25vh auto;
cursor: pointer;
}
#frame{
text-align: center !important;
font-family: monospace;

View File

@ -43,6 +43,7 @@ declare class Display {
unsetFocus(): void;
setFraming(): void;
unsetFraming(): void;
blank(): void;
private onResize;
}
declare class Client {
@ -93,9 +94,11 @@ declare class Client {
sendFraming(): void;
private receiveFraming;
private receiveUnframing;
private receiveBlank;
sendOffset(x: number, y: number): void;
sendSize(width: number, height: number): void;
sendScale(scale: number): void;
sendBlank(): void;
fullscreen(): void;
exitFullscreen(): void;
private active;

View File

@ -117,6 +117,13 @@ class Display {
unsetFraming() {
this.framing = false;
}
blank() {
this.unsetFocus();
this.unsetFraming();
this.updateSize();
this.clear();
this.updateScreen();
}
onResize(event) {
this.updateSize();
this.clear();
@ -421,6 +428,9 @@ class Client {
this.display.unsetFraming();
this.display.updateImage();
}
receiveBlank(msg) {
this.display.blank();
}
sendOffset(x, y) {
this.client.send(JSON.stringify({ cmd: 'offset', x, y }));
}
@ -430,6 +440,9 @@ class Client {
sendScale(scale) {
this.client.send(JSON.stringify({ cmd: 'scale', scale }));
}
sendBlank() {
this.client.send(JSON.stringify({ cmd: 'blank' }));
}
fullscreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();

File diff suppressed because one or more lines are too long

1
test/example_cli.txt Normal file
View File

@ -0,0 +1 @@
E,test/grayscale_43.jpg,500

BIN
test/grayscale_43.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -121,6 +121,7 @@
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
<button id="focus" class="manualCtrl" onclick="client.sendFocus();">Focus</button>
<button id="framing" class="manualCtrl" onclick="client.sendFraming();">Framing</button>
<button id="blank" class="manualCtrl" onclick="client.sendBlank();">Blank</button>
</form>
</fieldset>
</div>
@ -276,7 +277,11 @@
</div>
</div>
</div>
<div id="overlay"></div>
<div id="overlay">
<div id="overlayWrapper">
<div id="overlayMessage" onclick="window.location.reload();">Refresh</div>
</div>
</div>
<script>
const WEBSOCKET_PORT = {{wsPort}};
</script>