206 lines
24 KiB
HTML
206 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
<meta http-equiv="Expires" content="0">
|
|
<title>Led Matrix Pixel Art Converter</title>
|
|
<style>
|
|
h1,h2{line-height:.5;margin:1px 0}h1,h2,h3{margin:1px 0}#fieldTable,#scaleTable,p{color:#777;font-family:Arcade,Arial,sans-serif}#drop-zone,.container{text-align:center;padding:20px}#drop-zone,#fieldTable,#scaleTable,body,h1,h2,h3,p{font-family:Arcade,Arial,sans-serif}.rangeNumber,.svg-icon{vertical-align:middle}a:active,a:link,a:visited,h2,h3{color:rgba(126,76,128,.61)}a:hover,h1{color:#7e4c80}a:active,a:hover,a:link,a:visited{background-color:transparent;text-decoration:none}.box{border:2px solid #fff}body{background-color:#151515}.top-part{width:600px;margin:0 auto}.container{max-width:100% -40px;border-radius:0}h1{font-size:2.3em}h2{font-size:1.1em;text-align:center}h3{font-size:.7em;line-height:1.4;text-align:center}p{font-size:1.2em;line-height:1.5}#fieldTable,#scaleTable{font-size:1 em;line-height:1}#drop-zone{display:block;width:100%-40px;border:3px dashed #7e4c80;border-radius:0;margin:0;cursor:pointer;font-size:15px;color:#777}* select,.fullTextField[type=text]{background-color:#333;border:1px solid silver;width:100%;height:27px;color:#777;font-size:15px}#file-picker,.hide{display:none}* select{margin-top:.5em;margin-bottom:.5em;padding:0;border-radius:0}* input[type=range]{-webkit-appearance:none;flex-grow:1;border-radius:0;background:linear-gradient(to right,#333 0,#333 100%);color:silver;border:1px solid silver;margin-top:.5em;margin-left:0}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:25px;height:25px;background:#7e4c80;position:relative;z-index:3}.rangeNumber{width:20px}.fullTextField[type=text]{padding-inline-start:5px;margin-top:10px;border-radius:0;font-family:Arcade,Arial,sans-serif}* button,* input[type=submit]{background-color:#333;border:1px solid silver;width:100%;font-family:Arcade,Arial,sans-serif}* input[type=submit]{padding:.5em;border-radius:0;font-size:1.3em;color:#777}* button{padding-inline:5px;border-radius:0;font-size:1em;color:#777;display:flex;align-items:center;justify-content:center;cursor:pointer}.sizeInputFields,textarea{background-color:#333;border:1px solid silver;color:#777}textarea{grid-row:1/2;width:100%;height:200px}.grids-class{position:fixed;top:0;left:0;width:100vw;height:100vh;display:grid;grid-template-columns:repeat(auto-fill,20px);grid-template-rows:repeat(auto-fill,20px);grid-gap:0px}.buttondivmid-class,.gap{width:10px}#sizeDiv *,.buttondiv-class,.buttondivmid-class{display:inline-block}.buttondiv-class{flex:1}#image-container{display:grid;grid-template-rows:1fr 1fr}#button-container{display:flex;padding-bottom:10px;padding-top:10px}.buttonclass{flex:1;padding-top:5px;padding-bottom:5px}#submitConvert::before{content:"";display:inline-block;background-image:url('data:image/svg+xml;utf8, <svg style="width:24px;height:24px" viewBox="0 0 24 24" <path fill="currentColor" d="M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z" /></svg>');width:36px;height:36px}.sizeInputFields{width:50px;padding-inline-start:5px;margin-top:10px;height:27px;border-radius:0;font-family:Arcade,Arial,sans-serif;font-size:15px}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="top-part" >
|
|
<div style="display: flex; justify-content: center;">
|
|
<h1 style="display: flex; align-items: center;">
|
|
<svg style="width:36px;height:36px" viewBox="0 0 24 24">
|
|
<path fill="currentColor" d="M12 16C13.1 16 14 16.9 14 18S13.1 20 12 20 10 19.1 10 18 10.9 16 12 16M12 10C13.1 10 14 10.9 14 12S13.1 14 12 14 10 13.1 10 12 10.9 10 12 10M12 4C13.1 4 14 4.9 14 6S13.1 8 12 8 10 7.1 10 6 10.9 4 12 4M6 16C7.1 16 8 16.9 8 18S7.1 20 6 20 4 19.1 4 18 4.9 16 6 16M6 10C7.1 10 8 10.9 8 12S7.1 14 6 14 4 13.1 4 12 4.9 10 6 10M6 4C7.1 4 8 4.9 8 6S7.1 8 6 8 4 7.1 4 6 4.9 4 6 4M18 16C19.1 16 20 16.9 20 18S19.1 20 18 20 16 19.1 16 18 16.9 16 18 16M18 10C19.1 10 20 10.9 20 12S19.1 14 18 14 16 13.1 16 12 16.9 10 18 10M18 4C19.1 4 20 4.9 20 6S19.1 8 18 8 16 7.1 16 6 16.9 4 18 4Z" />
|
|
</svg>
|
|
Led Matrix Pixel Art Converter
|
|
</h1>
|
|
</div>
|
|
<h2>Convert image to WLED JSON (pixel art on WLED matrix)</h2>
|
|
<p>
|
|
<table id="fieldTable" style="width: 100%; table-layout: fixed; align-content: center;">
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="ledSetupSelector">Led setup:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<select id="ledSetupSelector">
|
|
<option value="matrix" selected>2D Matrix</option>
|
|
<option value="r2l">Serpentine, first row right to left <-</option>
|
|
<option value="l2r">Serpentine, first row left to right -></option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="formatSelector">Output format:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<select id="formatSelector">
|
|
<option value="wled" selected>WLED JSON</option>
|
|
<option value="curl">CURL</option>
|
|
<option value="ha">Home Assistant YAML</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="colorFormatSelector">Color code format:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<select id="colorFormatSelector">
|
|
<option value="hex" selected>HEX (#f4f4f4)</option>
|
|
<option value="dec">DEC (244,244,244)</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="addressingSelector">Addressing:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<select id="addressingSelector">
|
|
<option value="hybrid" selected>Hybrid (#f0f0f0,10, 17, #f4f4f4)</option>
|
|
<option value="range">Range (10, 17, #f4f4f4)</option>
|
|
<option value="single">Single (#f4f4f4)</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="brightnessNumber">Brightness:</label>
|
|
</td>
|
|
<td style="vertical-align: middle; display: flex; align-items: center;">
|
|
<input type="range" id="brightnessNumber" min="1" max="255" value="255">
|
|
<span id="brightnessValue">255</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="colorLimitNumber">Max no of colors/JSON:</label>
|
|
</td>
|
|
<td style="vertical-align: middle; display: flex; align-items: center;">
|
|
<input type="range" id="colorLimitNumber" min="1" max="512" value="256">
|
|
<span id="colorLimitValue" >256</span>
|
|
</td>
|
|
</tr>
|
|
<tr class="ha-hide">
|
|
<td style="vertical-align: middle;">
|
|
<label for="haID">HA Device ID:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<input type="text" id="haID" value="pixel_art_controller_001">
|
|
</td>
|
|
</tr>
|
|
<tr class="ha-hide">
|
|
<td style="vertical-align: middle;">
|
|
<label for="haUID">HA Device Unique ID:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<input class="fullTextField" type="text" id="haUID" value="pixel_art_controller_001a">
|
|
</td>
|
|
</tr>
|
|
<tr class="ha-hide">
|
|
<td style="vertical-align: middle;">
|
|
<label for="haName">HA Device Name:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<input class="fullTextField" type="text" id="haName" value="Pixel Art Kitchen">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="curlUrl">Device IP/host name:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<input class="fullTextField" type="text" id="curlUrl" value="">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<label for="targetSegment">Target segment id:</label>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<select id="targetSegment">
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table class= "scaleTableClass" id="scaleTable" style="width: 100%; table-layout: fixed; align-content: center;">
|
|
<tr>
|
|
<td style="vertical-align: middle;">
|
|
<div id="scaleDiv">
|
|
<svg id="scaleToggle" style="width:36px;height:36px" viewBox="0 0 24 24" onclick="switchScale()">
|
|
<path id="scaleTogglePath" fill="currentColor" d="M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M7,15A3,3 0 0,1 4,12A3,3 0 0,1 7,9A3,3 0 0,1 10,12A3,3 0 0,1 7,15Z" />
|
|
</svg>
|
|
|
|
<svg id="scaleSvg" style="width:36px;height:36px" viewBox="0 0 24 24" onclick="switchScale()">
|
|
<path id="scalePath" fill="currentColor" d="M21,15H23V17H21V15M21,11H23V13H21V11M23,19H21V21C22,21 23,20 23,19M13,3H15V5H13V3M21,7H23V9H21V7M21,3V5H23C23,4 22,3 21,3M1,7H3V9H1V7M17,3H19V5H17V3M17,19H19V21H17V19M3,3C2,3 1,4 1,5H3V3M9,3H11V5H9V3M5,3H7V5H5V3M1,11V19A2,2 0 0,0 3,21H15V11H1M3,19L5.5,15.79L7.29,17.94L9.79,14.72L13,19H3Z" />
|
|
</svg>
|
|
</div>
|
|
</td>
|
|
<td style="vertical-align: middle;">
|
|
<div id="sizeDiv" style="display: none;">
|
|
<label for="sizeX">X : </label> <input class="sizeInputFields" type="number" id="sizeX" value="0">
|
|
|
|
<label for="sizeY">Y : </label> <input class="sizeInputFields" type="number" id="sizeY" value="0">
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</p>
|
|
|
|
</p>
|
|
<p>
|
|
<label for="file-picker">
|
|
<div id="drop-zone">
|
|
Drop image here <br>or <br>
|
|
Click to select a file
|
|
</div>
|
|
</label>
|
|
</p>
|
|
|
|
<p>
|
|
<input type="file" id="file-picker" style="display: none;">
|
|
<div style="width: 100%; text-align: center;" >
|
|
<img id="preview" style="display: block; margin: 0 auto;">
|
|
<img id="newimage" style="display: block; margin: 0 auto;"><br>
|
|
</div>
|
|
|
|
<div id="submitConvertDiv" style="display: none;">
|
|
<button id="convertbutton" class="buttonclass"></button>
|
|
</div>
|
|
|
|
<div id="raw-image-container" style="display: none">
|
|
<img id="image" src="" alt="RawImage image">
|
|
</div>
|
|
|
|
</p>
|
|
|
|
<div id="image-container" style="display: none;">
|
|
<div id="image-info" style="display: none"></div>
|
|
<textarea id="JSONled"></textarea>
|
|
</div>
|
|
|
|
<div id="button-container" style="display: none;">
|
|
<button id="copyJSONledbutton" class="buttonclass"></button>
|
|
<div id="gap1" class="gap"></div>
|
|
<button id="sendJSONledbutton" class="buttonclass"></button>
|
|
<div id = "gap2" class="gap"></div>
|
|
<button id="fileJSONledbutton" class="buttonclass"></button>
|
|
</div>
|
|
<div>
|
|
<h3>Version 1.0.3 - <a href="https://github.com/werkstrom/WLED-PixelArtConverter/blob/main/README.md" target="_blank">Help/About</a></h3>
|
|
</div>
|
|
</div>
|
|
<div id=bottom-part style="display: none" class=bottom-part></div>
|
|
<canvas id="pixelCanvas"></canvas>
|
|
</div>
|
|
<script>
|
|
var curlStart='curl -X POST "http://',curlMid1="/json/state\" -d '",curlEnd='\' -H "Content-Type: application/json"';const haStart="#Uncomment if you don't allready have these defined in your switch section of your configuration.yaml\n#- platform: command_line\n #switches:\n ",haMid1="\n friendly_name: ",haMid2="\n unique_id: ",haMid3="\n command_on: >\n ",haMid4='\n command_off: >\n curl -X POST "http://',haEnd='/json/state" -d \'{"on":false}\' -H "Content-Type: application/json"',haCommandLeading=" ",JSONledStringStart='{"on":true,"bri":',JSONledStringMid1=',"seg":{"id":',JSONledStringMid2=',"i":[',JSONledStringEnd="]}}";var accentColor="#7E4C80",accentTextColor="#777",scaleToggleOffd="M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M7,15A3,3 0 0,1 4,12A3,3 0 0,1 7,9A3,3 0 0,1 10,12A3,3 0 0,1 7,15Z",scaleToggleOnd="M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M17,15A3,3 0 0,1 14,12A3,3 0 0,1 17,9A3,3 0 0,1 20,12A3,3 0 0,1 17,15Z";document.getElementById("curlUrl").value=location.host;let devMode=!1;const urlParams=new URLSearchParams(window.location.search);urlParams.has("dev")&&(devMode=!0),devMode?console.log("Developer mode active. Experimental and unstable functions active."):console.log('Developer mode inactive. Append "?dev" to the URL.'),devMode?(document.getElementById("fileJSONledbutton").style.display="buttonclass",document.getElementById("gap2").style.display="gap"):(document.getElementById("fileJSONledbutton").style.display="none",document.getElementById("gap2").style.display="none");let httpArray=[],fileJSON="";async function postPixels(){for(let e of httpArray)try{console.log(e),console.log(e.length);let t=await fetch("http://"+document.getElementById("curlUrl").value+"/json/state",{method:"POST",headers:{"Content-Type":"application/json"},body:e}),l=await t.json();console.log(l)}catch(n){console.error(n)}}document.getElementById("convertbutton").addEventListener("click",function(){let e=document.getElementById("preview").src;if(isValidBase64Gif(e))document.getElementById("image").src=e,getPixelRGBValues(e),document.getElementById("image-container").style.display="block",document.getElementById("button-container").style.display="";else{let t=document.getElementById("image-info");t.innerHTML="<p><b>WARNING!</b> File does not appear to be a valid image</p>",t.style.display="block",document.getElementById("image-container").style.display="none",document.getElementById("JSONled").value="",console.log("The string '"+e+"' is not a valid base64 image.")}}),copyJSONledbutton.addEventListener("click",async()=>{let e=document.getElementById("JSONled");e.select();try{await navigator.clipboard.writeText(e.value)}catch(t){try{await document.execCommand("copy")}catch(l){console.error("Failed to copy text: ",l)}}}),sendJSONledbutton.addEventListener("click",async()=>{"https:"===window.location.protocol?alert("Will only be available when served over http (or WLED is run over https)"):postPixels()}),fileJSONledbutton.addEventListener("click",async()=>{if("https:"===window.location.protocol)alert("Will only be available when served over http (or WLED is run over https)");else{let e;sendAsFile(fileJSON,"TheName.json","http://"+document.getElementById("curlUrl").value+"/upload")}});const dropZone=document.getElementById("drop-zone"),filePicker=document.getElementById("file-picker"),preview=document.getElementById("preview");function zoneClicked(e){e.preventDefault(),filePicker.click()}function dragEnter(e){e.preventDefault(),this.classList.add("drag-over")}function dragOver(e){e.preventDefault()}function dropped(e){e.preventDefault(),this.classList.remove("drag-over");let t=e.dataTransfer.files[0];updatePreview(t)}function filePicked(e){let t=e.target.files[0];updatePreview(t)}function updatePreview(e){let t=new FileReader;t.onload=function(){preview.src=t.result,document.getElementById("submitConvertDiv").style.display=""},t.readAsDataURL(e)}function isValidBase64Gif(e){return!0}dropZone.addEventListener("dragenter",dragEnter),dropZone.addEventListener("dragover",dragOver),dropZone.addEventListener("drop",dropped),dropZone.addEventListener("click",zoneClicked),filePicker.addEventListener("change",filePicked),document.getElementById("brightnessNumber").oninput=function(){document.getElementById("brightnessValue").textContent=this.value},document.getElementById("colorLimitNumber").oninput=function(){document.getElementById("colorLimitValue").textContent=this.value};for(var formatSelector=document.getElementById("formatSelector"),hideableRows=document.querySelectorAll(".ha-hide"),i=0;i<hideableRows.length;i++)hideableRows[i].classList.add("hide");function switchScale(){let e=document.getElementById("scalePath"),t=document.getElementById("scaleTogglePath"),l=e.getAttribute("fill"),n="";l===accentColor?(l=accentTextColor,n=scaleToggleOffd,document.getElementById("sizeDiv").style.display="none"):(l=accentColor,n=scaleToggleOnd,document.getElementById("sizeDiv").style.display=""),e.setAttribute("fill",l),t.setAttribute("fill",l),t.setAttribute("d",n)}function sendAsFile(e,t,l){var n=new Blob([e],{type:"application/json"});console.log(e),console.log(t),console.log(l);var a=new FormData;a.append("file",n,t);var o=new XMLHttpRequest;o.open("POST",l,!0),o.onload=function(){200===o.status?console.log("File uploaded successfully!"):console.log("File upload failed!")},o.send(a)}function generateSegmentOptions(e){var t=document.getElementById("targetSegment");t.innerHTML="";for(var l=0;l<e.length;l++){var n=document.createElement("option");n.value=e[l].value,n.text=e[l].text,t.appendChild(n),0===l&&(n.selected=!0)}}function generateSegmentArray(e){for(var t=[],l=0;l<e;l++)t.push({value:l,text:"Segment index "+l});return t}formatSelector.addEventListener("change",function(){for(var e=0;e<hideableRows.length;e++)hideableRows[e].classList.toggle("hide","ha"!==this.value)});var segmentData=generateSegmentArray(10);function getPixelRGBValues(e){httpArray=[],fileJSON=JSONledStringStart+document.getElementById("brightnessNumber").value+JSONledStringMid1+document.getElementById("targetSegment").value+JSONledStringMid2;let t=document.getElementById("JSONled"),l=document.getElementById("colorLimitNumber").value,n=!1,a=-1,o=document.getElementById("formatSelector");a=o.selectedIndex;let r=o.options[a].value;a=(o=document.getElementById("ledSetupSelector")).selectedIndex;let d=o.options[a].value;a=(o=document.getElementById("colorFormatSelector")).selectedIndex;let s=!0;"dec"==o.options[a].value&&(s=!1),a=(o=document.getElementById("addressingSelector")).selectedIndex;let _=!0;"single"==o.options[a].value?_=!1:"hybrid"==o.options[a].value&&(n=!0);let c="",g="",$="'",u="'";s||($="[",u="]");let p=!1,y="";var m=document.createElement("canvas"),h=m.getContext("2d"),v=new Image;v.src=e,v.onload=function(){let e=document.getElementById("scalePath").getAttribute("fill"),a=document.getElementById("sizeX").value,o=document.getElementById("sizeY").value;(e!=accentColor||a<1||o<1)&&(a=v.width,o=v.height),m.width=a,m.height=o,y="<p>Width: "+a+", Height: "+o+" (make sure this matches your led matrix setup)</p>",h.drawImage(v,0,0,a,o);var f=h.getImageData(0,0,a,o).data,E=[];let B=1;"l2r"==d&&(B=0);for(var S=0;S<f.length;S+=4){var I=f[S],b=f[S+1],w=f[S+2],A=f[S+3];let L=S/4,x=Math.floor(L/a),M=L;if("matrix"==d);else if((x+B)%2==0);else{let H=M-x*a,C=a-1-H;M=x*a+C}E.push([I,b,w,A,M,L,x])}E.sort((e,t)=>e[5]-t[5]);let O=[...E];O.sort((e,t)=>e[4]-t[4]);let N="",T=-1,k=O.length,J=0,V=[];for(let P=0;P<k;P++){let D=O[P],R=D[0],j=D[1],W=D[2],Z=D[3],U="",z=-1;if(_){if(T<0&&(T=P),P<k-1){let F=O[P+1];(F[0]!=R||F[1]!=j||F[2]!=W)&&(z=P+1,U=T==P&&n?""==N?""+P+",":"":T+","+z+",")}else U=T+1==(z=P+1)&&n?""==N?""+P+",":"":T+","+z+","}else""==N&&(N=P),T=P,z=P;if(Z<255&&(p=!0),z>-1){let G=R+","+j+","+W;if(s){let[Q,q,X]=[R,j,W];G=`${[Q,q,X].map(e=>e.toString(16).padStart(2,"0")).join("")}`}fileJSON=(N=N+U+$+G+u)+U+$+G+u,(J+=1)%l==0||P==k-1?(V.push(N),N=""):N+=",",T=-1}}N="";for(let Y=0;Y<V.length;Y++){let K=JSONledStringStart+document.getElementById("brightnessNumber").value+JSONledStringMid1+document.getElementById("targetSegment").value+JSONledStringMid2+V[Y]+"]}}";httpArray.push(K);let ee=curlStart+document.getElementById("curlUrl").value+curlMid1+K+curlEnd;Y>0&&(N+="\n",c+=" && "),N+=K,c+=ee}g="#Uncomment if you don't allready have these defined in your switch section of your configuration.yaml\n#- platform: command_line\n #switches:\n "+document.getElementById("haID").value+"\n friendly_name: "+document.getElementById("haName").value+"\n unique_id: "+document.getElementById("haUID").value+haMid3+c+haMid3+document.getElementById("curlUrl").value+'/json/state" -d \'{"on":false}\' -H "Content-Type: application/json"',"wled"==r?t.value=N:"curl"==r?t.value=c:"ha"==r?t.value=g:t.value="ERROR!/n"+r+" is an unknown format.",fileJSON+="]}}";let et=document.getElementById("image-info"),el=document.getElementById("image-info");p&&(y+="<p><b>WARNING!</b> Transparency info detected in image. Transparency (alpha) has been ignored. To ensure you get the result you desire, use only solid colors in your image.</p>"),et.innerHTML=y,el.style.display="block",drawBoxes(E,a,o)}}function drawBoxes(e,t,l){var n=document.getElementById("pixelCanvas"),a=n.getContext("2d");window.innerHeight<window.innerWidth?n.width=Math.floor(.98*window.innerHeight):n.width=Math.floor(.98*window.innerWidth);let o=Math.floor(n.width/t);n.height=o*l+10;for(let r=0;r<l;r++)for(let d=0;d<t;d++){let s=e[r*t+d],_="rgb("+s[0]+", "+s[1]+", "+s[2]+")";s[0],s[1],s[2];let c=s[4];a.fillStyle=_,a.fillRect(d*o,r*o,o,o),a.strokeStyle="#888888",a.lineWidth=1,a.strokeRect(d*o,r*o,o,o),a.font="10px Arial",a.fillStyle="rgb(128,128,128)",a.textAlign="center",a.textBaseline="middle",a.fillText(c+1,d*o+o/2,r*o+o/2)}}function drawBackground(){let e=document.createElement("div");e.id="grid",e.classList.add("grid-class"),e.style.cssText="";let t=Math.ceil(window.innerWidth/20)*Math.ceil(window.innerHeight/20);for(let l=0;l<t;l++){let n=document.createElement("div");n.classList.add("box"),n.style.backgroundColor=getRandomColor(),e.appendChild(n)}e.style.zIndex=-1,document.body.appendChild(e)}function getRandomColor(){let e="rgba(";for(let t=0;t<3;t++)e+=Math.floor(256*Math.random())+",";return e+"0.05)"}generateSegmentOptions(segmentData),document.getElementById("fileJSONledbutton").innerHTML='<svg style="width:36px;height:36px" viewBox="0 0 24 24"><path fill="currentColor" d="M20 18H4V8H20M20 6H12L10 4H4A2 2 0 0 0 2 6V18A2 2 0 0 0 4 20H20A2 2 0 0 0 22 18V8A2 2 0 0 0 20 6M16 17H14V13H11L15 9L19 13H16Z" /></svg> File to device',document.getElementById("convertbutton").innerHTML='<svg style="width:36px;height:36px" viewBox="0 0 24 24"><path fill="currentColor" d="M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z" /> </svg> Convert to WLED JSON ',document.getElementById("copyJSONledbutton").innerHTML='<svg class="svg-icon" style="width:36px;height:36px" viewBox="0 0 24 24"> <path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" /> </svg> Copy to clipboard',document.getElementById("sendJSONledbutton").innerHTML='<svg class="svg-icon" style="width:36px;height:36px" viewBox="0 0 24 24"> <path fill="currentColor" d="M6.5 20Q4.22 20 2.61 18.43 1 16.85 1 14.58 1 12.63 2.17 11.1 3.35 9.57 5.25 9.15 5.88 6.85 7.75 5.43 9.63 4 12 4 14.93 4 16.96 6.04 19 8.07 19 11 20.73 11.2 21.86 12.5 23 13.78 23 15.5 23 17.38 21.69 18.69 20.38 20 18.5 20H13Q12.18 20 11.59 19.41 11 18.83 11 18V12.85L9.4 14.4L8 13L12 9L16 13L14.6 14.4L13 12.85V18H18.5Q19.55 18 20.27 17.27 21 16.55 21 15.5 21 14.45 20.27 13.73 19.55 13 18.5 13H17V11Q17 8.93 15.54 7.46 14.08 6 12 6 9.93 6 8.46 7.46 7 8.93 7 11H6.5Q5.05 11 4.03 12.03 3 13.05 3 14.5 3 15.95 4.03 17 5.05 18 6.5 18H9V20M12 13Z" /> </svg> Send to device',window.drawBackground=drawBackground;
|
|
</script>
|
|
</body>
|
|
</html> |