1<html> 2<head> 3 <meta charset="UTF-8"> 4 <title>Pablo's Page</title> 5 <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/aaaakshat/cm-web-fonts@latest/fonts.css"> 6<style> 7body, html { 8 overscroll-behavior: none; 9} 10</style> 11
11<script src="main.js"></script>
11 12
12<script> 13 class ColorConverter extends HTMLElement { 14 attributeChangedCallback() { this.setStyle(); } 15 static get observedAttributes () {return ['style'];} 16 17 setStyle () { 18 const colorscheme = this.getAttribute('style'); 19 20 const colorsinput = this.shadowRoot.querySelector('#colorsInput'); 21 const fileinput = this.shadowRoot.querySelector('#fileInput'); 22 const downloadlink = this.shadowRoot.querySelector('#downloadLink'); 23 24 if (colorscheme === "True") { 25 colorsinput.style.backgroundColor = "rgb(0,43,54)"; 26 fileinput.style.backgroundColor = "rgb(0,43,54)"; 27 downloadlink.style.backgroundColor = "rgb(0,43,54)"; 28 29 colorsinput.style.color = "rgb(131,148,150)"; 30 fileinput.style.color = "rgb(131,148,150)"; 31 downloadlink.style.color = "rgb(131,148,150)"; 32 33 fileinput.style.border = "1px solid rgb( 88, 110, 117)"; 34 colorsinput.style.border = "1px solid rgb( 88, 110, 117)"; 35 downloadlink.style.border = "1px solid rgb( 88, 110, 117)"; 36 37 } else { 38 colorsinput.style.backgroundColor = "rgb(253,246,227)"; 39 fileinput.style.backgroundColor = "rgb(253,246,227)"; 40 downloadlink.style.backgroundColor = "rgb(253,246,227)"; 41 42 colorsinput.style.color = "rgb(101,123,131)"; 43 fileinput.style.color = "rgb(101,123,131)"; 44 downloadlink.style.color = "rgb(101,123,131)"; 45 46 fileinput.style.border = "1px solid rgb(147,161,161)"; 47 colorsinput.style.border = "1px solid rgb(147,161,161)"; 48 downloadlink.style.border = "1px solid rgb(147,161,161)"; 49 } 50 } 51 52 constructor() { 53 super(); 54 this.shadow = this.attachShadow({mode: 'open'}) 55 this.shadowRoot.innerHTML = 56 `<style> #buttonContainer { 57 display: flex; 58 flex-wrap: wrap; 59 } 60 #fileInput,#colorsInput,#downloadLink{ 61 flex-grow: 1; 62 width: 25%; 63 color: inherit; 64 font: inherit; 65 text-align: center; 66 font-size: min(3vh,3vw); 67 margin-right: 10px; /* add a margin to the buttons */ 68 margin-bottom: 10px; 69 padding: 10px; 70 border-radius: 10px; 71 cursor: pointer; 72 text-decoration: none; 73 } 74 p { 75 text-align: center; 76 margin: 0; 77 padding: 0; 78 } 79 #canvas { 80 flex-grow: 1; 81 width: 100%; 82 }</style><div id="buttonContainer"> 83 <button id="fileInput">Choose Image</button> 84 <select id="colorsInput"> 85 <option value="solarized">Solarized</option> 86 <option value="grayscale">Grayscale</option> 87 <option value="neons">Neons</option> 88 <option value="black and white">Black and White</option></select><a id="downloadLink">Download Image</a> 89 </div><input type="file" id="inputFile" accept="*" style="display:none"/><canvas id="canvas"></canvas>`; 90 this._colors = 91 { neons: [[0,0,0],[255,0,0],[0,255,0],[0,0,255],[0,255,255],[255,0,255],[255,255,0],[255,255,255]] 92 , solarized : [ [131,148,150] 93 , [ 0, 43, 54] 94 , [ 7, 54, 66] 95 , [ 88,110,117] 96 , [101,123,131] 97 , [131,148,150] 98 , [147,161,161] 99 , [238,232,213] 100 , [253,246,227] 101 , [181,137, 0] 102 , [203, 75, 22] 103 , [220, 50, 47] 104 , [211, 54,130] 105 , [108,113,196] 106 , [ 38,139,210] 107 , [ 42,161,152] 108 , [133,153, 0] 109 ] 110 , grayscale : [[0,0,0],[255,255,255],[127,127,127],[63,63,63],[191,191,191]] 111 , "black and white" : [[0,0,0],[255,255,255]] 112 } 113 this.fileInputButton = this.shadow.querySelector("#fileInput"); 114 this.colorSelector = this.shadow.querySelector("#colorsInput"); 115 this.imageCanvas = this.shadow.querySelector("canvas"); 116 this.fileInputButton.addEventListener("click", this.openFileDialog.bind(this)); 117 this.colorSelector.addEventListener("change", this.updateCanvas.bind(this)); 118 this.image = null; 119 120 this.downloadLink = this.shadow.querySelector("#downloadLink"); 121 this.downloadLink.download = 'colorconverted.png'; 122 } 123 124 updateCanvas(){ 125 console.log(this.colorSelector.value); 126 console.log(this._colors); 127 console.log(this._colors[this.colorSelector.value]); 128 const selectedColorScheme = this._colors[this.colorSelector.value]; 129 130 const ctx = this.imageCanvas.getContext("2d"); 131 ctx.drawImage(this.image, 0, 0, this.image.width, this.image.height); 132 133 const imageData = ctx.getImageData(0, 0, this.imageCanvas.width, this.imageCanvas.height); 134 135 const data = imageData.data; 136 137 for (let i = 0; i < data.length; i += 4) { 138 let r = data[i]; 139 let g = data[i + 1]; 140 let b = data[i + 2]; 141 let nearestColor = this._getNearestColor(r, g, b, selectedColorScheme.palette); 142 143 data[i] = nearestColor[0]; 144 data[i + 1] = nearestColor[1]; 145 data[i + 2] = nearestColor[2]; 146 } 147 ctx.putImageData(imageData, 0, 0); 148 149 var tdu = this.imageCanvas.toDataURL; 150 HTMLCanvasElement.toDataURL = function(type){ 151 var res = tdu.apply(this,arguments); 152 if (res.substr(0,6) == "data:,"){ 153 var encoder = new JPEGEncoder(); 154 return encoder.encode(this.getContext("2d").getImageData(0,0, this.image.width, this.image.height), 90); 155 } 156 else return res; 157 } 158 159 this.downloadLink.href = this.imageCanvas.toDataURL("image/png").replace(/^data:image\/png/,'data:application/octet-stream'); 160 } 161 openFileDialog() { 162 const fileInput = document.createElement("input"); 163 fileInput.type = "file"; 164 165 fileInput.addEventListener("change", (event) => { 166 const file = event.target.files[0]; 167 const reader = new FileReader(); 168 169 reader.addEventListener("load", (event) => { 170 this.image = new Image(); 171 this.image.src = event.target.result; 172 173 this.image.addEventListener("load", () => { 174 this.imageCanvas.width = this.image.width; 175 this.imageCanvas.height = this.image.height; 176 177 const ctx = this.imageCanvas.getContext("2d"); 178 ctx.drawImage(this.image, 0, 0,this.image.width,this.image.height); 179 this.updateCanvas(); 180 }); 181 });
182 reader.readAsDataURL(file); 183 }); 184 fileInput.click(); 185 } 186 187 _getNearestColor(r,g,b){ 188 let palette = this._colors[this.colorSelector.value] 189 let nearestColor = palette[0]; 190 let nearestDistance = Number.MAX_SAFE_INTEGER; 191 for (let color of palette){ 192 let distance = this._getColorDistanceSquared(r,g,b,color[0],color[1],color[2]); 193 if (distance < nearestDistance){ 194 nearestColor = color; 195 nearestDistance = distance; 196 } 197 } 198 return nearestColor; 199 } 200 201 _getColorDistanceSquared(r1, g1, b1, r2, g2, b2) { 202 function RGBtoL(red,green,blue) { 203 return (0.2126 * red) + (0.7152 * green) + (0.0722 * blue); 204 } 205 let l = Math.abs(RGBtoL(r1,g1,b1) - RGBtoL(r2,g2,b2)); 206 return l; 207 } 208 } 209 customElements.define('color-converter',ColorConverter) 210 </script>
210 211</head> 212<body> 213 <div id="myapp"></div> 214
214<script> 215 let app = Elm.Main.init({ 216 node: document.getElementById('myapp'), 217 flags: 218 { width: Math.max 219 ( document.documentElement.clientWidth || 0 220 , window.innerWidth || 0 221 ) 222 , height: Math.max 223 ( document.documentElement.clientHeight || 0 224 , window.innerHeight || 0 225 ) 226 , style : window.matchMedia("(prefers-color-scheme: dark)").matches 227 } 228 }); 229 </script>
229 230 </body> 231</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.