convert

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: BSD-3-Clause Imports: 15 Imported by: 0

README

convert

Pictures into a PDF, and a PDF back into pictures. Pure Go, CGO-free, including GOOS=js.

pdfconv to-pdf   -dpi 300 -o scan.pdf page1.jpg page2.jpg page3.jpg
pdfconv from-pdf -dpi 150 -format png -pages 1,4-6 -o ./pages scan.pdf
pdfconv formats
pdf, err := convert.ToPDF(images, convert.Options{DPI: 300})
err = convert.WriteTo(f, images, convert.Options{DPI: 300, Page: pdfkit.A4})
pages, err := convert.FromPDF(pdf, convert.RasterOptions{DPI: 150, Format: "png"})

Why it is small

Both ends were already here. go-pdfkit/pdfkit writes a PDF and can place an image on a page; go-pdfkit/render draws a page into a raster. What was missing was the join — so this is wiring and codecs, not a new engine.

Formats

read PNG, JPEG, GIF (standard library); BMP, TIFF, WebP (golang.org/x/image)
write PNG, JPEG, GIF, BMP, TIFF

⛔ WebP is refused by name, not as an unknown format. There is no WebP encoder in pure Go. "I do not know that format" would be a lie — it reads here perfectly well — and writing a PNG under a .webp name would be worse than either. The two refusals are different sentences and a test asserts that neither reads like the other.

⛔ The content decides the format, never the name. A scanner writing JPEG into page.png is ordinary; a converter that believed the extension would hand the decoder the wrong reader, or refuse a file it can read.

What decides the page

A picture has pixels, a page has points, and only the DPI says which page a picture is:

pdfconv to-pdf -dpi 300 scan.jpg   # 2480x3508 comes out A4
pdfconv to-pdf -dpi 72  scan.jpg   # the same file comes out a metre tall

With no -page, each page is sized to its own picture — which is what a set of scans of different sizes needs, and why an empty page size is an instruction rather than a missing value. With -page a4 the picture is fitted inside the paper:

  • ⛔ one scale for both axes. Scaling them separately fills the page and stretches the picture, and a stretched scan is a defect nobody reports because the page looks full;
  • ⛔ only ever shrink. "Fit on this paper" is not "make it as large as this paper": a 32-pixel logo blown up to A4 is a poster nobody asked for;
  • centred, and a margin wider than the paper gives way rather than erasing the picture — the picture is the content, the margin is a preference.

What it refuses

no pictures an empty PDF is a file, and a caller who passed an empty slice sees one and believes it worked
a picture past MaxPixels the size is decided by the input; the default ceiling is a hundred megapixels
-margin with no -page a page sized to its picture has no room to leave, and ignoring it lets somebody believe their pages have one
a page number past the end and it says how many there are
a PDF that opens and holds no pages said out loud, because an empty result otherwise reads like a selection that matched nothing

A page that cannot be written stops the run: a directory that looks like a complete conversion and is one page short is not something anybody checks. For the same reason the output directory is created after the conversion succeeds, so a failure leaves nothing behind that could be mistaken for "no pages".

Checks

100 % statement coverage on both packages, go vet and gofmt clean, and builds for nine targets including js/wasm, linux/loong64 and linux/s390x.

The end-to-end witness is a picture, not a number: a four-quadrant swatch goes in, comes back through a real rasteriser, and each quadrant is sampled in its own corner — ⛔ a flat fill survives being drawn upside down, so the test has to be able to see an orientation it does not expect.

Licence

BSD-3-Clause.

Documentation

Overview

Package convert turns pictures into a PDF and a PDF back into pictures.

Everything either side of the PDF was already here: github.com/go-pdfkit/pdfkit writes one and can place an image on a page, and github.com/go-pdfkit/render draws a page into a raster. What was missing was the join — which is why this package is wiring and codecs rather than a new engine.

Formats

Reading: PNG, JPEG and GIF from the standard library; BMP, TIFF and WebP from golang.org/x/image. Writing: PNG, JPEG, GIF, BMP and TIFF.

⛔ There is no WebP ENCODER in pure Go, so FromPDF refuses "webp" by name instead of quietly writing something else. A converter that answers a request it did not carry out is worse than one that says no.

What decides the page

A picture has pixels and a DPI; a PDF page has points. ToPDF sizes each page to its picture at the DPI given, so a 300-dpi scan comes back the size of the paper it came off. Asking for a fixed page size instead fits the picture inside it, centred, never cropping and never stretching: see Options.Page.

Pure Go

CGO-free, including GOOS=js. No C anywhere in the chain.

Index

Constants

View Source
const DefaultMaxPixels = 100_000_000

DefaultMaxPixels is how large a picture Decode will read when no ceiling is given. A hundred megapixels is A4 at a thousand dots to the inch.

⛔ Said in bytes, because "a hundred megapixels" does not tell anybody what it permits: a decoded picture is four bytes a pixel, so this default lets a file of a few dozen bytes cost FOUR HUNDRED MEGABYTES. That is bounded, which is the property that matters and the one this package did not have — but a service taking pictures from strangers should set Options.MaxPixels to what its own pages actually need rather than inherit this.

Variables

This section is empty.

Functions

func Decode

func Decode(r io.Reader) (image.Image, string, error)

Decode reads a picture and says what format it turned out to be.

⛔ It reads the CONTENT. A file's name is a claim its bytes do not have to honour: a scanner that writes JPEG into "page.png" is ordinary, and a converter that believed the extension would hand the encoder the wrong picture or refuse a file it can read perfectly well. It refuses a picture of more than DefaultMaxPixels pixels, and it refuses it by its HEADER — see decodeWithin for why that distinction is the guard.

func DecodeBytes

func DecodeBytes(b []byte) (image.Image, string, error)

DecodeBytes is Decode over a slice.

func Encoders

func Encoders() []string

Encoders names every format FromPDF can write, in a stable order.

func PageSizes

func PageSizes() []string

PageSizes names every paper size this package knows, in a stable order.

func ParsePageSize

func ParsePageSize(s string) (pdfkit.PageSize, error)

ParsePageSize reads a paper size: a name such as "a4", optionally with "-landscape", or "WIDTHxHEIGHT" in points.

⛔ "" is NOT an error and NOT a default size: it means "size each page to its own picture", which is a different instruction from "use A4". A set of scans of different sizes must not all be forced onto one paper because the caller said nothing.

func ReadersToPDF

func ReadersToPDF(rs []io.Reader, opt Options) ([]byte, error)

ReadersToPDF decodes each reader and lays the pictures out as ToPDF does. The format of each is decided by its CONTENT, never by a name.

func ToPDF

func ToPDF(images []image.Image, opt Options) ([]byte, error)

ToPDF lays each picture on a page of its own, in the order given.

func WriteTo

func WriteTo(w io.Writer, images []image.Image, opt Options) error

WriteTo is ToPDF straight to a writer, so a conversion of a hundred scans does not hold the finished PDF in memory as well as the pictures.

Types

type Encoder

type Encoder func(w io.Writer, m image.Image, quality int) error

Encoder is a picture format this package can WRITE. Reading is wider than writing — WebP decodes and does not encode — so the two are separate tables rather than one list with exceptions in it.

type Options

type Options struct {
	// DPI is how many pixels of the picture go to an inch of paper. Zero means
	// 72, at which one pixel is one point and a picture comes out at the size
	// a PDF viewer calls 100%.
	//
	// It is what turns pixels into a page: a 2480x3508 scan at 300 is A4, and
	// the same scan at 72 is a page a metre tall. There is no right answer this
	// package could pick for you, only a sane default.
	DPI float64

	// Page, when set, is the page size every picture is placed on, and the
	// picture is FITTED inside it: scaled down to fit if it is too big, centred
	// either way, never cropped and never stretched out of proportion.
	//
	// When it is the zero value each page is sized to its own picture, which is
	// what a set of scans of different sizes needs.
	Page pdfkit.PageSize

	// Margin is how much paper is left around a fitted picture, in points. It
	// is only consulted when Page is set, because a page sized to its picture
	// has no room to leave.
	Margin float64

	// Title goes in the document information dictionary.
	Title string

	// MaxPixels refuses a picture larger than this, so that a file cannot
	// decide how much memory this package uses. Zero means a hundred million,
	// which is A4 at a thousand dots to the inch and well past any scanner.
	MaxPixels int
}

Options says how pictures become pages.

type Page

type Page struct {
	Number int    // one-based, as the file numbers it
	Format string // the format actually written
	Data   []byte
}

Page is one drawn page and the bytes it encoded to.

func FromPDF

func FromPDF(pdf []byte, opt RasterOptions) ([]Page, error)

FromPDF draws the pages of a PDF and encodes each one.

func FromPDFReader

func FromPDFReader(r io.Reader, opt RasterOptions) ([]Page, error)

FromPDFReader is FromPDF over a reader, for a file on disk.

type RasterOptions

type RasterOptions struct {
	// DPI is dots per inch. Zero means 150, which is legible on a screen and
	// not so large that a hundred-page file fills a disk.
	DPI float64

	// Pages selects which pages to draw, one-based, in the order given. Nil
	// means every page in the file's own order.
	Pages []int

	// Format is what to encode as: png, jpeg, gif, bmp or tiff. Empty means
	// png, which is lossless and what a page of text should be.
	Format string

	// Quality is the JPEG quality, 1 to 100. Zero means 85. It is ignored by
	// every other format.
	Quality int

	// Password opens an encrypted file.
	Password string

	// MaxPixels refuses a page that would come out larger than this. Zero
	// leaves it to the renderer, whose own default is a little over A4 at 600
	// dots to the inch.
	MaxPixels int
}

RasterOptions says how pages become pictures.

Directories

Path Synopsis
cmd
pdfconv command
pdfconv turns pictures into a PDF and a PDF back into pictures.
pdfconv turns pictures into a PDF and a PDF back into pictures.

Jump to

Keyboard shortcuts

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