What sizes should a favicon.ico contain?
16, 32 and 48 px Those three cover the browser tab, the Alt-Tab switcher and the desktop, and have been the recommended set since 1995. Add 256 only if the icon also has to hold up in a large-icon view.
Convert PNG, JPG, SVG or WebP into a real multi-size .ico — 16, 32 and 48 px in one file, full alpha kept. Choose PNG or uncompressed BMP storage and see both sizes. Opens .ico files back up too.
Drop an image here or click to browse
PNG, JPG, SVG, WebP, GIF or BMP · up to 10 MB
Both are legal inside a .ico. PNG has been read by Windows since Vista and by every current browser; uncompressed BMP is what 13 of the 14 genuine ICO files found across 20 sampled sites actually use, because ImageMagick converts to it by default.
<link rel="icon" href="/favicon.ico" sizes="16x16 32x32 48x48"> <link rel="icon" type="image/svg+xml" href="/icon.svg"> <link rel="apple-touch-icon" href="/apple-touch-icon.png">
Drop an .ico file here or click to browse
Every size inside the file is listed separately
| Offset | Bytes | Field | Value |
|---|---|---|---|
| 0 | 2 | idReserved | 0 |
| 2 | 2 | idType | 1 |
| 4 | 2 | idCount | 3 |
| 6 | 1 | bWidth[0] | 16 → 16 |
| 7 | 1 | bHeight[0] | 16 → 16 |
| 8 | 1 | bColorCount[0] | 0 |
| 9 | 1 | bReserved[0] | 0 |
| 10 | 2 | wPlanes[0] | 1 |
| 12 | 2 | wBitCount[0] | 32 |
| 14 | 4 | dwBytesInRes[0] | 248 |
| 18 | 4 | dwImageOffset[0] | 54 |
| 22 | 1 | bWidth[1] | 32 → 32 |
| 23 | 1 | bHeight[1] | 32 → 32 |
| 24 | 1 | bColorCount[1] | 0 |
| 25 | 1 | bReserved[1] | 0 |
| 26 | 2 | wPlanes[1] | 1 |
| 28 | 2 | wBitCount[1] | 32 |
| 30 | 4 | dwBytesInRes[1] | 720 |
| 34 | 4 | dwImageOffset[1] | 302 |
| 38 | 1 | bWidth[2] | 48 → 48 |
| 39 | 1 | bHeight[2] | 48 → 48 |
| 40 | 1 | bColorCount[2] | 0 |
| 41 | 1 | bReserved[2] | 0 |
| 42 | 2 | wPlanes[2] | 1 |
| 44 | 2 | wBitCount[2] | 32 |
| 46 | 4 | dwBytesInRes[2] | 1464 |
| 50 | 4 | dwImageOffset[2] | 1022 |
Written and reviewed by the developers who build the Go Tools conversion utilities. The container layout, the byte counts and the failure modes described here come from a written domain review rather than from other people's summaries of the format.
16, 32 and 48 px Those three cover the browser tab, the Alt-Tab switcher and the desktop, and have been the recommended set since 1995. Add 256 only if the icon also has to hold up in a large-icon view.
Yes — that is what it is for The format is a container: a six-byte header, one sixteen-byte directory entry per image, then the images. Each one is a separate drawing, which is why a good icon stays crisp at 16 px.
No, not if it is done properly Both ways of storing an image inside a .ico carry a full eight-bit alpha channel. Transparency is lost only when a tool leaves the alpha bytes blank or drops the one-bit mask that older software reads instead.
264 KB uncompressed, or a few KB as PNG An uncompressed 256 px layer is exactly 270,376 bytes — 40 bytes of header, 262,144 of pixels and 8,192 of mask — whatever the picture is. Stored as PNG the same layer usually costs a couple of kilobytes.
An .ico file is not an image format so much as a small archive of images. It starts with a six-byte header saying how many pictures are inside, followed by one sixteen-byte directory entry per picture giving its width, height, byte count and position in the file, and then the picture data itself. Each picture can be stored in either of two ways: as a complete PNG file embedded whole, or as an uncompressed Windows bitmap with a one-bit transparency mask bolted underneath it.
That design is why a favicon can look sharp at 16 px in a browser tab and at 48 px in a file manager — they are different drawings, hand-tuned at each size, not one image being resized. It is also why the format has a few surprises. The side length is stored in a single byte, so 256 is written as zero and 512 cannot be written at all. And the directory records a size for each entry that the image data itself also records, which means the two can disagree — and different software believes different ones.
$ file favicon.ico
favicon.ico: MS Windows icon resource - 3 icons, 16x16, 32 bits/pixel, 32x32, 32 bits/pixel
$ python3 -c "from PIL import Image; print(sorted(Image.open('favicon.ico').ico.sizes()))"
[(16, 16), (32, 32), (48, 48)] 16, 32 and 48 px by default, up to 256. Each size is drawn separately from the original at full quality rather than being scaled from the layer above it, so small sizes do not inherit a bigger size's blur.
The two legal payload formats have very different trade-offs and most converters never mention which one they write. Here it is a switch, and the resulting file size for each is displayed so the decision is made on a number rather than a guess.
The alpha channel is written in full, and the one-bit mask that older software reads instead is derived from it rather than left blank. Leaving that mask blank is what turns a transparent icon into a black square in the places that only read the mask.
The reverse tab lists every image inside a .ico with its real size, storage format, bit depth and where its transparency comes from — including palette-based bitmaps that several well-known favicons still use. A browser will only ever show you one of them.
If the directory claims a size the image data does not match, that is flagged. So is an embedded PNG that Firefox will throw away — its ICO decoder only takes 8-bit RGB or RGBA, so a palette or greyscale layer simply vanishes there while every other browser shows it. Both are common reasons an icon works in one program and is blank in another, and no other converter reports either.
Reading, resizing and packing all happen on this page. The file never reaches a server, so there is nothing to delete afterwards and no queue to wait in.
magick in.png -define icon:auto-resize=48,32,16 favicon.ico The usual answer, and the reason so many favicons are uncompressed. Every layer except 256 px is converted to a bitmap before packing, so three sizes come out around 15 KB instead of a few hundred bytes. The sizes are written largest-first.
img.save('favicon.ico', sizes=[(16,16),(32,32),(48,48)]) Embeds PNG, so the same three sizes land in roughly a tenth of the space. Pillow also reads ICO well: Image.open(f).ico.sizes() lists what is inside, which is handy for checking someone else's file.
npx png-to-ico icon.png > favicon.ico A single-purpose CLI that takes one or more PNGs and packs them as PNG payloads. Convenient in a build script; it will not resize for you, so you supply each size as its own file.
sharp(input).resize(32).png() Excellent for producing the individual PNGs but it does not write ICO containers, so it is normally paired with one of the packers above. A common source of confusion when a build pipeline is already standardised on sharp.
github.com/Kodeworks/golang-image-ico Writes a single-image ICO from an image.Image. Enough for a one-size favicon; packing several sizes into one container means writing the directory yourself, which is about thirty lines.
.rc resource script, rc.exe How application icons are normally produced. The compiler embeds the .ico into the executable's resource section; the container inside is exactly the same format as a web favicon.
.ico Exports each layer of the image as one icon size and lets you choose the bit depth per layer, including compressed PNG. One of the few graphical tools that exposes the choice rather than deciding silently.
sips -s format ico in.png --out favicon.ico macOS does have an ICO writer after all: sips --formats lists com.microsoft.ico as writable, and the command above produced a valid file here. What it will not do is pack several sizes — the output was a single 48×48 layer. iconutil, which search results usually suggest instead, makes .icns, Apple's own container, which Windows and browsers do not read.
$ xxd -l 38 favicon.ico
00000000: 0000 0100 0300 1010 0000 0100 2000 e903 ............ ... 00000010: 0000 3600 0000 2020 0000 0100 2000 6c05 ..6... .... .l. 00000020: 0000 1f04 0000 ......
0000 is the reserved field, 0100 is type 1 (icon, not cursor), 0300 says three images. Then the first 16-byte directory entry: 10 10 is 16×16, 00 colour count, 00 reserved, 0100 one plane, 2000 32 bits per pixel, e903 0000 is 1,001 bytes of payload at offset 3600 0000 = 54 — which is exactly 6 + 3 × 16, the end of the directory. Every number is little-endian except the sizes, which are single bytes.
bWidth = 0x00 bHeight = 0x00
256 × 256
The directory has one byte for each side, so 255 is the largest number it can hold and 0 is defined to mean 256. This is also why 512 px is not offered anywhere on this page: there is no byte that means 512. Several online converters offer it anyway and write a 512 px image behind a directory entry that cannot describe it.
16 + 32 + 48 px, PNG payloads 16 + 32 + 48 px, uncompressed BMP payloads
389 bytes 15,086 bytes
An uncompressed payload costs 40 + width × height × 4 bytes plus a 1-bit mask, so its size depends only on the dimensions and not at all on the picture. That is why three different sites can ship three completely different icons in files of identical length.
$ magick logo.png -define icon:auto-resize=48,32,16 favicon.ico $ file favicon.ico
favicon.ico: MS Windows icon resource - 3 icons, 48x48, 32 bits/pixel, 32x32, 32 bits/pixel
ImageMagick converts every layer except 256 px to an uncompressed bitmap before packing it, which is why its output is around 15 KB rather than a few hundred bytes. Pillow does the opposite and embeds PNG: Image.open('logo.png').save('favicon.ico', sizes=[(16,16),(32,32),(48,48)]).
$ magick favicon.ico favicon-%d.png
favicon-0.png 48×48 favicon-1.png 32×32 favicon-2.png 16×16
A browser cannot do this for you. Give a multi-size .ico to an <img> tag and you get exactly one image — the largest one — no matter what order the sizes are in. Listing what is actually inside a file means parsing the container by hand, which is what the ICO → PNG tab does.
PNG, JPG, SVG, WebP, GIF and BMP are all accepted, up to 10 MB. Nothing leaves the browser: the file is read with the File API and every pixel is drawn on a local canvas.
16, 32 and 48 px are ticked to start with. Add 64, 128 or 256 if the icon needs to survive a large-icon view or a high-DPI desktop. If your source is smaller than the largest size you ticked, the page says so rather than quietly enlarging it.
PNG is the default because it is an order of magnitude smaller and every current browser and every Windows since Vista reads it. Switch to uncompressed BMP if you want the form that most shipped favicons are actually in. The two file sizes are displayed side by side.
Save the .ico, and use the Copy link tags button for the markup. The root /favicon.ico path still works as a fallback, but an explicit link element is the path browsers are told to try first.
The directory byte for a 256 px image must be 0. Writing 255 looks like a harmless off-by-one and produces a file that some browsers silently refuse to draw.
bWidth = 0xFF bHeight = 0xFF ; "255", meant as 256
bWidth = 0x00 bHeight = 0x00 ; 0 is defined to mean 256
When a directory entry says 16×16 over a payload that is really 32×32, decoders split: some trust the directory and draw nothing at all, others trust the payload and render it fine. The file then works on one machine and is invisible on another.
entry: 16×16 payload IHDR: 32×32
entry: 32×32 payload IHDR: 32×32
Inside an uncompressed layer the height covers the colour data and the mask together. Writing the plain height produces a file that shows as blank in some decoders and as the bottom half of the image in others, with no error either way.
biHeight = 32 ; for a 32 px image
biHeight = 64 ; 2 × 32, colour data plus mask
Some tools fill the mask and leave every alpha byte at zero. One decoder reads that as a fully transparent image and the icon vanishes; another falls back to the mask and shows it correctly. Writing both, consistently, avoids the whole argument.
alpha bytes: all 0x00 mask: all 0x00
alpha bytes: real values mask: set where alpha < 128
External references inside an SVG are blocked when it is rasterised, and nothing reports it — no error fires and the canvas stays readable. The broken-image placeholder simply gets baked into the icon. Inline the artwork before converting.
<image href="https://cdn.example.com/logo.png"/>
<image href="data:image/png;base64,iVBORw0KGgo…"/>
00 00 reserved, 01 00 for an icon (02 00 marks a cursor file), then a two-byte count. Each directory entry is width, height, palette size and a reserved byte — one byte each — followed by two-byte plane and bit-depth fields and two four-byte fields giving the payload's length and offset. Everything multi-byte is little-endian.ceil(width ÷ 32) × 4 bytes per row. A 16 px layer is therefore 1,128 bytes, 48 px is 9,640, and 256 px is 270,376 — regardless of what the picture shows. That fixed cost is why three unrelated sites can ship favicons of byte-identical length, and why a 256 px layer is only offered here when the payload is PNG.image/vnd.microsoft.icon was registered with IANA in September 2003, and the reference it cites is a 1995 Microsoft article called "Icons in Win32". RFC 2361, which is widely quoted as the ICO specification, is in fact titled "WAVE and AVI Codec Registries" and says nothing about images at all.magick logo.png -define icon:auto-resize=48,32,16 favicon.ico. Conversion Tools
Convert between binary, hex, decimal, octal and any base (2-36) instantly. Free, private — all processing in your browser.
Conversion Tools
Type a signed integer and get sign-magnitude, ones' complement, two's complement and offset binary at once, at 4 to 64 bits. Or paste a bit pattern or hex byte and see all five readings side by side. Local, free, no sign-up.
Conversion Tools
Convert Linux file permissions between octal (755, 644) and rwx symbols. Get chmod commands, spot risky settings like 777 — free, right in your browser.
Conversion Tools
Convert HEX to RGB, HSL, OKLCH, OKLAB and CMYK in your browser — copy any format with one click. Free, no signup, your colors never leave the page.
Conversion Tools
Convert HEX colors to CMYK in your browser. Naive sRGB-based approximation for print previews. Free, no signup, your colors stay local.
Conversion Tools
Convert any hex color to HSL in your browser — 3-digit, 6-digit, 8-digit alpha all supported. Free, instant, no signup, your colors never leave the page.