https://txtfetch.com/extract/tiff/
Every page of the TIFF, not just the first.
A multi-page fax TIFF is a chain of image directories, not one picture. Read the file the way most image loaders do and you silently lose every page after the first.
the-problem
Unlike PNG or JPEG, TIFF is a container format. It's a chain of Image File Directories (IFDs), each pointing to the next, and each holding one page's worth of image data. A generic image-loading library built around 'one file, one image' reads the first IFD, produces a picture, and stops. The rest of a multi-page fax or scanned document simply never gets read, with no error to signal that pages are missing. Fax-originated TIFFs add compression variety on top. Their pages are bitonal (1-bit) and compressed with CCITT Group 3 or Group 4 fax encoding. Resolutions are often asymmetric too, like 200×100 dpi, twice the horizontal detail of vertical. A generic OCR pipeline tuned for square-pixel photos doesn't expect that. Other TIFFs use LZW compression, or embed a full JPEG per page instead. All of these encodings still need to decode correctly before OCR ever runs.
one-request-solution
txtfetch's image path walks the full IFD chain, decoding every page: CCITT G3/G4 fax-compressed, LZW, or JPEG-in-TIFF. It runs OCR on each one, not just the first. Because detection classifies TIFF as an image, OCR always runs automatically. There's no flag to set to make multi-page decoding or OCR happen.
curl -X POST https://api.txtfetch.com/v1/extract \
-H "Authorization: Bearer $TXTFETCH_KEY" \
-F file=@faxed-purchase-order.tiffimport os
import requests
with open("faxed-purchase-order.tiff", "rb") as f:
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
files={"file": f},
)
print(r.json()["extracted_text"])import { readFile } from "node:fs/promises";
const file = new Blob([await readFile("faxed-purchase-order.tiff")]);
const form = new FormData();
form.append("file", file, "faxed-purchase-order.tiff");
const res = await fetch("https://api.txtfetch.com/v1/extract", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
body: form,
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
f, err := os.Open("faxed-purchase-order.tiff")
if err != nil {
panic(err)
}
defer f.Close()
var body bytes.Buffer
writer := multipart.NewWriter(&body)
part, err := writer.CreateFormFile("file", "faxed-purchase-order.tiff")
if err != nil {
panic(err)
}
if _, err := io.Copy(part, f); err != nil {
panic(err)
}
writer.Close()
req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}Or skip the download. Pass a url parameter and txtfetch fetches the document server-side:
curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/scans/multi-page-fax.tif" \
-H "Authorization: Bearer $TXTFETCH_KEY"import os
import requests
r = requests.post(
"https://api.txtfetch.com/v1/extract",
headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"},
params={"url": "https://example.com/scans/multi-page-fax.tif"},
)
print(r.json()["extracted_text"])const endpoint = new URL("https://api.txtfetch.com/v1/extract");
endpoint.searchParams.set("url", "https://example.com/scans/multi-page-fax.tif");
const res = await fetch(endpoint, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` },
});
const { extracted_text } = await res.json();
console.log(extracted_text);package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
)
type extractResponse struct {
Status string `json:"status"`
ExtractedText string `json:"extracted_text"`
}
func main() {
endpoint, err := url.Parse("https://api.txtfetch.com/v1/extract")
if err != nil {
panic(err)
}
q := endpoint.Query()
q.Set("url", "https://example.com/scans/multi-page-fax.tif")
endpoint.RawQuery = q.Encode()
req, err := http.NewRequest("POST", endpoint.String(), nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result extractResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
panic(err)
}
fmt.Println(result.ExtractedText)
}{
"status": "success",
"extracted_text": "..."
}what-comes-back
The corpus behind /diff has no recorded .tiff document yet, so we have nothing honest to show you here. Run one of your own instead. The free converter reads the file in your browser, and nothing is uploaded.
formats-covered
.tiff.tif.jpg.png.bmp.webp.gif
faq
- Why am I only getting the first page of a multi-page TIFF?
- TIFF stores multiple pages as a chain of Image File Directories (IFDs). Many generic image loaders are built around 'one file, one image' and only read the first IFD. txtfetch walks the full chain and OCRs every page.
- Does it handle CCITT fax-compressed TIFFs, not just plain images?
- Yes. Bitonal fax scans compressed with CCITT Group 3 or Group 4 encoding decode and OCR correctly. That includes asymmetric resolutions like 200×100 dpi, common on faxed documents.
- Do I need to set an OCR flag for TIFF files?
- No. Detection classifies any TIFF as an image, and images always run through Tesseract OCR automatically. There's no ocr parameter to set.
- What about LZW-compressed or JPEG-in-TIFF files?
- Both are supported. The parser decodes whichever compression scheme the file actually uses, CCITT, LZW, or embedded JPEG per page, before handing pixels to OCR.
go-further
Images & OCR
Send a real .tiff through it.
One HTTP call returns the text. Read one in your browser first, for free.
Get an API key →