Loading src/jp4-canvas/elphel.js +4 −4 Original line number Original line Diff line number Diff line Loading @@ -129,13 +129,13 @@ var Elphel = { * @lowres - valid values: 1 (not scaled), 2, 4, 8 (lowest resolution) * @lowres - valid values: 1 (not scaled), 2, 4, 8 (lowest resolution) * * */ */ reorderBlocksJP4_lowres: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ //reorderBlocksJP4_lowres: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ reorderBlocksJP4_lowres: async function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ // the output image is 1/4 because demosaicing = 4 single color channel pixels are put into 1 rgb pixel // the output image is 1/4 because demosaicing = 4 single color channel pixels are put into 1 rgb pixel var oPixels = new Uint8Array(pixels.length/4); var oPixels = new Uint8Array(pixels.length/4); // check // check if ((lowres!=1)&&(lowres!=2)&&(lowres!=4)&&(lowres!=8)){ if (![1,2,4,8].includes(lowres)){ lowres = 4; lowres = 4; } } Loading src/jp4-canvas/jp4-canvas.html +4 −4 Original line number Original line Diff line number Diff line Loading @@ -7,12 +7,12 @@ <body> <body> <table> <table> <tr> <tr> <td><div id='test1'></div></td> <td valign='top'><div id='test1'></div></td> <td><div id='test2'></div></td> <td valign='top'><div id='test2'></div></td> </tr> </tr> <tr> <tr> <td><div id='test3'></div></td> <td valign='top'><div id='test3'></div></td> <td><div id='test4'></div></td> <td valign='top'><div id='test4'></div></td> </tr> </tr> </table> </table> <script src="js/elphel.js"></script> <script src="js/elphel.js"></script> Loading src/jp4-canvas/jp4-canvas.js +5 −5 Original line number Original line Diff line number Diff line Loading @@ -27,9 +27,9 @@ $(function(){ $(function(){ var t1 = $("#test1").jp4({ip:location.host, port:2323,width:600,fast:true,lowres:4}); let t1 = $("#test1").jp4({src:"http://"+location.host+":"+2323+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t2 = $("#test2").jp4({ip:location.host, port:2324,width:600,fast:true,lowres:4}); let t2 = $("#test2").jp4({src:"http://"+location.host+":"+2324+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t3 = $("#test3").jp4({ip:location.host, port:2325,width:600,fast:true,lowres:4}); let t3 = $("#test3").jp4({src:"http://"+location.host+":"+2325+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t4 = $("#test4").jp4({ip:location.host, port:2326,width:600,fast:true,lowres:4}); let t4 = $("#test4").jp4({src:"http://"+location.host+":"+2326+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); }); }); src/jp4-canvas/jquery-jp4.js +279 −377 Original line number Original line Diff line number Diff line Loading @@ -28,15 +28,13 @@ (function ( $ ) { (function ( $ ) { //https://gist.github.com/leolux/c794fc63d9c362013448 //https://gist.github.com/leolux/c794fc63d9c362013448 var JP4 = function(element,options){ let JP4 = function(element,options){ var elem = $(element); let elem = $(element); var obj = this; let obj = this; var settings = $.extend({ let settings = $.extend({ ip: "", src: "test.jp4", port: "", image: "test.jp4", fromhtmlinput: false, fromhtmlinput: false, refresh: false, refresh: false, mosaic: [["Gr","R"],["B" ,"Gb"]], mosaic: [["Gr","R"],["B" ,"Gb"]], Loading @@ -56,22 +54,23 @@ } } },options); },options); var DEBUG = settings.debug; let DEBUG = settings.debug; // work time let T0, TX; // working time let BAYER = settings.mosaic; var T0; let FLIPV = 0; var TX; let FLIPH = 0; let IMAGE_FORMAT = "JPEG"; let SATURATION = [0,0,0,0]; var BAYER = settings.mosaic; let PIXELS = []; var FLIPV = 0; var FLIPH = 0; var IMAGE_FORMAT = "JPEG"; var SATURATION = [0,0,0,0]; var PIXELS = []; let INIT = false; // https://stackoverflow.com/questions/28495390/thermal-imaging-palette // https://stackoverflow.com/questions/28495390/thermal-imaging-palette var iron_palette = ["#00000a","#000014","#00001e","#000025","#00002a","#00002e","#000032","#000036", let iron_palette = [ "#00000a","#000014","#00001e","#000025","#00002a","#00002e","#000032","#000036", "#00003a","#00003e","#000042","#000046","#00004a","#00004f","#000052","#010055", "#00003a","#00003e","#000042","#000046","#00004a","#00004f","#000052","#010055", "#010057","#020059","#02005c","#03005e","#040061","#040063","#050065","#060067", "#010057","#020059","#02005c","#03005e","#040061","#040063","#050065","#060067", "#070069","#08006b","#09006e","#0a0070","#0b0073","#0c0074","#0d0075","#0d0076", "#070069","#08006b","#09006e","#0a0070","#0b0073","#0c0074","#0d0075","#0d0076", Loading Loading @@ -125,55 +124,45 @@ "#fff5a6","#fff6aa","#fff6af","#fff7b3","#fff7b6","#fff8ba","#fff8bd","#fff8c1", "#fff5a6","#fff6aa","#fff6af","#fff7b3","#fff7b6","#fff8ba","#fff8bd","#fff8c1", "#fff8c4","#fff9c7","#fff9ca","#fff9cd","#fffad1","#fffad4","#fffbd8","#fffcdb", "#fff8c4","#fff9c7","#fff9ca","#fff9cd","#fffad1","#fffad4","#fffbd8","#fffcdb", "#fffcdf","#fffde2","#fffde5","#fffde8","#fffeeb","#fffeee","#fffef1","#fffef4", "#fffcdf","#fffde2","#fffde5","#fffde8","#fffeeb","#fffeee","#fffef1","#fffef4", "#fffff6"]; "#fffff6" ]; function get_palette_color(v){ function get_palette_color(v){ v = v*(iron_palette.length-1); v = v*(iron_palette.length-1); v_lo = Math.floor(v); v_lo = Math.floor(v); //v_hi = Math.ceil(v); //v_hi = Math.ceil(v); // don't interpolate // don't interpolate return iron_palette[v_lo]; return iron_palette[v_lo]; } } // only valid values are allowed otherwise - disable // only valid values are allowed otherwise - disable if ((settings.lowres!=0)&&(settings.lowres!=1)&&(settings.lowres!=2)&&(settings.lowres!=4)&&(settings.lowres!=8)){ if (![0,1,2,4,8].includes(settings.lowres)){ settings.lowres = 0; settings.lowres = 0; } } var cnv_working = $("<canvas>",{id:"working"}); var cnv_working = $("<canvas>",{id:"working"}); var cnv_display = $("<canvas>",{id:"display"}); var cnv_display = $("<canvas>",{id:"display"}); obj.busy = false; // hide working canvas // hide working canvas cnv_working.css({display:"none"}); cnv_working.css({display:"none"}); /* cnv_working.css({ position:"absolute", top: "500px", left: "500px" }); */ elem.append(cnv_working); elem.append(cnv_working); elem.append(cnv_display); elem.append(cnv_display); if (DEBUG){ if (DEBUG){ TX = Date.now(); T0 = Date.now(); T0 = Date.now(); TX = T0; } } obj.busy = true; if (settings.fromhtmlinput){ if (settings.fromhtmlinput){ /* /* * if image is being loaded from <input type='file'> * if image is being loaded from <input type='file'> * make sure the image data starts with: "data:image/jpeg;base64," * make sure the image data starts with: "data:image/jpeg;base64," * EXIF.js does not like empty data type: "data:;base64," * EXIF.js does not like empty data type: "data:;base64," */ */ obj.busy = true; process_image(settings.src); process_image(settings.image); }else{ }else{ send_request(); send_request(); } } Loading @@ -181,21 +170,14 @@ function send_request(){ function send_request(){ var rq = ""; let rq = settings.src; // old, when CORS was not enabled var http = new XMLHttpRequest(); //rq = "http://"+settings.ip+"/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); if (settings.port!=""&&settings.ip!=""){ //rq = "/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=bimg&ts="+Date.now(); rq = "http://"+settings.ip+"/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); //rq = "get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); //settings.refresh = true; }else{ rq = settings.image; } let http = new XMLHttpRequest(); http.open("GET", rq, true); http.open("GET", rq, true); http.responseType = "blob"; //http.responseType = "blob"; http.responseType = "arraybuffer"; http.onload = function(e) { http.onload = function(e) { if (DEBUG){ if (DEBUG){ Loading @@ -205,57 +187,45 @@ if (this.status===200) { if (this.status===200) { var contentType = http.getResponseHeader("Content-Type"); let contentType = http.getResponseHeader("Content-Type"); if (contentType=="image/tiff"){ if (contentType=="image/tiff"){ process_image_tiff(http.response); process_image_tiff(http.response); }else{ }else{ obj.blob = window.URL.createObjectURL(http.response); //obj.blob = window.URL.createObjectURL(http.response); process_image(obj.blob); //process_image(obj.blob); process_image(http.response); } } delete this; delete this; //URL.revokeObjectURL(imgdata); //URL.revokeObjectURL(imgdata); } } }; }; obj.busy = true; http.send(); http.send(); } } this.refresh = function(){ this.refresh = function(){ // skip if busy? // skip if busy? if (!obj.busy){ if (!obj.busy){ if (DEBUG){ T0 = Date.now(); TX = T0; } send_request(); send_request(); } } } } this.resize = function(w){ this.resize = function(w){ settings.width = w; settings.width = w; INIT = false; send_request(); send_request(); } } this.setAddr = function(url,port){ this.setSrc = function(src){ settings.src = src; settings.port = port; settings.ip = url; return 0; return 0; } } this.getFormat = function(){ this.getFormat = () => this.format; this.getSrc = () => settings.src; return this.format; } this.getAddr = function(){ return Array(settings.ip,settings.port); } function process_image_tiff(blob){ function process_image_tiff(blob){ Loading Loading @@ -397,89 +367,78 @@ function process_image(imagedata){ function process_image(imagedata){ var canvas = cnv_working; let img = {}; //reset format img.exifdata = EXIF.readFromBinaryFile(imagedata); IMAGE_FORMAT = "JPEG"; parseEXIFMakerNote(img); var heavyImage = new Image(); if (DEBUG){ console.log("#"+elem.attr("id")+", exif parse time: "+(Date.now()-TX)/1000+" s"); TX = Date.now(); } var heavyImage = new Image(); heavyImage.onload = function(){ heavyImage.onload = function(){ /* if (DEBUG){ if (obj.blob){ console.log("#"+elem.attr("id")+", file reload (from Blob) as image time: "+(Date.now()-TX)/1000+" s"); console.log("revoking object"); TX = Date.now(); window.URL.revokeObjectURL(obj.blob); } } */ EXIF.getData(this, function() { let cnv_w = this.width; let cnv_h = this.height; var cnv_w; var cnv_h; if (settings.lowres!=0){ if (settings.lowres!=0){ cnv_w = this.width/settings.lowres; cnv_w = this.width/settings.lowres; cnv_h = this.height/settings.lowres; cnv_h = this.height/settings.lowres; }else{ } cnv_w = this.width; cnv_h = this.height; } //update canvas size canvas.attr("width",cnv_w); canvas.attr("height",cnv_h); parseEXIFMakerNote(this); canvas.drawImage({ x:0, y:0, source: this, width: cnv_w, height: cnv_h, //source: heavyImage, load: redraw, sx: 0, sy: 0, sWidth: this.width, sHeight: this.height, //scale: scale, fromCenter: false }); }); if (!INIT) { let w = settings.width; let h = (cnv_h/cnv_w*settings.width).toFixed(0); }; if ((cnv_display[0].width!=w)||(cnv_display[0].height!=h)){ heavyImage.src = imagedata; cnv_display[0].width = w; cnv_display[0].height = h; } INIT = true; } } function redraw(){ if (IMAGE_FORMAT=="JPEG"){ //URL.revokeObjectURL($(this).source.src); let canvas = cnv_display[0]; //console.log(this); //canvas.width = settings.width; //canvas.height = Math.floor(cnv_h*settings.width/cnv_w); let ctx = canvas.getContext('2d'); ctx.drawImage(this,0,0,canvas.width,canvas.height); //for debugging conclude_processing(); //IMAGE_FORMAT="JPEG"; } $(this).draw({ if ((IMAGE_FORMAT=="JP4")||(IMAGE_FORMAT=="JP46")){ fn: function(ctx){ if (DEBUG){ let canvas = cnv_working[0]; console.log("#"+elem.attr("id")+", raw image drawn time: "+(Date.now()-TX)/1000+" s"); canvas.width = cnv_w; TX = Date.now(); canvas.height = cnv_h; } if (IMAGE_FORMAT=="JPEG"){ let ctx = canvas.getContext('2d'); ctx.drawImage(this,0,0,cnv_w,cnv_h); // if JP4/JP46 it will work through webworker and exit later on workers message decode_and_display(ctx); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); } }; //obj.blob = window.URL.createObjectURL(http.response); //process_image(obj.blob); heavyImage.src = window.URL.createObjectURL(new Blob([imagedata])); } function conclude_processing(){ if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); } } $(this).trigger("canvas_ready"); cnv_working.trigger("canvas_ready"); obj.busy = false; obj.busy = false; if (settings.refresh) { if (settings.refresh) { Loading @@ -489,70 +448,20 @@ } } send_request(); send_request(); } } }else if ((IMAGE_FORMAT=="JP4")||(IMAGE_FORMAT=="JP46")){ if (settings.fast){ quickestPreview(ctx); }/*else{ Elphel.reorderJP4Blocks(ctx,"JP4"); if (settings.precise){ PIXELS = Elphel.pixelsToArrayLinear(ctx); Elphel.demosaicBilinear(ctx,PIXELS,settings.mosaic,true); PIXELS = Elphel.pixelsToArray(ctx); }else{ PIXELS = Elphel.pixelsToArray(ctx); Elphel.demosaicBilinear(ctx,PIXELS,settings.mosaic,false); PIXELS = Elphel.pixelsToArray(ctx); } if (settings.channel!="all"){ Elphel.showSingleColorChannel(ctx,settings.channel); } if (settings.diff){ Elphel.diffColorChannels(PIXELS,settings.chn1,settings.chn2,1); Elphel.drawImageData(ctx,PIXELS); } if (settings.ndvi){ console.log(PIXELS[0]+" "+PIXELS[1]+" "+PIXELS[2]+" "+PIXELS[3]+" "); PIXELS = Elphel.someIndex(PIXELS); console.log(PIXELS[0]+" "+PIXELS[1]+" "+PIXELS[2]+" "+PIXELS[3]+" "); Elphel.drawImageData(ctx,PIXELS); } } */ // RGB -> YCbCr x SATURATION -> RGB // Taking SATURATION[0] = 1/GAMMA[0] (green pixel of GR-line) //saturation(ctx,SATURATION[0]); } } // too early function decode_and_display(ctx){ //console.log("#"+elem.attr("id")+", time: "+(Date.now()-t0)/1000+" s"); } }); } function quickestPreview(ctx){ var worker = new Worker(settings.webworker_path+'/webworker.js'); let worker = new Worker(settings.webworker_path+'/webworker.js'); if (DEBUG){ if (DEBUG){ TX = Date.now(); TX = Date.now(); } } //ctx.canvas.width = ctx.canvas.width/2; let width = ctx.canvas.width; //ctx.canvas.height = ctx.canvas.height/2; let height = ctx.canvas.height; //ctx.canvas.style.width = ctx.canvas.style.width/4; let image = ctx.getImageData(0,0,width,height); //ctx.canvas.style.height = ctx.canvas.style.height/4; let pixels = image.data; var width = ctx.canvas.width; var height = ctx.canvas.height; var image = ctx.getImageData(0,0,width,height); var pixels = image.data; if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", data from canvas for webworker time: "+(Date.now()-TX)/1000+" s"); console.log("#"+elem.attr("id")+", data from canvas for webworker time: "+(Date.now()-TX)/1000+" s"); Loading @@ -574,42 +483,34 @@ }, }, },[pixels.buffer]); },[pixels.buffer]); worker.onmessage = function(e){ worker.onmessage = function(e){ var pixels = new Uint8Array(e.data.pixels); let width = e.data.width; var working_context = cnv_working[0].getContext('2d'); let height = e.data.height; let pixels = new Uint8Array(e.data.pixels); var width = e.data.width; var height = e.data.height; if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", worker time: "+(Date.now()-TX)/1000+" s"); console.log("#"+elem.attr("id")+", worker time: "+(Date.now()-TX)/1000+" s"); TX = Date.now(); TX = Date.now(); } } Elphel.Canvas.putImageData(working_context,pixels,width,height); let ctx = cnv_working[0].getContext('2d'); Elphel.Canvas.putImageData(ctx,pixels,width,height); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); if (DEBUG){ /* // report time let ctx = cnv_display[0].getContext('2d'); console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); let imgdata = new ImageData(new Uint8ClampedArray(pixels), width, height); } ctx.putImageData(imgdata,0,0); //trigger here let k = settings.width/width; cnv_working.trigger("canvas_ready"); ctx.scale(k,k); obj.busy = false; ctx.drawImage(cnv_display[0],0,0); ctx.scale(1/k,1/k); if (settings.refresh) { */ if (DEBUG){ TX = Date.now(); T0 = Date.now(); } send_request(); } conclude_processing(); this.terminate(); this.terminate(); } } } } /** /** Loading Loading @@ -667,6 +568,7 @@ if (typeof MakerNote !== 'undefined') color_mode=(MakerNote[10]>>4)&0x0f; if (typeof MakerNote !== 'undefined') color_mode=(MakerNote[10]>>4)&0x0f; switch(color_mode){ switch(color_mode){ case 0: IMAGE_FORMAT = "JPEG"; break; case 2: IMAGE_FORMAT = "JP46"; break; case 2: IMAGE_FORMAT = "JP46"; break; case 5: IMAGE_FORMAT = "JP4"; break; case 5: IMAGE_FORMAT = "JP4"; break; //default: //default: Loading src/jp4-canvas/webworker.js +33 −32 Original line number Original line Diff line number Diff line importScripts('elphel.js'); importScripts('elphel.js'); self.onmessage = function(e) { onmessage = async (e) => { var W = e.data.width; let W = e.data.width; var H = e.data.height; let H = e.data.height; var Mosaic = e.data.mosaic; let Mosaic = e.data.mosaic; var Format = e.data.format; let Format = e.data.format; var settings = e.data.settings; let settings = e.data.settings; var Pixels = new Uint8Array(e.data.pixels); let Pixels = new Uint8Array(e.data.pixels); let reorderedPixels; if (settings.lowres==0){ if (settings.lowres==0){ var reorderedPixels = Elphel.Pixels.reorderBlocksJPx(Pixels,W,H,Format,Mosaic,settings.fast); reorderedPixels = Elphel.Pixels.reorderBlocksJPx(Pixels,W,H,Format,Mosaic,settings.fast); //reorder first then downscale //reorder first then downscale if (settings.fast){ if (settings.fast){ W = W/2; W = W/2; H = H/2; H = H/2; } } }else{ }else{ var reorderedPixels = Elphel.Pixels.reorderBlocksJP4_lowres(Pixels,W,H,Format,Mosaic,settings.lowres); reorderedPixels = await Elphel.Pixels.reorderBlocksJP4_lowres(Pixels,W,H,Format,Mosaic,settings.lowres); W = W/2; W = W/2; H = H/2; H = H/2; } } Loading @@ -35,5 +37,4 @@ self.onmessage = function(e) { //Elphel.test(); //Elphel.test(); this.close(); this.close(); }; }; Loading
src/jp4-canvas/elphel.js +4 −4 Original line number Original line Diff line number Diff line Loading @@ -129,13 +129,13 @@ var Elphel = { * @lowres - valid values: 1 (not scaled), 2, 4, 8 (lowest resolution) * @lowres - valid values: 1 (not scaled), 2, 4, 8 (lowest resolution) * * */ */ reorderBlocksJP4_lowres: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ //reorderBlocksJP4_lowres: function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ reorderBlocksJP4_lowres: async function(pixels,width,height,format="JP4",mosaic=[["Gr","R"],["B" ,"Gb"]],lowres){ // the output image is 1/4 because demosaicing = 4 single color channel pixels are put into 1 rgb pixel // the output image is 1/4 because demosaicing = 4 single color channel pixels are put into 1 rgb pixel var oPixels = new Uint8Array(pixels.length/4); var oPixels = new Uint8Array(pixels.length/4); // check // check if ((lowres!=1)&&(lowres!=2)&&(lowres!=4)&&(lowres!=8)){ if (![1,2,4,8].includes(lowres)){ lowres = 4; lowres = 4; } } Loading
src/jp4-canvas/jp4-canvas.html +4 −4 Original line number Original line Diff line number Diff line Loading @@ -7,12 +7,12 @@ <body> <body> <table> <table> <tr> <tr> <td><div id='test1'></div></td> <td valign='top'><div id='test1'></div></td> <td><div id='test2'></div></td> <td valign='top'><div id='test2'></div></td> </tr> </tr> <tr> <tr> <td><div id='test3'></div></td> <td valign='top'><div id='test3'></div></td> <td><div id='test4'></div></td> <td valign='top'><div id='test4'></div></td> </tr> </tr> </table> </table> <script src="js/elphel.js"></script> <script src="js/elphel.js"></script> Loading
src/jp4-canvas/jp4-canvas.js +5 −5 Original line number Original line Diff line number Diff line Loading @@ -27,9 +27,9 @@ $(function(){ $(function(){ var t1 = $("#test1").jp4({ip:location.host, port:2323,width:600,fast:true,lowres:4}); let t1 = $("#test1").jp4({src:"http://"+location.host+":"+2323+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t2 = $("#test2").jp4({ip:location.host, port:2324,width:600,fast:true,lowres:4}); let t2 = $("#test2").jp4({src:"http://"+location.host+":"+2324+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t3 = $("#test3").jp4({ip:location.host, port:2325,width:600,fast:true,lowres:4}); let t3 = $("#test3").jp4({src:"http://"+location.host+":"+2325+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); var t4 = $("#test4").jp4({ip:location.host, port:2326,width:600,fast:true,lowres:4}); let t4 = $("#test4").jp4({src:"http://"+location.host+":"+2326+"/img",width:600,fast:true,lowres:4,debug:false,refresh:false}); }); });
src/jp4-canvas/jquery-jp4.js +279 −377 Original line number Original line Diff line number Diff line Loading @@ -28,15 +28,13 @@ (function ( $ ) { (function ( $ ) { //https://gist.github.com/leolux/c794fc63d9c362013448 //https://gist.github.com/leolux/c794fc63d9c362013448 var JP4 = function(element,options){ let JP4 = function(element,options){ var elem = $(element); let elem = $(element); var obj = this; let obj = this; var settings = $.extend({ let settings = $.extend({ ip: "", src: "test.jp4", port: "", image: "test.jp4", fromhtmlinput: false, fromhtmlinput: false, refresh: false, refresh: false, mosaic: [["Gr","R"],["B" ,"Gb"]], mosaic: [["Gr","R"],["B" ,"Gb"]], Loading @@ -56,22 +54,23 @@ } } },options); },options); var DEBUG = settings.debug; let DEBUG = settings.debug; // work time let T0, TX; // working time let BAYER = settings.mosaic; var T0; let FLIPV = 0; var TX; let FLIPH = 0; let IMAGE_FORMAT = "JPEG"; let SATURATION = [0,0,0,0]; var BAYER = settings.mosaic; let PIXELS = []; var FLIPV = 0; var FLIPH = 0; var IMAGE_FORMAT = "JPEG"; var SATURATION = [0,0,0,0]; var PIXELS = []; let INIT = false; // https://stackoverflow.com/questions/28495390/thermal-imaging-palette // https://stackoverflow.com/questions/28495390/thermal-imaging-palette var iron_palette = ["#00000a","#000014","#00001e","#000025","#00002a","#00002e","#000032","#000036", let iron_palette = [ "#00000a","#000014","#00001e","#000025","#00002a","#00002e","#000032","#000036", "#00003a","#00003e","#000042","#000046","#00004a","#00004f","#000052","#010055", "#00003a","#00003e","#000042","#000046","#00004a","#00004f","#000052","#010055", "#010057","#020059","#02005c","#03005e","#040061","#040063","#050065","#060067", "#010057","#020059","#02005c","#03005e","#040061","#040063","#050065","#060067", "#070069","#08006b","#09006e","#0a0070","#0b0073","#0c0074","#0d0075","#0d0076", "#070069","#08006b","#09006e","#0a0070","#0b0073","#0c0074","#0d0075","#0d0076", Loading Loading @@ -125,55 +124,45 @@ "#fff5a6","#fff6aa","#fff6af","#fff7b3","#fff7b6","#fff8ba","#fff8bd","#fff8c1", "#fff5a6","#fff6aa","#fff6af","#fff7b3","#fff7b6","#fff8ba","#fff8bd","#fff8c1", "#fff8c4","#fff9c7","#fff9ca","#fff9cd","#fffad1","#fffad4","#fffbd8","#fffcdb", "#fff8c4","#fff9c7","#fff9ca","#fff9cd","#fffad1","#fffad4","#fffbd8","#fffcdb", "#fffcdf","#fffde2","#fffde5","#fffde8","#fffeeb","#fffeee","#fffef1","#fffef4", "#fffcdf","#fffde2","#fffde5","#fffde8","#fffeeb","#fffeee","#fffef1","#fffef4", "#fffff6"]; "#fffff6" ]; function get_palette_color(v){ function get_palette_color(v){ v = v*(iron_palette.length-1); v = v*(iron_palette.length-1); v_lo = Math.floor(v); v_lo = Math.floor(v); //v_hi = Math.ceil(v); //v_hi = Math.ceil(v); // don't interpolate // don't interpolate return iron_palette[v_lo]; return iron_palette[v_lo]; } } // only valid values are allowed otherwise - disable // only valid values are allowed otherwise - disable if ((settings.lowres!=0)&&(settings.lowres!=1)&&(settings.lowres!=2)&&(settings.lowres!=4)&&(settings.lowres!=8)){ if (![0,1,2,4,8].includes(settings.lowres)){ settings.lowres = 0; settings.lowres = 0; } } var cnv_working = $("<canvas>",{id:"working"}); var cnv_working = $("<canvas>",{id:"working"}); var cnv_display = $("<canvas>",{id:"display"}); var cnv_display = $("<canvas>",{id:"display"}); obj.busy = false; // hide working canvas // hide working canvas cnv_working.css({display:"none"}); cnv_working.css({display:"none"}); /* cnv_working.css({ position:"absolute", top: "500px", left: "500px" }); */ elem.append(cnv_working); elem.append(cnv_working); elem.append(cnv_display); elem.append(cnv_display); if (DEBUG){ if (DEBUG){ TX = Date.now(); T0 = Date.now(); T0 = Date.now(); TX = T0; } } obj.busy = true; if (settings.fromhtmlinput){ if (settings.fromhtmlinput){ /* /* * if image is being loaded from <input type='file'> * if image is being loaded from <input type='file'> * make sure the image data starts with: "data:image/jpeg;base64," * make sure the image data starts with: "data:image/jpeg;base64," * EXIF.js does not like empty data type: "data:;base64," * EXIF.js does not like empty data type: "data:;base64," */ */ obj.busy = true; process_image(settings.src); process_image(settings.image); }else{ }else{ send_request(); send_request(); } } Loading @@ -181,21 +170,14 @@ function send_request(){ function send_request(){ var rq = ""; let rq = settings.src; // old, when CORS was not enabled var http = new XMLHttpRequest(); //rq = "http://"+settings.ip+"/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); if (settings.port!=""&&settings.ip!=""){ //rq = "/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=bimg&ts="+Date.now(); rq = "http://"+settings.ip+"/get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); //rq = "get-image.php?ip="+settings.ip+"&port="+settings.port+"&rel=img&ts="+Date.now(); //settings.refresh = true; }else{ rq = settings.image; } let http = new XMLHttpRequest(); http.open("GET", rq, true); http.open("GET", rq, true); http.responseType = "blob"; //http.responseType = "blob"; http.responseType = "arraybuffer"; http.onload = function(e) { http.onload = function(e) { if (DEBUG){ if (DEBUG){ Loading @@ -205,57 +187,45 @@ if (this.status===200) { if (this.status===200) { var contentType = http.getResponseHeader("Content-Type"); let contentType = http.getResponseHeader("Content-Type"); if (contentType=="image/tiff"){ if (contentType=="image/tiff"){ process_image_tiff(http.response); process_image_tiff(http.response); }else{ }else{ obj.blob = window.URL.createObjectURL(http.response); //obj.blob = window.URL.createObjectURL(http.response); process_image(obj.blob); //process_image(obj.blob); process_image(http.response); } } delete this; delete this; //URL.revokeObjectURL(imgdata); //URL.revokeObjectURL(imgdata); } } }; }; obj.busy = true; http.send(); http.send(); } } this.refresh = function(){ this.refresh = function(){ // skip if busy? // skip if busy? if (!obj.busy){ if (!obj.busy){ if (DEBUG){ T0 = Date.now(); TX = T0; } send_request(); send_request(); } } } } this.resize = function(w){ this.resize = function(w){ settings.width = w; settings.width = w; INIT = false; send_request(); send_request(); } } this.setAddr = function(url,port){ this.setSrc = function(src){ settings.src = src; settings.port = port; settings.ip = url; return 0; return 0; } } this.getFormat = function(){ this.getFormat = () => this.format; this.getSrc = () => settings.src; return this.format; } this.getAddr = function(){ return Array(settings.ip,settings.port); } function process_image_tiff(blob){ function process_image_tiff(blob){ Loading Loading @@ -397,89 +367,78 @@ function process_image(imagedata){ function process_image(imagedata){ var canvas = cnv_working; let img = {}; //reset format img.exifdata = EXIF.readFromBinaryFile(imagedata); IMAGE_FORMAT = "JPEG"; parseEXIFMakerNote(img); var heavyImage = new Image(); if (DEBUG){ console.log("#"+elem.attr("id")+", exif parse time: "+(Date.now()-TX)/1000+" s"); TX = Date.now(); } var heavyImage = new Image(); heavyImage.onload = function(){ heavyImage.onload = function(){ /* if (DEBUG){ if (obj.blob){ console.log("#"+elem.attr("id")+", file reload (from Blob) as image time: "+(Date.now()-TX)/1000+" s"); console.log("revoking object"); TX = Date.now(); window.URL.revokeObjectURL(obj.blob); } } */ EXIF.getData(this, function() { let cnv_w = this.width; let cnv_h = this.height; var cnv_w; var cnv_h; if (settings.lowres!=0){ if (settings.lowres!=0){ cnv_w = this.width/settings.lowres; cnv_w = this.width/settings.lowres; cnv_h = this.height/settings.lowres; cnv_h = this.height/settings.lowres; }else{ } cnv_w = this.width; cnv_h = this.height; } //update canvas size canvas.attr("width",cnv_w); canvas.attr("height",cnv_h); parseEXIFMakerNote(this); canvas.drawImage({ x:0, y:0, source: this, width: cnv_w, height: cnv_h, //source: heavyImage, load: redraw, sx: 0, sy: 0, sWidth: this.width, sHeight: this.height, //scale: scale, fromCenter: false }); }); if (!INIT) { let w = settings.width; let h = (cnv_h/cnv_w*settings.width).toFixed(0); }; if ((cnv_display[0].width!=w)||(cnv_display[0].height!=h)){ heavyImage.src = imagedata; cnv_display[0].width = w; cnv_display[0].height = h; } INIT = true; } } function redraw(){ if (IMAGE_FORMAT=="JPEG"){ //URL.revokeObjectURL($(this).source.src); let canvas = cnv_display[0]; //console.log(this); //canvas.width = settings.width; //canvas.height = Math.floor(cnv_h*settings.width/cnv_w); let ctx = canvas.getContext('2d'); ctx.drawImage(this,0,0,canvas.width,canvas.height); //for debugging conclude_processing(); //IMAGE_FORMAT="JPEG"; } $(this).draw({ if ((IMAGE_FORMAT=="JP4")||(IMAGE_FORMAT=="JP46")){ fn: function(ctx){ if (DEBUG){ let canvas = cnv_working[0]; console.log("#"+elem.attr("id")+", raw image drawn time: "+(Date.now()-TX)/1000+" s"); canvas.width = cnv_w; TX = Date.now(); canvas.height = cnv_h; } if (IMAGE_FORMAT=="JPEG"){ let ctx = canvas.getContext('2d'); ctx.drawImage(this,0,0,cnv_w,cnv_h); // if JP4/JP46 it will work through webworker and exit later on workers message decode_and_display(ctx); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); } }; //obj.blob = window.URL.createObjectURL(http.response); //process_image(obj.blob); heavyImage.src = window.URL.createObjectURL(new Blob([imagedata])); } function conclude_processing(){ if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); } } $(this).trigger("canvas_ready"); cnv_working.trigger("canvas_ready"); obj.busy = false; obj.busy = false; if (settings.refresh) { if (settings.refresh) { Loading @@ -489,70 +448,20 @@ } } send_request(); send_request(); } } }else if ((IMAGE_FORMAT=="JP4")||(IMAGE_FORMAT=="JP46")){ if (settings.fast){ quickestPreview(ctx); }/*else{ Elphel.reorderJP4Blocks(ctx,"JP4"); if (settings.precise){ PIXELS = Elphel.pixelsToArrayLinear(ctx); Elphel.demosaicBilinear(ctx,PIXELS,settings.mosaic,true); PIXELS = Elphel.pixelsToArray(ctx); }else{ PIXELS = Elphel.pixelsToArray(ctx); Elphel.demosaicBilinear(ctx,PIXELS,settings.mosaic,false); PIXELS = Elphel.pixelsToArray(ctx); } if (settings.channel!="all"){ Elphel.showSingleColorChannel(ctx,settings.channel); } if (settings.diff){ Elphel.diffColorChannels(PIXELS,settings.chn1,settings.chn2,1); Elphel.drawImageData(ctx,PIXELS); } if (settings.ndvi){ console.log(PIXELS[0]+" "+PIXELS[1]+" "+PIXELS[2]+" "+PIXELS[3]+" "); PIXELS = Elphel.someIndex(PIXELS); console.log(PIXELS[0]+" "+PIXELS[1]+" "+PIXELS[2]+" "+PIXELS[3]+" "); Elphel.drawImageData(ctx,PIXELS); } } */ // RGB -> YCbCr x SATURATION -> RGB // Taking SATURATION[0] = 1/GAMMA[0] (green pixel of GR-line) //saturation(ctx,SATURATION[0]); } } // too early function decode_and_display(ctx){ //console.log("#"+elem.attr("id")+", time: "+(Date.now()-t0)/1000+" s"); } }); } function quickestPreview(ctx){ var worker = new Worker(settings.webworker_path+'/webworker.js'); let worker = new Worker(settings.webworker_path+'/webworker.js'); if (DEBUG){ if (DEBUG){ TX = Date.now(); TX = Date.now(); } } //ctx.canvas.width = ctx.canvas.width/2; let width = ctx.canvas.width; //ctx.canvas.height = ctx.canvas.height/2; let height = ctx.canvas.height; //ctx.canvas.style.width = ctx.canvas.style.width/4; let image = ctx.getImageData(0,0,width,height); //ctx.canvas.style.height = ctx.canvas.style.height/4; let pixels = image.data; var width = ctx.canvas.width; var height = ctx.canvas.height; var image = ctx.getImageData(0,0,width,height); var pixels = image.data; if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", data from canvas for webworker time: "+(Date.now()-TX)/1000+" s"); console.log("#"+elem.attr("id")+", data from canvas for webworker time: "+(Date.now()-TX)/1000+" s"); Loading @@ -574,42 +483,34 @@ }, }, },[pixels.buffer]); },[pixels.buffer]); worker.onmessage = function(e){ worker.onmessage = function(e){ var pixels = new Uint8Array(e.data.pixels); let width = e.data.width; var working_context = cnv_working[0].getContext('2d'); let height = e.data.height; let pixels = new Uint8Array(e.data.pixels); var width = e.data.width; var height = e.data.height; if (DEBUG){ if (DEBUG){ console.log("#"+elem.attr("id")+", worker time: "+(Date.now()-TX)/1000+" s"); console.log("#"+elem.attr("id")+", worker time: "+(Date.now()-TX)/1000+" s"); TX = Date.now(); TX = Date.now(); } } Elphel.Canvas.putImageData(working_context,pixels,width,height); let ctx = cnv_working[0].getContext('2d'); Elphel.Canvas.putImageData(ctx,pixels,width,height); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); Elphel.Canvas.drawScaled(cnv_working,cnv_display,settings.width); if (DEBUG){ /* // report time let ctx = cnv_display[0].getContext('2d'); console.log("#"+elem.attr("id")+", Total time: "+(Date.now()-T0)/1000+" s"); let imgdata = new ImageData(new Uint8ClampedArray(pixels), width, height); } ctx.putImageData(imgdata,0,0); //trigger here let k = settings.width/width; cnv_working.trigger("canvas_ready"); ctx.scale(k,k); obj.busy = false; ctx.drawImage(cnv_display[0],0,0); ctx.scale(1/k,1/k); if (settings.refresh) { */ if (DEBUG){ TX = Date.now(); T0 = Date.now(); } send_request(); } conclude_processing(); this.terminate(); this.terminate(); } } } } /** /** Loading Loading @@ -667,6 +568,7 @@ if (typeof MakerNote !== 'undefined') color_mode=(MakerNote[10]>>4)&0x0f; if (typeof MakerNote !== 'undefined') color_mode=(MakerNote[10]>>4)&0x0f; switch(color_mode){ switch(color_mode){ case 0: IMAGE_FORMAT = "JPEG"; break; case 2: IMAGE_FORMAT = "JP46"; break; case 2: IMAGE_FORMAT = "JP46"; break; case 5: IMAGE_FORMAT = "JP4"; break; case 5: IMAGE_FORMAT = "JP4"; break; //default: //default: Loading
src/jp4-canvas/webworker.js +33 −32 Original line number Original line Diff line number Diff line importScripts('elphel.js'); importScripts('elphel.js'); self.onmessage = function(e) { onmessage = async (e) => { var W = e.data.width; let W = e.data.width; var H = e.data.height; let H = e.data.height; var Mosaic = e.data.mosaic; let Mosaic = e.data.mosaic; var Format = e.data.format; let Format = e.data.format; var settings = e.data.settings; let settings = e.data.settings; var Pixels = new Uint8Array(e.data.pixels); let Pixels = new Uint8Array(e.data.pixels); let reorderedPixels; if (settings.lowres==0){ if (settings.lowres==0){ var reorderedPixels = Elphel.Pixels.reorderBlocksJPx(Pixels,W,H,Format,Mosaic,settings.fast); reorderedPixels = Elphel.Pixels.reorderBlocksJPx(Pixels,W,H,Format,Mosaic,settings.fast); //reorder first then downscale //reorder first then downscale if (settings.fast){ if (settings.fast){ W = W/2; W = W/2; H = H/2; H = H/2; } } }else{ }else{ var reorderedPixels = Elphel.Pixels.reorderBlocksJP4_lowres(Pixels,W,H,Format,Mosaic,settings.lowres); reorderedPixels = await Elphel.Pixels.reorderBlocksJP4_lowres(Pixels,W,H,Format,Mosaic,settings.lowres); W = W/2; W = W/2; H = H/2; H = H/2; } } Loading @@ -35,5 +37,4 @@ self.onmessage = function(e) { //Elphel.test(); //Elphel.test(); this.close(); this.close(); }; };