Custom icons do not shown anymore / custom icons upload fails
Moderators: leecollings, remb0
Forum rules
Before posting here, make sure you are on the latest Beta or Stable version.
If you have problems related to the web gui, clear your browser cache + appcache first.
Use the following template when posting here:
Version: xxxx
Platform: xxxx
Plugin/Hardware: xxxx
Description:
.....
If you are having problems with scripts/blockly, always post the script (in a spoiler or code tag) or screenshots of your blockly
If you are replying, please do not quote images/code from the first post
Please mark your topic as Solved when the problem is solved.
Before posting here, make sure you are on the latest Beta or Stable version.
If you have problems related to the web gui, clear your browser cache + appcache first.
Use the following template when posting here:
Version: xxxx
Platform: xxxx
Plugin/Hardware: xxxx
Description:
.....
If you are having problems with scripts/blockly, always post the script (in a spoiler or code tag) or screenshots of your blockly
If you are replying, please do not quote images/code from the first post
Please mark your topic as Solved when the problem is solved.
- frank666
- Posts: 21
- Joined: Monday 07 December 2020 10:11
- Target OS: Linux
- Domoticz version: 2025.1
- Location: San Marino
Re: Custom icons do not shown anymore / custom icons upload fails
Same problem domoticz2025.1 (Build 16675) in container, I tried to import icons created with https://domoticz- icon.aurelien-ve.fr but it gives me error :
error in loading the icon set: icon file: tower.png is to small or issue with extraction.
error in loading the icon set: icon file: tower.png is to small or issue with extraction.
Domoticz running on Docker,Orange Pi Zero Plus
- gizmocuz
- Posts: 2536
- Joined: Thursday 11 July 2013 18:59
- Target OS: Raspberry Pi / ODroid
- Domoticz version: beta
- Location: Top of the world
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
Ahh, sorry about that, but I added an 'Inverter' icon a long time ago... I think your Icons had the same name (Inveter, Inverter48_On/Off)
It's an Inverter, does it really matter what brand it is? You got a much better one now

All custom icons are stored inside the database.
They are reloaded/stored on disk at Domoticz startup
It will check if the file exists, and if it does, it will not overwrite it
It will probably also find that the file exists when it is 0 bytes
I have changed this in beta xx, it will not try to overwrite 0 length files
When uploading a new custom image
But this is not an error, but for you an unfortunate event... You can create a new custom icon with the names SolarEdge
Quality outlives Quantity!
- gizmocuz
- Posts: 2536
- Joined: Thursday 11 July 2013 18:59
- Target OS: Raspberry Pi / ODroid
- Domoticz version: beta
- Location: Top of the world
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
That's great, but you really have to attach the zip file with the custom icon so we can have a look at it...
It is always easy to say it's a bug
Try it with this nice flour.... No issues here at all, also running Domoticz inside a docker compose container
Quality outlives Quantity!
- frank666
- Posts: 21
- Joined: Monday 07 December 2020 10:11
- Target OS: Linux
- Domoticz version: 2025.1
- Location: San Marino
Re: Custom icons do not shown anymore / custom icons upload fails
gizmo thanks for the example zip, I have now succeeded; the problem is https://domoticz- icon.aurelien-ve.fr there seems to be some problem as it creates a file in the zip with the extension 0 .
I enclose the files the first constructed manually
the second built via the site result :



I enclose the files the first constructed manually
the second built via the site result :
Domoticz running on Docker,Orange Pi Zero Plus
- RonkA
- Posts: 115
- Joined: Tuesday 14 June 2022 12:57
- Target OS: NAS (Synology & others)
- Domoticz version: 2025.1
- Location: Harlingen
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
Here is a python-script that generates the right icons from the generated ones by domoticz- icon.aurelien-ve.fr:
save code as Iconcrop.py
I copied all custom icon zipfiles from the download-folder from windows into a new folder, also placed the python script and from commandprompt do for example the reply should be:
Code: Select all
import sys
import os
import zipfile
from PIL import Image
from io import BytesIO
def crop_icon(image_data):
with Image.open(BytesIO(image_data)) as img:
if img.size == (50, 50):
cropped = img.crop((1, 1, 49, 49)) # Remove 1 pixel from each edge
output = BytesIO()
cropped.save(output, format="PNG")
return output.getvalue(), cropped
return image_data, img.copy()
def resize_to_16x16(image: Image.Image):
resized = image.resize((16, 16), Image.LANCZOS)
output = BytesIO()
resized.save(output, format="PNG")
return output.getvalue()
def process_zip(zip_path):
zip_dir = os.path.dirname(zip_path)
zip_name = os.path.basename(zip_path)
new_zip_path = os.path.join(zip_dir, f"processed_{zip_name}")
icons_txt = None
cropped_icons = {}
resized_icons = {}
with zipfile.ZipFile(zip_path, 'r') as zin:
for item in zin.infolist():
data = zin.read(item.filename)
# Keep only icons.txt
if item.filename.lower() == "icons.txt":
icons_txt = (item.filename, data)
# Process only 48_Off and 48_On icons
elif item.filename.endswith("48_Off.png") or item.filename.endswith("48_On.png"):
cropped_data, cropped_img = crop_icon(data)
cropped_icons[item.filename] = cropped_data
# Create 16x16 icon from *_48_On.png only
if item.filename.endswith("48_On.png"):
base_name = item.filename.replace("48_On", "")
resized_data = resize_to_16x16(cropped_img)
resized_icons[base_name] = resized_data
# Create the new ZIP file
with zipfile.ZipFile(new_zip_path, 'w') as zout:
if icons_txt:
zout.writestr(icons_txt[0], icons_txt[1])
for filename, data in cropped_icons.items():
zout.writestr(filename, data)
for filename, data in resized_icons.items():
zout.writestr(filename, data)
print(f"Processed ZIP file saved as: {new_zip_path}")
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: python Iconcrop.py <file.zip>")
sys.exit(1)
zip_file_path = sys.argv[1]
if not os.path.isfile(zip_file_path) or not zip_file_path.endswith(".zip"):
print("Please provide a valid .zip file.")
sys.exit(1)
process_zip(zip_file_path)
I copied all custom icon zipfiles from the download-folder from windows into a new folder, also placed the python script and from commandprompt do for example
Code: Select all
C:\Users\Ron\domoticz icons>python Iconcrop.py domoticz_custom_icon_Kliko.zip
Code: Select all
Nieuw ZIP-file created as: processed_domoticz_custom_icon_Kliko.zip
SolarEdge ModbusTCP - Kaku - Synology NAS - Watermeter - ESPEasy - DS18b20
Work in progress = Life in general..
Work in progress = Life in general..
- frank666
- Posts: 21
- Joined: Monday 07 December 2020 10:11
- Target OS: Linux
- Domoticz version: 2025.1
- Location: San Marino
Re: Custom icons do not shown anymore / custom icons upload fails
tnx Ronka
I made this , it is to be saved in .html and used on a server works well .
Code: Select all
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Domoticz Icon Generator</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background: #f3f4f6; /* Soft light gray (grigio tenue) */
}
.container {
transition: transform 0.3s ease-in-out;
}
.container:hover {
transform: scale(1.02);
}
.glow {
box-shadow: 0 0 10px rgba(34, 197, 94, 0.5);
}
</style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen">
<div class="container bg-white p-10 rounded-2xl shadow-md w-full max-w-lg mx-4">
<h1 class="text-3xl font-extrabold text-center text-indigo-700 mb-6">Domoticz Icon Generator</h1>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-900 mb-2">Upload Icon (Any PNG)</label>
<input type="file" id="iconInput" accept="image/png" class="block w-full text-sm text-gray-900 file:mr-4 file:py-3 file:px-5 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 transition duration-200">
</div>
<button id="generateZip" class="glow w-full py-3 px-4 bg-green-500 text-white text-lg font-semibold rounded-lg hover:bg-green-600 focus:ring-4 focus:ring-green-300 transition duration-200">Generate ZIP</button>
<p id="status" class="mt-4 text-sm text-gray-900 text-center"></p>
</div>
<script>
const iconInput = document.getElementById('iconInput');
const generateZip = document.getElementById('generateZip');
const status = document.getElementById('status');
// Image processing functions
function resizeTo48x48(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, 48, 48);
canvas.toBlob(callback, 'image/png');
}
function cropIcon(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 1, 1, 48, 48, 0, 0, 48, 48);
canvas.toBlob(callback, 'image/png');
}
function resizeTo16x16(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, 16, 16);
canvas.toBlob(callback, 'image/png');
}
function createOffIcon(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
const ctx = canvas.getContext('2d');
ctx.filter = 'grayscale(100%) opacity(50%)';
ctx.drawImage(img, 0, 0, 48, 48);
canvas.toBlob(callback, 'image/png');
}
// ZIP generation
generateZip.addEventListener('click', async () => {
if (!iconInput.files[0]) {
status.textContent = 'Please upload a PNG file.';
return;
}
status.textContent = 'Processing...';
const zip = new JSZip();
// Determine icon name
let iconName = iconInput.files[0].name.replace(/\.[^/.]+$/, '');
const iconNameCapitalized = iconName.charAt(0).toUpperCase() + iconName.slice(1);
let img = new Image();
let source = URL.createObjectURL(iconInput.files[0]);
img.onload = async () => {
// Resize input image to 48x48
const resizedBlob = await new Promise(resolve => resizeTo48x48(img, resolve));
const resizedImg = new Image();
resizedImg.src = URL.createObjectURL(resizedBlob);
resizedImg.onload = async () => {
// Crop the "On" icon
const croppedOnBlob = await new Promise(resolve => cropIcon(resizedImg, resolve));
zip.file(`${iconName}48_On.png`, croppedOnBlob);
// Create and crop the "Off" icon
const offImg = await new Promise(resolve => {
createOffIcon(resizedImg, blob => {
const offImg = new Image();
offImg.onload = () => resolve(offImg);
offImg.src = URL.createObjectURL(blob);
});
});
const croppedOffBlob = await new Promise(resolve => cropIcon(offImg, resolve));
zip.file(`${iconName}48_Off.png`, croppedOffBlob);
// Resize cropped "On" icon to 16x16
const croppedOnImg = new Image();
croppedOnImg.src = URL.createObjectURL(croppedOnBlob);
croppedOnImg.onload = async () => {
const resizedBlob = await new Promise(resolve => resizeTo16x16(croppedOnImg, resolve));
zip.file(`${iconName}.png`, resizedBlob);
// Add icons.txt with name;Name;Name format
zip.file('icons.txt', `${iconName};${iconNameCapitalized};${iconNameCapitalized}`);
// Generate and download ZIP
const content = await zip.generateAsync({ type: 'blob' });
const link = document.createElement('a');
link.href = URL.createObjectURL(content);
link.download = `${iconName}_icons.zip`;
link.click();
status.textContent = 'ZIP file downloaded!';
};
};
};
img.onerror = () => status.textContent = 'Error loading image.';
img.src = source;
});
</script>
</body>
</html>
Domoticz running on Docker,Orange Pi Zero Plus
- gizmocuz
- Posts: 2536
- Joined: Thursday 11 July 2013 18:59
- Target OS: Raspberry Pi / ODroid
- Domoticz version: beta
- Location: Top of the world
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
Thanks for the feedback. Maybe you could let the author of this tool know that it sometimes generates icons with 0 byte length
Quality outlives Quantity!
-
- Posts: 612
- Joined: Sunday 01 November 2015 22:45
- Target OS: Raspberry Pi / ODroid
- Domoticz version: 2023.2
- Location: Twente
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
Which reminds me to say thank you to the Domoticz developers for the new icons in the latest release.
Bugs bug me.
- RonkA
- Posts: 115
- Joined: Tuesday 14 June 2022 12:57
- Target OS: NAS (Synology & others)
- Domoticz version: 2025.1
- Location: Harlingen
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
I couldn't reach him, i don't have twitter/X, his GitHub is 404, and i don't have LinkedIn..Maybe you could let the author of this tool know that it sometimes generates icons with 0 byte length
Also Nice, saves a lot of time making new icons!!I made this , it is to be saved in .html and used on a server works well
SolarEdge ModbusTCP - Kaku - Synology NAS - Watermeter - ESPEasy - DS18b20
Work in progress = Life in general..
Work in progress = Life in general..
-
- Posts: 110
- Joined: Thursday 03 November 2016 10:12
- Target OS: Raspberry Pi / ODroid
- Domoticz version:
- Contact:
Re: Custom icons do not shown anymore / custom icons upload fails
I like this tool? Just some suggestions: I would prefer the possibility to upload 2 different files; one for ON and one for OFF. Because sometime the OFF icon is not just a "gray" version of the ON one...frank666 wrote: ↑Wednesday 11 June 2025 20:54 tnx Ronkaimage_2025-06-12_165737833.pngCode: Select all
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Domoticz Icon Generator</title> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script> <script src="https://cdn.tailwindcss.com"></script> <style> body { background: #f3f4f6; /* Soft light gray (grigio tenue) */ } .container { transition: transform 0.3s ease-in-out; } .container:hover { transform: scale(1.02); } .glow { box-shadow: 0 0 10px rgba(34, 197, 94, 0.5); } </style> </head> <body class="flex flex-col items-center justify-center min-h-screen"> <div class="container bg-white p-10 rounded-2xl shadow-md w-full max-w-lg mx-4"> <h1 class="text-3xl font-extrabold text-center text-indigo-700 mb-6">Domoticz Icon Generator</h1> <div class="mb-6"> <label class="block text-sm font-medium text-gray-900 mb-2">Upload Icon (Any PNG)</label> <input type="file" id="iconInput" accept="image/png" class="block w-full text-sm text-gray-900 file:mr-4 file:py-3 file:px-5 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 transition duration-200"> </div> <button id="generateZip" class="glow w-full py-3 px-4 bg-green-500 text-white text-lg font-semibold rounded-lg hover:bg-green-600 focus:ring-4 focus:ring-green-300 transition duration-200">Generate ZIP</button> <p id="status" class="mt-4 text-sm text-gray-900 text-center"></p> </div> <script> const iconInput = document.getElementById('iconInput'); const generateZip = document.getElementById('generateZip'); const status = document.getElementById('status'); // Image processing functions function resizeTo48x48(img, callback) { const canvas = document.createElement('canvas'); canvas.width = 48; canvas.height = 48; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, 48, 48); canvas.toBlob(callback, 'image/png'); } function cropIcon(img, callback) { const canvas = document.createElement('canvas'); canvas.width = 48; canvas.height = 48; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 1, 1, 48, 48, 0, 0, 48, 48); canvas.toBlob(callback, 'image/png'); } function resizeTo16x16(img, callback) { const canvas = document.createElement('canvas'); canvas.width = 16; canvas.height = 16; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, 16, 16); canvas.toBlob(callback, 'image/png'); } function createOffIcon(img, callback) { const canvas = document.createElement('canvas'); canvas.width = 48; canvas.height = 48; const ctx = canvas.getContext('2d'); ctx.filter = 'grayscale(100%) opacity(50%)'; ctx.drawImage(img, 0, 0, 48, 48); canvas.toBlob(callback, 'image/png'); } // ZIP generation generateZip.addEventListener('click', async () => { if (!iconInput.files[0]) { status.textContent = 'Please upload a PNG file.'; return; } status.textContent = 'Processing...'; const zip = new JSZip(); // Determine icon name let iconName = iconInput.files[0].name.replace(/\.[^/.]+$/, ''); const iconNameCapitalized = iconName.charAt(0).toUpperCase() + iconName.slice(1); let img = new Image(); let source = URL.createObjectURL(iconInput.files[0]); img.onload = async () => { // Resize input image to 48x48 const resizedBlob = await new Promise(resolve => resizeTo48x48(img, resolve)); const resizedImg = new Image(); resizedImg.src = URL.createObjectURL(resizedBlob); resizedImg.onload = async () => { // Crop the "On" icon const croppedOnBlob = await new Promise(resolve => cropIcon(resizedImg, resolve)); zip.file(`${iconName}48_On.png`, croppedOnBlob); // Create and crop the "Off" icon const offImg = await new Promise(resolve => { createOffIcon(resizedImg, blob => { const offImg = new Image(); offImg.onload = () => resolve(offImg); offImg.src = URL.createObjectURL(blob); }); }); const croppedOffBlob = await new Promise(resolve => cropIcon(offImg, resolve)); zip.file(`${iconName}48_Off.png`, croppedOffBlob); // Resize cropped "On" icon to 16x16 const croppedOnImg = new Image(); croppedOnImg.src = URL.createObjectURL(croppedOnBlob); croppedOnImg.onload = async () => { const resizedBlob = await new Promise(resolve => resizeTo16x16(croppedOnImg, resolve)); zip.file(`${iconName}.png`, resizedBlob); // Add icons.txt with name;Name;Name format zip.file('icons.txt', `${iconName};${iconNameCapitalized};${iconNameCapitalized}`); // Generate and download ZIP const content = await zip.generateAsync({ type: 'blob' }); const link = document.createElement('a'); link.href = URL.createObjectURL(content); link.download = `${iconName}_icons.zip`; link.click(); status.textContent = 'ZIP file downloaded!'; }; }; }; img.onerror = () => status.textContent = 'Error loading image.'; img.src = source; }); </script> </body> </html>
I made this , it is to be saved in .html and used on a server works well .
And would be good to have it somewhere in the domoticz git...
Thanks!
- frank666
- Posts: 21
- Joined: Monday 07 December 2020 10:11
- Target OS: Linux
- Domoticz version: 2025.1
- Location: San Marino
Re: Custom icons do not shown anymore / custom icons upload fails
@Filip I have modified as suggested here :
Code: Select all
<script type="text/javascript">
var gk_isXlsx = false;
var gk_xlsxFileLookup = {};
var gk_fileData = {};
function filledCell(cell) {
return cell !== '' && cell != null;
}
function loadFileData(filename) {
if (gk_isXlsx && gk_xlsxFileLookup[filename]) {
try {
var workbook = XLSX.read(gk_fileData[filename], { type: 'base64' });
var firstSheetName = workbook.SheetNames[0];
var worksheet = workbook.Sheets[firstSheetName];
// Convert sheet to JSON to filter blank rows
var jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, blankrows: false, defval: '' });
// Filter out blank rows (rows where all cells are empty, null, or undefined)
var filteredData = jsonData.filter(row => row.some(filledCell));
// Heuristic to find the header row by ignoring rows with fewer filled cells than the next row
var headerRowIndex = filteredData.findIndex((row, index) =>
row.filter(filledCell).length >= filteredData[index + 1]?.filter(filledCell).length
);
// Fallback
if (headerRowIndex === -1 || headerRowIndex > 25) {
headerRowIndex = 0;
}
// Convert filtered JSON back to CSV
var csv = XLSX.utils.aoa_to_sheet(filteredData.slice(headerRowIndex)); // Create a new sheet from filtered array of arrays
csv = XLSX.utils.sheet_to_csv(csv, { header: 1 });
return csv;
} catch (e) {
console.error(e);
return "";
}
}
return gk_fileData[filename] || "";
}
</script><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Domoticz Icon Generator</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background: #1f2937; /* Dark gray background */
}
.container {
transition: transform 0.3s ease-in-out;
}
.container:hover {
transform: scale(1.02);
}
.glow {
box-shadow: 0 0 10px rgba(34, 197, 94, 0.5);
}
</style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen">
<div class="container bg-gray-300 p-10 rounded-2xl shadow-md w-full max-w-lg mx-4">
<h1 class="text-3xl font-extrabold text-center text-indigo-700 mb-6">Domoticz Icon Generator</h1>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-900 mb-2">Upload On Icon (PNG)</label>
<input type="file" id="onIconInput" accept="image/png" class="block w-full text-sm text-gray-900 file:mr-4 file:py-3 file:px-5 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 transition duration-200">
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-900 mb-2">Upload Off Icon (PNG)</label>
<input type="file" id="offIconInput" accept="image/png" class="block w-full text-sm text-gray-900 file:mr-4 file:py-3 file:px-5 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 transition duration-200">
</div>
<button id="generateZip" class="glow w-full py-3 px-4 bg-green-500 text-white text-lg font-semibold rounded-lg hover:bg-green-600 focus:ring-4 focus:ring-green-300 transition duration-200">Generate ZIP</button>
<p id="status" class="mt-4 text-sm text-gray-900 text-center"></p>
</div>
<script>
const onIconInput = document.getElementById('onIconInput');
const offIconInput = document.getElementById('offIconInput');
const generateZip = document.getElementById('generateZip');
const status = document.getElementById('status');
// Image processing functions
function resizeTo48x48(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, 48, 48);
canvas.toBlob(callback, 'image/png');
}
function cropIcon(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 48;
canvas.height = 48;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 1, 1, 48, 48, 0, 0, 48, 48);
canvas.toBlob(callback, 'image/png');
}
function resizeTo16x16(img, callback) {
const canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, 16, 16);
canvas.toBlob(callback, 'image/png');
}
// ZIP generation
generateZip.addEventListener('click', async () => {
if (!onIconInput.files[0] || !offIconInput.files[0]) {
status.textContent = 'Please upload both On and Off PNG files.';
return;
}
status.textContent = 'Processing...';
const zip = new JSZip();
// Determine icon name from On icon
let iconName = onIconInput.files[0].name.replace(/\.[^/.]+$/, '');
const iconNameCapitalized = iconName.charAt(0).toUpperCase() + iconName.slice(1);
// Process On icon
let onImg = new Image();
onImg.src = URL.createObjectURL(onIconInput.files[0]);
onImg.onload = async () => {
// Resize On image to 48x48
const resizedOnBlob = await new Promise(resolve => resizeTo48x48(onImg, resolve));
const resizedOnImg = new Image();
resizedOnImg.src = URL.createObjectURL(resizedOnBlob);
resizedOnImg.onload = async () => {
// Crop the On icon
const croppedOnBlob = await new Promise(resolve => cropIcon(resizedOnImg, resolve));
zip.file(`${iconName}48_On.png`, croppedOnBlob);
// Resize cropped On icon to 16x16
const croppedOnImg = new Image();
croppedOnImg.src = URL.createObjectURL(croppedOnBlob);
croppedOnImg.onload = async () => {
const resized16Blob = await new Promise(resolve => resizeTo16x16(croppedOnImg, resolve));
zip.file(`${iconName}.png`, resized16Blob);
// Process Off icon
let offImg = new Image();
offImg.src = URL.createObjectURL(offIconInput.files[0]);
offImg.onload = async () => {
// Resize Off image to 48x48
const resizedOffBlob = await new Promise(resolve => resizeTo48x48(offImg, resolve));
const resizedOffImg = new Image();
resizedOffImg.src = URL.createObjectURL(resizedOffBlob);
resizedOffImg.onload = async () => {
// Crop the Off icon
const croppedOffBlob = await new Promise(resolve => cropIcon(resizedOffImg, resolve));
zip.file(`${iconName}48_Off.png`, croppedOffBlob);
// Add icons.txt with name;Name;Name format
zip.file('icons.txt', `${iconName};${iconNameCapitalized};${iconNameCapitalized}`);
// Generate and download ZIP
const content = await zip.generateAsync({ type: 'blob' });
const link = document.createElement('a');
link.href = URL.createObjectURL(content);
link.download = `${iconName}_icons.zip`;
link.click();
status.textContent = 'ZIP file downloaded!';
};
};
offImg.onerror = () => status.textContent = 'Error loading Off image.';
};
};
};
onImg.onerror = () => status.textContent = 'Error loading On image.';
});
</script>
</body>
</html>
Domoticz running on Docker,Orange Pi Zero Plus
Who is online
Users browsing this forum: No registered users and 1 guest