utilime

Small tools that finish the job.

Convert PNG to ICO

Write an icon file carrying the entry sizes a shell, a tab strip and a shortcut each ask for separately.

Drop a file hereor click to choose · it stays on your device

How it works

One fork before anything else, because most people who type this query want the other page. If the icon is for a website, the favicon generator is the tool: it writes the same .ico and adds the apple-touch-icon iOS asks for, the 192 and 512 pixel PNGs a web manifest asks for, and the link tags to paste, none of which this page produces. Stay here when the icon is for Windows — a shortcut, a folder, an application, a file association — because that job needs a 256 pixel entry and the favicon set does not write one.

Windows keeps four shell image lists, and the SHGetImageList documentation names their sizes: SHIL_SMALL at 16 pixels, SHIL_LARGE at 32, SHIL_EXTRALARGE at 48, SHIL_JUMBO at 256. Explorer's Details and List views read the first of those, a desktop shortcut reads the third, the Extra large icons view reads the last. Microsoft's WM_SETICON page splits two further roles by hand: ICON_SMALL is drawn in the window title bar and on the taskbar button, ICON_BIG is the picture the Alt-Tab switcher shows. A single file answers all of those requests, and it answers each one from a different entry.

Display scaling moves every one of them. At 150 per cent the shell wants 24 where it wanted 16, and 72 where it wanted 48. A browser tab strip asks for 16 CSS pixels multiplied by the device pixel ratio, so 16 on an ordinary monitor and 32 on a retina laptop panel. Drag a window between two screens with different scale factors and the size requested changes mid-session. No single number covers a week of one machine's requests.

What a consumer does when the size is missing

It does not fail, and it does not report anything. It takes the nearest entry the file does carry, resamples that itself at draw time, and uses whatever general-purpose filter its graphics stack provides. That filter has no idea which strokes in the artwork carried the meaning; it is the same code path that scales a holiday photograph in a picture viewer. Handing it one large entry to answer a small request puts the artwork through two reductions rather than one, and the second happens on a frame deadline with no quality budget.

Measured here on Tux.png from Wikimedia Commons, 265x314 and 11,913 bytes, padded to a 314 pixel square master. A tab that wants 16 and finds a 16 pixel entry does no resampling at all. The same tab reading a file that carries only 256 must reduce 16:1, and a two-tap bilinear sample, which is what an unprefiltered draw does, reads 1,024 of that entry's 65,536 pixels: 1.6 per cent of them. Against an exact area average of the master, that result sits 29.96 RMS luma levels away. The single Lanczos3 pass written here sits 16.00 away.

The spread matters more than any one of those figures. Where the consumer does own a prefilter and the ratio is kind, the second reduction is nearly free: 48 to 16 is an exact 3:1, and a 3x3 box average of the 48 pixel entry scores 6.26 against the same reference, ahead of the direct pass, because an area average is precisely what a box computes. So the quality of a missing size belongs to whichever filter the consumer happens to own, and it ranged from 6 to 30 in that test. Writing the 16 pixel entry and removing the question cost 821 bytes.

The filter used here

Every entry is resampled once, from the square master, by the Lanczos3 kernel in @jsquash/resize, the Squoosh resizer compiled to wasm. Its defaultOptions set method to lanczos3, premultiply to true and linearRGB to true. A three-lobe windowed sinc holds edge contrast that a box or triangle average flattens, because its negative lobes overshoot slightly at a transition, and that overshoot is what still reads as a deliberate stroke once a mark is 16 pixels wide.

Premultiplying alpha matters more for an icon than for a photograph. Blending colour and alpha as independent channels drags the stored colour of fully transparent pixels into the average along every edge, which appears as a dark or pale fringe against a tab strip. Working in linear light rather than on gamma-encoded values keeps a reduced gradient at the brightness the original had, instead of the darkening that averaging sRGB numbers produces.

Choosing the set, and the 256 entry

16, 32, 48 answers a tab strip at both common scale factors, the taskbar button, a desktop shortcut. On the Tux source those three cost 6,736 bytes in total: 821 for the 16, 2,117 for the 32, 3,744 for the 48. Adding 256 answers the Extra large icons view and the big thumbnail in a file dialog, and it swamps everything else. The four-entry file came to 51,544 bytes, of which the 256 entry alone is 44,792, or 86.9 per cent of the download.

That makes the four-size set a deliberate choice rather than a default. A favicon served on every page view is a poor place to spend 44 KB on a size no browser tab will request; an application icon a user meets at full size in Explorer is exactly where those bytes belong. The 256 entry carries one quirk worth knowing once: the directory records each side in a single byte, so 256 is stored as zero, and every reader since Windows Vista reads that zero back as 256.

Questions

Where does the image go while it is being converted?

Nowhere outside this tab. Decoding, resampling and PNG encoding all run inside a Web Worker belonging to this page, using wasm codecs fetched from this origin when the page opened. Open the Network tab before you choose a file and leave it open: every request listed is same-origin, and every one is a GET for a script or a codec binary. Nothing at all is sent after the file is selected, and the finished icon reaches you as an in-memory blob rather than a download link.

Which entry does a browser tab strip actually pick?

The one nearest 16 CSS pixels times the device pixel ratio, which is 16 on a 1x display and 32 on a 2x one. A file carrying both is answered exactly on either machine with no resampling. A file carrying only 256 forces a 16:1 reduction inside the browser on every tab it draws, and that reduction is the cheap kind described above rather than the careful one performed here.

Is the 256 pixel entry worth its bytes?

For a favicon, rarely. Measured on the 265x314 test source, the three-entry file was 6,736 bytes and the four-entry file 51,544, a difference of 44,808 bytes serving a size no browser tab requests. For an application icon, a file association, or anything a user meets in Explorer's Extra large icons view, it is the entry that gets seen, and the only one that spares the shell an upscale from 48.

Why does adding a size make the file so much larger than its biggest entry?

Because the entries share nothing with each other. Each is a complete PNG with its own header and its own compressed pixel data, stored one after another, with no common palette, no shared compression dictionary, no mipmap relationship. The total is close to the sum of the parts: 6,736 bytes for three entries here, 51,544 for the same three plus 256. An entry nothing on the target platform requests is pure download cost.