Update index.html
Browse filesAdded options to choose quantization method and enabling dithering and kmeans
Plus, switch to simplecss for a better looking interface.
- index.html +31 -22
index.html
CHANGED
|
@@ -2,10 +2,10 @@
|
|
| 2 |
<html>
|
| 3 |
<head>
|
| 4 |
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"></script>
|
|
|
|
| 5 |
<style>
|
| 6 |
body {
|
| 7 |
-
|
| 8 |
-
font-family: sans-serif;
|
| 9 |
}
|
| 10 |
|
| 11 |
.editor {
|
|
@@ -16,11 +16,11 @@
|
|
| 16 |
|
| 17 |
.toolbar {
|
| 18 |
width: 500px;
|
| 19 |
-
background: #eeeeee;
|
| 20 |
}
|
| 21 |
|
| 22 |
.toolbar-item {
|
| 23 |
padding: 15px;
|
|
|
|
| 24 |
}
|
| 25 |
|
| 26 |
.tool-label {
|
|
@@ -37,7 +37,6 @@
|
|
| 37 |
.image-area {
|
| 38 |
flex-grow: 1;
|
| 39 |
padding: 20px;
|
| 40 |
-
background: #555555;
|
| 41 |
}
|
| 42 |
|
| 43 |
#canvas {
|
|
@@ -53,22 +52,32 @@
|
|
| 53 |
<div class="toolbar-item">
|
| 54 |
<input type="file" id="imageFileInput">
|
| 55 |
</div>
|
|
|
|
| 56 |
<div class="toolbar-item">
|
| 57 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
</div>
|
|
|
|
| 59 |
<div class="toolbar-item">
|
| 60 |
-
<label
|
| 61 |
-
<
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
</div>
|
| 64 |
<div class="toolbar-item">
|
| 65 |
-
<
|
| 66 |
-
<
|
| 67 |
-
<output>16</output>
|
| 68 |
</div>
|
| 69 |
<div class="toolbar-item">
|
| 70 |
-
<input type="checkbox" id="
|
| 71 |
-
<label for="
|
| 72 |
</div>
|
| 73 |
<div class="toolbar-item">
|
| 74 |
<input type="checkbox" id="rgb555" name="rgb555" checked />
|
|
@@ -82,10 +91,12 @@
|
|
| 82 |
<input type="checkbox" id="rescale" name="rescale" checked />
|
| 83 |
<label for="rescale">Rescale post-processing</label>
|
| 84 |
</div>
|
| 85 |
-
</fieldset>
|
| 86 |
<div class="toolbar-item">
|
| 87 |
<button onclick="pixelize()">Run</button>
|
| 88 |
</div>
|
|
|
|
|
|
|
|
|
|
| 89 |
<div class="toolbar-item">
|
| 90 |
<textarea id="consoleOutput" style="width: 465px;" rows="20" disabled></textarea>
|
| 91 |
</div>
|
|
@@ -128,7 +139,7 @@ function addToOutput(s) {
|
|
| 128 |
async function main() {
|
| 129 |
let pyodide = await loadPyodide();
|
| 130 |
await pyodide.loadPackage("numpy");
|
| 131 |
-
await pyodide.loadPackage("
|
| 132 |
return pyodide;
|
| 133 |
}
|
| 134 |
|
|
@@ -144,7 +155,7 @@ async function pixelize() {
|
|
| 144 |
pyodide.runPython(`
|
| 145 |
import numpy as np
|
| 146 |
from PIL import Image
|
| 147 |
-
from js import canvas, scale, colors, quant, rgb555, snescrop, rescale, addToOutput, ImageData
|
| 148 |
from pyodide.ffi import create_proxy
|
| 149 |
|
| 150 |
# Access to canvas content
|
|
@@ -178,12 +189,10 @@ async function pixelize() {
|
|
| 178 |
addToOutput(f"Resized by scale {s} to ({w},{h})")
|
| 179 |
|
| 180 |
# Reduce or quantize colors
|
| 181 |
-
if
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
im = im.convert('RGB').quantize(colors=int(colors.value),method=Image.Quantize.MEDIANCUT).convert('RGBA')
|
| 186 |
-
addToOutput(f"Reduced to {colors.value} colors")
|
| 187 |
|
| 188 |
# Apply RGB555
|
| 189 |
if rgb555.checked:
|
|
|
|
| 2 |
<html>
|
| 3 |
<head>
|
| 4 |
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"></script>
|
| 5 |
+
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
|
| 6 |
<style>
|
| 7 |
body {
|
| 8 |
+
grid-template-columns: none !important;
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
.editor {
|
|
|
|
| 16 |
|
| 17 |
.toolbar {
|
| 18 |
width: 500px;
|
|
|
|
| 19 |
}
|
| 20 |
|
| 21 |
.toolbar-item {
|
| 22 |
padding: 15px;
|
| 23 |
+
display: inline-block;
|
| 24 |
}
|
| 25 |
|
| 26 |
.tool-label {
|
|
|
|
| 37 |
.image-area {
|
| 38 |
flex-grow: 1;
|
| 39 |
padding: 20px;
|
|
|
|
| 40 |
}
|
| 41 |
|
| 42 |
#canvas {
|
|
|
|
| 52 |
<div class="toolbar-item">
|
| 53 |
<input type="file" id="imageFileInput">
|
| 54 |
</div>
|
| 55 |
+
|
| 56 |
<div class="toolbar-item">
|
| 57 |
+
<label class="tool-label" for="scale">Scale (4)</label>
|
| 58 |
+
<input class="tool-input" type="range" id="scale" min="2" max="16" value="4" step="2" oninput="this.previousElementSibling.innerHTML = 'Scale (' + this.value + ')'">
|
| 59 |
+
</div>
|
| 60 |
+
<div class="toolbar-item">
|
| 61 |
+
<label class="tool-label" for="colors">Colors (16)</label>
|
| 62 |
+
<input class="tool-input" type="range" id="colors" min="4" max="256" value="16" step="2" oninput="this.previousElementSibling.innerHTML = 'Colors (' + this.value + ')'">
|
| 63 |
</div>
|
| 64 |
+
<br />
|
| 65 |
<div class="toolbar-item">
|
| 66 |
+
<label for="quant">Quantization method:</label><!-- https://pillow.readthedocs.io/en/stable/_modules/PIL/Image.html#Quantize -->
|
| 67 |
+
<select name="quant" id="quant">
|
| 68 |
+
<option value="3">LibImageQuant</option>
|
| 69 |
+
<option value="0">MedianCut</option>
|
| 70 |
+
<option value="2">FastOctree</option>
|
| 71 |
+
<option value="1">MaxCoverage</option>
|
| 72 |
+
</select>
|
| 73 |
</div>
|
| 74 |
<div class="toolbar-item">
|
| 75 |
+
<input type="checkbox" id="dither" name="dither" checked />
|
| 76 |
+
<label for="dither">Enable Dithering</label>
|
|
|
|
| 77 |
</div>
|
| 78 |
<div class="toolbar-item">
|
| 79 |
+
<input type="checkbox" id="kmeans" name="kmeans" />
|
| 80 |
+
<label for="kmeans">Enable K-Means</label>
|
| 81 |
</div>
|
| 82 |
<div class="toolbar-item">
|
| 83 |
<input type="checkbox" id="rgb555" name="rgb555" checked />
|
|
|
|
| 91 |
<input type="checkbox" id="rescale" name="rescale" checked />
|
| 92 |
<label for="rescale">Rescale post-processing</label>
|
| 93 |
</div>
|
|
|
|
| 94 |
<div class="toolbar-item">
|
| 95 |
<button onclick="pixelize()">Run</button>
|
| 96 |
</div>
|
| 97 |
+
<div class="toolbar-item">
|
| 98 |
+
<button id="reloadBtn" onclick="loadImage()" disabled>Reload original</button>
|
| 99 |
+
</div>
|
| 100 |
<div class="toolbar-item">
|
| 101 |
<textarea id="consoleOutput" style="width: 465px;" rows="20" disabled></textarea>
|
| 102 |
</div>
|
|
|
|
| 139 |
async function main() {
|
| 140 |
let pyodide = await loadPyodide();
|
| 141 |
await pyodide.loadPackage("numpy");
|
| 142 |
+
await pyodide.loadPackage("./pillow-10.2.0-cp312-cp312-pyodide_2024_0_wasm32.whl");
|
| 143 |
return pyodide;
|
| 144 |
}
|
| 145 |
|
|
|
|
| 155 |
pyodide.runPython(`
|
| 156 |
import numpy as np
|
| 157 |
from PIL import Image
|
| 158 |
+
from js import canvas, scale, colors, quant, dither, kmeans, rgb555, snescrop, rescale, addToOutput, ImageData
|
| 159 |
from pyodide.ffi import create_proxy
|
| 160 |
|
| 161 |
# Access to canvas content
|
|
|
|
| 189 |
addToOutput(f"Resized by scale {s} to ({w},{h})")
|
| 190 |
|
| 191 |
# Reduce or quantize colors
|
| 192 |
+
dither_method = Image.Dither.FLOYDSTEINBERG if dither.checked else Image.Dither.NONE
|
| 193 |
+
kmeans_colors = int(colors.value) if kmeans.checked else 0
|
| 194 |
+
im = im.convert('RGB').quantize(colors=int(colors.value), method=int(quant.value), dither=dither_method, kmeans=kmeans_colors).convert('RGBA')
|
| 195 |
+
addToOutput(f"Quantized to {colors.value} colors")
|
|
|
|
|
|
|
| 196 |
|
| 197 |
# Apply RGB555
|
| 198 |
if rgb555.checked:
|