MacOSX and Windows use icon container files to show the best resolution. Windows uses ICO and holds a various sized images (see: Which icon sizes should my Windows application's icon include?) and Mac does same.
To me it looks like Linux icons (like Ubuntu) are using PNG. Don't they have a container file? They have to I'm sure of it I'm thinkg xpm
but I'm not sure, what is it and what are the sizes that should go into this container file.
Any documentation on this file type, I'm going to try to use javascript and canvas to take a drawing of an icon. Resize it to make multiple drawings for to the dimensions needed for this container file. Then save it to file. Like I was able to do this for Windows
.ico
tells us how to encode to ico: http://msdn.microsoft.com/en-us/library/ms997538.aspx and I can easily replicate this in javascript like so:// Our own little ico encoder // http://msdn.microsoft.com/en-us/library/ms997538.aspx // Note: We would have been able to skip ICONDIR/ICONDIRENTRY, // if we were to use CreateIconFromResourceEx only instead of also // writing the icon to a file. let data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; let XOR = data.length; let AND = canvas.width * canvas.height / 8; let size = 22 /* ICONDIR + ICONDIRENTRY */ + 40 /* BITMAPHEADER */ + XOR + AND; let buffer = new ArrayBuffer(size); // ICONDIR let view = new DataView(buffer); view.setUint16(2, 1, true); // type 1 view.setUint16(4, 1, true); // count; // ICONDIRENTRY view = new DataView(buffer, 6); view.setUint8(0, canvas.width % 256); view.setUint8(1, canvas.height % 256); view.setUint16(4, 1, true); // Planes view.setUint16(6, 32, true); // BPP view.setUint32(8, 40 + XOR + AND, true); // data size view.setUint32(12, 22, true); // data start // BITMAPHEADER view = new DataView(buffer, 22); view.setUint32(0, 40, true); // BITMAPHEADER size view.setInt32(4, canvas.width, true); view.setInt32(8, canvas.height * 2, true); view.setUint16(12, 1, true); // Planes view.setUint16(14, 32, true); // BPP view.setUint32(20, XOR + AND, true); // size of data // Reorder RGBA -> BGRA for (let i = 0; i < XOR; i += 4) { let temp = data[i]; data[i] = data[i + 2]; data[i + 2] = temp; } let ico = new Uint8Array(buffer, 22 + 40); let stride = canvas.width * 4; // Write bottom to top for (let i = 0; i < canvas.height; ++i) { let su = data.subarray(XOR - i * stride, XOR - i * stride + stride); ico.set(su, i * stride); }