200 lines
8.5 KiB
HTML
200 lines
8.5 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>led bikewheel image generator</title>
|
|
</head>
|
|
|
|
<body>
|
|
<h1>Generate image for led_bikewheel</h1>
|
|
<p>Tool to convert an image to a byte array in C with 8 bit color depth + palette. This works directly in browser,
|
|
so selected image file is NOT uploaded!</p>
|
|
<input type="file" id="file" accept="image/*" /><br>
|
|
<label for="num_segments">Num Segments</label>
|
|
<input type="number" id="num_segments" min="1" value="360" /><br>
|
|
<label for="num_leds">Num LEDs</label>
|
|
<input type="number" id="num_leds" min="1" value="28" /><br>
|
|
<label for="led_offset">LED Offsett</label>
|
|
<input type="number" id="led_offset" min="0" value="15" /><br>
|
|
|
|
<br>
|
|
<canvas id="canvas_in" width="0" height="0"></canvas><br>
|
|
|
|
<hr>
|
|
<h2>Preview</h2>
|
|
<canvas id="canvas_out" width="0" height="0"></canvas>
|
|
<br>
|
|
<canvas id="canvas_out2" width="0" height="0"></canvas>
|
|
<h2>Output</h2>
|
|
<pre id="output"></pre>
|
|
|
|
<script>
|
|
let file_elem = document.getElementById("file");
|
|
let num_segments_elem = document.getElementById("num_segments");
|
|
let num_leds_elem = document.getElementById("num_leds");
|
|
let led_offset_elem = document.getElementById("led_offset");
|
|
let canvas_elem = document.getElementById("canvas_in");
|
|
let output_elem = document.getElementById("output");
|
|
let canvas_out_elem = document.getElementById("canvas_out");
|
|
let canvas_out2_elem = document.getElementById("canvas_out2");
|
|
|
|
// helper for printing number as hex value
|
|
let intToHex = function (color, int16) {
|
|
let text = color.toString(16);
|
|
|
|
if (text.length == 1) {
|
|
text = (int16 ? "000" : "0") + text;
|
|
} if (text.length == 2 && int16) {
|
|
text = "00" + text;
|
|
} else if (text.length == 3) {
|
|
text = "0" + text;
|
|
}
|
|
|
|
return "0x" + text.toUpperCase();
|
|
}
|
|
|
|
let read_image = function () {
|
|
let file_reader = new FileReader();
|
|
file_reader.onload = function () {
|
|
let image = new Image();
|
|
image.onload = function () {
|
|
canvas_elem.width = image.width;
|
|
canvas_elem.height = image.height;
|
|
let canvas_context = canvas_elem.getContext("2d");
|
|
canvas_context.drawImage(image, 0, 0);
|
|
|
|
const num_segments = parseInt(num_segments_elem.value);
|
|
const num_leds = parseInt(num_leds_elem.value);
|
|
const led_offset = Math.floor(led_offset_elem.value);
|
|
|
|
const offset_x = image.width / 2;
|
|
const offset_y = image.height / 2;
|
|
|
|
let data = new Array();
|
|
|
|
let canvas_out_context = canvas_out_elem.getContext("2d");
|
|
canvas_out_elem.width = image.width;
|
|
canvas_out_elem.height = image.height;
|
|
let out_data = canvas_out_context.createImageData(canvas_out_elem.width, canvas_out_elem.height);
|
|
|
|
|
|
let canvas_out2_context = canvas_out2_elem.getContext("2d");
|
|
canvas_out2_elem.width = num_segments * 2;
|
|
canvas_out2_elem.height = num_leds;
|
|
let out_data2 = canvas_out_context.createImageData(num_segments * 2, num_leds);
|
|
|
|
let color_palette = new Array();
|
|
|
|
for (let led = 0; led < num_leds; led++) {
|
|
for (let seg = 0; seg < num_segments; seg++) {
|
|
let x = Math.floor(offset_x + (led_offset + led) * Math.cos((seg * (1 / num_segments) * 360) * (Math.PI / 180)));
|
|
let y = Math.floor(offset_y + (led_offset + led) * Math.sin((seg * (1 / num_segments) * 360) * (Math.PI / 180)));
|
|
if (!data[seg]) {
|
|
data[seg] = new Array();
|
|
}
|
|
let led_index = num_leds - led - 1;
|
|
data[seg][led_index] = canvas_context.getImageData(x, y, 1, 1).data;
|
|
for (let i = 0; i < 3; i++) {
|
|
data[seg][led_index][i] = data[seg][led_index][i] - (data[seg][led_index][i] % 32);
|
|
}
|
|
let index = 4 * (x + y * canvas_out_elem.width);
|
|
out_data.data[index] = data[seg][led_index][0];
|
|
out_data.data[index + 1] = data[seg][led_index][1];
|
|
out_data.data[index + 2] = data[seg][led_index][2];
|
|
out_data.data[index + 3] = data[seg][led_index][3];
|
|
|
|
index = 4 * ((seg * 2) + (num_leds - led_index) * num_segments * 2);
|
|
out_data2.data[index] = data[seg][led_index][0];
|
|
out_data2.data[index + 1] = data[seg][led_index][1];
|
|
out_data2.data[index + 2] = data[seg][led_index][2];
|
|
out_data2.data[index + 3] = data[seg][led_index][3];
|
|
|
|
let found = -1;
|
|
for (color = 0; color < color_palette.length; color++) {
|
|
if (color_palette[color][0] == data[seg][led_index][0] && color_palette[color][1] == data[seg][led_index][1] && color_palette[color][2] == data[seg][led_index][2]) {
|
|
found = color;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found < 0) {
|
|
color_palette[color_palette.length] = data[seg][led_index];
|
|
found = 0;
|
|
}
|
|
|
|
data[seg][led_index] = found;
|
|
}
|
|
}
|
|
canvas_out_context.putImageData(out_data, 0, 0);
|
|
canvas_out2_context.putImageData(out_data2, 0, 0);
|
|
|
|
let text = "const PROGMEM uint8_t " + (file_elem.files[0].name).replace(" ", "_").replace(".", "_") + "_palette";
|
|
|
|
text += "[][" + 3 + "]";
|
|
|
|
// text += "[" + num_leds + "]";
|
|
|
|
text += " = {";
|
|
|
|
text += "\n";
|
|
|
|
for (let color = 0; color < color_palette.length; color++) {
|
|
text += "\t{" + intToHex(color_palette[color][0]) + "," + intToHex(color_palette[color][1]) + "," + intToHex(color_palette[color][2]) + "}";
|
|
if (color < color_palette.length - 1) {
|
|
text += ", // " + intToHex(color) + "\n";
|
|
} else {
|
|
text += " // " + intToHex(color) + "\n";
|
|
}
|
|
}
|
|
|
|
text += "};\n\n";
|
|
|
|
text += "const PROGMEM uint8_t " + (file_elem.files[0].name).replace(" ", "_").replace(".", "_");
|
|
|
|
text += "[]";
|
|
|
|
text += " = {";
|
|
|
|
text += "\n";
|
|
|
|
for (let seg = 0; seg < num_segments; seg++) {
|
|
for (let led = 0; led < num_leds; led++) {
|
|
if (led == 0) {
|
|
text += "\t";
|
|
}
|
|
if (led > 0) {
|
|
text += ", ";
|
|
}
|
|
text += intToHex(data[seg][led].toString(16));
|
|
}
|
|
if (seg < num_segments - 1) {
|
|
text += ", // " + intToHex(seg, true) + "\n";
|
|
} else {
|
|
text += " // " + intToHex(seg, true) + "\n";
|
|
}
|
|
}
|
|
text += "};";
|
|
|
|
output_elem.textContent = text;
|
|
|
|
output_elem.textContent = text;
|
|
|
|
};
|
|
image.src = file_reader.result;
|
|
|
|
};
|
|
|
|
if (file_elem.files && file_elem.files[0]) {
|
|
file_reader.readAsDataURL(file_elem.files[0]);
|
|
}
|
|
}
|
|
|
|
file_elem.addEventListener('input', read_image);
|
|
num_segments_elem.addEventListener('change', read_image);
|
|
num_leds_elem.addEventListener('change', read_image);
|
|
led_offset_elem.addEventListener('change', read_image);
|
|
</script>
|
|
</body>
|
|
|
|
</html> |