QOI to TIFF API
POST a QOI to /v2/convert/qoi/to/tiff and get an uncompressed, single-page TIFF with the QOI's exact pixels. ImageResolution sets the DPI tags; the sample asks for 150.
- Endpoint
- POST /v2/
convert/ qoi/ to/ tiff - Accepts
- qoi
- 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/qoi/to/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@trail-map-card.qoi \
--form-string ImageResolution=150 \
-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/qoi/to/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("trail-map-card.qoi", "rb"))],
data={
"ImageResolution": "150",
},
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 = "trail-map-card.qoi";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageResolution", "150");
const url = "https://api.pdfconversionapi.com/v2/convert/qoi/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.001,
"Files": [
{
"FileName": "trail-map-card.tiff",
"FileExt": "tiff",
"FileSize": 480214,
"FileData": "SUkqAChTBwCWAAAAAQAAAJYA…"
}
]
}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
- trail-map-card.qoi (66 KB)
- Output
- trail-map-card.tiff (469 KB)
- Source
- A 400 x 300 trail map card with a sunrise sky, rounded transparent corners and a soft drop shadow, drawn by us and saved as a 4-channel QOI. (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 |
|---|---|
ImageResolutioninteger | Writes this value to XResolution and YResolution, in inches. The sample reads back as 150 dpi, so the 400 px card prints 2.67 inches wide.Values: 10–800 |
ImageWidthinteger | Resample to a new width (128 px: 49,366 bytes).Values: 1–20000 |
ImageHeightinteger | Resample to a new height, or fit inside a box with a width.Values: 1–20000 |
ScaleProportionsboolean, default true | false allows the aspect ratio to change. |
ScaleIfLargerboolean, default false | true never scales a QOI up. |
ScaleImageboolean, default true | false takes a crop of the requested size. |
ColorSpaceenum, default default | gray gives an 8-bit grayscale TIFF from a 3-channel QOI (120,198 bytes for the card). On the 4-channel card, gray and monochrome keep the alpha and write RGBA with equal gray channels (480,214 bytes); rgb drops an alpha channel no pixel uses.Values: default, rgb, gray, monochrome; cmyk returns 400 |
TransparentColorstring | Turns one exact color transparent, which also makes an RGB QOI's TIFF RGBA.Values: #RRGGBB, R,G,B or a basic color name |
FileNamestring | Base name of the TIFF. |
StoreFileboolean, default false | Store for 3 hours and return a URL. |
What carries over, and what doesn't
Kept
- Every pixel and alpha value of the card (4 samples of 8 bits)
- The channel count: a 3-channel QOI gives an RGB TIFF of 360,210 bytes with no alpha
- The DPI you send, as inches
Lost or not yet supported
- Compactness: the sample TIFF is 480,214 bytes, seven times the QOI, because the strip is not compressed.
- An explicit alpha marker. The fourth sample carries no ExtraSamples tag; readers we tried treated it as alpha, but a strict one warned.
- A one-channel file for transparent QOIs:
ColorSpace=grayon the card gives RGBA with the gray value in each color sample, not an 8-bit gray TIFF. - The colorspace byte of the QOI header.
Limits
- One QOI per request, one TIFF page out.
- 100,000,000 pixels per image, checked from the header.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- 120 seconds per conversion.
Where teams use it
Print and prepress
Layout tools take TIFF with a resolution. Convert a QOI illustration and set ImageResolution so it lands at the intended print size.
Archival copies of QOI captures
If your archive requires TIFF, this route gives an uncompressed copy with the exact pixels, readable without any QOI support.
Questions
Why is the TIFF so large?
It is stored uncompressed: 400 × 300 × 4 bytes of pixels plus 214 bytes of header and tags. There is no compression option on this route; PNG (49,290 bytes for the card) is the compact lossless choice.
How do I get a grayscale TIFF from a QOI with alpha?
Send ColorSpace=gray. With transparency in the QOI, the TIFF keeps 4 samples: the gray level three times plus the alpha, 480,214 bytes for the card. For a one-channel file, flatten first by converting to PNM with an AlphaColor, then send that to /v2/convert/pnm/to/tiff with ColorSpace=gray: the card came back as a 120,198-byte grayscale TIFF.
What resolution does the TIFF have without ImageResolution?
The tags read 1 by 1 with no unit, so no physical size is recorded and each program falls back on its own default. Send ImageResolution if print size matters.
Convert your first QOI file in a minute.