qr

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
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.

View Source
const ContentType = "image/svg+xml"

ContentType is what a QR response is served as.

View Source
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

View Source
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

func Render

func Render(content string, style Style) ([]byte, error)

Render encodes content and draws it, in one call, for the common case.

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

func Encode(content string, level Level) (*Code, error)

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

func (c *Code) Dark(x, y int) bool

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

func (c *Code) SVG(st Style) []byte

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

type FieldError struct {
	Field   string
	Code    string
	Message string
}

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.

const (
	LevelL Level = "L" // ~7% recoverable
	LevelM Level = "M" // ~15%
	LevelQ Level = "Q" // ~25%
	LevelH Level = "H" // ~30%
)

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.

Jump to

Keyboard shortcuts

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