GIF to TIFF API
Upload a GIF to POST /v2/convert/gif/to/tiff to receive frame 1 as an uncompressed 8-bit RGBA TIFF. Send ImageResolution to record a DPI, which GIF itself cannot store.
- Endpoint
- POST /v2/
convert/ gif/ to/ tiff - Accepts
- gif
- 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/gif/to/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@parcel-tracker.gif \
--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/gif/to/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("parcel-tracker.gif", "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 = "parcel-tracker.gif";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageResolution", "150");
const url = "https://api.pdfconversionapi.com/v2/convert/gif/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.001,
"Files": [
{
"FileName": "parcel-tracker.tiff",
"FileExt": "tiff",
"FileSize": 256214,
"FileData": "SUkqACjoAwCWAAAAAQAAAJYA…"
}
]
}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
- parcel-tracker.gif (8.7 KB)
- Output
- parcel-tracker.tiff (250 KB)
- Source
- A four-frame animated parcel-tracking card with a transparent outside and a QR code, drawn by us for this page. (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 | Sets the TIFF XResolution and YResolution in dots per inch. The sample sends 150. Without it the tags say 1/1 with no unit.Values: 10–800 |
ImageWidthinteger | Scales to this width: 200 gave a 200 × 80 TIFF of 64,214 bytes.Values: 1–20000 |
ImageHeightinteger | Scales to this height; both together set a box the frame fits into.Values: 1–20000 |
ScaleProportionsboolean, default true | false stretches the frame to fill the box. |
ScaleIfLargerboolean, default false | true skips any enlargement. |
ScaleImageboolean, default true | false crops from the top-left corner instead of resizing. |
TransparentColorstring | Turns one more exact color clear: #FFFFFF made the white card face transparent.Values: Color name, #RRGGBB or R,G,B |
ColorSpaceenum, default default | gray and monochrome write a one-sample TIFF for GIFs without transparent pixels (100,198 bytes for an opaque 400 × 250 GIF). When some pixels are transparent, as the tracker card's corners are, the TIFF stays RGBA, 256,214 bytes, with equal red, green and blue and the alpha kept; monochrome then uses only 0 and 255. rgb drops an alpha channel no pixel uses: the opaque GIF gave a 300,210-byte RGB TIFF instead of 400,214 bytes of RGBA.Values: default, rgb, gray, monochrome |
MultiPageboolean, default true | Accepted with either value. A GIF gives one page, so it changes nothing here. |
ImageQualityinteger, default 75 | Accepted only as 75. The TIFF is uncompressed, so other values return 400. |
FileNamestring | Output name without extension. |
StoreFileboolean, default false | Return a 3-hour download URL. |
Not supported yet
Setting one of these to anything but its default returns 400.
| Option | What to do instead |
|---|---|
ImageQuality | Other values than 75 return 400 "ImageQuality is not supported yet for GIF → TIFF". |
What carries over, and what doesn't
Kept
- Frame 1 with no change to any pixel, alpha included
- Transparency as a fourth sample per pixel (an RGBA TIFF, 4 samples of 8 bits)
- The DPI you set: 150 in the sample, stored with the unit inches
Lost or not yet supported
- Every frame after the first.
- Size: there is no compression, so the sample went from 8,956 bytes to 256,214, about 4 bytes per pixel.
- A smaller gray file for transparent GIFs: with
ColorSpace=graythe sample keeps four samples per pixel and its 256,214 bytes. - A meaningful resolution unless you send one; the default tags read 1/1 with no unit.
Limits
- One GIF per call; one TIFF page comes back.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- Images over 100,000,000 pixels: 413 before decoding.
- Resize sides from 1 to 20,000 px.
- A 504 after 120 seconds of conversion time.
Where teams use it
Print and prepress inputs
Layout and print workflows often ask for TIFF with a set resolution. Converting a GIF badge with ImageResolution=300 gives it a defined print size.
Archives that standardize on TIFF
Document and records systems that keep images as TIFF can take a converted GIF without a separate tool.
Questions
Is the TIFF compressed?
No. It is written uncompressed (compression tag 1) in one strip. That keeps it readable everywhere but large; compress it afterwards if size matters.
Do I get a multi-page TIFF from an animated GIF?
No. Only the first frame is decoded, so the TIFF has one page whatever MultiPage says.
What does ColorSpace=gray do with a transparent GIF?
Our TIFF output has no gray-plus-alpha layout, so a GIF with transparent pixels comes back as an RGBA TIFF whose red, green and blue are equal and whose alpha matches the GIF: 256,214 bytes for the sample. An opaque GIF becomes a one-sample gray TIFF, even one that declares a transparent color no pixel uses.
How do I set 300 DPI?
Send ImageResolution=300. The XResolution and YResolution tags then read 300/1 with ResolutionUnit 2 (inches). Values from 10 to 800 are accepted.
Convert your first GIF file in a minute.