I want to create multifile favicon.ico according to great favicon cheat sheet.
I created 3 .png files, optimized them with OptiPNG and received files with 1, 2 and 3kb size.
Now I'm trying to create favicon.ico from them using Imagemagick but final file is around 15kb big (sum of component files is around 6kB).
What causes this effect and how i can avoid it ?
A workaround is to rely on the HTTP gzip compression.
For example, I packed 3 PNG pictures (3580 bytes in total) in a 15086 bytes favicon.ico
file. When I download it with gzip compression enabled on the server side, I get 2551 bytes of data. This is even more efficient than downloading the PNG pictures one by one, as gzip is usually not enabled for this kind of file.
However, gzip is often not configured for .ico
files (this is more for text files). On Apache, this can be fixed by adding:
<IfModule mod_deflate.c>
(... other rules here...)
AddOutputFilterByType DEFLATE image/x-icon
</IfModule>
in an Apache configuration file, such as /etc/apache2/mods-available/deflate.conf
.
This is not the answer you expected and I hope someone will come with a magic command line to produce the lightweight favicon.ico
we deserve!
Another workaround is using other another tool to create favicon file.
I found (on stack ofc ;)) png2ico tool. It gave me 8kb file (sum of components is around 6) which is size I can live with.
Please read comments to this answer - philippe_b observed that sometimes png2ico gives him poor results.
You can combine PNGs into an ICO through a simple Python script:
png2ico.py 1.png 2.png -o out.ico
import argparse
import struct
import io
import PIL.Image
def main():
ap = argparse.ArgumentParser()
ap.add_argument('inputs', nargs='+')
ap.add_argument('-o', '--output', required=True)
args = ap.parse_args()
pngs = []
for path in args.inputs:
with open(path, 'rb') as fp:
pngs.append(fp.read())
headers = []
headers.append(struct.pack('<HHH', 0, 1, len(pngs)))
offset = 6 + 16 * len(pngs)
for data in pngs:
with PIL.Image.open(io.BytesIO(data)) as im:
w, h = im.size
headers.append(struct.pack('<BBBBHHII', w, h, 0, 0, 1, 0, len(data), offset))
offset += len(data)
with open(args.output, 'wb') as fp:
fp.truncate()
fp.write(b''.join(headers + pngs))
main()
Only the 256x256 32bit icon is PNG compressed, others are stored as classic icons in .ICO file. So, there's a logical increase in filesize since it will decompress the other smaller size icons.
© 2022 - 2024 — McMap. All rights reserved.