ORA to GIF API
/v2/convert/ora/to/gif composites the visible layers of an .ora and reduces the result to a single palette for a one-frame GIF89a. Flat-color drawings like the sample plan survive this well; soft gradients may band.
- Endpoint
- POST /v2/
convert/ ora/ to/ gif - Accepts
- ora
- Sample timing
- 97 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/gif \
-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/gif",
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/gif";
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.097,
"Files": [
{
"FileName": "garden-plan.gif",
"FileExt": "gif",
"FileSize": 33787,
"FileData": "R0lGODlhkAEsAYAAAAAAAAAA…"
}
]
}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.gif (33 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 | Width of the GIF. A 200 px version of the plan is 200 × 150 and 15,784 bytes.Values: 1–20000 |
ImageHeightinteger | Height of the GIF, or the second side of a bounding box.Values: 1–20000 |
ScaleProportionsboolean, default true | false stretches into the full box, for example a 200 × 200 square of 19,459 bytes. |
ScaleIfLargerboolean, default false | true prevents upscaling past 400 × 300. |
ScaleImageboolean, default true | false cuts a region from the top-left corner (4,292 bytes for 120 × 90). |
ColorSpaceenum, default default | monochrome gives a two-tone plan of 3,749 bytes; gray gives 33,442.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
TransparentColorstring | Gives the GIF a transparent index for one exact color. With #FFFFFF, 13 pixels of the opaque plan turned see-through.Values: #RRGGBB, R,G,B or a color name |
FileNamestring | Name of the output, garden-plan.gif by default. |
StoreFileboolean, default false | Get a link to the stored GIF, valid for 3 hours. |
What carries over, and what doesn't
Kept
- The composited plan at 400 × 300, with the hidden layer left out
- Colors closely for flat drawings: 230 palette entries, average error 0.31 levels, largest 25
- Transparency for fully clear pixels, when the canvas has any; the opaque sample has no transparent index
Lost or not yet supported
- Colors beyond 256: the plan's 3,371 distinct colors were merged into 199, stored in 230 palette entries because some entries repeat.
- Soft transparency. A pixel is either transparent or opaque in GIF, so partly transparent pixels are written fully opaque.
- Animation: one frame only, even if your painting app uses layers as frames.
- Resolution data; GIF has no DPI field.
Limits
- One .ora per request, canvas up to 100,000,000 pixels and 300,000 px per side.
- GIF keeps width and height in 16 bits. Our 65,536 × 10 test .ora returned 413
GIF images can be at most 65,535 pixels on a side, and this one is 65,536×10. - Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- 120 seconds, then 504.
- One frame, one global palette of at most 256 colors.
Where teams use it
GIF-only upload fields
When a form, an email signature or an intranet page accepts GIF only, composite the .ora and get a GIF in one call, sized with ImageWidth.
Small diagrams with few colors
Plans and diagrams with large flat areas suit a palette. The garden plan's 3,371 colors were mapped to 230 palette entries with an average error of 0.31 levels per channel.
Questions
Can layers become frames of an animated GIF?
No. The route composites the whole stack into one image and writes a single frame. There is no option to export layers as frames.
How much color is lost?
For the sample plan, the average difference from the full-color composite was 0.31 levels per channel and the largest 25; 379 pixels moved by 10 levels or more. Drawings with smooth gradients can lose more, since they need more than 256 colors.
Is a semi-transparent layer kept semi-transparent?
Inside the composite, yes: opacity is applied when layers are merged, so the 60% drip line blends with the beds below. Only the final pixels must be fully opaque or fully clear in the GIF.
Convert your first ORA file in a minute.