EXR to TIFF API
POST an .exr to /v2/convert/exr/to/tiff and get an uncompressed TIFF with four 16-bit samples per pixel. The sample sends ImageWidth=200, so the 240 × 300 render comes back as 200 × 250 in 400,214 bytes, still 16 bits deep.
- Endpoint
- POST /v2/
convert/ exr/ to/ tiff - Accepts
- exr
- Sample timing
- 25 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/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@glowing-bulb-render.exr \
--form-string ImageWidth=200 \
-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/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("glowing-bulb-render.exr", "rb"))],
data={
"ImageWidth": "200",
},
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);
form.append("ImageWidth", "200");
const url = "https://api.pdfconversionapi.com/v2/convert/exr/to/tiff";
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.025,
"Files": [
{
"FileName": "glowing-bulb-render.tiff",
"FileExt": "tiff",
"FileSize": 400214,
"FileData": "SUkqAKgaBgABAAAAAQAAAAEA…"
}
]
}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.tiff (391 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 after scaling. The sample's 200 gave 200 × 250; the resampling runs on the 16-bit values, so the TIFF stays 16 bits per sample.Values: 1–20000 |
ImageHeightinteger | Height after scaling: ImageHeight=100 produced 80 × 100 (64,214 bytes). A width and height together act as a box.Values: 1–20000 |
ScaleProportionsboolean, default true | false with 200 × 200 gives that exact square, 320,214 bytes. |
ScaleIfLargerboolean, default false | true prevents upscaling; a plain ImageWidth=800 wrote 800 × 1000 at 6,400,270 bytes. |
ScaleImageboolean, default true | false keeps a 200 × 100 corner at full resolution instead of scaling. |
ImageResolutioninteger | Writes this DPI into XResolution and YResolution with the unit set to inches. Without it the tags read 1/1 with no unit.Values: 10–800 |
TransparentColorstring | Makes one exact color clear, but the TIFF then drops to 8 bits per sample (288,214 bytes at full size).Values: #RRGGBB, R,G,B or a color name |
ColorSpaceenum, default default | rgb leaves the file unchanged. gray and monochrome give an 8-bit RGBA TIFF of 288,214 bytes with equal red, green and blue and the render's alpha kept; monochrome leaves only 0 and 255 in the color samples.Values: default, rgb, gray, monochrome; cmyk returns 400 |
FileNamestring | Name of the .tiff file, from the upload unless set. |
StoreFileboolean, default false | Delivers a 3-hour link instead of the bytes. |
What carries over, and what doesn't
Kept
- 16 bits per sample in all four channels, including alpha, after resizing too
- Every value from 0 to 1: at full size the TIFF holds the same numbers as the PNG route
- Plain uncompressed strips, which need no decompression code to read
Lost or not yet supported
- Floating point. TIFF can store 32-bit float samples, but this route writes 16-bit unsigned integers (SampleFormat 1), so anything above 1.0 is clipped.
- The alpha label. No ExtraSamples tag is written, so a reader has to guess that the fourth sample is alpha.
- Linear-light information. No ICC profile or transfer curve goes in, so the values display as if they were sRGB.
- Size: 8 bytes per pixel, 400,214 bytes for the 200 × 250 sample.
- Correct soft edges: premultiplied colors are not divided by alpha.
Limits
- One EXR in, one TIFF out.
- 10 MB on the Free plan or 100 MB on paid plans per request, upload and fields together.
- 100,000,000 pixels per input; larger returns 413.
- Targets of 1 to 20,000 px per side.
- 120 seconds per conversion.
Where teams use it
Print and layout workflows
Print layout and prepress tools that import TIFF but not EXR can take a 16-bit RGBA copy of a rendered product shot, with more tonal steps for retouching than an 8-bit file.
Archiving a display copy
Asset archives that require TIFF can store a 16-bit RGBA copy next to the original EXR, which stays the master for anything above 1.0.
Questions
Does the TIFF keep floating-point values?
No. The samples are 16-bit unsigned integers, so values are clipped to 0 to 1 and stored as 0 to 65535. Keep the EXR if you need the range above 1.0.
What does ColorSpace=gray do to a render with alpha?
It returns an 8-bit RGBA TIFF in which red, green and blue are equal: 288,214 bytes for the sample, with its 26,592 clear pixels still clear. The 16-bit depth is lost. An opaque input, such as a Radiance .hdr, gets a one-channel 8-bit gray TIFF instead.
Why is the TIFF so large?
It is uncompressed: 4 samples × 2 bytes per pixel. The 240 × 300 render at full size is 576,214 bytes, three times the ZIP-compressed EXR. There is no compression option yet.
Convert your first EXR file in a minute.