Documentation
¶
Overview ¶
Package qr encodes a string as a QR code and draws it as SVG (M41).
**SVG only, and that is decision D11**: the output is vector text, so no image encoder joins the dependency set and no rasteriser runs on a request. A PNG download, if it is ever wanted, is an additive change here and nowhere else.
**The encoder is github.com/boombuler/barcode, MIT, with no module dependencies of its own** — see decisions.md, D72, for what it was weighed against. This package uses it for one thing: turning a string into a matrix of dark and light modules. Everything a reader can see — the quiet zone, the colours, the size — is drawn here, because `qr_codes.style` has to drive it and a library's own renderer would have its own opinions instead.
**Nothing an attacker controls reaches the output.** The SVG is built from integers and from colours that have already been parsed as `#rrggbb`, and it carries no title, no aria-label naming the destination, and no metadata. That is what makes it safe to inline into a dashboard page as `template.HTML`: the bytes cannot contain a `<` that did not come from this file. A QR code that announced its own URL to a screen reader would read better and would put a workspace-controlled string inside markup the template engine no longer escapes, so the surrounding page carries the label instead.
Index ¶
Constants ¶
const ( DefaultLevel = LevelM DefaultMargin = 4 DefaultScale = 8 // MinScale and MaxScale bound what a stored style may ask for. The ceiling // is not about pixels — SVG has none — but about the `width` attribute a // downloaded file carries into whatever opens it. MinScale = 2 MaxScale = 32 // MaxMargin. Beyond this the quiet zone is most of the picture. MaxMargin = 16 // DefaultForeground and DefaultBackground are dark-on-light, and the // background is always painted rather than left transparent. A QR code // inverted onto a dark page is refused by a large share of scanners, and a // transparent one becomes inverted the moment somebody views the dashboard // in dark mode. So the code carries its own background and does not follow // the theme; the frame around it does. See decisions.md, D74. DefaultForeground = "#000000" DefaultBackground = "#ffffff" )
Defaults. M is the level nearly every printed QR code in the world uses, and four modules of quiet zone is the minimum ISO/IEC 18004 specifies — below it scanners start failing against busy backgrounds. Eight pixels per module puts a short URL at roughly 300px, which is a size a phone camera reads from a screen without zooming.
const ContentType = "image/svg+xml"
ContentType is what a QR response is served as.
const MaxContent = 1024
MaxContent is the longest string this package will encode. Version 40 at level L holds 2953 bytes, and a short URL is two orders of magnitude below that; the bound exists so an oversized input is a sentence rather than a library error nobody can act on.
Variables ¶
var ErrTooLong = errors.New("too long to encode as a QR code")
ErrTooLong is returned for content past MaxContent.
Levels is every level a style may name, in the order a form should offer them.
Functions ¶
Types ¶
type Code ¶
type Code struct {
// Size is the width of the matrix in modules, quiet zone excluded.
Size int
// contains filtered or unexported fields
}
Code is an encoded matrix, before anything has been drawn.
func Encode ¶
Encode turns content into a matrix at the style's error-correction level.
The style's colours and sizes do not reach here: they change the drawing, not the encoding, which is why a workspace re-styling its code cannot change what the code says.
func (*Code) Dark ¶
Dark reports whether the module at (x, y) is dark. Out of range is light, which is what the quiet zone is.
func (*Code) SVG ¶
SVG draws the matrix. The style must already be normalized — Render is the entry point that guarantees it, and passing an unchecked one is a programming error rather than a runtime one.
**Dark modules are drawn as horizontal runs, one rect per run.** A rect per module is the obvious shape and produces roughly ten times the bytes for a version-10 code; a single path with move-and-draw commands is smaller still and cannot be read back by anything simpler than a path parser. Runs are the middle: about a quarter of the size of per-module rects, and a shape whose test can reconstruct the matrix and compare it to the encoder's.
type FieldError ¶
FieldError is one thing wrong with a style. Deliberately its own type rather than domain.FieldError: this package draws pictures and knows nothing about HTTP, and the service that calls it converts.
type Level ¶
type Level string
Level is the error-correction level, as ISO/IEC 18004 names them. A higher level survives more damage and costs modules, which makes the code denser at the same printed size.
type Style ¶
type Style struct {
Foreground string `json:"foreground,omitempty"`
Background string `json:"background,omitempty"`
Level Level `json:"level,omitempty"`
// Margin is the quiet zone, in modules.
Margin int `json:"margin,omitempty"`
// Scale is pixels per module, and decides only the `width` and `height`
// attributes. The drawing itself is in module units inside a viewBox, so a
// consumer that sizes the element with CSS gets the same code at any size.
Scale int `json:"scale,omitempty"`
}
Style is how a code is drawn. It is what `qr_codes.style` holds, field for field, and the zero value is the default style rather than a blank one — a style row that has never been written renders exactly as a link with no row at all.
func (Style) Normalize ¶
func (s Style) Normalize() (Style, []FieldError)
Normalize fills in the defaults and returns the field errors for anything it cannot. It is the only way a Style reaches the renderer, so every colour in an SVG this package emits has been through the parser below.