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

ops

package module
v0.14.0 Latest Latest
Warning

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

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

README

ops

CI Go Reference Go Report Card Coverage

The verbs of go-pdfkit: what people actually do to a PDF they already have. Merge two files, pull out pages three to seven, turn a page the right way up, drop the metadata, split a report into chapters.

Built on reader, which takes a file apart and puts one back together; nothing outside the Go standard library is used, so this builds for GOOS=js/wasm and every architecture the fleet targets.

The model

A document here is an ordered list of pages, each borrowed from a source file, plus the document-level pieces. Every operation rearranges that list or annotates its entries; nothing is applied until the document is written out. An operation therefore costs nothing until it has to, several files can be mixed freely, and — the reason the model is shaped this way — the list is a plain value that two people can edit at the same time.

What it does

go install github.com/go-pdfkit/ops/cmd/pdfops@latest

pdfops merge whole.pdf part1.pdf part2.pdf
pdfops select -pages 3-7,last report.pdf extract.pdf
pdfops delete -pages even scan.pdf fronts.pdf
pdfops rotate -pages all -by 90 sideways.pdf upright.pdf
pdfops crop -box 20,20,575,820 wide.pdf trimmed.pdf
pdfops split -every 10 book.pdf chapters/
pdfops reverse back-to-front.pdf right-way-round.pdf
pdfops nup -n 4 slides.pdf handout.pdf
pdfops booklet chapter.pdf to-fold.pdf
pdfops overlay -with letterhead.pdf plain.pdf headed.pdf
pdfops blank -before 3 report.pdf report-with-a-gap.pdf
pdfops watermark -text CONFIDENTIAL contract.pdf marked.pdf
pdfops number -format "{page} of {pages}" report.pdf numbered.pdf
pdfops bates -prefix ACME- -start 1 exhibits.pdf stamped.pdf
pdfops stamp -text "seen 25 August" -at top-right -bold notes.pdf seen.pdf
pdfops sanitize downloaded.pdf safe.pdf
pdfops flatten filled-form.pdf final.pdf
pdfops strip -annotations -bookmarks private.pdf clean.pdf
pdfops compress fat.pdf lean.pdf
pdfops encrypt -user letmein -allow print,copy plain.pdf locked.pdf
pdfops -password letmein decrypt locked.pdf plain.pdf
pdfops -password letmein permissions locked.pdf
pdfops text paper.pdf
pdfops text -layout -pages 1 paper.pdf
pdfops images paper.pdf pictures/
pdfops info file.pdf

A page range is written 1-3,7,10- and may say all, even, odd or last. It keeps its own order and its own repeats, so select -pages 3-1 reverses three pages and select -pages 1,1 gives you two copies.

-password opens an encrypted file.

text reads the page back as words, and -layout says where every piece of it sits — a page, a place, a size, and what it says. A piece the document gave no way to read comes back marked rather than guessed at, so you can tell a page that says nothing from one that could not be read. images writes out the pictures a page places, a JPEG as a JPEG.

Links and bookmarks are carried over and pointed at the pages they became here, so extracting three pages of a book leaves the links between those three working and drops the ones that led out of them. A link or a bookmark that already led nowhere in the source keeps its place without a destination, because a file with broken bookmarks should keep its shape rather than lose it.

The catalogue is always written from nothing, so a document-level script, an action that runs on opening, or a tree of embedded files never survives any operation at all. sanitize deals with what travels attached to a page: its own actions, an annotation's actions, JavaScript, launching, form submission, the annotation types that exist to play or embed something, and files associated with a page. A link to the web is not executable and stays.

What a screen reader follows

A tagged document says which run of marks on which page is a heading, a paragraph, a table cell, the label of a form field. That is the reading order a screen reader follows, and for a government form it is often what the law requires — RGAA in France, Section 508 in the United States, EN 301 549 in the EU. It cannot be copied across a rebuild: every part of it points into the document, and the number tree that indexes it is keyed by a number each page carries. So it is rebuilt, element by element, around the pages that survived, and those numbers are handed out afresh. A page that kept the number it had in a file it is no longer part of is a page a reader would look up and be told, with every confidence, about somebody else's.

An element whose every page has gone is removed and its parent pruned; one with some pages gone keeps the children that are left. An empty table cell is kept, because the shape of a table is part of what it says. A page written twice carries the structure once, on the first copy, since an element names one page. Merging two files carries no tree at all: two files have two role maps in which the same name may mean two different things, and there is no honest way to choose between them.

Of 1 633 real government forms from eighteen issuers, 1 021 carry a structure tree. After a rotate 1 014 still do — the seven that do not are the seven whose tree was empty in the file we were given — and 991 of the 1 021 are identical down to the last element, mark and annotation reference. The thirty that differ are accounted for one by one in the commit that added this. What cannot be carried is named in catalogue.go with the reason, rather than disappearing quietly.

Text is drawn in the four faces every viewer already has — Helvetica, Helvetica-Bold, Courier and Courier-Bold — so nothing is embedded and a watermark costs about a kilobyte. Stamp text may say {page}, {pages} and {n}, the last being a counter for serial numbering.

Verified against real files

Every operation is checked on the same corpus of 118 863 real PDFs the reader is measured against — Matplotlib, cairo, pdfTeX, Ghostscript, Adobe, R, Apache FOP, PDF 1.3 through 1.7. For each of the 118 833 that open, four properties have to hold, compared on the bytes of every page's content stream rather than on an exit status:

  • writing the document unchanged reproduces every page;
  • reversing twice is the identity;
  • merging a document with itself doubles it exactly;
  • selecting the last page yields exactly that page.

All four hold on all 118 833 files.

Laying pages out is checked the same way: for each of the 1 959 multi-page files in that corpus, two-up produces the right number of sheets and every form drawn on them carries exactly the bytes of the page it stands for, blanks included. All 1 959 hold.

Testing

go test -covermode=set ./...

CI gates on exact 100% statement coverage, go vet, and a cross-compile across linux/{amd64,arm64,riscv64,loong64,ppc64le,s390x}, js/wasm, darwin/arm64 and windows/amd64.

The rest of the family

reader reads and writes the format · ops is the verbs and the pdfops command · render turns a page into pixels · pdffont is what a document says about a font · extract reads a page back · coedit is a PDF several people edit at once · app is the browser workbench.

Documentation for all of it: https://go-pdfkit.github.io/docs/

License

BSD-3-Clause — see LICENSE. Copyright the go-pdfkit/ops authors.

Forms

pdfops fields lists what a form asks for and what it holds; pdfops fill fills it in and saves it.

$ pdfops fields fw9.pdf
note: the file also carries an XFA form, which is not read; the standard one is.
topmostSubform[0].Page1[0].f1_01[0]                       text      ""
topmostSubform[0].Page1[0].Boxes3a-b_ReadOrder[0].c1_1[0] checkbox  "Off"
                                                            buttons [1]

$ pdfops fill -set 'topmostSubform[0].Page1[0].f1_01[0]=Wolfgang Amadeus Mozart' \
              -set 'topmostSubform[0].Page1[0].Boxes3a-b_ReadOrder[0].c1_1[0]=1' \
              fw9.pdf filled.pdf

A filled form is written as an incremental update: the original file, byte for byte, with the objects that changed appended after it and a new cross-reference section pointing back at the old one. That is how every program that saves a form saves one, and it is the safest thing a program can do to somebody's document — nothing already there is rewritten, so whatever this does not understand survives untouched, and if the update is wrong the original is still the first part of the file.

The update says where its objects went the same way the file already does. A file whose cross-reference is a stream cannot be pointed back at by a plain table: a reader following /Prev would find an object where it expected the word xref. That is not a nicety — macOS's own renderer draws nothing at all for such a file, which is how the mistake was found.

Two things it will not do. A document that had to be repaired to be read has no cross-reference section worth pointing back at, so it is refused rather than added to. A document that is encrypted has every string and stream in it written through a key, and this does not yet write into one.

Measured on a real form: fw9.pdf filled in every field, written out, read back with every value in place, and rendered by macOS — which drew what we drew, in the same places, comb cells and ticks included.

⚠ Filling a form is the only verb that keeps one. Every other verb here takes the pages apart and builds a new document round them, and a form is tied into a document by object number in a dozen places at once — so merging, splitting or rotating a form's pages loses the form. Use fill on the file itself.

The form inside a blank document

Some PDFs are blank to look at and are not blank. Their pages hold one panel — "Please wait... your PDF viewer may not be able to display this type of document" — and the real form exists only as XML beside them, laid out when Adobe's own reader opens it. Adobe removed the format from PDF 2.0; no browser and no other reader lays one out.

pdfops xfa lays it out and draws it, which turns such a file into one anything can show.

$ pdfops xfa t1135-fill-23e.pdf readable.pdf
6 sheets, 497 elements drawn

Measured over every dynamic form in a corpus of 2 240 real government forms — fourteen of them, from the Canada Revenue Agency, the French cerfa series, the US Department of Labor and the Office of Personnel Management: all fourteen laid out, 111 sheets, 9 808 elements, nothing left unplaced, and every file read back by poppler.

WHERE each element goes is go-pdfkit/xfa's, measured against pdf.js and pdfium. What is drawn INSIDE each box is this package's own and much simpler: the four standard faces, a greedy line break, a rule round each field. So this is legibility rather than fidelity — the difference between a blank sheet and a form somebody can read, not between this and Adobe.

Pictures are drawn — 27 of them across twelve of the fourteen. For most that is a logo; for French cerfa 12064 it is the whole printed form. That one carries 212 fields, 7 draws, 4 images and — counted, not guessed — no <text> and no <caption> whatever, so without its pictures it is a grid of empty boxes and with them it is the customs declaration it is. How big each one is drawn follows pdfium's own arithmetic (xfa/fxfa/cxfa_ffwidget.cpp:55-86), because pdf.js declines to settle fit and actual and leaves them to a browser's sizing of an <img>.

A picture's own size is its pixels at its own resolution, read from a PNG's pHYs chunk or a JPEG's JFIF density, and that is not a detail. Every Canada Revenue Agency form in the corpus writes aspect="actual", and their logos are 1200-dpi PNGs: 2617 pixels across is 157.02 points, which is to a hundredth of a point the width the template writes for the box. Taken at 72 dpi — one point per pixel, the assumption for a picture that declares nothing — the same logo is 2617 points wide and covers a third of the sheet in black. It did, until the render was looked at.

Page numbers come out right — "Page 3 of 11", and "Page 3 sur 4" on a French form — without running the form's scripts. A footer like that is not text: it is rich text holding a floating field naming a hidden field whose value a script sets. All sixteen of those in the corpus ask one of exactly two things:

this.rawValue = xfa.layout.page(this);
this.rawValue = xfa.layout.pageCount();

Those are questions asked of the layout, which has just answered them. Recognising the two and handing back what the pager computed is not evaluating anything. Neither reference does this — pdf.js's layout ignores xfa:embed entirely, pdfium runs a JavaScript engine — so it is named as ours. Anything else a floating field names is left as a gap, because a wrong number that looks right is worse than a blank: four cerfa fields carry a static default beside their script, and printing that would put "Page 1 of 1" on every sheet.

Two limits, both named rather than left to be discovered:

  • A picture in a file outside the document is not fetched. That is pdf.js's position and its words: "we don't get remote data and use what we have in the pdf itself, so no picture for non null href". Two of cerfa 12818's are like that, and both name an absolute path on the machine of whoever drew the form — C:\Users\…\Downloads\logo ministere.PNG. They are reported, not passed over.
  • Text is set smaller rather than cut off. The box was measured with the font the template names and this draws in Helvetica, which is wider; at the template's own size the words come to more lines than the box holds. The size comes down until they fit, with a floor of four points, because losing the end of a sentence is worse than setting it a point smaller.

Documentation

Overview

Package ops is the verb layer of go-pdfkit: what people actually do to a PDF they already have. Merge two files, pull out pages three to seven, turn a page the right way up, drop the metadata, split a report into chapters.

A document here is an ordered list of pages, each borrowed from a source file, plus the document-level pieces. Every operation rearranges that list or annotates its entries, and nothing is applied until Doc.Bytes is called. An operation therefore costs nothing until it has to, pages from several files mix freely, and the list stays a plain value.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromXFA added in v0.12.0

func FromXFA(src *reader.Document) (*Doc, *XFAReport, error)

FromXFA lays out the XFA form a document carries and returns a document of its pages, drawn.

The source document's own pages are not kept: for a dynamic form they are the placeholder, and for a static one they are the form itself and this is the wrong verb — see forms.Form.Dynamic, which says which kind a document is. This does not refuse a static one, because a caller may legitimately want to see what the XML says as against what the pages show, but a caller that has not asked which kind it has will replace a perfectly good form with a plainer drawing of it.

func ParseRange

func ParseRange(spec string, pageCount int) ([]int, error)

ParseRange turns the page selection people write — "1-3,7,10-", "even", "last", "all" — into page numbers counting from one, in the order given and with duplicates kept, because "1,1,2" really does mean three pages.

A range with no start begins at the first page and one with no end runs to the last. A descending range like "5-2" counts down, which is how a reversed extract is written.

Types

type Attachment added in v0.10.0

type Attachment struct {
	// Name is what the document calls it.
	Name string
	// Description is what it says the file is, when it says anything.
	Description string
	// Data is the file.
	Data []byte
}

An Attachment is a file travelling inside the document.

type Bookmark added in v0.4.0

type Bookmark struct {
	Title    string
	Page     int
	Children []Bookmark
}

A Bookmark is an entry of an outline written from scratch: what it says, the page of this document it points at counting from one, and whatever sits under it.

It is what a document assembled rather than merged carries — a shared edit, a report built out of pieces — where there is no source outline to carry over because the outline is the caller's own.

type Doc

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

A Doc is a document being assembled: pages in the order they will be written, and the trailer's information dictionary.

func FromDocument

func FromDocument(src *reader.Document) *Doc

FromDocument wraps an already-parsed document. Every page the document reports can be read — the page tree walk has already established that — so there is nothing here that can fail.

func Merge

func Merge(docs ...*Doc) *Doc

Merge joins documents in the order given.

func New

func New() *Doc

New returns an empty document, for merging into.

func Open

func Open(b []byte) (*Doc, error)

Open reads a PDF file held in memory, with the empty password.

func OpenWithPassword

func OpenWithPassword(b []byte, password string) (*Doc, error)

OpenWithPassword reads a PDF file that may be encrypted.

func (*Doc) Append

func (d *Doc) Append(other *Doc)

Append adds the pages of another document to the end of this one. The other document is not changed, and the two may come from different files.

func (*Doc) Attach added in v0.10.0

func (d *Doc) Attach(name string, data []byte, description string) error

Attach puts a file inside the document, under a name.

The name is what a reader shows and what another tool looks it up by. Two files under one name is a document that has lost one of them, so a name already used is refused rather than quietly replacing what is there.

func (*Doc) Attachments added in v0.10.0

func (d *Doc) Attachments() []Attachment

Attachments are the files the document carries, in the order it names them.

A PDF can hold whole files inside it — the spreadsheet a report was drawn from, the XML a form was filled from, the source of a figure. They are not drawn and nothing on the page says they are there, which is why a tool that rewrites a document can drop them without anyone noticing until the file is wanted.

func (*Doc) Bates

func (d *Doc) Bates(spec, prefix string, start, digits int) error

Bates numbers the pages a range names with a running serial, the way a legal exhibit is marked: a fixed prefix and a zero-padded counter.

func (*Doc) Blank

func (d *Doc) Blank(width, height float64)

Blank adds an empty page of the given size at the end.

func (*Doc) Booklet

func (d *Doc) Booklet() error

Booklet reorders the pages for saddle-stitch printing — folded in half and stapled through the spine — and lays them two to a sheet. Blank pages are added so the count is a multiple of four, which is what folding needs.

func (*Doc) Bytes

func (d *Doc) Bytes() ([]byte, error)

Bytes writes the document out as a PDF file. Every borrowed page is copied out of the file it came from with the attributes it inherited written onto it, so pages from different documents keep their own geometry and resources.

func (*Doc) ClearInfo

func (d *Doc) ClearInfo()

ClearInfo drops the whole information dictionary, which is what "remove the metadata" means.

func (*Doc) Compress added in v0.2.0

func (d *Doc) Compress()

Compress asks for the file to be written with its objects packed into compressed streams and a cross-reference stream, which is what every writer since PDF 1.5 does and what makes a file a good deal smaller. It costs nothing but a version of 1.5, which every reader in use has understood for twenty years.

func (*Doc) Crop

func (d *Doc) Crop(spec string, box [4]float64) error

Crop sets the visible area of the pages the range names, in points, as [left bottom right top]. It sets the crop box; the media box, which is the paper the page is on, is left alone.

func (*Doc) Decrypt added in v0.2.0

func (d *Doc) Decrypt()

Decrypt writes the file without protection. A document opened with the right password is already decrypted, so this only undoes an earlier call to Doc.Encrypt; a file read with OpenWithPassword and written out is unprotected either way.

func (*Doc) Delete

func (d *Doc) Delete(spec string) error

Delete removes the pages the range names.

func (*Doc) Detach added in v0.10.0

func (d *Doc) Detach(name string) bool

Detach removes the file of that name, and says whether there was one.

func (*Doc) DropOutlines

func (d *Doc) DropOutlines()

DropOutlines leaves the bookmarks behind. They are kept by default: a merge that loses every bookmark is a poor merge.

func (*Doc) Encrypt added in v0.2.0

func (d *Doc) Encrypt(e reader.Encryption)

Encrypt protects the file that will be written. Two people can open it: whoever knows the user password, subject to the permissions, and whoever knows the owner password, subject to nothing.

An encrypted file is not byte-for-byte reproducible — encryption needs randomness, by design — so a document written twice with the same call comes out different both times, and neither can be compared with the other.

func (*Doc) Flatten

func (d *Doc) Flatten()

Flatten draws each annotation's own appearance into the page and then drops the annotation, so what one reader sees is what every reader sees — which is what filling in a form and then flattening it means.

func (*Doc) Info

func (d *Doc) Info() reader.Dict

Info returns the document information dictionary, which may be nil.

func (*Doc) InsertBlank

func (d *Doc) InsertBlank(i int) error

InsertBlank puts an empty page before the page at i, counting from one; an index one past the end appends. The size is taken from the page it precedes, or from the one before it at the end of the document.

func (*Doc) Interleave added in v0.9.0

func (d *Doc) Interleave(others ...*Doc) error

Interleave takes pages from each document in turn — the first of this, the first of the next, and round again — until every one of them is used up.

It is what a duplex scanner leaves behind. A stack fed through a single-sided feeder twice comes out as two files: the fronts in order, and the backs, which is the same document taken apart. Merging them end to end gives every front then every back; this gives the document.

The backs are usually in reverse: the stack is turned over as a stack, so the last sheet's back is scanned first. Reverse that one before interleaving and the pages land in the right order.

Documents of different lengths do not stop it. A shorter one simply runs out, and the rest of the longer one follows in order — which is what a scanner leaves when the last sheet is single-sided.

func (*Doc) Move

func (d *Doc) Move(from, to int) error

Move takes the page at from and puts it at to, both counting from one, the other pages closing up behind it.

func (*Doc) NUp

func (d *Doc) NUp(n int) error

NUp lays n pages on each sheet, in reading order. The sheet keeps the size of the first page, and the grid is whichever arrangement of at least n cells gives cells closest in shape to the pages going into them.

func (*Doc) OnePage added in v0.9.0

func (d *Doc) OnePage() error

OnePage puts every page on a single sheet, one below the other.

A page is a unit of paper, not a unit of reading: a receipt, a chat log and a web page cut into A4 are one thing that a printer divided. This puts them back, so what is read scrolls rather than turns.

The sheet is as wide as the widest page and as tall as all of them stacked. Pages narrower than the widest are centred, because a column of text that jumps from side to side is harder to read than one that does not.

func (*Doc) Overlay

func (d *Doc) Overlay(other *Doc) error

Overlay draws each page of another document on top of the pages here, in order. When the other document has fewer pages its last page is not repeated: pages past its end are left alone.

func (*Doc) PageCount

func (d *Doc) PageCount() int

PageCount reports how many pages the document has.

func (*Doc) PageNumbers

func (d *Doc) PageNumbers(spec, format string) error

PageNumbers writes a number at the foot of the pages a range names. The format is a stamp's text, so "{page} of {pages}" and "— {page} —" both work.

func (*Doc) Picture added in v0.8.0

func (d *Doc) Picture(data []byte, dpi float64) error

Picture adds a page holding one image, the size of the image.

This is the other half of drawing a page: a scanner, a camera and a screenshot all produce a picture, and what people want of a PDF toolkit is to be handed one back with the picture in it.

Every format go-gfx/gfx reads is accepted, which is more than a PDF can carry. A JPEG is put in as it stands, because a PDF carries JPEG and re-encoding one loses a little of it for nothing; everything else is decoded and written as samples, compressed. An image with any transparency in it gets a soft mask, so a PNG drawn over the page's white does not come out with black behind it.

dpi says how many of the image's pixels go into an inch of paper; 0 means 72, one point per pixel. A photograph from a telephone at 72 is a page the size of a wall, and at 300 it is a photograph.

func (*Doc) Poster added in v0.11.0

func (d *Doc) Poster(across, down int) error

Poster spreads each page over across×down sheets, so that the sheets printed and taped edge to edge make one page the size of a wall. It is the inverse of Doc.NUp, which puts several pages on one sheet.

Every sheet is the size of the page it came from. A poster of an A4 document therefore prints on A4, and each piece has the page's own proportions — pieces of some other shape do not tape back into the page they were cut from. Because the sheets keep their shape, a wall of them is only the page's shape again when across and down are equal; otherwise the page is enlarged as far as it will go inside the wall and centred, and the sheets at the edges carry the white that is left over.

The sheets meet exactly: nothing is repeated from one to the next, and no margin is left for taping. An overlap would have to be a constant here, because Poster is told how many sheets to use and not how wide the printer's unprinted border is; too small a guess still leaves a seam, too large a one loses more of the poster to trimming than it saves, and neither could be turned off. Meeting exactly is also the only arrangement that is exactly undone: every part of the page lands on one sheet and one only, so the pieces butt together — taped from behind — with nothing to cut away and nothing printed twice.

The sheets come out in reading order: left to right, top to bottom, the top-left one first, so a printed pile can be laid out on a table in the order it came off the printer.

func (*Doc) Protection added in v0.2.0

func (d *Doc) Protection() (reader.Protection, bool)

Protection reports how the file this document was read from was protected, and false when it was not protected at all — or when the document was not read from a file. It says nothing about how the document will be written: that is what was passed to Doc.Encrypt.

func (*Doc) RemoveAnnotations

func (d *Doc) RemoveAnnotations()

RemoveAnnotations drops every annotation: links, comments, form fields and all. What was drawn on the page stays; what sat on top of it goes.

func (*Doc) Resize

func (d *Doc) Resize(spec string, box [4]float64) error

Resize sets the media box — the paper — of the pages the range names.

func (*Doc) Reverse

func (d *Doc) Reverse()

Reverse puts the pages in the opposite order.

func (*Doc) Rotate

func (d *Doc) Rotate(spec string, degrees int) error

Rotate turns the pages the range names by the given number of degrees, which must be a multiple of ninety. The rotation is relative to what the page already had, so rotating twice by ninety turns a page upside down.

func (*Doc) Rotation

func (d *Doc) Rotation(i int) (int, error)

Rotation reports the rotation of the i'th page, counting from one.

func (*Doc) Sanitize

func (d *Doc) Sanitize()

Sanitize strips the parts of a file that do something rather than show something: page and annotation actions, JavaScript, launching, form submission, files travelling with a page, and the annotation types that exist to embed or play something.

A document written by this package always carries a catalogue of this package's own making, so document-level scripts, automatic actions on opening and embedded file trees are gone whatever this setting says; sanitising deals with what travels attached to a page.

func (*Doc) Select

func (d *Doc) Select(spec string) error

Select keeps only the pages the range names, in the order it names them, so it extracts, reorders and duplicates in one verb.

func (*Doc) SetInfo

func (d *Doc) SetInfo(key reader.Name, value string)

SetInfo replaces one entry of the information dictionary. An empty value removes it.

func (*Doc) SetOutline added in v0.4.0

func (d *Doc) SetOutline(marks []Bookmark)

SetOutline writes these bookmarks rather than carrying over the ones the sources had. An entry pointing at a page this document has not got is left out, and so is everything under it: a heading whose section has gone is not a heading any more.

Passing nothing puts the sources' own bookmarks back.

func (*Doc) SetRotation

func (d *Doc) SetRotation(spec string, degrees int) error

SetRotation turns the pages the range names to an absolute angle.

func (*Doc) SetVersion

func (d *Doc) SetVersion(v string)

SetVersion sets the version written in the header.

func (*Doc) Split

func (d *Doc) Split(n int) ([]*Doc, error)

Split cuts the document into pieces of at most n pages each.

func (*Doc) SplitAt

func (d *Doc) SplitAt(at ...int) ([]*Doc, error)

SplitAt cuts the document before each of the given page numbers, which is how a report is broken into chapters.

func (*Doc) Stamp

func (d *Doc) Stamp(spec string, s Stamp) error

Stamp draws text on the pages a range names.

func (*Doc) Underlay

func (d *Doc) Underlay(other *Doc) error

Underlay draws each page of another document underneath the pages here.

func (*Doc) Version

func (d *Doc) Version() string

Version reports the PDF version that will be written.

func (*Doc) Watermark

func (d *Doc) Watermark(spec, text string) error

Watermark draws large, pale, slanted text across the pages a range names — the thing the word usually means.

type Filling added in v0.5.0

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

A Filling is a document's form, opened so that it can be filled in and written back.

func OpenForm added in v0.5.0

func OpenForm(b []byte) (*Filling, bool, error)

OpenForm reads a document's form. It reports false, with no error, for a document that simply has none — including one carrying an AcroForm dictionary a producer left behind with an empty field list, which 561 of the figure corpus's 118 833 files do.

func OpenFormWithPassword added in v0.5.0

func OpenFormWithPassword(b []byte, password string) (*Filling, bool, error)

OpenFormWithPassword is the same for a document that is protected.

func (*Filling) Bytes added in v0.5.0

func (f *Filling) Bytes() ([]byte, error)

Bytes writes the original file with the changes appended to it.

func (*Filling) Fill added in v0.5.0

func (f *Filling) Fill(name, value string) error

Fill sets one field by name, which is what a command line or a map of answers wants.

func (*Filling) Form added in v0.5.0

func (f *Filling) Form() *forms.Form

Form is what was read, to be asked about its fields and told what they hold.

type Font

type Font string

A Font names one of the four faces this package can draw with.

const (
	Helvetica     Font = "Helvetica"
	HelveticaBold Font = "Helvetica-Bold"
	Courier       Font = "Courier"
	CourierBold   Font = "Courier-Bold"
)

The faces available. Any other name reads as Helvetica.

func (Font) Width

func (f Font) Width(s string, size float64) float64

Width reports how wide a string is at the given point size, once encoded.

type Page

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

A Page is one page of a document, borrowed from the file it came from. The rotation is what will be written, not what the source said.

type Position

type Position uint8

A Position says where on a page something goes.

const (
	Center Position = iota
	TopLeft
	TopCenter
	TopRight
	BottomLeft
	BottomCenter
	BottomRight
	MiddleLeft
	MiddleRight
)

The nine places a stamp can sit.

type Stamp

type Stamp struct {
	Text     string
	Font     Font
	Size     float64    // in points; zero means twelve
	Colour   [3]float64 // red, green and blue, each from zero to one
	Opacity  float64    // zero means fully opaque
	Rotate   float64    // degrees, anticlockwise, about the text's own centre
	Position Position
	Margin   float64 // distance from the edge, in points; zero means 24
	Start    int     // the first value of {n}; zero means one
	Digits   int     // {n} padded to this many digits
}

A Stamp is a line of text drawn on a page.

The text may name what it is being drawn on: {page} is the page's number, {pages} the number of pages, and {n} a counter that starts wherever the stamp says and advances once per page stamped, which is what a numbering scheme like Bates needs.

type XFAReport added in v0.12.0

type XFAReport struct {
	// Sheets is how many pages the form came to.
	Sheets int
	// Drawn is how many elements were put on them.
	Drawn int
	// Hidden is how many the template asks not to be shown. They are placed —
	// they take up room, and what follows them sits below — and not drawn.
	Hidden int
	// Pictures is how many of the drawn elements carried one.
	Pictures int
	// Unplaced is everything the layout could not place, and every picture
	// that could not be drawn, one line each with the reason. Empty is the
	// ordinary case.
	Unplaced []string
}

An XFAReport says what laying a form out came to. A caller showing somebody the result needs to be able to say what is missing from it.

Directories

Path Synopsis
cmd
pdfops command
Command pdfops does to a PDF the things people actually want done to one: merge, extract, delete, reorder, rotate, crop, split, and read or strip the metadata.
Command pdfops does to a PDF the things people actually want done to one: merge, extract, delete, reorder, rotate, crop, split, and read or strip the metadata.

Jump to

Keyboard shortcuts

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