Reader/Writer streaming I/O
Starting in govips v2.19.0, applications can connect an io.Reader directly to libvips and write encoded chunks to an io.Writer. This avoids copying the complete compressed file into a Go byte slice with io.ReadAll, and gives HTTP bodies, object-storage streams, and pipes a common interface.
Responsibilities of the three APIs
Section titled “Responsibilities of the three APIs”| API | Role | Access strategy |
|---|---|---|
LoadImageFromReader |
Create an ImageRef from any io.Reader |
Materialized by default; lazy with explicit AccessSequential |
SaveToWriter / typed variants |
Write encoded chunks to an io.Writer |
Codec-dependent; formats such as TIFF may need full buffering |
TranscodeStream |
Combine a Reader, optional auto-rotation, and a Writer | Selects sequential or materialized loading from orientation metadata |
These APIs are not present in govips v2.17.0. This page and its executable example are verified against govips v2.19.0.
Executable sequential-stream example
Section titled “Executable sequential-stream example”govips selects AccessSequential and keeps the input Reader open until ImageRef.Close(). sharp, pyvips, and the CLI use their own sequential file hints. Those switches are not the same Reader/Writer API.
params := vips.NewImportParams()params.Access.Set(vips.AccessSequential)image, err := vips.LoadImageFromReader(input, params)if err != nil { return err }defer image.Close()export := vips.NewWebpExportParams()export.Quality = 82export.StripMetadata = trueif err := image.SaveToWriterWebp(output, export); err != nil { return err }await sharp('input.jpg', { sequentialRead: true }) .webp({ quality: 82 }) .toFile('streamed.webp');image = pyvips.Image.new_from_file("input.jpg", access="sequential")image.write_to_file("streamed.webp", Q=82, keep="none")vips copy 'input.jpg[access=sequential]' 'streamed.webp[Q=82,keep=none]'Inspect the generated result
Section titled “Inspect the generated result”
Generated with govips v2.19.0 / libvips 8.17.3.
- Format: WEBP
- Dimensions: 1938 × 1292
- Bands: 3
- Alpha: No
- File size: 398,898 bytes
- Generated with: govips v2.19.0 / libvips 8.17.3
Automated tests cover propagation of Reader and Writer failures in the reference implementation. A sequential load normally consumes only enough bytes for the header. Truncation or a mid-stream failure can therefore surface later, when SaveToWriterWebp first consumes all pixels.
Sequential and materialized paths
Section titled “Sequential and materialized paths”The sequential path works for shrinking, cropping, flattening, colourspace conversion, horizontal flips, and most line-kernel operations. Operations that read rows out of order—90°/180°/270° rotation, vertical flip, and smart crop, for example—must materialize first or fail with out of order read.
params := vips.NewImportParams()params.Access.Set(vips.AccessSequential)
image, err := vips.LoadImageFromReader(input, params)if err != nil { return fmt.Errorf("load stream: %w", err)}defer image.Close()
if err := image.SaveToWriterWebp(output, vips.NewWebpExportParams()); err != nil { return fmt.Errorf("save stream: %w", err)}Use TranscodeStream when the pipeline must choose materialization from EXIF orientation:
err := vips.TranscodeStream(input, output, &vips.TranscodeOptions{ Format: vips.ImageTypeWEBP, AutoRotate: true, ExportParams: &vips.ExportParams{ Quality: 82, Interlaced: false, StripMetadata: true, },})if err != nil { return fmt.Errorf("transcode stream: %w", err)}TranscodeStream keeps orientations 1 and 2 on the sequential path. Orientations that transpose or reverse row order are materialized first.
Untrusted input and error boundaries
Section titled “Untrusted input and error boundaries”- Limit the complete request body at the HTTP layer.
SetPipeReadLimitonly limits header buffering for non-seekable Readers; it is not an upload-size limit. - In sequential mode, keep the Reader alive until
ImageRef.Close(). - Original Reader and Writer errors are wrapped and remain detectable with
errors.Is. - Progressive JPEG, interlaced PNG, HEIF decoding, and TIFF output can require additional buffering. Do not infer a memory ceiling from the API name alone.
- For cancellation in an explicit Load/Save flow, another goroutine can call
image.SetKill(true)and clear the flag after completion.TranscodeStreamdoes not currently accept acontext.Context.
Reproducible observation
Section titled “Reproducible observation”When comparing sequential and materialized paths, hold the input, libvips/govips versions, concurrency, and encoding parameters constant. Record peak RSS, exit status, output dimensions, and file size. A single-machine observation describes that environment only; it is not a universal performance claim.
On 2026-10-12, on Fedora Linux 43 with govips v2.19.0 and libvips 8.17.3, one sequential WebP transcode of this 1938 × 1292 JPEG was covered by automated tests. A writer that fails mid-stream surfaces through SaveToWriterWebp. A reader that fails after about a third of the bytes surfaces to the caller as well. Calling SetKill(true) before export makes evaluation return an error; clear the flag back to false after the attempt. Those tests focus on lifecycle and error propagation rather than multi-request concurrency ceilings.
libvips tracked memory counts allocations it recorded. It is not process RSS.
Where the other three interfaces stop
Section titled “Where the other three interfaces stop”| Interface | What this example actually did | How that differs from govips Reader/Writer |
|---|---|---|
| sharp 0.35.5 | sequentialRead: true, then WebP encode |
The sequential hint applies to sharp’s file load, not to io.Reader / io.Writer |
| pyvips 3.2.0 | access="sequential" |
This is the libvips access enum. pyvips still opens the file |
| vips CLI 8.17.3 | [access=sequential] |
A load hint. It has no kill flag and does not wrap errors for Go’s errors.Is |
Matching WebP dimensions across the four outputs only align format and size. The sequential switch does not make them the same streaming interface.
- Read the execution model to understand demand-driven evaluation.
- Read production lifecycle management for
Startup,Shutdown, andImageRef.Close()rules.