PNG to ICO API
POST a PNG to /v2/convert/png/to/ico and get a .ico holding one 32-bit icon image, compressed as PNG, with the alpha channel intact. The sample asks for 48 px and gets a 48 × 48 icon of 4,843 bytes from the 300 × 300 sticker.
- Endpoint
- POST /v2/
convert/ png/ to/ ico - Accepts
- png
- Sample timing
- 1 ms median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/png/to/ico \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@garden-plot-badge.png \
--form-string ImageWidth=48 \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/png/to/ico",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("garden-plot-badge.png", "rb"))],
data={
"ImageWidth": "48",
},
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "garden-plot-badge.png";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageWidth", "48");
const url = "https://api.pdfconversionapi.com/v2/convert/png/to/ico";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.001,
"Files": [
{
"FileName": "garden-plot-badge.ico",
"FileExt": "ico",
"FileSize": 4843,
"FileData": "AAABAAEAMDAAAAAAIADVEgAA…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample, converted
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- garden-plot-badge.png (39 KB)
- Output
- garden-plot-badge.ico (4.7 KB)
- Source
- A round garden-plot sticker with a QR code, a transparent background and a soft drop shadow, drawn by us for these pages. (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
ImageWidthinteger | Icon size for square art. The sample's 48 gives 48 × 48; 32 gave 2,637 bytes and 16 gave 964. Without it the 300 px sticker is fitted to 256 × 256 (55,346 bytes).Values: 1–20000 (output capped at 256) |
ImageHeightinteger | Icon height; with a width too, the art is fitted into the box and keeps its shape.Values: 1–20000 (capped at 256) |
ScaleProportionsboolean, default true | false stretches to the exact width and height, which only matters for art that isn't square. |
ScaleIfLargerboolean, default false | true keeps a 64 px PNG at 64 px when you ask for 128, instead of enlarging it. |
ScaleImageboolean, default true | false crops the top-left area at the requested size rather than scaling it. |
ColorSpaceenum, default default | gray turns the icon gray and keeps its transparency (4,856 bytes at 48 px). monochrome leaves only black and white pixels after the fit, with the soft alpha kept (1,625 bytes at 48 px).Values: default, rgb, gray, monochrome; cmyk refused |
FileNamestring | Output name, such as favicon; otherwise garden-plot-badge.ico. |
StoreFileboolean, default false | true returns a URL (3 hours) instead of base64 data. |
What carries over, and what doesn't
Kept
- Transparency, including partly transparent edge pixels: at 48 px the icon has 508 clear, 541 partly clear and 1,255 opaque pixels
- Square art stays square
- Full 8-bit color in a 32-bit PNG-compressed entry
- Palette PNGs with a transparent index
Lost or not yet supported
- Anything above 256 px; bigger art is scaled down to fit.
- Multiple sizes. Each .ico has one image, so a 16/32/48 set needs three calls and a tool to merge them.
- 16-bit precision, text chunks, DPI and color profiles.
- Animation: an animated PNG yields its first frame.
Limits
- One PNG and one icon image per request.
- Largest icon: 256 × 256.
- Uploads up to 10 MB on the Free plan or 100 MB on paid plans.
- Source images up to 100,000,000 pixels.
- 120 seconds per conversion.
Where teams use it
Favicons from a logo PNG
Send the transparent logo with ImageWidth=48 (or 32) and FileName=favicon and serve the result at /favicon.ico. The round sticker kept its transparent corners and soft edge at 48 px.
Windows shortcut and app icons
Leave out the size to get the largest icon the format holds, 256 × 256, for shortcuts and installers built from artwork your users upload.
Questions
Does the .ico contain several sizes?
No, one. The directory lists a single 48 × 48, 32-bit entry for the sample. Call the API once per size if you need more, and merge them with an icon tool.
What size do I get if I send nothing?
Your PNG's own size if it is 256 px or smaller on both sides; otherwise it is fitted into 256 × 256. The 300 px sample became 256 × 256.
Is the transparency kept?
Yes. The icon image is stored as a PNG with alpha. TransparentColor is not applied to icons, so only the PNG's own transparency counts.
Why is the 256 px icon 55 KB?
It holds 65,536 pixels of 32-bit color, compressed as PNG. At 48 px the same art is 4,843 bytes, so send the size you actually serve.
Convert your first PNG file in a minute.