Skip to content

Multi-page documents (PDF and TIFF), tiling, and pyramidal TIFF export

Copy page

Beyond animated GIF and WebP strips, libvips’s multi-page model (page and n) powers two major enterprise document workflows:

  1. 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);
  2. 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)
}
}

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.TiffCompressionDeflate
tiffParams.Predictor = vips.TiffPredictorHorizontal
tiffParams.Tile = true
tiffParams.TileWidth = 256
tiffParams.TileHeight = 256
tiffParams.Pyramid = true
tiffParams.BigTiff = true
data, _, err := image.ExportTiff(tiffParams)
if err != nil {
return err
}
return os.WriteFile("pyramid.tif", data, 0o644)

govips 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.