matrix_websocket_2023_18x18.../data/matrix2.html
2023-08-18 00:03:31 +02:00

625 lines
19 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type = "text/javascript">
var framecount=0;
var buf = new Uint8ClampedArray(768);
var framebuffer1 = "";
var starttime = new Date().getTime();
var currentfps = 25;
var fpsms = 1000/currentfps;
var videocontrast=0;
var sat_r=256;
var sat_g=256;
var sat_b=256;
var vf_size_x = 480;
var vf_size_y = 360;
var vf_pos_x = 0;
var vf_pos_y = 0;
var v_size_x = 32;
var v_size_y = 24;
var v_pos_x = 0;
var v_pos_y = 0;
var zoom=1;
var loop_video=0;
var mute_video=0;
function contrastImage(imgData, contrast){ //input range [-100..100]
var d = imgData.data;
contrast = (contrast/100) + 1; //convert to decimal & shift range: [0..2]
var intercept = 128 * (1 - contrast);
for(var i=0;i<d.length;i+=4){ //r,g,b,a
d[i] = d[i]*contrast + intercept;
d[i+1] = d[i+1]*contrast + intercept;
d[i+2] = d[i+2]*contrast + intercept;
}
return imgData;
}
var loc = window.location, new_uri;
new_uri = "ws://" + loc.host + "/ws";
var ws = new WebSocket(new_uri);
ws.onopen = function() {
console.log("WS BINARY TYPE: "+ws.binaryType);
};
ws.onmessage = function(evt) {
/* INCOMING MESSAGE */
};
let processor = {
timerCallback: function() {
var timenow = new Date().getTime();
var timediff = timenow-starttime;
if (this.video.paused || this.video.ended) {
return;
}
if (timediff>fpsms) {
starttime=timenow;
//console.log("timediff: "+timediff);
this.computeFrame();
}
let self = this;
setTimeout(function () {
self.timerCallback();
}, 0);
},
doLoad: function() {
console.log("doLoad");
document.querySelector('input').addEventListener('change', processor.extractFrames, false);
this.video = document.getElementById("video");
this.c1 = document.getElementById("c1");
this.ctx1 = this.c1.getContext("2d");
this.matrix = document.getElementById("matrix");
let self = this;
/* CREATE PIXEL NODES */
for (var i=0; i<768; i++) {
var px = document.createElement("div");
px.className = "px";
matrix.appendChild(px);
}
this.video.addEventListener("play", function() {
self.width = self.video.videoWidth / 10;
self.height = self.video.videoHeight / 10;
self.timerCallback();
}, false);
},
readURL: function(input) {
console.log("readURL");
var video = document.getElementById("video");
var matrix = document.getElementById("matrix");
video.pause();
if (input.files && input.files[0]) {
var file = input.files[0];
var url = URL.createObjectURL(file);
console.log(url);
var reader = new FileReader();
reader.onload = function() {
video.src = url;
video.load();
video.addEventListener('loadeddata', function() {
var xratio = video.videoWidth/480;
var yratio = video.videoHeight/360;
console.log(video.videoWidth);
var video_container = document.getElementById("video_container");
var video_frame = document.getElementById("vidframe");
var vidframe_offset_x = video_frame.offsetLeft-video_container.offsetLeft;
var vidframe_offset_y = video_frame.offsetTop-video_container.offsetTop;
v_pos_x=Math.floor(vidframe_offset_x*xratio);
v_pos_y=Math.floor(vidframe_offset_y*yratio);
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
console.log("vpx: "+v_pos_x+" --- vpy: "+v_pos_y);
/*
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
v_pos_x=Math.floor(vf_pos_x*10*xratio);
v_pos_y=Math.floor(vf_pos_y*10*yratio);
*/
console.log("V z "+zoom+" "+xratio+" "+v_pos_x+" "+v_pos_y+" "+v_size_x+" "+v_size_y);
video.controls = false;
video.play();
}, false);
//video.controls = true;
console.log(video);
console.log("loaded height "+video.videoHeight);
}
reader.readAsDataURL(file);
for (let i = 0; i < 768; i+=1) {
matrix.childNodes[i].style.backgroundColor = "rgb(0,0,0)";
buf[i]=0;
}
}
},
computeFrame: function() {
framebuffer1="";
this.ctx1 = this.c1.getContext("2d");
var ratio = this.video.videoHeight/this.video.videoWidth;
this.width = 32;
this.cw = Math.round(32*ratio);
if (this.cw%2!=0) this.cw+=1;
//if (zoom>1) this.cw = 24;
this.height = this.cw;
this.offsety = Math.floor((24-this.cw)*.5)*32;
this.ctx1.drawImage(this.video, v_pos_x, v_pos_y, v_size_x, v_size_y, 0, 0, this.width, this.height);
//let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
let frame = contrastImage(this.ctx1.getImageData(0, 0, this.width, this.height),videocontrast);
let l = frame.data.length / 4;
for (let i = 0; i < 768; i+=1) {
buf[i]=0;
}
for (let i = 0; i < l; i+=1) {
var true_r = Math.floor((frame.data[i * 4 + 0] / 32 * (sat_r/256)));
var true_g = Math.floor((frame.data[i * 4 + 1] / 32 * (sat_g/256)));
var true_b = Math.floor((frame.data[i * 4 + 2] / 64 * (sat_b/256)));
let r = (true_r << 5);
let g = (true_g << 2); //0 << 2;
let b = true_b;
var px_r = true_r * 32;
var px_g = true_g * 32;
var px_b = true_b * 64;
if (i+this.offsety<768) {
matrix.childNodes[i+this.offsety].style.backgroundColor = "rgb("+px_r+","+px_g+","+px_b+")";
var py = Math.floor((i+this.offsety)/32);
var pii = (i+this.offsety)-(py*32);
//var pii = (i+this.offsety);
if (py%2==0) {
//buf[py*32+31-pii]=r+g+b;
buf[py*32+pii]=r+g+b;
} else {
//buf[py*32+pii]=r+g+b;
buf[py*32+31-pii]=r+g+b;
}
}
}
ws.send(buf.buffer);
framecount+=1;
return;
}
};
document.addEventListener("DOMContentLoaded", () => {
processor.doLoad();
var slider_r = document.getElementById("rgb_r");
var slider_g = document.getElementById("rgb_g");
var slider_b = document.getElementById("rgb_b");
var slider_zoom = document.getElementById("zoom");
var contrast_slider = document.getElementById("video_contrast");
var slider_offsetx = document.getElementById("vf_offset_x");
var slider_offsety = document.getElementById("vf_offset_y");
slider_offsetx.value=0;
slider_offsety.value=0;
slider_zoom.value=1;
slider_r.value=8;
slider_g.value=8;
slider_b.value=8;
var playvid = document.getElementById("playvid");
var loopvid = document.getElementById("loopvid");
var mutevid = document.getElementById("mutevid");
var myVideo = document.getElementById("video");
var viframe = document.getElementById("vidframe");
var v_progress = document.getElementById("v_progress");
var v_volume = document.getElementById("v_volume");
var docbody = document.getElementById("body");
var fullvid = document.getElementById("fullvid");
docbody.onresize = function() {
var vidc = document.getElementById("video_container");
var vidfr = document.getElementById("vidframe");
console.log("newx "+vidc.offsetLeft);
vidfr.style.top = (parseInt(vidc.offsetTop)+parseInt(slider_offsety.value))+"px";
vidfr.style.left = (parseInt(vidc.offsetLeft)+parseInt(slider_offsetx.value))+"px";
console.log("vidframe x: "+vidfr.offsetLeft);
console.log("slider x: "+slider_offsetx.value);
//console.log("vidcontainer x: "+vidc.offsetLeft+" "+slider_offsetx.value);
}
v_progress.oninput = function() {
var skipto = Math.floor((v_progress.value/100)*myVideo.duration);
myVideo.currentTime = skipto;
processor.computeFrame();
};
v_volume.oninput = function() {
myVideo.volume = v_volume.value*.01;
if (v_volume.value==0) {
mutevid.className = "muteactive";
} else {
mutevid.className = "";
}
};
function togglePlay() {
if (myVideo.paused) {
myVideo.play();
playvid.innerHTML = "⏸";
} else {
myVideo.pause();
playvid.innerHTML = "▶";
}
};
myVideo.onended = function() {
console.log("The video has ended");
playvid.innerHTML = "▶";
};
myVideo.onplay = function() {
console.log("The video has started");
playvid.innerHTML = "⏸";
};
myVideo.ontimeupdate = function(){
var percentage = Math.floor(( myVideo.currentTime / myVideo.duration ) * 100);
//console.log("percent: "+percentage);
v_progress.value = percentage;
};
slider_r.oninput = function() {
sat_r=this.value*32;
this.style.backgroundColor = "rgb("+sat_r+",0,0)";
processor.computeFrame();
}
slider_g.oninput = function() {
sat_g=this.value*32;
this.style.backgroundColor = "rgb(0,"+sat_g+",0)";
processor.computeFrame();
}
slider_b.oninput = function() {
sat_b=this.value*64;
this.style.backgroundColor = "rgb(0,0,"+sat_b+")";
processor.computeFrame();
}
slider_zoom.oninput = function() {
zoom=this.value*.1;
makeZoom();
}
contrast_slider.oninput = function() {
videocontrast=this.value;
}
slider_offsetx.oninput = function() {
var tempvideo = document.getElementById("video");
var vidframe = document.getElementById("vidframe");
vf_pos_x=this.value;
vidframe.style.marginLeft = ((vf_pos_x*10)-2)+"px";
var xratio = tempvideo.videoWidth/480;
v_pos_x=Math.floor(vf_pos_x*10*xratio);
console.log("xratio: "+xratio);
processor.computeFrame();
}
slider_offsety.oninput = function() {
var tempvideo = document.getElementById("video");
var vidframe = document.getElementById("vidframe");
vf_pos_y=this.value;
vidframe.style.marginTop = ((vf_pos_y*10)-2)+"px";
var yratio = tempvideo.videoHeight/360;
v_pos_y=Math.floor(vf_pos_y*10*yratio);
console.log("yratio: "+yratio);
processor.computeFrame();
}
playvid.onclick = function() {
var tempvideo = document.getElementById("video");
console.log("aka");
//tempvideo.play();
togglePlay();
}
fullvid.onclick = function() {
var tempvideo = document.getElementById("video");
tempvideo.requestFullscreen();
}
loopvid.onclick = function() {
var tempvideo = document.getElementById("video");
var loopvid = document.getElementById("loopvid");
if (loop_video==0) {
tempvideo.loop = true;
loop_video=1;
loopvid.classList.add("loopactive");
} else {
tempvideo.loop = false;
loop_video=0;
loopvid.classList.remove("loopactive");
}
}
mutevid.onclick = function() {
var tempvideo = document.getElementById("video");
if (mute_video==1) {
tempvideo.volume = .5;
mute_video=0;
this.classList.remove("muteactive");
v_volume.value=50;
} else {
tempvideo.volume = 0;
mute_video=1;
this.classList.add("muteactive");
v_volume.value=0;
}
}
function doZoom(event) {
event.preventDefault();
console.log(event.deltaY);
if (zoom-event.deltaY*.1>=1 && zoom-event.deltaY*.1<=10) {
zoom-=event.deltaY*.1;
makeZoom();
}
}
function makeZoom(event) {
var tempvideo = document.getElementById("video");
var xratio = tempvideo.videoWidth/480;
var yratio = tempvideo.videoHeight/360;
vf_size_x = Math.floor(480/zoom);
console.log("vf_Sx: "+vf_size_x);
console.log("vf_Px: "+vf_pos_x);
vf_size_y = Math.floor(360/zoom);
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
var vidframe = document.getElementById("vidframe");
vidframe.style.width = vf_size_x+"px";
vidframe.style.height = vf_size_y+"px";
processor.computeFrame();
}
video.onwheel = doZoom;
viframe.onwheel = doZoom;
dragElement(document.getElementById("vidframe"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0, vftop = 0, vfleft = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
var video_container = document.getElementById("video_container");
var video_frame = document.getElementById("vidframe");
var vf_rightbound = elmnt.offsetLeft-pos1-video_container.offsetLeft+video_frame.offsetWidth;
var vf_bottombound = elmnt.offsetTop-pos2-video_container.offsetTop+video_frame.offsetHeight;
//console.log("vf_right: "+vf_rightbound+" --- vf_bottom: "+vf_bottombound);
if (vf_rightbound<480 && (elmnt.offsetLeft - pos1)>=video_container.offsetLeft && vf_bottombound<360 && (elmnt.offsetTop - pos2)>=video_container.offsetTop) {
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
/* UPDATE FRAME INFO */
var tempvideo = document.getElementById("video");
var yratio = tempvideo.videoHeight/360;
var xratio = tempvideo.videoWidth/480;
var tvf_pos_x=elmnt.offsetLeft-video_container.offsetLeft;
var tvf_pos_y=elmnt.offsetTop-video_container.offsetTop;
vf_pos_x=tvf_pos_x;
vf_pos_y=tvf_pos_y;
v_pos_x=Math.floor(tvf_pos_x*xratio);
v_pos_y=Math.floor(tvf_pos_y*yratio);
var slide_offsetx = document.getElementById("vf_offset_x");
var slide_offsety = document.getElementById("vf_offset_y");
slide_offsetx.value = tvf_pos_x;
slide_offsety.value = tvf_pos_y;
} else {
}
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
var video_container = document.getElementById("video_container");
//console.log(video_container);
var video_frame = document.getElementById("vidframe");
//console.log(video_frame);
processor.computeFrame();
}
}
});
</script>
<style>
body { background:#333; font-family:sans-serif; margin:0px; padding:20px; color:#f7f7f7; }
#c2 { background-repeat: no-repeat; }
#matrix { float:none; clear:both; width:320px; height:240px; }
.px { float:left; width:9px; height:9px; margin:0px; padding:0px; display:block; border:0px; border-left:1px solid #222; border-top:1px solid #222; }
#video_container { width:480px; height:360px; margin-bottom:10px; }
#video { width:100%; height:100%; outline:0; }
#c1 { float:left; display:none; }
/* slider */
.slidecontainer { width: 482px; float:right; margin-bottom:20px; }
.slidecontainer span { margin-bottom:10px; display:block; font-weight:bold; }
.slider { -webkit-appearance: none; width: 100%; height: 9px; border-radius: 5px; background: #444; outline: 0px!important; -webkit-transition: .2s; transition: opacity .2s; margin-bottom:10px; }
.slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 50%; background: #00f; cursor: pointer; outline:0px!important; }
.slider::-moz-range-thumb { width: 11px; height: 11px; border-radius: 50%; border:0px; background: #fff; cursor: pointer; outline:0px!important; }
.slider.red { background:#e00; }
.slider.green { background:#0a0; }
.slider.blue { background:#00b; }
.slider.white { background:#555; }
.slider.grey { background:#222; }
.slider.grey:hover::-moz-range-thumb { background:#098; }
.slider.grey::-moz-range-thumb:hover { background:#098; }
#vidframe { position:absolute; width:480px; height:360px; border:1px solid rgba(255,255,255,.5); margin-top:0px; margin-left:0px; cursor:grab; }
#playvid { display:block; background:#222; padding:5px; width:20px; text-align:center; cursor:pointer; height:22px; margin-left:0px; margin-bottom:10px; float:left; }
#playvid:hover { background:#089; }
#outputleft { float:left; width:340px; }
#outputleft span { margin-bottom:10px; display:block; font-weight:bold; }
#inputright { float:right; width:500px; }
#v_progress { float:left; width:250px; margin-top:12px; margin-left:10px; }
#v_volume { float:left; width:100px; margin-top:12px; margin-left:10px; }
#fullvid { float:right; margin-top:7px; text-align:center; background:#222; cursor:pointer; }
#mutevid { float:left; margin-top:7px; text-align:center; margin-left:15px; cursor:pointer; }
#loopvid { float:left; margin-top:7px; margin-left:10px; text-align:center; cursor:pointer; }
.loopactive { color:#089; }
.muteactive { color:rgba(255,255,255,.1); }
</style>
</head>
<body id="body">
<div id="outputleft">
<span>Matrix Output</span>
<div id="matrix"></div>
</div>
<div id="inputright">
<div class="slidecontainer">
<span>Video Input &amp; Controls</span>
<div id="video_container">
<div id="vidframe"></div>
<video id="video" src="input.mp4" />
</div>
<div id="playvid"></div>
<input type="range" min="0" max="100" value="0" class="slider grey" id="v_progress">
<div id="loopvid"></div>
<div id="mutevid">🔊</div>
<input type="range" min="0" max="100" value="50" class="slider grey" id="v_volume">
<div id="fullvid"></div>
<br/>
<input type="file" accept="video/*" style="margin-top:30px; float:none; clear:both; display:block; max-width:100%;" onchange="processor.readURL(this);" />
<div style="clear:both"></div>
<br/>
</div>
<div class="slidecontainer">
<span>Channel Saturation</span>
<input type="range" min="1" max="8" value="8" class="slider red" id="rgb_r">
<input type="range" min="1" max="8" value="8" class="slider green" id="rgb_g">
<input type="range" min="1" max="4" value="4" class="slider blue" id="rgb_b">
</div>
<div class="slidecontainer">
<span>Contrast</span>
<input type="range" min="-100" max="200" value="0" class="slider white" id="video_contrast">
</div>
<div class="slidecontainer">
<span>Zoom</span>
<input type="range" min="10" max="100" value="1" class="slider white" id="zoom">
</div>
<div class="slidecontainer">
<span>Offset</span>
<input type="range" min="0" max="480" value="0" class="slider white" id="vf_offset_x">
<input type="range" min="0" max="360" value="0" class="slider white" id="vf_offset_y">
</div>
<canvas id="c1" width="320" height="240"></canvas>
<div style="clear:both;"></div>
</div>
</body>
</html>