HEIC to TGA API
POST a HEIC to /v2/convert/heic/to/tga and get an uncompressed Targa: 8 bits per color channel plus an alpha byte, stored top row first. The size follows from the pixel count alone, so the 400 × 300 sample came back at 480,018 bytes: an 18-byte header and four bytes a pixel.
- Endpoint
- POST /v2/
convert/ heic/ to/ tga - Accepts
- heic
- Sample timing
- 24 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/heic/to/tga \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@harbor-dusk.heic \
-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/heic/to/tga",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("harbor-dusk.heic", "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 = "harbor-dusk.heic";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/heic/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.024,
"Files": [
{
"FileName": "harbor-dusk.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
- harbor-dusk.heic (22 KB)
- Output
- harbor-dusk.tga (469 KB)
- Source
- A harbor at dusk that we drew ourselves, saved as a 400 x 300 HEIC stored sideways with a rotation flag and made-up camera and GPS tags. (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 | Scales the photo; 200 gave a 200 × 150 Targa of 120,018 bytes.Values: 1–20000 |
ImageHeightinteger | Target height, or the second side of a bounding box.Values: 1–20000 |
ScaleProportionsboolean, default true | false stretches to the exact width and height. |
ScaleIfLargerboolean, default false | true keeps smaller photos at their own size. |
ScaleImageboolean, default true | false crops the top-left area rather than scaling. |
ColorSpaceenum, default default | gray and monochrome change the color bytes, not the layout: both files are 480,018 bytes, like the color one, with blue, green and red equal in every pixel. monochrome leaves only 0 and 255.Values: default, rgb, gray, monochrome |
TransparentColorstring | Pixels of exactly this color get alpha 0. On the grainy sample, 13,32,62 touched 718 pixels.Values: #RRGGBB, R,G,B or a basic color name |
FileNamestring | Base name of the .tga. |
StoreFileboolean, default false | true returns a 3-hour download link. |
What carries over, and what doesn't
Kept
- Every pixel: read back, the Targa matched the HEIC to PNG output on all 120,000 pixels
- An 8-bit alpha channel, 255 throughout for an opaque photo
- Row order marked in the header as top-left first; both readers we tried opened the file and showed the harbor upright, matching our PNG pixel for pixel
Lost or not yet supported
- Compactness. With no run-length packets, 400 × 300 pixels take 480,000 bytes plus the 18-byte header, 21 times the HEIC.
- The TGA 2.0 footer, image ID and developer area.
- EXIF, XMP and the photo's GPS tags.
Limits
- One HEIC per request, up to 100,000,000 decoded pixels.
- A Targa side can't exceed 65,535 px: a 65,536 × 16 HEIC returned 413
TGA images can be at most 65,535 pixels on a side, and this one is 65,536×16, and 65,535 × 16 converted. - Requests up to 10 MB on the Free plan or 100 MB on paid plans; 120 seconds per conversion.
- Always 32-bit and uncompressed: there is no option for 24-bit or run-length output.
Where teams use it
Textures for game engines and 3D tools
Older engines and modding tools import Targa textures. A reference photo shot on a phone converts without opening an image editor, upright and with an alpha channel ready for masking.
Frames for video and compositing tools
Some compositing and video titling tools take TGA image sequences. Converting each HEIC still gives files those tools load with a full alpha byte.
Questions
Why is the Targa so large?
Nothing is compressed: each pixel takes four bytes (blue, green, red and alpha), so the file is width × height × 4 plus an 18-byte header. The sample is 480,018 bytes, where heic/to/png stores the same pixels in 195,656. Scale down with ImageWidth if size matters.
Will strict Targa readers open it?
The file is image type 2, plain true color with no run-length packets, so there are no packet boundaries for a reader to object to. Both readers we tried opened the sample and gave the same pixels as our PNG output.
Is the image stored upside down?
No. Bit 5 of the descriptor byte is set, meaning rows start at the top-left. Readers that ignore the flag would show the image flipped; the two we tried honored it.
Convert your first HEIC file in a minute.