> Source: https://txtfetch.com/extract/tiff > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # 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 ```curl curl -X POST https://api.txtfetch.com/v1/extract \ -H "Authorization: Bearer $TXTFETCH_KEY" \ -F file=@faxed-purchase-order.tiff ``` Python ```python import 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"]) ``` JavaScript ```javascript 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); ``` Go ```go 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 ```curl curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/scans/multi-page-fax.tif" \ -H "Authorization: Bearer $TXTFETCH_KEY" ``` Python ```python 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"]) ``` JavaScript ```javascript 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); ``` Go ```go 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](https://txtfetch.com/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](https://txtfetch.com/tools/file-to-text) 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 - [Read the .tiff guide →](https://txtfetch.com/blog/ocr-scanned-documents-api) - [Scanned PDFs use a different OCR-escalation path →](https://txtfetch.com/extract/scanned-pdf) - [Not sure a scan will OCR cleanly? Check it free, in your browser →](https://txtfetch.com/tools/image-ocr-check) - [API quickstart →](https://txtfetch.com/docs) - [How the pipeline works →](https://txtfetch.com/how-it-works) - [Extract it from your language →](https://txtfetch.com/for) - [Get an API key →](https://app.txtfetch.com/signup) Images & OCR - [`.png`](https://txtfetch.com/extract/image) - [All formats →](https://txtfetch.com/extract) ## Send a real .tiff through it. One HTTP call returns the text. Read one in your browser first, for free. [Get an API key →](https://app.txtfetch.com/signup) [Open the free .tiff reader →](https://txtfetch.com/tools/image-ocr-check)