Help us shape the future of Go! Take the 2026 Go Developer Survey

goprint

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 18 Imported by: 0

README

goprint

CI Fuzz Coverage Go Reference

Platform-independent printing for Go: one API for Linux/BSD, macOS and Windows, headless or through the native print dialog.

  • Pure Go – builds with CGO_ENABLED=0 for every GOOS/GOARCH from any host. Native APIs are reached through golang.org/x/sys/windows, purego and plain protocols (IPP, D-Bus).
  • PDF in, paper out – documents are PDF (or images, wrapped into a PDF). CUPS, PDFKit and Windows.Data.Pdf render them natively.
  • Native dialogs, fully preset – printer, copies, page ranges, media, orientation, duplex, color, collation – and the user's choice comes back as structured Settings. On Windows the modern dialog with live preview is supported.

Status: early development, the API is not stable yet.

Feature Linux/BSD macOS Windows
Printers, GetCapabilities ✓ (CUPS) ✓ (CUPS) ✓
Print (headless) ✓ all settings via IPP ✓ all settings via IPP ✓ amd64/386/arm64, all settings via DEVMODE/PrintTicket
IPP Everywhere printer by URI (Printer: "ipp://…") ✓ ✓ ✓
Dialog ✓ desktop dialog via xdg-desktop-portal (presets + result; no job tracking) ✓ print panel with PDFKit preview; bare panel (no preview) for PrintNow == false ✓ modern dialog with live preview and page selection; classic PrintDlgEx for settings-only use

Unimplemented parts return ErrUnsupported / ErrNoDialog.

Usage

doc := goprint.Document{
	Title: "Invoice 4711",
	PDF:   func() (io.ReadSeekCloser, error) { return os.Open("invoice.pdf") },
}

// Headless
job, err := goprint.Print(ctx, doc, goprint.Settings{
	Copies: 2,
	Media:  goprint.MediaA4,
	Duplex: goprint.DuplexLongEdge,
})
if err != nil {
	return err
}
for _, w := range job.Warnings() {
	log.Println("not honored:", w)
}
err = job.Wait(ctx)

// Interactive
job, chosen, err := goprint.Dialog(ctx, doc, goprint.DialogOptions{
	Settings: goprint.Settings{Copies: 2},
	PrintNow: true,
})
if errors.Is(err, goprint.ErrCanceled) {
	// user canceled
}

On Linux/BSD, Dialog shows the desktop's print dialog through xdg-desktop-portal (org.freedesktop.portal.Print), so it also works in Flatpak and Snap. Whether a preview is shown and whether presets such as the printer are honored is up to the portal implementation; with RequirePrinter, goprint refuses to print if the dialog returns another printer. Jobs printed through the portal cannot be tracked or canceled. Without a running portal, Dialog returns ErrNoDialog.

On Windows, the modern print dialog cannot preselect a printer. Windows 11 also shows the classic dialog (PrintDlgEx) as its modern dialog and then ignores the preselection, so DialogOptions.RequirePrinter returns ErrUnsupported there. StyleAuto uses the modern dialog (with preview) for printing and the classic one for PrintNow == false, which creates no job and so never asks print-to-file printers for a file name.

On Windows, Settings.Vendor[goprint.VendorOutputFile] writes the printer output to a file instead of the device, e.g. to get a PDF from "Microsoft Print to PDF" without its save dialog.

macOS: main thread

AppKit runs only on the main thread. Lock the main goroutine to it in an init of package main and run your program through goprint.RunMain; Dialog may then be called from any goroutine inside it (or directly from the main goroutine). Called from another thread without RunMain, Dialog returns ErrWrongThread. Programs with their own Cocoa event loop call Dialog on that thread. RunMain just calls f on other platforms.

func init() { runtime.LockOSThread() }

func main() {
	goprint.RunMain(func() {
		job, chosen, err := goprint.Dialog(ctx, doc, goprint.DialogOptions{PrintNow: true})
		// ...
	})
}

The panel is app-modal (DialogOptions.Owner is not used for a sheet yet) and takes a single page range. A job printed from the panel is found in CUPS by name; if the user saves a PDF or opens Preview instead, the returned Job cannot be tracked and reports completed.

Platforms

Platform Headless Dialog
Linux/BSD IPP to CUPS (no libcups) xdg-desktop-portal (org.freedesktop.portal.Print)
macOS IPP to CUPS NSPrintOperation via purego
Windows PDF → Direct2D → XPS → spooler Modern (PrintManager, preview) or classic (PrintDlgEx)
any IPP Everywhere printers (goprint/ipp) –

Packages

Package Purpose
goprint Public API, types, errors
goprint/ipp IPP codec and client (RFC 8010/8011), usable standalone
goprint/ipp/ipptest IPP mock server for tests
goprint/fyneprint Fyne integration (separate module)

Fyne

Fyne's event loop owns the main thread, so a Fyne app uses fyneprint instead of goprint.RunMain: importing it lets goprint reach the main thread through fyne.DoAndWait, and ShowDialog runs the dialog owned by a Fyne window without blocking the UI:

fyneprint.ShowDialog(w, doc, goprint.DialogOptions{PrintNow: true},
	func(job *goprint.Job, s goprint.Settings, err error) { /* on the UI goroutine */ })

Other toolkits that own the main thread install their own runner with goprint.SetMainThreadRunner.

Example

examples/printdemo lists printers, shows capabilities, opens the print dialog and prints headless; its README has a manual test checklist for macOS.

Development

go test -race ./...
./.github/scripts/fuzz.sh 30s          # all fuzz targets
GOOS=windows go vet ./...             # vet another platform

CI runs tests on Linux, macOS and Windows, go vet, staticcheck, govulncheck, a cross-compile matrix with CGO_ENABLED=0 and nightly fuzzing.

Changes to main go through pull requests; the ci-ok check must be green.

License

MIT

Documentation

Overview

Package goprint prints documents on Linux/BSD, macOS and Windows through one API, either headless or through the platform's native print dialog.

The package is pure Go: it builds with CGO_ENABLED=0 for every supported GOOS/GOARCH from any host. Documents are handled as PDF internally; raster sources ([]image.Image) are wrapped into an image-only PDF so that there is a single print path.

The API has three verbs:

Settings flows both ways: into Dialog as presets, out of it as the user's choice.

Index

Constants

View Source
const (
	// VendorOutputFile (Windows): the printer output is written to this file
	// instead of the device (print to file). With "Microsoft Print to PDF"
	// this yields a PDF without the save dialog.
	VendorOutputFile = "windows:output-file"

	// VendorGTKPrefix (Linux/BSD dialog) marks keys passed to the print
	// portal as GTK print settings, e.g. Vendor["gtk:output-bin"] = "top".
	// On the IPP path, keys without a namespace are sent as IPP attributes.
	VendorGTKPrefix = "gtk:"
)

Settings.Vendor keys with platform-specific meaning. They are defined on every platform so that portable code compiles everywhere; backends that do not know a key report it as a warning.

Variables

View Source
var (
	ErrCanceled        = errdefs.ErrCanceled
	ErrNoPrinter       = errdefs.ErrNoPrinter
	ErrPrinterNotFound = errdefs.ErrPrinterNotFound
	ErrUnsupported     = errdefs.ErrUnsupported
	ErrNoDialog        = errdefs.ErrNoDialog
	ErrWrongThread     = errdefs.ErrWrongThread
	ErrBusy            = errdefs.ErrBusy
	ErrInvalid         = errdefs.ErrInvalid
)

Sentinel errors. Detailed errors wrap them and are reachable via errors.Is.

View Source
var (
	MediaA3     = Media{"iso_a3_297x420mm", 297000, 420000}
	MediaA4     = Media{"iso_a4_210x297mm", 210000, 297000}
	MediaA5     = Media{"iso_a5_148x210mm", 148000, 210000}
	MediaLetter = Media{"na_letter_8.5x11in", 215900, 279400}
	MediaLegal  = Media{"na_legal_8.5x14in", 215900, 355600}
)

Common media.

Functions

func Dialog

func Dialog(ctx context.Context, doc Document, opts DialogOptions) (*Job, Settings, error)

Dialog shows the native print dialog, preset with opts.Settings, and returns the job (if printed) together with the settings the user chose. It returns ErrCanceled if the user cancels and ErrNoDialog if the platform has no dialog available.

func RunMain

func RunMain(f func())

RunMain runs f and, while f runs, lets Dialog use the calling thread for the native UI. It returns when f returns.

On macOS, AppKit (and so the print panel) works only on the process's main thread. A program that shows dialogs locks its main goroutine to the main thread in an init function of package main and runs its work through RunMain:

func init() { runtime.LockOSThread() }

func main() {
	goprint.RunMain(func() {
		// Dialog may be called from any goroutine in here.
	})
}

Alternatively Dialog can be called directly from the (locked) main goroutine. Called from another thread without RunMain, Dialog returns ErrWrongThread. Programs that already run a Cocoa event loop on the main thread (e.g. a GUI toolkit) call Dialog from that thread instead.

On other platforms RunMain just calls f.

func SetMainThreadRunner added in v0.2.0

func SetMainThreadRunner(run func(f func()))

SetMainThreadRunner tells goprint how to run code on the process's main thread in programs whose main thread is owned by a GUI toolkit, so that RunMain cannot be used. run must execute its argument on the main thread and return after it returned, e.g. fyne.DoAndWait. nil removes the runner. The package github.com/timzifer/goprint/fyneprint installs one for Fyne.

Only macOS needs the main thread (for the print panel); elsewhere run is never called. If run does not reach the main thread, Dialog returns ErrWrongThread. A RunMain loop, when active, takes precedence.

Types

type Capabilities

type Capabilities struct {
	Media       []Media
	Duplex      bool
	Color       bool
	Resolutions []Resolution
	// Formats lists accepted document MIME types, e.g. "application/pdf".
	Formats []string
	// DialogPreview reports whether the native dialog shows a print preview.
	DialogPreview bool
}

Capabilities lists what a printer (and the platform's dialog) supports.

func GetCapabilities

func GetCapabilities(ctx context.Context, printer string) (Capabilities, error)

GetCapabilities reports the capabilities of the named printer. An empty name refers to the default printer.

type ColorMode

type ColorMode int

ColorMode selects color or monochrome output.

const (
	ColorAuto ColorMode = iota
	Color
	Monochrome
)

func (ColorMode) String

func (c ColorMode) String() string

type Credentials

type Credentials struct {
	Username string
	Password string
}

Credentials for authenticated print queues.

type DialogOptions

type DialogOptions struct {
	// Settings are the presets shown in the dialog.
	Settings Settings
	// Owner is the parent window: HWND, NSWindow* or X11 window / portal
	// parent. 0 means a private helper window.
	Owner uintptr
	// Style selects the dialog on Windows.
	Style DialogStyle
	// RequirePrinter forces a dialog that preselects Settings.Printer.
	RequirePrinter bool
	// PrintNow prints after confirmation. If false, Dialog only returns the
	// chosen settings and a nil Job.
	//
	// On Windows, StyleAuto without PrintNow shows the classic dialog: it
	// reports the chosen printer and full settings but has no preview, also
	// where Windows 11 draws it in the modern look. StyleModern previews,
	// but cannot report the printer and makes print-to-file printers ask
	// for a file name.
	PrintNow bool
}

DialogOptions configures Dialog.

type DialogStyle

type DialogStyle int

DialogStyle selects the native dialog on platforms that offer several.

const (
	// StyleAuto picks the best dialog for the platform and settings.
	StyleAuto DialogStyle = iota
	// StyleModern is the dialog with print preview (Windows 10+).
	StyleModern
	// StyleClassic is the dialog with full presets, including the printer.
	StyleClassic
)

func (DialogStyle) String

func (s DialogStyle) String() string

type Document

type Document struct {
	// Title is the job name in the spooler and the dialog title.
	Title string

	// PDF opens the PDF content. It is called once per consumer (preview
	// and print run separately), so it must return a fresh reader each time.
	PDF func() (io.ReadSeekCloser, error)

	// Images is a raster source, one image per page.
	Images []image.Image
	// DPI is the resolution of Images. Required when Images is set.
	DPI int
}

Document is the content to print. Exactly one of PDF or Images is set.

type Duplex

type Duplex int

Duplex mode.

const (
	DuplexDefault Duplex = iota
	DuplexNone
	DuplexLongEdge
	DuplexShortEdge
)

func (Duplex) String

func (d Duplex) String() string

type Job

type Job struct {
	// contains filtered or unexported fields
}

Job is a submitted print job.

func Print

func Print(ctx context.Context, doc Document, s Settings) (*Job, error)

Print prints doc with s, without any UI.

func (*Job) Cancel

func (j *Job) Cancel(ctx context.Context) error

Cancel cancels the job.

func (*Job) ID

func (j *Job) ID() string

ID returns the platform job id (IPP job-id or spooler job id).

func (*Job) State

func (j *Job) State(ctx context.Context) (JobState, error)

State queries the current job state.

func (*Job) Wait

func (j *Job) Wait(ctx context.Context) error

Wait blocks until the job reaches a final state or ctx is done.

func (*Job) Warnings

func (j *Job) Warnings() []Warning

Warnings lists settings that could not be honored.

type JobState

type JobState int

JobState is the state of a print job.

const (
	JobPending JobState = iota
	JobProcessing
	JobCompleted
	JobCanceled
	JobAborted
)

func (JobState) Done

func (s JobState) Done() bool

Done reports whether the state is final.

func (JobState) String

func (s JobState) String() string

type Media

type Media struct {
	Name          string
	Width, Height int
}

Media is a paper size, identified by its PWG 5101.1 self-describing name (e.g. "iso_a4_210x297mm"). Width and Height are in micrometers.

func ParseMedia

func ParseMedia(name string) (Media, error)

ParseMedia parses a PWG 5101.1 self-describing media name of the form "class_name_WxHunit" where unit is "mm" or "in".

func (Media) String

func (m Media) String() string

type Orientation

type Orientation int

Orientation of the content on the page.

const (
	OrientationDefault Orientation = iota
	Portrait
	Landscape
	ReversePortrait
	ReverseLandscape
)

func (Orientation) String

func (o Orientation) String() string

type PageRange

type PageRange struct {
	From, To int
}

PageRange is an inclusive, 1-based page range. To == 0 means "to the end".

type Printer

type Printer struct {
	Name        string
	Description string
	Location    string
	Default     bool
	Caps        Capabilities
}

Printer describes a print queue.

func Printers

func Printers(ctx context.Context) ([]Printer, error)

Printers lists the available printers.

type Quality

type Quality int

Quality is the print quality.

const (
	QualityDefault Quality = iota
	QualityDraft
	QualityNormal
	QualityHigh
)

func (Quality) String

func (q Quality) String() string

type Resolution

type Resolution struct {
	X, Y int
}

Resolution is a printer resolution in dots per inch.

type Scaling

type Scaling int

Scaling controls how pages are fitted to the media.

const (
	ScalingDefault Scaling = iota
	ScalingFit
	ScalingFill
	ScalingNone
)

func (Scaling) String

func (s Scaling) String() string

type Settings

type Settings struct {
	// Printer is the queue or printer name; empty means the default printer.
	Printer string
	// Copies is the number of copies; 0 means 1.
	Copies int
	// Collate requests collated copies; nil means printer default.
	Collate *bool
	// PageRanges selects pages (1-based, inclusive); empty means all pages.
	PageRanges  []PageRange
	Media       Media
	Orientation Orientation
	Duplex      Duplex
	Color       ColorMode
	Quality     Quality
	Scaling     Scaling
	// Tray is the media source, e.g. "tray-1" or "manual".
	Tray string
	// Vendor carries platform-specific values verbatim: IPP attributes on
	// Unix and macOS, PrintTicket features on Windows.
	Vendor map[string]string

	// Strict turns warnings about unsupported settings into errors.
	Strict bool
	// Credentials authenticate against queues that require it (CUPS).
	Credentials *Credentials
}

Settings are print settings. Zero values mean "printer default".

type Warning

type Warning struct {
	// Setting names the affected setting, e.g. "Duplex".
	Setting string
	Message string
}

Warning reports a setting that could not be honored.

func (Warning) String

func (w Warning) String() string

Directories

Path Synopsis
examples
printdemo command
Command printdemo exercises goprint by hand: list printers, show capabilities, open the native print dialog, or print headless.
Command printdemo exercises goprint by hand: list printers, show capabilities, open the native print dialog, or print headless.
fyneprint module
internal
com
Package com calls COM and WinRT interfaces through hand-written vtables and implements COM objects in Go, without cgo.
Package com calls COM and WinRT interfaces through hand-written vtables and implements COM objects in Go, without cgo.
core
Package core holds the platform-independent core: settings mapping, media tables and the PDF source.
Package core holds the platform-independent core: settings mapping, media tables and the PDF source.
errdefs
Package errdefs defines the sentinel errors shared by goprint and its internal backends.
Package errdefs defines the sentinel errors shared by goprint and its internal backends.
macprint
Package macprint shows the macOS print panel and runs PDFKit print operations.
Package macprint shows the macOS print panel and runs PDFKit print operations.
portal
Package portal talks to the print portal of xdg-desktop-portal (org.freedesktop.portal.Print) over D-Bus.
Package portal talks to the print portal of xdg-desktop-portal (org.freedesktop.portal.Print) over D-Bus.
portal/portaltest
Package portaltest runs a private D-Bus session with a fake org.freedesktop.portal.Print implementation for tests.
Package portaltest runs a private D-Bus session with a fake org.freedesktop.portal.Print implementation for tests.
testpdf
Package testpdf generates small, valid PDF documents for tests.
Package testpdf generates small, valid PDF documents for tests.
winprint
Package winprint implements printing on Windows: PDF pages are rendered by Windows.Data.Pdf onto Direct2D command lists, which ID2D1PrintControl turns into an XPS package for the spooler.
Package winprint implements printing on Windows: PDF pages are rendered by Windows.Data.Pdf onto Direct2D command lists, which ID2D1PrintControl turns into an XPS package for the spooler.
ipp
Package ipp implements the Internet Printing Protocol (RFC 8010/8011): an attribute codec and a client for CUPS and IPP Everywhere printers.
Package ipp implements the Internet Printing Protocol (RFC 8010/8011): an attribute codec and a client for CUPS and IPP Everywhere printers.
ipptest
Package ipptest provides an in-process IPP mock server for tests.
Package ipptest provides an in-process IPP mock server for tests.
raster module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL