HEIC to TIFF API
POST a HEIC to /v2/convert/heic/to/tiff and get a single-page, uncompressed RGB TIFF of the upright photo. The sample sends ImageResolution=300, which writes 300 pixels per inch into the resolution tags; the 400 × 300 harbor takes 360,210 bytes.
- Endpoint
- POST /v2/
convert/ heic/ to/ tiff - Accepts
- heic
- Sample timing
- 23 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/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@harbor-dusk.heic \
--form-string ImageResolution=300 \
-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/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("harbor-dusk.heic", "rb"))],
data={
"ImageResolution": "300",
},
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);
form.append("ImageResolution", "300");
const url = "https://api.pdfconversionapi.com/v2/convert/heic/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.023,
"Files": [
{
"FileName": "harbor-dusk.tiff",
"FileExt": "tiff",
"FileSize": 360210,
"FileData": "SUkqAGR+BQAsAQAAAQAAACwB…"
}
]
}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.tiff (352 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 |
|---|---|
ImageResolutioninteger | Written to the X and Y resolution tags with the unit set to inches. Without it the tags say 1, with no unit.Values: 10–800 |
ImageWidthinteger | Scales before writing; 200 gave 200 × 150 and 90,210 bytes.Values: 1–20000 |
ImageHeightinteger | Target height, or a fitting box with ImageWidth.Values: 1–20000 |
ScaleProportionsboolean, default true | false stretches to both sizes. |
ScaleIfLargerboolean, default false | true only shrinks. |
ScaleImageboolean, default true | false crops from the top-left corner. |
ColorSpaceenum, default default | gray writes one 8-bit gray channel, 120,198 bytes. monochrome writes the same 8-bit layout with only black and white values, not a 1-bit file.Values: default, rgb, gray, monochrome |
TransparentColorstring | Adds an alpha channel and clears pixels of exactly this color. The alpha channel is added even when nothing matches, so the file grows to 480,214 bytes.Values: #RRGGBB, R,G,B or a basic color name |
MultiPageboolean, default true | Accepted because ConvertAPI documents it here; a HEIC gives one page either way. |
FileNamestring | Base name for the .tiff. |
StoreFileboolean, default false | true stores the TIFF for 3 hours and returns its URL. |
Not supported yet
Setting one of these to anything but its default returns 400.
| Option | What to do instead |
|---|---|
ImageQuality | The TIFF is uncompressed, so there is no quality to set. ConvertAPI's default of 75 is accepted; other values return 400. |
What carries over, and what doesn't
Kept
- Every decoded pixel, written without compression
- The resolution you ask for: the sample reports 300 dpi
- The upright orientation of a HEIC stored sideways
Lost or not yet supported
- Compression. 360,210 bytes for a 22,517-byte HEIC; the TIFF uses compression type 1, none.
- EXIF, XMP and GPS: the TIFF has only its 14 basic tags.
- The color profile. No ICC tag is written, so the values carry no statement of their color space.
- Display P3 tones, which the decoder stretches: in our test gray 235 came out at 255.
Limits
- One HEIC per request, one page per TIFF.
- Up to 100,000,000 pixels; requests up to 10 MB on the Free plan or 100 MB on paid plans.
- 120 seconds per conversion.
- HEIC files saved at a desktop encoder's top quality setting returned 422 'malformed data' in our tests.
Where teams use it
Photos for print and layout
Print shops and page-layout software expect TIFF with a stated resolution. Send ImageResolution=300 and the file opens at the intended size: 400 × 300 pixels prints 1.33 × 1 inch.
Document management and scanning systems
Archives that store pages and photos as TIFF can take phone pictures without HEIC support on their side. The orientation is already fixed, so no viewer has to read a rotation tag.
Questions
Is the TIFF compressed?
No. Rows are stored raw, 3 bytes a pixel, with no LZW or ZIP option. If size matters, heic/to/png keeps the same pixels in 195,656 bytes instead of 360,210 for the sample.
How do I get a 300 dpi TIFF for print?
Send ImageResolution=300, as the sample does. Only the resolution tags change; to change the printed size too, set the pixels with ImageWidth (for example 1200 for 4 inches at 300 dpi).
Can I get a CMYK TIFF?
Not yet. ColorSpace=cmyk returns 400 'ColorSpace cmyk is not supported yet; use rgb, gray or monochrome'.
What does MultiPage do?
It's accepted for compatibility with ConvertAPI, where it combines several pages into one TIFF. A HEIC converts to a single page, so MultiPage=false returns the same file.
Convert your first HEIC file in a minute.