TGA to PNM API
POST a TGA to /v2/convert/tga/to/pnm and get a Netpbm file back: a binary PPM (P6), or a PGM (P5) with ColorSpace=gray or monochrome. Transparency is blended onto AlphaColor, white by default.
- Endpoint
- POST /v2/
convert/ tga/ to/ pnm - Accepts
- tga
- 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/tga/to/pnm \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@shield-icon.tga \
--form-string AlphaColor=black \
-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/tga/to/pnm",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("shield-icon.tga", "rb"))],
data={
"AlphaColor": "black",
},
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 = "shield-icon.tga";
form.append("File", new Blob([await readFile(file)]), file);
form.append("AlphaColor", "black");
const url = "https://api.pdfconversionapi.com/v2/convert/tga/to/pnm";
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": "shield-icon.pnm",
"FileExt": "pnm",
"FileSize": 196623,
"FileData": "UDYKMjU2IDI1NiAyNTUKAAAA…"
}
]
}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
- shield-icon.tga (16 KB)
- Output
- shield-icon.pnm (192 KB)
- Source
- A 256 x 256 pixel-art shield icon with a transparent background and a half-transparent shadow, drawn by us and saved as a 32-bit run-length-encoded TGA. (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 |
|---|---|
AlphaColorstring, default white | Color under transparent pixels. The sample sends black, so the empty area is (0, 0, 0) and the 112-alpha shadow becomes (11, 8, 16).Values: #RRGGBB, R,G,B or white, black, red, green, blue, gray |
BackgroundColorstring, default white | Fallback matte when AlphaColor is left out.Values: Same as AlphaColor |
ImageWidthinteger | Resized width; the file grows 3 bytes per added pixel (128 px wide: 49,167 bytes).Values: 1–20000 |
ImageHeightinteger | Resized height, or a box together with ImageWidth.Values: 1–20000 |
ScaleProportionsboolean, default true | false ignores the aspect ratio when both sizes are set. |
ScaleIfLargerboolean, default false | true keeps textures that are already small at their size. |
ScaleImageboolean, default true | false crops at the requested size from the top-left. |
ColorSpaceenum, default default | gray or monochrome writes a one-channel P5 file: 65,551 bytes for the shield instead of 196,623, and monochrome uses only the values 0 and 255.Values: default, rgb, gray, monochrome; cmyk returns 400 |
FileNamestring | Name without the .pnm extension. |
StoreFileboolean, default false | Keep the file for 3 hours behind a URL. |
What carries over, and what doesn't
Kept
- Exact color for opaque pixels, and an exact blend for the rest: the sample matched the TGA flattened onto black at every pixel we compared
- Size and orientation: 256 × 256, rows top to bottom
- The 8-bit depth of each channel (MAXVAL 255)
Lost or not yet supported
- Transparency. The file has three channels, so alpha is blended away using
AlphaColor. - Compression: 15 bytes of header plus 196,608 bytes of raw RGB, 196,623 in all, from a 16,376-byte TGA.
- Resolution: Netpbm has no DPI field, so
ImageResolutionis ignored.
Limits
- One TGA per request.
- 100,000,000 pixels per image (413 above).
- 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
Input for command-line image pipelines
Netpbm-style tools read P6 directly, and raw pixel bytes need no decoding library in a script. Flatten a TGA once here and pipe the pixels on.
Masks and textures for scientific code
A fixed header plus raw RGB bytes is trivial to load in Python, C or MATLAB. Pick AlphaColor so empty regions get the value your code expects.
Questions
Is this a PPM file?
Yes, a binary one. The header is P6, then 256 256 255 on one line, 15 bytes in all, and the raw RGB bytes follow, top row first. With ColorSpace=gray the magic number is P5 and each pixel is a single byte, the .pgm layout.
How do I keep the shield's background transparent?
You can't in this format, because the file is written with three channels. Choose AlphaColor to match what will sit behind the image, or convert to PNG to keep the alpha channel.
What happens to a grayscale TGA?
Without ColorSpace it comes out as P6 with three equal channels, three times the bytes the gray data needs: 196,623 for a 256 × 256 gray test TGA. Send ColorSpace=gray to get a 65,551-byte P5 file with the same gray values.
Convert your first TGA file in a minute.