rqrcode

package module
v0.0.0-...-6cb1347 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

README

go-ruby-rqrcode/rqrcode

rqrcode — go-ruby-rqrcode

Docs License Go Coverage

A pure-Go (no cgo) reimplementation of Ruby's rqrcode_core and rqrcode gems (MRI 4.0.5). It generates the QR-code module matrix deterministically — modes, error-correction levels, versions 1–40 with auto-selection, Reed–Solomon ECC, all eight mask patterns with penalty scoring, finder / alignment / timing patterns and format / version info — and renders it (SVG, ANSI, HTML, PNG) module-for-module and byte-for-byte as the gems do, without any Ruby runtime or a C QR library.

It is a QR backend for go-embedded-ruby, but is a standalone, reusable module — a sibling of go-ruby-regexp, go-ruby-erb and go-ruby-yaml.

What it is — and isn't. Building the QR matrix (segment encoding, RS error correction, mask selection, module layout) is fully deterministic and needs no interpreter, so it lives here as pure Go, matching the gems exactly. Binding RQRCode::QRCode to live Ruby objects is the host's job; this library hands back a plain [][]bool matrix and the renderers.

Features

Faithful port of rqrcode_core + rqrcode, validated against the gems on every supported platform:

  • All encoding modes — numeric, alphanumeric, byte (8-bit), plus multi-segment codes — with the gems' automatic mode detection.
  • All four EC levels:l / :m / :q / :h (default :h, as in the gem).
  • Versions 1–40 with the gem's smallest-that-fits auto-selection, or an explicit WithSize.
  • Reed–Solomon ECC over GF(256), block interleaving, and the exact QRMAXBITS / RS_BLOCK_TABLE capacity tables.
  • Mask selection — all eight mask predicates and the four-part penalty (get_lost_points) scoring, choosing the same mask as the gem.
  • Function patterns — finder + separators, alignment, timing, dark module, 15-bit BCH format info and 18-bit BCH version info (v ≥ 7).
  • RenderersAsSVG (both <rect> and the size-optimised <path>), AsANSI, AsHTML, ToString, and a pure-Go AsPNG (stdlib image/png, still CGO-free).

CGO-free, dependency-free, 100% test coverage, gofmt + go vet clean, and green across the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x) and three OSes.

Install

go get github.com/go-ruby-rqrcode/rqrcode

Usage

package main

import (
	"fmt"

	"github.com/go-ruby-rqrcode/rqrcode"
)

func main() {
	// RQRCode::QRCode.new("hello world", level: :h)
	qr, err := rqrcode.New("hello world", rqrcode.WithLevelSymbol("h"))
	if err != nil {
		panic(err)
	}

	fmt.Println(qr.Version)     // 2  (auto-selected smallest version)
	fmt.Println(qr.ModuleCount) // 25

	// The boolean module matrix (qr.Modules[row][col] == qrcode.modules).
	dark, _ := qr.Checked(0, 0)
	fmt.Println(dark) // true — top-left finder pattern

	fmt.Println(qr.String())                    // to_s
	fmt.Println(qr.AsSVG(rqrcode.SVGOptions{}))  // as_svg
	fmt.Println(qr.AsANSIDefault())              // as_ansi
	fmt.Println(qr.AsHTML())                     // as_html

	png, _ := qr.AsPNG(rqrcode.PNGOptions{})     // as_png (pure-Go image/png)
	_ = png
}

Multi-segment codes mirror passing an array of {data:, mode:} hashes:

qr, _ := rqrcode.NewMulti([]rqrcode.Segment{
	rqrcode.Seg("foo", rqrcode.ModeByte8bit),
	rqrcode.Seg("1234", rqrcode.ModeNumeric),
})

API

// New builds a QR code from a string (RQRCode::QRCode.new). Default level :h.
func New(data string, opts ...Option) (*QRCode, error)

// NewMulti builds a multi-segment code (array of {data:, mode:} hashes).
func NewMulti(segs []Segment, opts ...Option) (*QRCode, error)

type QRCode struct {
	Modules     [][]bool // dark/light matrix; Modules[row][col]
	ModuleCount int
	Version     int
	// ...
}
func (q *QRCode) Checked(row, col int) (bool, error) // checked?
func (q *QRCode) Mode() Mode
func (q *QRCode) ErrorCorrectionLevel() Level
func (q *QRCode) String() string                        // to_s (default x / space)
func (q *QRCode) ToString(opts StringOptions) string    // to_s(dark:, light:, quiet_zone_size:)
func (q *QRCode) AsSVG(opts SVGOptions) string          // as_svg (rect + path)
func (q *QRCode) AsANSI(opts ANSIOptions) string        // as_ansi
func (q *QRCode) AsANSIDefault() string                 // as_ansi with gem defaults
func (q *QRCode) AsHTML() string                        // as_html
func (q *QRCode) AsPNG(opts PNGOptions) ([]byte, error) // as_png (pure-Go)

// Options mirror the gems' keyword arguments.
func WithSize(v int) Option        // :size (QR version 1..40; 0 = auto)
func WithMaxSize(v int) Option     // :max_size
func WithLevel(l Level) Option     // :level (typed)
func WithLevelSymbol(s string) Option // :level as "l"/"m"/"q"/"h"
func WithMode(m Mode) Option       // :mode (typed)
func WithModeSymbol(s string) Option  // :mode as "number"/"alphanumeric"/"byte_8bit"

type Level int  // LevelL, LevelM, LevelQ, LevelH (values match QRERRORCORRECTLEVEL)
type Mode  int  // ModeNumeric, ModeAlphanumeric, ModeByte8bit

Tests & coverage

The suite pairs deterministic, gem-free golden tests (which alone hold coverage at 100%, so the qemu cross-arch and Windows lanes pass the gate) with a differential MRI oracle: a corpus of numeric / alphanumeric / byte payloads across every level and a spread of versions is generated here and compared — module-for-module and byte-for-byte — against the rqrcode_core / rqrcode gems run through the system ruby (matrix, to_s, as_svg rect + path, as_ansi, as_html). The oracle skips itself where the gems are absent.

COVERPKG=$(go list ./... | paste -sd, -)
go test -race -coverpkg="$COVERPKG" -coverprofile=cover.out ./...
go tool cover -func=cover.out | tail -1   # 100.0%

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-rqrcode/rqrcode authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package rqrcode is a pure-Go (CGO-free) faithful reimplementation of Ruby's rqrcode_core / rqrcode gems (MRI 4.0.5). It generates the QR-code module matrix deterministically and renders it (SVG / ANSI / HTML / PNG) exactly as the gems do, so a host such as go-embedded-ruby can bind RQRCode::QRCode without any Ruby runtime or a C QR library.

Value model

The generated matrix is a [][]bool where true is a dark module. A QRCode is built with New; renderers are methods that mirror rqrcode's `as_svg`, `as_ansi`, `as_html` and `as_png`. Everything here is fully deterministic given input + version (size) + level + mode, so it matches the gems' `to_a` / module layout module-for-module.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrArgument corresponds to RQRCodeCore::QRCodeArgumentError.
	ErrArgument = errors.New("rqrcode: argument error")
	// ErrRunTime corresponds to RQRCodeCore::QRCodeRunTimeError.
	ErrRunTime = errors.New("rqrcode: runtime error")
)

Sentinel errors mirroring the gem's QRCodeArgumentError / QRCodeRunTimeError.

Functions

This section is empty.

Types

type ANSIOptions

type ANSIOptions struct {
	Light         string // foreground escape (default "\033[47m")
	Dark          string // background escape (default "\033[40m")
	FillCharacter string // written cell (default "  ")
	QuietZoneSize int    // quiet-zone width (default 4); negative selects the default
}

ANSIOptions configures AsANSI, mirroring rqrcode's as_ansi option hash. Empty strings fall back to the gem defaults, and QuietZoneSize < 0 means "unset" so the default of 4 applies (0 is a meaningful value: no quiet zone).

type Level

type Level int

Level is a QR error-correction level (rqrcode's :l/:m/:q/:h symbols).

const (
	LevelM Level = 0 // 15% recovery (Psych-style value m => 0)
	LevelL Level = 1 // 7% recovery
	LevelH Level = 2 // 30% recovery
	LevelQ Level = 3 // 25% recovery
)

The four error-correction levels, matching RQRCodeCore::QRERRORCORRECTLEVEL.

func (Level) Symbol

func (l Level) Symbol() string

Symbol returns the rqrcode level symbol name ("l"/"m"/"q"/"h"), matching RQRCodeCore::QRCode#error_correction_level's key.

type Mode

type Mode int

Mode is a QR encoding mode.

const (
	ModeNumeric      Mode = 1 << 0 // 1
	ModeAlphanumeric Mode = 1 << 1 // 2
	ModeByte8bit     Mode = 1 << 2 // 4
)

The encoding modes matching RQRCodeCore::QRMODE.

type Option

type Option func(*Options)

Option mutates Options, matching rqrcode's keyword arguments.

func WithLevel

func WithLevel(l Level) Option

WithLevel sets the error-correction level (:level).

func WithLevelSymbol

func WithLevelSymbol(s string) Option

WithLevelSymbol sets the level from a symbol string (:l/:m/:q/:h).

func WithMaxSize

func WithMaxSize(v int) Option

WithMaxSize sets the maximum auto-selected version (:max_size).

func WithMode

func WithMode(m Mode) Option

WithMode forces an encoding mode (:mode).

func WithModeSymbol

func WithModeSymbol(s string) Option

WithModeSymbol forces a mode from a symbol (:number/:alphanumeric/:byte_8bit).

func WithSize

func WithSize(v int) Option

WithSize sets the QR version (:size). 0 keeps auto-selection.

type Options

type Options struct {
	// Size is the QR version (1..40). Zero means auto-select the smallest that fits.
	Size int
	// MaxSize caps auto-selection (default qrMaxSize, i.e. 40).
	MaxSize int
	// Level is the error-correction level; the zero value LevelM matches Ruby's
	// numeric m=0, so callers should use WithLevel / set it explicitly to get :h.
	Level Level

	// Mode forces an encoding mode; zero means auto-detect from the data.
	Mode Mode
	// contains filtered or unexported fields
}

Options configures New, mirroring RQRCodeCore::QRCode.new's option hash.

type PNGOptions

type PNGOptions struct {
	ModulePxSize  int         // pixels per module (default 6)
	BorderModules int         // quiet-zone width in modules (default 4)
	Color         color.Color // foreground (default black)
	Fill          color.Color // background (default white)
}

PNGOptions configures AsPNG. This renderer is a pure-Go (stdlib image/png, CGO=0) implementation of rqrcode's "Original" as_png sizing: each module is ModulePxSize pixels square and BorderModules modules of quiet zone surround the code. (The gem's chunky_png "Google" resize mode is intentionally not reproduced byte-for-byte, as it depends on chunky_png's own zlib encoder; the module geometry here is deterministic and standard.)

type QRCode

type QRCode struct {
	Modules     [][]bool // the dark/light module matrix (Modules[row][col])
	ModuleCount int      // side length in modules
	Version     int      // QR version (1..40)
	// contains filtered or unexported fields
}

QRCode is a generated QR code: the module matrix plus its metadata. It mirrors RQRCodeCore::QRCode's public attributes (modules, module_count, version).

func New

func New(data string, opts ...Option) (*QRCode, error)

New builds a QR code from a string, matching RQRCode::QRCode.new(string, ...) and RQRCodeCore::QRCode.new. The default level is :h (as in the gems).

func NewMulti

func NewMulti(segs []Segment, opts ...Option) (*QRCode, error)

NewMulti builds a multi-segment QR code, matching passing an array of {data:, mode:} hashes to RQRCodeCore::QRCode.new.

func (*QRCode) AsANSI

func (q *QRCode) AsANSI(opts ANSIOptions) string

AsANSI renders the QR code with ANSI background colors, matching RQRCode's as_ansi. The zero-value options reproduce the gem defaults (note: a zero QuietZoneSize means no quiet zone; use -1 or leave DefaultANSIOptions to get 4).

func (*QRCode) AsANSIDefault

func (q *QRCode) AsANSIDefault() string

AsANSIDefault renders with the gem's default options (quiet zone 4).

func (*QRCode) AsHTML

func (q *QRCode) AsHTML() string

AsHTML renders the QR code as an HTML table, matching RQRCode's as_html.

func (*QRCode) AsPNG

func (q *QRCode) AsPNG(opts PNGOptions) ([]byte, error)

AsPNG renders the QR code to PNG bytes with the given options, using the deterministic module-per-pixel geometry.

func (*QRCode) AsSVG

func (q *QRCode) AsSVG(opts SVGOptions) string

AsSVG renders the QR code as an SVG document, matching RQRCode's as_svg. The zero-value options reproduce the gem defaults.

func (*QRCode) Checked

func (q *QRCode) Checked(row, col int) (bool, error)

Checked reports whether the module at (row, col) is dark, matching RQRCodeCore::QRCode#checked? (note the row, col order).

func (*QRCode) ErrorCorrectionLevel

func (q *QRCode) ErrorCorrectionLevel() Level

ErrorCorrectionLevel returns the QR code's level.

func (*QRCode) Mode

func (q *QRCode) Mode() Mode

Mode returns the effective mode of the (first) data writer, mirroring RQRCodeCore::QRCode#mode.

func (*QRCode) String

func (q *QRCode) String() string

String renders the code with the gem's default to_s (dark "x", light " ").

func (*QRCode) ToString

func (q *QRCode) ToString(opts StringOptions) string

ToString renders the matrix as text, matching RQRCodeCore::QRCode#to_s. The zero-value options reproduce the gem's defaults (dark "x", light " ", no quiet zone).

type SVGOptions

type SVGOptions struct {
	Offset         int    // padding around the QR in pixels (default 0)
	OffsetX        int    // X padding; falls back to Offset when OffsetXSet is false
	OffsetXSet     bool   // whether OffsetX was explicitly provided
	OffsetY        int    // Y padding; falls back to Offset when OffsetYSet is false
	OffsetYSet     bool   // whether OffsetY was explicitly provided
	Fill           string // background color hex (no leading #); empty = none
	FillNamed      bool   // treat Fill as a named color (no "#" prefix)
	Color          string // foreground color hex (default "000")
	ColorNamed     bool   // treat Color as a named color (no "#" prefix)
	ShapeRendering string // default "crispEdges"
	ModuleSize     int    // pixel size of each module (default 11)
	Standalone     *bool  // full SVG file when true/nil; embeddable svg when false
	Viewbox        bool   // use viewBox instead of width/height
	UsePath        bool   // render with <path> instead of <rect>
	SVGAttributes  [][2]string
}

SVGOptions configures AsSVG, mirroring rqrcode's as_svg option hash.

type Segment

type Segment struct {
	Data string
	// Mode forces this segment's mode; zero auto-detects.
	Mode Mode
	// contains filtered or unexported fields
}

Segment is one piece of multi-segment data (rqrcode's {data:, mode:} hash).

func Seg

func Seg(data string, mode Mode) Segment

Seg builds a Segment with an explicit mode.

func SegAuto

func SegAuto(data string) Segment

SegAuto builds a Segment whose mode is auto-detected.

type StringOptions

type StringOptions struct {
	Dark          string // character(s) for a dark module (default "x")
	Light         string // character(s) for a light module (default " ")
	QuietZoneSize int    // quiet-zone width in modules (default 0)
}

StringOptions configures ToString, mirroring RQRCodeCore::QRCode#to_s options.

Jump to

Keyboard shortcuts

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