XCF to TIFF API
POST an .xcf to /v2/convert/xcf/to/tiff and get one uncompressed TIFF of the merged layers. 16-bit GIMP files stay 16-bit, and ImageResolution writes the print resolution into the TIFF tags.
- Endpoint
- POST /v2/
convert/ xcf/ to/ tiff - Accepts
- xcf
- Sample timing
- 44 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/xcf/to/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@gull-rock-lighthouse.xcf \
--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/xcf/to/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("gull-rock-lighthouse.xcf", "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 = "gull-rock-lighthouse.xcf";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageResolution", "150");
const url = "https://api.pdfconversionapi.com/v2/convert/xcf/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.044,
"Files": [
{
"FileName": "gull-rock-lighthouse.tiff",
"FileExt": "tiff",
"FileSize": 360210,
"FileData": "SUkqAGR+BQCWAAAAAQAAAJYA…"
}
]
}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
- gull-rock-lighthouse.xcf (203 KB)
- Output
- gull-rock-lighthouse.tiff (352 KB)
- Source
- A 400 x 300 harbor poster we drew and wrote as a layered XCF file ourselves: 11 layers, including a two-layer group, a layer mask, Multiply and Screen modes and a hidden guide 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 |
|---|---|
ImageResolutioninteger | Writes XResolution and YResolution in inches. The sample sends 150, matching the ppi set in the XCF; without it the TIFF says 1 × 1 with no unit.Values: 10–800 |
ImageWidthinteger | Width in pixels. 200 gave a 200 × 150 TIFF of 90,210 bytes.Values: 1–20000 |
ImageHeightinteger | Height in pixels; with ImageWidth, a box to fit the canvas into.Values: 1–20000 |
ScaleProportionsboolean, default true | false makes the TIFF exactly ImageWidth × ImageHeight, stretched if need be. |
ScaleIfLargerboolean, default false | true refuses to enlarge, so an 800 px request kept the 400 px poster. |
ScaleImageboolean, default true | false crops the top-left region instead of resizing. |
ColorSpaceenum, default default | gray writes a one-channel 8-bit TIFF, a third of the size (120,198 bytes); monochrome writes black and white in the same layout. On a canvas with transparent pixels the TIFF stays RGBA instead, with gray values in the color samples and the alpha kept.Values: default, rgb, gray, monochrome; cmyk returns 400 |
TransparentColorstring | Adds an alpha channel with pixels of this color cleared; the TIFF becomes RGBA (480,214 bytes with #FFFFFF).Values: #RRGGBB, R,G,B or a basic color name |
FileNamestring | Base name for the .tiff file. |
StoreFileboolean, default false | true returns a 3-hour link instead of base64 data. |
What carries over, and what doesn't
Kept
- Every pixel of the merged layers: the 8-bit TIFF decodes to exactly the PNG of the same XCF
- 16 bits per channel from a 16-bit XCF, with exact values in our ramp test
- Grayscale GIMP files as one-channel gray TIFF
- Your print resolution when you send it: 150 in the sample, stored as XResolution 150 with the unit set to inches
Lost or not yet supported
- Compression. The TIFF is uncompressed in a single strip: 360,210 bytes for a 400 × 300 RGB image.
- Layers. GIMP layers are merged; the TIFF holds one page with one image.
- The ppi stored in the XCF is not read. Without
ImageResolutionthe TIFF has resolution 1 and no unit. - The embedded color profile of the XCF.
Limits
- One XCF per request. The canvas may hold up to 67,108,864 pixels (8,192 × 8,192): 16,384 × 4,096 converts, 8,193 × 8,192 gets a 422.
- 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.
ImageResolutionfrom 10 to 800.
Where teams use it
Print and layout handoff
Print shops and page-layout programs commonly ask for TIFF. A GIMP master sent with ImageResolution=300 comes back flat and tagged for print, without opening GIMP to export.
Archiving at full depth
Scans and photos retouched in GIMP at 16 bits per channel can be archived as a flat 16-bit TIFF next to the layered .xcf, so the archive copy loses no tonal steps.
Questions
Can the TIFF keep the GIMP layers?
No. The route merges the visible layers and writes one flat image. Keep the .xcf if you need to edit layers later.
Is the TIFF compressed?
No. Pixels are stored raw in one strip, so the size is predictable: 400 × 300 × 3 bytes plus a small header gave 360,210 bytes. There is no option for LZW or ZIP compression on this route yet.
Does a 16-bit XCF stay 16-bit?
Yes. A 16-bit test XCF came back with 16 bits per sample and every value of its ramp unchanged. 32-bit float XCF files are written as 16-bit integer TIFF.
Convert your first XCF file in a minute.