XCF to TGA API
POST an .xcf to /v2/convert/xcf/to/tga and get an uncompressed 32-bit TGA (image type 2) of the merged layers. The alpha channel is always written, and the TGA is stored top-left first.
- Endpoint
- POST /v2/
convert/ xcf/ to/ tga - Accepts
- xcf
- Sample timing
- 45 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/tga \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@gull-rock-lighthouse.xcf \
-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/tga",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("gull-rock-lighthouse.xcf", "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 = "gull-rock-lighthouse.xcf";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/xcf/to/tga";
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.045,
"Files": [
{
"FileName": "gull-rock-lighthouse.tga",
"FileExt": "tga",
"FileSize": 480018,
"FileData": "AAACAAAAAAAAAAAAkAEsASAo…"
}
]
}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.tga (469 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 |
|---|---|
ImageWidthinteger | Texture width in pixels; 200 gave 200 × 150 and 120,018 bytes. Use it with ImageHeight for power-of-two sizes.Values: 1–20000 |
ImageHeightinteger | Texture height, or the second side of the fitting box.Values: 1–20000 |
ScaleProportionsboolean, default true | false forces both sizes, for example 256 × 256 from a 4:3 canvas. |
ScaleIfLargerboolean, default false | true means smaller canvases are left at their own size. |
ScaleImageboolean, default true | false crops the top-left area at the requested size. |
ColorSpaceenum, default default | gray gives gray values and monochrome only black and white, both in the same 32-bit layout, so the poster stays 480,018 bytes.Values: default, rgb, gray, monochrome; cmyk returns 400 |
TransparentColorstring | Sets alpha to 0 for one exact color, a common way to mark the cut-out color of a sprite. #FFFFFF cleared 87 pixels of the poster.Values: #RRGGBB, R,G,B or a basic color name |
FileNamestring | Name of the .tga without the extension. |
StoreFileboolean, default false | true gives a 3-hour link in place of base64. |
What carries over, and what doesn't
Kept
- The merged image: decoded, every pixel matched the PNG of the same XCF
- An 8-bit alpha channel, all 255 for the opaque poster
- Row order: the descriptor marks the image as top-left first, so readers that honor it show it upright
Lost or not yet supported
- Compression. The 207,799-byte XCF became a 480,018-byte TGA: an 18-byte header and 4 bytes a pixel.
- The TGA 2.0 footer and any image ID or developer area.
- Depth above 8 bits per channel and the XCF's resolution and color profile.
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.
- Always 32-bit uncompressed output; there is no option for 24-bit or run-length-encoded TGA.
Where teams use it
Game textures from GIMP sources
Modding and game projects often paint textures in GIMP and ship TGA. Sending the .xcf from a build script keeps the layered file as the only source and makes the TGA on demand.
Sprites with a key color
Artwork drawn on a solid background color can be sent with TransparentColor to get a TGA whose background is cut out in the alpha channel.
Questions
Is the TGA compressed?
No. The route writes uncompressed TGA (image type 2), so the size is always 18 + width × height × 4 bytes: 480,018 for the poster. The PNG of the same file is 31,750 bytes.
Will strict TGA readers open it?
Both readers we tried opened the sample and decoded exactly the pixels of the PNG route. The file has no run-length packets, so no packet can run across a row end, which some readers reject.
Can I get a 24-bit TGA?
Not yet. The route always writes 32 bits per pixel with alpha, even when the canvas is opaque.
Convert your first XCF file in a minute.