Documentation
¶
Overview ¶
Package sheet lays rendered codes out on a page for printing.
The unit of work is a Layout: a page size, a grid of cells, and the margins and gutters that put the grid where the die-cut labels actually are. Sheet knows nothing about encoding or rendering — Compose takes PNGs that someone else produced and arranges them — so the geometry can be reasoned about and tested without an encoder anywhere near it.
Everything physical is in millimetres, because that is the unit every label manufacturer publishes their stock in, and converting once at the PDF boundary is less error-prone than carrying points through the arithmetic. The origin for a Layout is the top-left of the page with y increasing downwards, which is how a datasheet describes a label sheet; Compose flips it to PDF's bottom-left origin at the last possible moment.
Index ¶
Constants ¶
const ( // MaxCells caps a whole document. Five hundred labels is seven A4 sheets // of the densest stock, which is more than one print run. MaxCells = 500 )
Limits on a compose job. They exist because the PDF holds every image uncompressed in memory while it is being built, so an unbounded job is an out-of-memory kill rather than a slow response.
Variables ¶
var ( // ErrInvalidLayout means the grid cannot be placed on the page. ErrInvalidLayout = errors.New("invalid sheet layout") // ErrNoCells means Compose was given nothing to lay out. ErrNoCells = errors.New("no cells to compose") // ErrTooManyCells means the job exceeds what one document may carry. ErrTooManyCells = errors.New("too many cells") // ErrBadImage means a cell's PNG could not be decoded or is too large. ErrBadImage = errors.New("invalid cell image") )
Sentinel errors for the sheet package.
var ( // A4 is ISO 216 A4. A4 = PageSize{Name: "a4", WidthMM: 210, HeightMM: 297} // Letter is ANSI A, 8.5 by 11 inches. Letter = PageSize{Name: "letter", WidthMM: 215.9, HeightMM: 279.4} // A3 is ISO 216 A3. A3 = PageSize{Name: "a3", WidthMM: 297, HeightMM: 420} )
The page sizes barqr lays out on. A4 is the ISO default everywhere outside North America, Letter is the default inside it, and A3 is what a print shop uses to gang up several sheets.
Functions ¶
func Compose ¶
Compose lays cells out across as many pages as they need and returns a PDF.
The document is written by hand: PDF 1.4, one page object per sheet, each image embedded as a /DeviceRGB /FlateDecode XObject. There is no PDF library involved because the whole grammar used here is a dozen operators, and a dependency would bring font embedding, ICC profiles and XMP metadata to a file that should be a few tens of kilobytes.
Identical PNGs are embedded once and referenced many times. That is not a micro-optimisation: a sheet of sixty-five copies of one asset tag is a completely ordinary request, and it is the difference between a 40 KB file and a 2.6 MB one.
Types ¶
type Cell ¶
type Cell struct {
// PNG is the rendered code. Empty means "skip this position".
PNG []byte
// Caption is drawn beneath the code when the layout asks for it.
Caption string
}
Cell is one position on the sheet.
A Cell with no PNG leaves its position blank, which is how a caller prints onto a part-used sheet: pad the front of the slice with empty cells until the first code lands on the first unused label.
type Layout ¶
type Layout struct {
// Page is the sheet being printed on.
Page PageSize
// Cols and Rows are the grid dimensions.
Cols, Rows int
// MarginTopMM and MarginLeftMM position the first cell's top-left corner.
MarginTopMM, MarginLeftMM float64
// CellWidthMM and CellHeightMM are one cell's dimensions.
CellWidthMM, CellHeightMM float64
// GutterXMM and GutterYMM are the gaps between cells. Most die-cut stock
// has a horizontal gutter and none vertically.
GutterXMM, GutterYMM float64
// LabelCaption draws each cell's caption beneath its code.
LabelCaption bool
}
Layout is a grid of cells on a page.
A cell is where one code goes. The grid is described the way a label manufacturer describes it — offset to the first label, label size, gap to the next — rather than as a set of absolute positions, because that is what the datasheet gives and what a user measuring their own stock can supply.
func (Layout) CellRectMM ¶
CellRectMM returns the cell at index, in millimetres from the page's top-left corner with y increasing downwards.
Cells are numbered left to right, then top to bottom — reading order, which is the order someone peeling labels off a sheet expects. ok is false when index is outside the page's grid, which is how a caller walks a page.
func (Layout) Validate ¶
Validate reports whether the layout can be printed.
The check that matters is the fit: a grid whose columns are wider than the page produces a PDF that silently loses its right-hand labels, which is only discovered after someone has fed a sheet of adhesive stock through a printer. The error names the overflow in millimetres so the caller knows how much to take off.
type PageSize ¶
type PageSize struct {
// Name is the size's common name, e.g. "A4".
Name string
// WidthMM and HeightMM are the portrait dimensions.
WidthMM, HeightMM float64
}
PageSize is a named sheet of paper, in millimetres.
func PageByName ¶
PageByName returns a page size by its lowercase name.
type Template ¶
type Template struct {
// Name is the slug a caller asks for, e.g. "avery-l7160".
Name string
// Title is the human-readable stock description.
Title string
// Layout is the grid this stock defines.
Layout Layout
}
Template is a named label stock: a layout that matches a real product.
The numbers are the manufacturer's published dimensions, not measurements taken off a printout. Anything else drifts: a template that is a fraction of a millimetre out is invisible on the first row and half a label out by the bottom of the sheet.
func TemplateByName ¶
TemplateByName returns the stock with the given name. Lookup ignores case and surrounding space, because the name arrives from a query parameter.