EXR to WebP API
POST an .exr to /v2/convert/exr/to/webp and get a lossless WebP (VP8L) that keeps the render's alpha channel; a render without one comes back as RGB. Each pixel is the render's value clipped to 0 to 1 and rounded to 8 bits; the WebP stores those values without further loss.
- Endpoint
- POST /v2/
convert/ exr/ to/ webp - Accepts
- exr
- Sample timing
- 24 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/exr/to/webp \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@glowing-bulb-render.exr \
-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/exr/to/webp",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("glowing-bulb-render.exr", "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 = "glowing-bulb-render.exr";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/exr/to/webp";
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.024,
"Files": [
{
"FileName": "glowing-bulb-render.webp",
"FileExt": "webp",
"FileSize": 52904,
"FileData": "UklGRqDOAABXRUJQVlA4TJPO…"
}
]
}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
- glowing-bulb-render.exr (187 KB)
- Output
- glowing-bulb-render.webp (52 KB)
- Source
- A glowing light bulb we drew in code and saved as a 240 × 300 OpenEXR render: half-float RGBA, premultiplied alpha, ZIP compression, values up to 12.0. (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 WebP. ImageWidth=120 returned 120 × 150 at 20,560 bytes.Values: 1–20000 |
ImageHeightinteger | Height of the WebP; ImageHeight=100 gave 80 × 100 (11,212 bytes). Both together define the box the render must fit.Values: 1–20000 |
ScaleProportionsboolean, default true | With false, a 200 × 200 box is filled exactly (38,982 bytes). |
ScaleIfLargerboolean, default false | Blocks upscaling when true. Without it, ImageWidth=800 gave an 800 × 1000 WebP of 385,618 bytes. |
ScaleImageboolean, default true | false crops the requested size from the top left: 200 × 100 was 19,866 bytes. |
ColorSpaceenum, default default | gray shrank the file to 23,424 bytes and monochrome to 8,828; alpha is kept in both.Values: default, rgb, gray, monochrome; cmyk returns 400 |
TransparentColorstring | Clears one exact color in addition to the render's own alpha; #FFFFFF gave 52,972 bytes.Values: #RRGGBB, R,G,B or a color name |
FileNamestring | Base name, glowing-bulb-render unless you send one. |
StoreFileboolean, default false | Swaps FileData for a link that lasts 3 hours. |
What carries over, and what doesn't
Kept
- Every 8-bit pixel exactly: decoding the WebP gives the same RGBA values as the BMP route
- Alpha at 8 bits, with 26,592 clear pixels in the sample
- Small files: 52,904 bytes, against 252,885 for the 16-bit PNG of the same render
Lost or not yet supported
- 16-bit precision; WebP is 8 bits per channel.
- Values above 1.0, which are clipped before encoding.
- Any sRGB conversion: the stored linear numbers become the WebP's values.
- Glow brightness at soft edges, because colors are not divided by alpha.
Limits
- One EXR per request.
- 10 MB on the Free plan or 100 MB on paid plans maximum request size.
- 100,000,000 input pixels at most.
- Width and height targets from 1 to 20,000 px, but a WebP side can't exceed 16,384 px: 17,000 × 100 returned 413
WebP images can be at most 16,384 pixels on a side, and this one is 17,000×100; lower ImageWidth or ImageHeight. - 120 seconds before the request ends.
Where teams use it
Render previews on the web
Portfolio sites, shops and documentation pages can show a rendered object on its transparent background as a WebP, which holds 8-bit alpha in a much smaller file than a 16-bit PNG.
Thumbnails for an asset manager
A 3D asset library can store a lossless WebP preview of each EXR render, at about a quarter of the EXR's size here, for its web front end.
Questions
Can I get a lossy WebP instead?
Not today. The WebP is always lossless, and ImageQuality is accepted but has no effect: quality 60 returned the identical file. For a smaller lossy file, use exr/to/jpg if you can do without transparency.
Does the WebP keep the transparent background?
Yes. Fully clear pixels stay clear and soft edges keep their 8-bit alpha. Their colors are the EXR's premultiplied values, so a glow looks dimmer than in the render. A render with no alpha channel, or with alpha at 1.0 everywhere, comes back as an RGB WebP with no alpha.
Why is the WebP so much smaller than the PNG?
The PNG route keeps 16 bits per channel, while the WebP stores 8 bits with a stronger lossless coder. For this render that is 52,904 bytes against 252,885.
Convert your first EXR file in a minute.