ORA to ICO API
/v2/convert/ora/to/ico composites the .ora layer stack and stores the result as a single 32-bit, PNG-compressed image inside an ICO file. Larger canvases are fitted into 256 × 256 with their shape kept, so the 400 × 300 sample becomes 256 × 192.
- Endpoint
- POST /v2/
convert/ ora/ to/ ico - Accepts
- ora
- Sample timing
- 47 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/ora/to/ico \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@garden-plan.ora \
-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/ora/to/ico",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("garden-plan.ora", "rb"))],
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-plan.ora";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/ora/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.047,
"Files": [
{
"FileName": "garden-plan.ico",
"FileExt": "ico",
"FileSize": 51941,
"FileData": "AAABAAEAAMAAAAAAIADPygAA…"
}
]
}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-plan.ora (123 KB)
- Output
- garden-plan.ico (51 KB)
- Source
- A backyard vegetable garden plan that we drew and saved as an OpenRaster file with seven layers and a layer group, including a hidden layer and a multiply layer. (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 width; the height follows the canvas. On the 4:3 plan, 64 gives a 64 × 48 icon of 6,839 bytes.Values: 1–20000 (the icon stays within 256) |
ImageHeightinteger | Icon height, or the second side of a box.Values: 1–20000 |
ScaleProportionsboolean, default true | Set false together with ImageWidth=256 and ImageHeight=256 for a square icon from non-square art; the plan is then stretched (62,570 bytes). |
ScaleIfLargerboolean, default false | true avoids enlarging small canvases. |
ScaleImageboolean, default true | false crops the top-left area instead (7,444 bytes for 120 × 90). |
ColorSpaceenum, default default | gray gave 44,118 bytes and monochrome 3,312 for the 256 × 192 icon; the monochrome icon holds only pure black and pure white.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
FileNamestring | Name of the icon file, garden-plan.ico by default. |
StoreFileboolean, default false | Store the icon for 3 hours and return its URL. |
What carries over, and what doesn't
Kept
- The composited stack, scaled with a Lanczos3 filter
- The aspect ratio: a 4:3 canvas gives a 4:3 icon unless you turn
ScaleProportionsoff - Alpha, when the canvas has transparent areas
Lost or not yet supported
- Square shape for non-square art: the plan becomes 256 × 192 unless you stretch it.
- Detail above 256 px per side.
- Extra sizes: one image per icon file.
- Layers and the 150 ppi from stack.xml.
Limits
- One .ora per request, canvas up to 100,000,000 pixels (300,000 px a side) before scaling.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- 120 seconds per conversion, then 504.
- One image per ICO, at most 256 × 256.
Where teams use it
Icons drawn in an OpenRaster app
Draw an app or folder icon on a transparent canvas in a painting app that saves .ora, then request the sizes you need, one call per size.
Favicons from a layered source
Keep the icon's layers editable in the .ora and regenerate a 32 or 48 px favicon in a build step.
Questions
How do I get a square icon from a rectangular drawing?
Draw on a square canvas, or send ImageWidth=256, ImageHeight=256 and ScaleProportions=false, which stretches the art to fill the square. Cropping with ScaleImage=false takes the top-left corner, not the center.
Why is my icon 256 × 192?
Icons are limited to 256 px per side, and the 400 × 300 canvas is scaled down to fit while keeping its 4:3 shape. Smaller canvases keep their size unless you set ImageWidth or ImageHeight.
Can I put several sizes into one .ico?
Not yet; each request returns an icon with one image. Request each size separately and combine them with an icon tool if you need a multi-size file.
Convert your first ORA file in a minute.