ODS to TIFF API
Send an .ods file to /v2/convert/ods/to/tiff for an uncompressed TIFF of each printed page. The sample keeps page 1, in grayscale, 800 pixels wide: an 800 × 618 image of 494,598 bytes.
- Endpoint
- POST /v2/
convert/ ods/ to/ tiff - Accepts
- ods
- Sample timing
- 0.598 s 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/ods/to/tiff \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@garden-plots-2026.ods \
--form-string PageRange=1 \
--form-string ColorSpace=gray \
--form-string ImageWidth=800 \
-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/ods/to/tiff",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("garden-plots-2026.ods", "rb"))],
data={
"PageRange": "1",
"ColorSpace": "gray",
"ImageWidth": "800",
},
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 = "garden-plots-2026.ods";
form.append("File", new Blob([await readFile(file)]), file);
form.append("PageRange", "1");
form.append("ColorSpace", "gray");
form.append("ImageWidth", "800");
const url = "https://api.pdfconversionapi.com/v2/convert/ods/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.598,
"Files": [
{
"FileName": "garden-plots-2026-1.tiff",
"FileExt": "tiff",
"FileSize": 494598,
"FileData": "SUkqAFiLBwABAAAAAQAAAAEA…"
}
]
}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
- garden-plots-2026.ods (30 KB)
- Output
- garden-plots-2026-1.tiff (483 KB)
- Source
- Written for this site: a fictional community garden's plot register and harvest chart in three sheets, one of them hidden, saved as an OpenDocument spreadsheet (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 |
|---|---|
PageRangestring | Pages to convert. 1 keeps the register and drops the chart page; the file name still ends in -1.Values: e.g. 1 or 1-2 |
ColorSpaceenum, default default | gray stores one byte per pixel instead of three, the biggest single saving for uncompressed TIFF. rgb gives the same three-channel file as the default.Values: rgb, gray, monochrome |
ImageWidthinteger | Draws each page at this width. Without ImageResolution alongside it, the TIFF stores no DPI (resolution 1 × 1, no unit).Values: 1–20000 |
ImageHeightinteger | Draws each page at this height.Values: 1–20000 |
ImageResolutioninteger, default 150 | Drawing resolution, stored in the TIFF tags when sent.Values: 36–600 |
WorksheetNamestring | Print one sheet by name. |
WorksheetIndexinteger | Print one sheet by number.Values: 1 to the sheet count |
PageSizeenum, default default | Paper size for every sheet.Values: letter, legal, tabloid, ledger, statement, executive, lettersmall, a3, a4, a4small, a5, b4, b5 |
PageOrientationenum, default default | Orientation for every sheet.Values: default, portrait, landscape |
FitToPageboolean, default false | One page wide. |
Scaleinteger | Print zoom.Values: 10–300 |
BackgroundColorstring, default white | Paper color.Values: a color name, #RRGGBB or R,G,B |
TransparentColorstring | Color to turn transparent in an RGBA TIFF.Values: a color name, #RRGGBB or R,G,B |
Passwordstring | For an encrypted ODS. |
MultiPageboolean, default false | true joins two or more pages in one LZW-compressed TIFF, garden-plots-2026.tiff. The register and chart pages in color at 150 DPI come to 222,810 bytes; in gray at 800 pixels wide, 53,414. |
FileNamestring | Stem for the TIFF names. |
StoreFileboolean, default false | Links valid for 3 hours. |
Not supported yet
Setting one of these to anything but its default returns 400.
Refused when set: AutoFitColumns, ThousandsSeparator, DecimalSeparator, DateFormat.
What carries over, and what doesn't
Kept
- The register page alone, 800 pixels wide, Letter landscape proportions
- The colored header row as a dark gray band with light text
- Header text, footer and every cell value, with formats such as $202.50 and 75%
- 256 shades of gray in a single 8-bit channel
Lost or not yet supported
- Color, by request: the green header band is gray.
- Compression: the page is stored raw, 494,598 bytes for 800 × 618 pixels.
- The DPI. With
ImageWidthand noImageResolution, the file records 1 × 1 with no unit. - The chart page, which
PageRange=1leaves out.
Limits
- One spreadsheet per request.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- No more than 2,000 page images per request.
- 16,000 pixels per side and 100,000,000 pixels per page image, or 413.
- 120 seconds per conversion, then 504.
Where teams use it
Archiving a register at the end of a season
Keep a page image of the year's register with the rest of the scanned paperwork, in the same TIFF format the scanner produces.
Grayscale pages for black and white printing
The colored header band and fills turn into shades of gray in a single channel, which also keeps the uncompressed file small.
Feeding imaging systems
Systems built around scanned TIFF pages can take spreadsheet pages the same way, one file per page.
Questions
Why does my TIFF say 1 × 1 resolution?
No DPI was requested. Sizing a page with ImageWidth or ImageHeight gives pixels, not inches, so nothing is stored. Add ImageResolution to write a real value into the TIFF tags.
How do I keep the files small?
Separate TIFF pages are not compressed, so file size is width × height × channels. Use ColorSpace=gray (one channel instead of three), a modest ImageWidth, and PageRange for only the pages you need. A color page at the default 150 DPI is 6,311,516 bytes; the sample is 494,598. MultiPage=true packs both color pages into one LZW-compressed file of 222,810 bytes.
Can I get one multi-page TIFF?
Yes, with MultiPage=true: both printed pages arrive as one file with two frames, compressed with LZW. Without it, each page is a separate, uncompressed file; choose the sheet or page you need with WorksheetName or PageRange to keep it to one.
Convert your first ODS file in a minute.