JPG to TGA API
POST a JPEG to /v2/convert/jpg/to/tga and get back an uncompressed Targa, 32 bits per pixel, rows stored from the top. Nothing is compressed, so the 25,110-byte sample sign became 480,018 bytes: an 18-byte header and 4 bytes per pixel.
- Endpoint
- POST /v2/
convert/ jpg/ to/ tga - Accepts
- jpg
- 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/jpg/to/tga \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@trailhead-sign.jpg \
-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/jpg/to/tga",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("trailhead-sign.jpg", "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 = "trailhead-sign.jpg";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/jpg/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.001,
"Files": [
{
"FileName": "trailhead-sign.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
- trailhead-sign.jpg (25 KB)
- Output
- trailhead-sign.tga (469 KB)
- Source
- A drawn mountain trailhead with a wooden sign and a QR code, made by us for these pages and saved at JPEG quality 92 with an EXIF block, an sRGB color profile and 300 dpi. (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 makes the 400 × 300 sign 200 × 150 and the file 120,018 bytes.Values: 1–20000 |
ImageHeightinteger | Texture height. Alone, it scales the width with it; next to ImageWidth it caps both sides and the photo keeps its 4:3 shape inside.Values: 1–20000 |
ScaleProportionsboolean, default true | false distorts the photo to the exact size you give. Use it for power-of-two textures: 256 × 256 from a 4:3 photo, 262,162 bytes. |
ScaleIfLargerboolean, default false | true keeps small JPEGs at their own size when the target is bigger. Without it, 800 px wide gives an 800 × 600 file of 1,920,018 bytes. |
ScaleImageboolean, default true | false takes a top-left cut of ImageWidth × ImageHeight pixels instead of resizing; 160 × 140 of the sign's sky and ridge, for example. |
TransparentColorstring | Pixels of exactly this color get alpha 0. JPEG noise makes exact matches rare: #FFFFFF matched 9 of the sample's 120,000 pixels.Values: Color name, #RRGGBB or R,G,B |
ColorSpaceenum, default default | gray stores gray values in the same 32-bit pixels, so the file stays 480,018 bytes.Values: default, rgb, gray, monochrome; cmyk gives 400 |
FileNamestring | Output name without extension; otherwise trailhead-sign.tga. |
StoreFileboolean, default false | true returns a 3-hour download link in Files[].Url rather than base64 data. |
What carries over, and what doesn't
Kept
- Decoded pixels exactly: the TGA matched our JPEG decode of the sample on every pixel
- Aspect ratio when a single side is requested
- The upright view of phone photos: a 300 × 200 test photo tagged EXIF Orientation 6 came back as a 200 × 300 Targa
- Row order: the header flags a top-left origin
- CMYK and grayscale JPEGs, which are read and stored as color
Lost or not yet supported
- Compression. The Targa is uncompressed (image type 2): 480,018 bytes for the sample, about 19 times the JPEG.
- EXIF, the sRGB profile and the 300 dpi value. A Targa written here has no extension area or footer to hold them.
- A byte per pixel goes to an alpha channel the JPEG never had; every alpha value is 255 unless
TransparentColorclears a color.
Limits
- A single JPEG per call.
- Upload size: up to 10 MB on the Free plan or 100 MB on paid plans.
- 100,000,000 pixels per image; larger ones are refused with 413.
- Resize values from 1 to 20,000.
- Two minutes per conversion.
Where teams use it
Photo textures for game and 3D tools
Game and 3D tools that load Targa textures can take reference photos converted on upload. Use ScaleProportions=false with a square size when the engine wants power-of-two dimensions.
Feeding older video and graphics software
If a titling or compositing tool imports TGA but not JPEG, convert the stills first. Each file arrives with an alpha channel already set to opaque.
Questions
Is the TGA compressed?
No. Every file from this route is uncompressed true color (image type 2): an 18-byte header, then 4 bytes per pixel, 480,018 bytes for the 400 × 300 sample. There is no switch for run-length encoding.
Does the TGA have an alpha channel?
Yes. Pixels are 32-bit BGRA with 8 alpha bits declared in the header. A JPEG has no transparency, so every alpha value is 255 unless you knock out a color with TransparentColor.
How big will a texture be?
Width × height × 4 bytes plus the 18-byte header, whatever the picture shows. A 256 × 256 texture made with ScaleProportions=false is 262,162 bytes, and 200 × 150 is 120,018. Scale down in the same request if the engine doesn't need the full size.
Which way up are the rows stored?
Top row first. The image descriptor byte is 0x28: 8 alpha bits plus the top-left origin flag.
Convert your first JPG file in a minute.