Why does my PNG to ICO conversion have a white background?
In our tests, the white background came from the source image, not the converter: the site owner's manual Chrome exports and a separate local reproduction both retained transparent corners until the source was flattened onto white.
Start by checking the source PNG's corner alpha, then check the same corners in the exported ICO. A white-looking preview alone does not establish that white pixels were saved.
Use the PNG to ICO converter to repeat the test with the source files below.
Three sources, two conversion environments
We used an opaque green image, a transparent circle, and that same circle flattened onto white. The site owner manually converted the sources in Chrome and supplied the downloaded ICO files. Those browser exports were not automated by us.
The local reproduction ran the downloaded SVGtopix conversion module with a Node canvas adapter. It used a different rendering environment. We kept its outputs separate from the manual browser exports.
Both sets were decoded with the same ICO inspection script. The script read each directory entry, extracted its PNG payload and recorded the pixels.
The sample labels in the tables are:
- G: opaque green image; manual export
on-green.ico. - T: transparent circle; manual export
trans-circle.ico. - W: the circle flattened onto white; manual export
white-bg.ico.
The corners separate transparency from painted white
Every value below was decoded from the saved files. Each of the seven frames—16, 24, 32, 48, 64, 128 and 256px—returned the same corner values shown for its sample. The manual site exports and local reproduction matched at all four corners.
| Sample | Top-left RGBA | Top-right RGBA | Bottom-left RGBA | Bottom-right RGBA |
|---|---|---|---|---|
| G | [24,77,65,255] | [24,77,65,255] | [24,77,65,255] | [24,77,65,255] |
| T | [0,0,0,0] | [0,0,0,0] | [0,0,0,0] | [0,0,0,0] |
| W | [255,255,255,255] | [255,255,255,255] | [255,255,255,255] | [255,255,255,255] |
The transparent circle retained alpha 0 at every corner. Flattening that source onto white changed the corner result to opaque white: alpha 255, with all three color channels at 255.
The green control stayed opaque green at its corners. These controls did not show the converter adding a white background to the transparent source.
That finding applies to these saved sources and exports. It does not identify the cause of an untested file's background.
Matching corners did not mean matching files
The complete comparison is below. All numbers come from the saved ICOs and decoded pixels. Differences are manual site export minus local reproduction. Offsets and payload lengths are in bytes.
| Sample | Frame (px) | Offset: local → site | Offset difference | Payload: local → site | Byte difference | Different RGBA pixels | Different alpha pixels |
|---|---|---|---|---|---|---|---|
| G | 16 | 118→118 | 0 | 115→122 | +7 | 0 | 0 |
| G | 24 | 233→240 | +7 | 125→137 | +12 | 0 | 0 |
| G | 32 | 358→377 | +19 | 139→136 | -3 | 0 | 0 |
| G | 48 | 497→513 | +16 | 172→240 | +68 | 0 | 0 |
| G | 64 | 669→753 | +84 | 240→283 | +43 | 0 | 0 |
| G | 128 | 909→1036 | +127 | 424→872 | +448 | 0 | 0 |
| G | 256 | 1333→1908 | +575 | 888→2377 | +1489 | 0 | 0 |
| T | 16 | 118→118 | 0 | 325→375 | +50 | 0 | 0 |
| T | 24 | 443→493 | +50 | 597→603 | +6 | 132 | 118 |
| T | 32 | 1040→1096 | +56 | 684→805 | +121 | 0 | 0 |
| T | 48 | 1724→1901 | +177 | 1273→1464 | +191 | 369 | 269 |
| T | 64 | 2997→3365 | +368 | 1745→2208 | +463 | 0 | 0 |
| T | 128 | 4742→5573 | +831 | 5567→7072 | +1505 | 2668 | 2460 |
| T | 256 | 10309→12645 | +2336 | 16930→22560 | +5630 | 10796 | 9292 |
| W | 16 | 118→118 | 0 | 374→405 | +31 | 0 | 0 |
| W | 24 | 492→523 | +31 | 632→647 | +15 | 118 | 0 |
| W | 32 | 1124→1170 | +46 | 724→867 | +143 | 0 | 0 |
| W | 48 | 1848→2037 | +189 | 1370→1495 | +125 | 379 | 0 |
| W | 64 | 3218→3532 | +314 | 1568→2158 | +590 | 0 | 0 |
| W | 128 | 4786→5690 | +904 | 5807→6791 | +984 | 2788 | 0 |
| W | 256 | 10593→12481 | +1888 | 15318→21028 | +5710 | 10544 | 0 |
The green control had identical decoded pixels at every size, despite different payload lengths. A byte difference alone therefore did not establish a pixel difference.
Both circle samples had pixel differences at 24, 48, 128 and 256px. The transparent circle also had alpha differences at those sizes. We cannot describe all those differences as RGB changes beneath fully transparent pixels.
The RGBA comparison includes stored RGB beneath transparent pixels. Those counts are not a visual white-fringe test. They do not, by themselves, establish a visible white edge.
For a separate controlled comparison of invisible source colors, see semi-transparent PNG pixels in ICO frames.
What to check in your own file
If the source already contains opaque white corners, removing the background must happen before conversion. Our flattened source carried that white into both sets of outputs.
If the source corners have alpha 0, inspect the exported frame's alpha too. In this test, transparent source corners remained transparent in the manual site exports. Do not infer saved pixel values from the preview's background color.
If the corners remain transparent but the edge still looks wrong, inspect the edge separately. Our corner agreement coexisted with other pixel differences. A corner check cannot certify the whole outline.
For vector input rather than a PNG source, use the separate SVG to ICO frame inspection. Its source artwork and measurements are different.
Reproduce it yourself
- Download the complete evidence package, choose each supplied source PNG in the linked converter, keep all seven sizes selected and save each ICO.
- Run
python -m pip install pillow, then runpython compare-manual.pyfrom the extracted package to inspect the included manual exports and local outputs. - Read
comparison-manual/comparison.jsonand the per-frame difference CSVs; compare all four corner values and the decoded pixels before drawing a conclusion from file size or a preview.