Multi-page documents (PDF and TIFF), tiling, and pyramidal TIFF export
Beyond animated GIF and WebP strips, libvips’s multi-page model (page and n) powers two major enterprise document workflows:
- On-demand page rasterization (PDF and multi-page scanned TIFF): rendering a single target page out of a multi-hundred-page PDF or document scan at a controlled
Density(DPI); - Tiled pyramidal TIFF export (
tiffsave): writing multi-resolution tiled pyramids (with Sub-IFDs and BigTIFF 64-bit offsets) for pathology whole-slide imaging (WSI), GIS, and archival viewers.
1. Loading a single PDF page at a controlled DPI
Section titled “1. Loading a single PDF page at a controlled DPI”For multi-page PDFs, never pass n=-1 to rasterize all pages at once. Read the total page count from the header first (Pages() / metadata.pages / n-pages), then pass Page (0-indexed) and NumPages: 1 to rasterize only the requested page:
package main
import ( "fmt" "os"
"github.com/davidbyttow/govips/v2/vips")
func main() { if err := vips.Startup(nil); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer vips.Shutdown()
// Rasterize only page 3 (0-indexed page=2) at 150 DPI (default is 72 DPI) params := vips.NewImportParams() params.Page.Set(2) params.NumPages.Set(1) params.Density.Set(150)
pageImg, err := vips.LoadImageFromFile("document.pdf", params) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer pageImg.Close()
// PDF pages often render with a transparent background; flatten onto white if needed if pageImg.HasAlpha() { if err := pageImg.Flatten(&vips.Color{R: 255, G: 255, B: 255}); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }
webpData, _, err := pageImg.ExportWebp(vips.NewWebpExportParams()) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := os.WriteFile("page-3.webp", webpData, 0o644); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) }}import sharp from 'sharp';
// page: 2 (third page, 0-indexed), pages: 1, density: 150 DPIawait sharp('document.pdf', { page: 2, pages: 1, density: 150,}) .flatten({ background: '#ffffff' }) .webp({ quality: 82 }) .toFile('page-3.webp');import pyvips
# Inspect page 0 header to read total page count ("n-pages")first = pyvips.Image.new_from_file("document.pdf", page=0, n=1)total_pages = first.get("n-pages")
# Rasterize only page 3 (page=2) at 150 DPIpage_img = pyvips.Image.new_from_file("document.pdf", page=2, n=1, dpi=150)if page_img.hasalpha(): page_img = page_img.flatten(background=[255, 255, 255])
page_img.write_to_file("page-3.webp", Q=82)#!/usr/bin/env bashset -euo pipefail
# Inspect total page countvipsheader -f n-pages document.pdf
# Render only page 3 (page=2, n=1) at 150 DPI and export to WebPvips pdfload document.pdf 'page-3.webp[Q=82]' --page 2 --n 1 --dpi 1502. Exporting tiled pyramidal TIFFs
Section titled “2. Exporting tiled pyramidal TIFFs”In digital pathology, GIS, and cultural-heritage archiving, tiled pyramidal TIFFs store 256 × 256 tiles alongside progressively halved overview levels so viewers can fetch arbitrary viewport regions without decoding the entire canvas.
| TIFF export setting | govips TiffExportParams |
sharp .tiff(options) |
pyvips / vips CLI tiffsave |
Notes |
|---|---|---|---|---|
| Compression | Compression (TiffCompressionDeflate / Lzw / Jpeg / Zstd / Webp) |
compression ('deflate' / 'lzw' / 'jpeg' / 'zstd' / 'webp') |
compression="deflate" |
Use deflate or zstd for lossless archival; jpeg / webp for smaller tile pyramids |
| Differencing predictor | Predictor (TiffPredictorHorizontal) |
predictor ('horizontal') |
predictor="horizontal" |
Improves lossless deflate/lzw compression on continuous-tone images |
| Tiled layout | Tile: true, TileWidth: 256, TileHeight: 256 |
tile: true, tileWidth: 256, tileHeight: 256 |
tile=True, tile_width=256, tile_height=256 |
Replaces scanline strips with 2D rectangular tiles |
| Multi-resolution pyramid | Pyramid: true |
pyramid: true |
pyramid=True / --pyramid |
Generates 1/2 downsampled pyramid levels (combine with subifd=True when supported) |
| 64-bit offsets | BigTiff: true |
bigtiff: true |
bigtiff=True / --bigtiff |
Required whenever the output TIFF may exceed 4 GB |
tiffParams := vips.NewTiffExportParams()tiffParams.Compression = vips.TiffCompressionDeflatetiffParams.Predictor = vips.TiffPredictorHorizontaltiffParams.Tile = truetiffParams.TileWidth = 256tiffParams.TileHeight = 256tiffParams.Pyramid = truetiffParams.BigTiff = true
data, _, err := image.ExportTiff(tiffParams)if err != nil { return err}return os.WriteFile("pyramid.tif", data, 0o644)import sharp from 'sharp';
await sharp('input.jpg') .tiff({ compression: 'deflate', predictor: 'horizontal', tile: true, tileWidth: 256, tileHeight: 256, pyramid: true, bigtiff: true, }) .toFile('pyramid.tif');import pyvips
image = pyvips.Image.new_from_file("input.jpg")image.write_to_file( "pyramid.tif", compression="deflate", predictor="horizontal", tile=True, tile_width=256, tile_height=256, pyramid=True, subifd=True, bigtiff=True,)vips tiffsave input.jpg pyramid.tif \ --compression deflate \ --predictor horizontal \ --tile \ --tile-width 256 \ --tile-height 256 \ --pyramid \ --subifd \ --bigtiffgovips v2.20.0 preserves page order and page-height for Rotate, Flip, Zoom, and Resize on loaded multi-page strips. That guarantee does not include Similarity, SmartCrop, or Gravity; see Animation and multi-page images for the full boundary.