convert

package module
v0.1.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

This section is empty.

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.

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