diff --git a/golang/examples/demo.go b/golang/examples/demo.go
new file mode 100644
index 0000000..53dd3f0
--- /dev/null
+++ b/golang/examples/demo.go
@@ -0,0 +1,231 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/nayuki/qrcodegen"
+ "github.com/nayuki/qrcodegen/mask"
+ "github.com/nayuki/qrcodegen/qrcodeecc"
+ "github.com/nayuki/qrcodegen/qrsegment"
+ "github.com/nayuki/qrcodegen/version"
+)
+
+// The main application program.
+func main() {
+ doBasicDemo()
+ doVarietyDemo()
+ doSegmentDemo()
+ doMaskDemo()
+}
+
+/*---- Demo suite ----*/
+
+// Creates a single QR Code, then prints it to the console.
+func doBasicDemo() {
+ text := "Hello, world!" // User-supplied Unicode text
+ errcorlevel := qrcodeecc.Low // Error correction level
+
+ // Make and print the QR Code symbol
+ qr, _ := qrcodegen.EncodeText(text, errcorlevel)
+ printQr(qr)
+ svg, _ := toSvgString(qr, 4)
+ fmt.Printf("%s", svg)
+}
+
+// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
+func doVarietyDemo() {
+ // Numeric mode encoding (3.33 bits per digit)
+ qr, _ := qrcodegen.EncodeText("314159265358979323846264338327950288419716939937510", qrcodeecc.Medium)
+ printQr(qr)
+
+ // Alphanumeric mode encoding (5.5 bits per character)
+ qr, _ = qrcodegen.EncodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", qrcodeecc.High)
+ printQr(qr)
+
+ // Unicode text as UTF-8
+ qr, _ = qrcodegen.EncodeText("こんにちwa、世界! αβγδ", qrcodeecc.Quartile)
+ printQr(qr)
+
+ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
+ qr, _ = qrcodegen.EncodeText(
+ strings.Join(
+ []string{
+ "Alice was beginning to get very tired of sitting by her sister on the bank, ",
+ "and of having nothing to do: once or twice she had peeped into the book her sister was reading, ",
+ "but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice ",
+ "'without pictures or conversations?' So she was considering in her own mind (as well as she could, ",
+ "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a ",
+ "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly ",
+ "a White Rabbit with pink eyes ran close by her.",
+ },
+ "",
+ ),
+ qrcodeecc.High,
+ )
+ printQr(qr)
+}
+
+// Creates QR Codes with manually specified segments for better compactness.
+func doSegmentDemo() {
+ // Illustration "silver"
+ silver0 := "THE SQUARE ROOT OF 2 IS 1."
+ silver1 := "41421356237309504880168872420969807856967187537694807317667973799"
+ qr, _ := qrcodegen.EncodeText(
+ strings.Join(
+ []string{
+ silver0,
+ silver1,
+ },
+ "",
+ ),
+ qrcodeecc.Low,
+ )
+ printQr(qr)
+
+ segs := []qrsegment.QrSegment{
+ qrsegment.MakeAlphanumeric(toChars(silver0)),
+ qrsegment.MakeNumeric(toChars(silver1)),
+ }
+ qr, _ = qrcodegen.EncodeSegments(segs, qrcodeecc.Low)
+ printQr(qr)
+
+ // Illustration "golden"
+ golden0 := "Golden ratio φ = 1."
+ golden1 := "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374"
+ golden2 := "......"
+ qr, _ = qrcodegen.EncodeText(
+ strings.Join(
+ []string{
+ golden0,
+ golden1,
+ golden2,
+ },
+ "",
+ ),
+ qrcodeecc.Low,
+ )
+ printQr(qr)
+
+ segs = []qrsegment.QrSegment{
+ qrsegment.MakeBytes([]byte(golden0)),
+ qrsegment.MakeNumeric(toChars(golden1)),
+ qrsegment.MakeAlphanumeric(toChars(golden2)),
+ }
+ qr, _ = qrcodegen.EncodeSegments(segs, qrcodeecc.Low)
+ printQr(qr)
+
+ // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
+ madoka := "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?"
+ qr, _ = qrcodegen.EncodeText(madoka, qrcodeecc.Low)
+ printQr(qr)
+
+ kanjichars := []uint32{ // Kanji mode encoding (13 bits per character)
+ 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
+ 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
+ 0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
+ 0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
+ 0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
+ 0x0000, 0x0208, 0x01FF, 0x0008,
+ }
+ bb := qrsegment.BitBuffer{}
+ for _, c := range kanjichars {
+ bb.AppendBits(c, 13)
+ }
+ segs = []qrsegment.QrSegment{
+ qrsegment.New(
+ qrsegment.ModeKanji,
+ uint(len(kanjichars)),
+ bb,
+ ),
+ }
+ qr, _ = qrcodegen.EncodeSegments(segs, qrcodeecc.Low)
+ printQr(qr)
+}
+
+// Creates QR Codes with the same size and contents but different mask patterns.
+func doMaskDemo() {
+ // Project Nayuki URL
+ segs := qrsegment.MakeSegments(toChars("https://www.nayuki.io/"))
+ qr, _ := qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.High, version.Min, version.Max, nil, true) // Automatic mask
+ printQr(qr)
+ m := mask.New(3)
+ qr, _ = qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.High, version.Min, version.Max, &m, true) // Force mask 3
+ printQr(qr)
+
+ // Chinese text as UTF-8
+ segs = qrsegment.MakeSegments(toChars("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"))
+ m = mask.New(0)
+ qr, _ = qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.Medium, version.Min, version.Max, &m, true) // Force mask 0
+ printQr(qr)
+ m = mask.New(1)
+ qr, _ = qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.Medium, version.Min, version.Max, &m, true) // Force mask 1
+ printQr(qr)
+ m = mask.New(5)
+ qr, _ = qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.Medium, version.Min, version.Max, &m, true) // Force mask 5
+ printQr(qr)
+ m = mask.New(7)
+ qr, _ = qrcodegen.EncodeSegmentsAdvanced(segs, qrcodeecc.Medium, version.Min, version.Max, &m, true) // Force mask 7
+ printQr(qr)
+}
+
+/*---- Utilities ----*/
+
+// Returns a string of SVG code for an image depicting
+// the given QR Code, with the given number of border modules.
+// The string always uses Unix newlines (\n), regardless of the platform.
+func toSvgString(qr *qrcodegen.QrCode, border int32) (string, error) {
+ if border < 0 {
+ return "", errors.New("Border must be non-negative")
+ }
+
+ var sb strings.Builder
+ sb.WriteString("\n")
+ sb.WriteString("\n")
+
+ // TODO: check overflow?
+ dimension := qr.Size() + border*2
+ sb.WriteString(fmt.Sprintf("\n")
+
+ return sb.String(), nil
+}
+
+// Prints the given QrCode object to the console.
+func printQr(qr *qrcodegen.QrCode) {
+ border := int32(4)
+
+ for y := -border; y < qr.Size()+border; y++ {
+ for x := -border; x < qr.Size()+border; x++ {
+ var c rune
+ if qr.GetModule(x, y) {
+ c = '█'
+ } else {
+ c = ' '
+ }
+ fmt.Printf("%c%c", c, c)
+ }
+ fmt.Println()
+ }
+ fmt.Println()
+}
+
+// Converts the given borrowed string slice to a new character vector.
+func toChars(str string) []rune {
+ return []rune(str)
+}
diff --git a/golang/go.mod b/golang/go.mod
new file mode 100644
index 0000000..2714f9c
--- /dev/null
+++ b/golang/go.mod
@@ -0,0 +1,3 @@
+module github.com/nayuki/qrcodegen
+
+go 1.16
diff --git a/golang/go.sum b/golang/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/golang/internal/bitx/bitx.go b/golang/internal/bitx/bitx.go
new file mode 100644
index 0000000..4ffa3b9
--- /dev/null
+++ b/golang/internal/bitx/bitx.go
@@ -0,0 +1,6 @@
+package bitx
+
+// GetBit returns true iff the i'th bit of x is set to 1.
+func GetBit(x uint32, i int32) bool {
+ return (x>>i)&1 != 0
+}
diff --git a/golang/internal/mathx/mathx.go b/golang/internal/mathx/mathx.go
new file mode 100644
index 0000000..e68f054
--- /dev/null
+++ b/golang/internal/mathx/mathx.go
@@ -0,0 +1,57 @@
+package mathx
+
+// TODO: refer to rust wrapping_neg(), not sure if same behavior on edge cases
+func WrappingNeg(x int) int {
+ if x > 0 {
+ return -x
+ }
+
+ return x
+}
+
+func MinUint(left, right uint) uint {
+ if left < right {
+ return left
+ }
+
+ return right
+}
+
+func MinInt(left, right int) int {
+ if left < right {
+ return left
+ }
+
+ return right
+}
+
+func MaxInt32(left, right int32) int32 {
+ if left > right {
+ return left
+ }
+
+ return right
+}
+
+func AbsInt32(x int32) int32 {
+ if x < 0 {
+ return -x
+ }
+ return x
+}
+
+func BoolToUint8(b bool) uint8 {
+ if b {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+func BoolToInt32(b bool) int32 {
+ if b {
+ return 1
+ } else {
+ return 0
+ }
+}
diff --git a/golang/mask/mask.go b/golang/mask/mask.go
new file mode 100644
index 0000000..a944b19
--- /dev/null
+++ b/golang/mask/mask.go
@@ -0,0 +1,19 @@
+package mask
+
+// Mask is a number between 0 and 7 (inclusive).
+type Mask uint8
+
+// New creates a mask object from the given number.
+func New(mask uint8) Mask {
+ // Panics if the number is outside the range [0, 7].
+ if mask > 7 {
+ panic("Mask value out of range")
+ }
+
+ return Mask(mask)
+}
+
+// Value returns the value, which is in the range [0, 7].
+func (m Mask) Value() uint8 {
+ return uint8(m)
+}
diff --git a/golang/qrcodeecc/qrcodeecc.go b/golang/qrcodeecc/qrcodeecc.go
new file mode 100644
index 0000000..69bd564
--- /dev/null
+++ b/golang/qrcodeecc/qrcodeecc.go
@@ -0,0 +1,49 @@
+package qrcodeecc
+
+/*---- QrCodeEcc functionality ----*/
+
+// QrCodeEcc is the error correction level in a QR Code symbol.
+type QrCodeEcc uint
+
+const (
+ // Low means the QR Code can tolerate about 7% erroneous codewords.
+ Low QrCodeEcc = 0
+ // Medium means the QR Code can tolerate about 15% erroneous codewords.
+ Medium QrCodeEcc = 1
+ // Quartile means the QR Code can tolerate about 25% erroneous codewords.
+ Quartile QrCodeEcc = 2
+ // High means the QR Code can tolerate about 30% erroneous codewords.
+ High QrCodeEcc = 3
+)
+
+// Ordinal returns an unsigned 2-bit integer (in the range 0 to 3).
+func (q QrCodeEcc) Ordinal() uint {
+ switch q {
+ case Low:
+ return 0
+ case Medium:
+ return 1
+ case Quartile:
+ return 2
+ case High:
+ return 3
+ default:
+ panic("unknown QrCodeEcc")
+ }
+}
+
+// FormatBits returns an unsigned 2-bit integer (in the range 0 to 3).
+func (q QrCodeEcc) FormatBits() uint8 {
+ switch q {
+ case Low:
+ return 1
+ case Medium:
+ return 0
+ case Quartile:
+ return 3
+ case High:
+ return 2
+ default:
+ panic("unknown QrCodeEcc")
+ }
+}
diff --git a/golang/qrcodegen.go b/golang/qrcodegen.go
new file mode 100644
index 0000000..200379c
--- /dev/null
+++ b/golang/qrcodegen.go
@@ -0,0 +1,889 @@
+package qrcodegen
+
+import (
+ "errors"
+ "fmt"
+ "math"
+
+ "github.com/nayuki/qrcodegen/internal/bitx"
+ "github.com/nayuki/qrcodegen/internal/mathx"
+ "github.com/nayuki/qrcodegen/mask"
+ "github.com/nayuki/qrcodegen/qrcodeecc"
+ "github.com/nayuki/qrcodegen/qrsegment"
+ "github.com/nayuki/qrcodegen/version"
+)
+
+/*---- Miscellaneous values ----*/
+
+var (
+ // ErrDataTooLong is the error type when the supplied data does not fit any QR Code version.
+ //
+ // Ways to handle this exception include:
+ //
+ // - Decrease the error correction level if it was greater than `QrCodeEcc::Low`.
+ // - If the `encode_segments_advanced()` function was called, then increase the maxversion
+ // argument if it was less than `Version::MAX`. (This advice does not apply to the
+ // other factory functions because they search all versions up to `Version::MAX`.)
+ // - Split the text data into better or optimal segments in order to reduce the number of bits required.
+ // - Change the text or binary data to be shorter.
+ // - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
+ // - Propagate the error upward to the caller/user.
+ ErrDataTooLong = errors.New("DataTooLong")
+)
+
+// alias
+type Version = version.Version
+type QrCodeEcc = qrcodeecc.QrCodeEcc
+type Mask = mask.Mask
+
+/*---- QrCode functionality ----*/
+
+// QrCode is a QR Code symbol, which is a type of two-dimension barcode.
+//
+// Invented by Denso Wave and described in the ISO/IEC 18004 standard.
+//
+// Instances of this struct represent an immutable square grid of dark and light cells.
+// The impl provides static factory functions to create a QR Code from text or binary data.
+// The struct and impl cover the QR Code Model 2 specification, supporting all versions
+// (sizes) from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
+//
+// Ways to create a QR Code object:
+//
+// - High level: Take the payload data and call `QrCode::encode_text()` or `QrCode::encode_binary()`.
+// - Mid level: Custom-make the list of segments and call
+// `QrCode::encode_segments()` or `QrCode::encode_segments_advanced()`.
+// - Low level: Custom-make the array of data codeword bytes (including segment
+// headers and final padding, excluding error correction codewords), supply the
+// appropriate version number, and call the `QrCode::encode_codewords()` constructor.
+//
+// (Note that all ways require supplying the desired error correction level.)
+type QrCode struct {
+ // Scalar parameters:
+
+ // The version number of this QR Code, which is between 1 and 40 (inclusive).
+ // This determines the size of this barcode.
+ version Version
+ // The width and height of this QR Code, measured in modules, between
+ // 21 and 177 (inclusive). This is equal to version * 4 + 17.
+ size int32
+ // The error correction level used in this QR Code.
+ errorcorrectionlevel QrCodeEcc
+ // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
+ // Even if a QR Code is created with automatic masking requested (mask = None),
+ // the resulting object still has a mask value between 0 and 7.
+ mask Mask
+
+ // Grids of modules/pixels, with dimensions of size*size:
+
+ // The modules of this QR Code (false = light, true = dark).
+ // Immutable after constructor finishes. Accessed through get_module().
+ modules []bool
+ // Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
+ isfunction []bool
+}
+
+/*---- Static factory functions (high level) ----*/
+
+// EncodeText returns a QR Code representing the given Unicode text string at the given error correction level.
+//
+// As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode
+// code points (not UTF-8 code units) if the low error correction level is used. The smallest possible
+// QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
+// the ecl argument if it can be done without increasing the version.
+//
+// Returns a wrapped `QrCode` if successful, or `Err` if the
+// data is too long to fit in any version at the given ECC level.
+func EncodeText(text string, ecl QrCodeEcc) (*QrCode, error) {
+ chrs := []rune(text)
+ segs := qrsegment.MakeSegments(chrs)
+
+ return EncodeSegments(segs, ecl)
+}
+
+// EncodeBinary returns a QR Code representing the given binary data at the given error correction level.
+//
+// This function always encodes using the binary segment mode, not any text mode. The maximum number of
+// bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+// The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+//
+// Returns a wrapped `QrCode` if successful, or `Err` if the
+// data is too long to fit in any version at the given ECC level.
+func EncodeBinary(data []uint8, ecl QrCodeEcc) (*QrCode, error) {
+ seg := qrsegment.MakeBytes(data)
+ segs := []qrsegment.QrSegment{seg}
+
+ return EncodeSegments(segs, ecl)
+}
+
+/*---- Static factory functions (mid level) ----*/
+
+// EncodeSegments returns a QR Code representing the given segments at the given error correction level.
+//
+// The smallest possible QR Code version is automatically chosen for the output. The ECC level
+// of the result may be higher than the ecl argument if it can be done without increasing the version.
+//
+// This function allows the user to create a custom sequence of segments that switches
+// between modes (such as alphanumeric and byte) to encode text in less space.
+// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`.
+//
+// Returns a wrapped `QrCode` if successful, or `Err` if the
+// data is too long to fit in any version at the given ECC level.
+func EncodeSegments(segs []qrsegment.QrSegment, ecl QrCodeEcc) (*QrCode, error) {
+ return EncodeSegmentsAdvanced(segs, ecl, version.Min, version.Max, nil, true)
+}
+
+// EncodeSegmentsAdvanced returns a QR Code representing the given segments with the given encoding parameters.
+//
+// The smallest possible QR Code version within the given range is automatically
+// chosen for the output. Iff boostecl is `true`, then the ECC level of the result
+// may be higher than the ecl argument if it can be done without increasing the
+// version. The mask number is either between 0 to 7 (inclusive) to force that
+// mask, or `None` to automatically choose an appropriate mask (which may be slow).
+//
+// This function allows the user to create a custom sequence of segments that switches
+// between modes (such as alphanumeric and byte) to encode text in less space.
+// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`.
+//
+// Returns a wrapped `QrCode` if successful, or `Err` if the data is too
+// long to fit in any version in the given range at the given ECC level.
+func EncodeSegmentsAdvanced(
+ segs []qrsegment.QrSegment,
+ ecl QrCodeEcc,
+ minversion Version,
+ maxversion Version,
+ mask *Mask,
+ boostecl bool,
+) (q *QrCode, err error) {
+ if minversion > maxversion {
+ panic("Invalid value")
+ }
+
+ // Find the minimal version number to use
+ ver := minversion
+ var datausedbits uint
+ for {
+ // Number of data bits available
+ datacapacitybits := getNumDataCodewords(ver, ecl) * 8
+ dataused := qrsegment.GetTotalBits(segs, ver)
+
+ // TODO: refactor to match closer to the semantics of rust counterpart map_or
+ mapOr := false
+ if dataused != nil {
+ mapOr = *dataused <= datacapacitybits
+ }
+
+ if mapOr {
+ datausedbits = *dataused // This version number is found to be suitable
+ break
+ } else if ver.Value() >= maxversion.Value() { // All versions in the range could not fit the given data
+ if dataused == nil {
+ return nil, fmt.Errorf("%w: Segment too long", ErrDataTooLong)
+ }
+ return nil, fmt.Errorf("%w: Data length = %v bits, Max capacity = %v bits", ErrDataTooLong, *dataused, datacapacitybits)
+ } else {
+ ver = version.New(ver.Value() + 1)
+ }
+ }
+
+ // Increase the error correction level while the data still fits in the current version number
+ for _, newecl := range []QrCodeEcc{qrcodeecc.Medium, qrcodeecc.Quartile, qrcodeecc.High} { // From low to high
+ if boostecl && datausedbits <= getNumDataCodewords(ver, newecl)*8 {
+ ecl = newecl
+ }
+ }
+
+ // Concatenate all segments to create the data bit string
+ bb := qrsegment.BitBuffer{}
+ for _, seg := range segs {
+ bb.AppendBits(seg.Mode().ModeBits(), 4)
+ bb.AppendBits(uint32(seg.NumChars()), seg.Mode().NumCharCountBits(ver))
+ bb = append(bb, seg.Data()...)
+ }
+ if len(bb) != int(datausedbits) {
+ panic("len(bb) != int(datausedbits)")
+ }
+
+ // Add terminator and pad up to a byte if applicable
+ datacapacitybits := getNumDataCodewords(ver, ecl) * 8
+ if len(bb) > int(datacapacitybits) {
+ panic("len(bb) > int(datacapacitybits)")
+ }
+ numzerobits := mathx.MinUint(4, datacapacitybits-uint(len(bb)))
+ bb.AppendBits(0, uint8(numzerobits))
+
+ // TODO: check edge case for WrappingNeg
+ numzerobits = uint(mathx.WrappingNeg(len(bb)) & 7)
+ bb.AppendBits(0, uint8(numzerobits))
+ if len(bb)%8 != 0 {
+ panic("len(bb)%8 != 0")
+ }
+
+ // TODO: refactor to match closer to the semantics of rust counterpart .iter().cycle()
+ // Pad with alternating bytes until data capacity is reached
+ for {
+ for _, padByte := range []uint32{0xEC, 0x11} {
+ if len(bb) >= int(datacapacitybits) {
+ goto Donepad
+ }
+ bb.AppendBits(padByte, 8)
+ }
+ }
+Donepad:
+
+ // Pack bits into bytes in big endian
+ datacodewords := make([]uint8, len(bb)/8)
+ for i, bit := range bb {
+ datacodewords[i>>3] |= mathx.BoolToUint8(bit) << (7 - (i & 7))
+ }
+
+ // Create the QR Code object
+ q = EncodeCodewords(ver, ecl, datacodewords, mask)
+
+ return q, nil
+}
+
+/*---- Constructor (low level) ----*/
+
+// EncodeCodewords creates a new QR Code with the given version number,
+// error correction level, data codeword bytes, and mask number.
+//
+// This is a low-level API that most users should not use directly.
+// A mid-level API is the `encode_segments()` function.
+func EncodeCodewords(ver Version, ecl QrCodeEcc, datacodewords []uint8, m *Mask) *QrCode {
+ size := uint(ver.Value())*4 + 17
+
+ result := &QrCode{
+ version: ver,
+ size: int32(size),
+ mask: mask.New(0), // Dummy value
+ errorcorrectionlevel: ecl,
+ modules: make([]bool, size*size), // Initially all light
+ isfunction: make([]bool, size*size),
+ }
+
+ // Compute ECC, draw modules
+ result.drawFunctionPatterns()
+ allcodewords := result.addEccAndInterleave(datacodewords)
+ result.drawCodewords(allcodewords)
+
+ // Do masking
+ if m == nil { // Automatically choose best mask
+ minpenalty := int32(math.MaxInt32)
+ for i, max := uint8(0), uint8(8); i < max; i++ {
+ newmask := mask.New(i)
+ result.applyMask(newmask)
+ result.drawFormatBits(newmask)
+ penalty := result.getPenaltyScore()
+ if penalty < minpenalty {
+ m = &newmask
+ minpenalty = penalty
+ }
+
+ result.applyMask(newmask) // Undoes the mask due to XOR
+ }
+ }
+ newmask := *m
+ result.mask = newmask
+ result.applyMask(newmask) // Apply the final choice of mask
+ result.drawFormatBits(newmask) // Overwrite old format bits
+
+ result.isfunction = result.isfunction[:0]
+ // TODO: need to implement rust shrink_to_fit() ?
+
+ return result
+}
+
+/*---- Public methods ----*/
+
+// Version returns this QR Code's version, in the range [1, 40].
+func (q QrCode) Version() Version {
+ return q.version
+}
+
+// Size returns this QR Code's size, in the range [21, 177].
+func (q QrCode) Size() int32 {
+ return q.size
+}
+
+// ErrorCorrectionLevel returns this QR Code's error correction level.
+func (q QrCode) ErrorCorrectionLevel() QrCodeEcc {
+ return q.errorcorrectionlevel
+}
+
+// Mask returns this QR Code's mask, in the range [0, 7].
+func (q QrCode) Mask() Mask {
+ return q.mask
+}
+
+// GetModule returns the color of the module (pixel) at the given coordinates,
+// which is `false` for light or `true` for dark.
+//
+// The top left corner has the coordinates (x=0, y=0). If the given
+// coordinates are out of bounds, then `false` (light) is returned.
+func (q QrCode) GetModule(x, y int32) bool {
+ return 0 <= x && x < q.size && 0 <= y && y < q.size && q.module(x, y)
+}
+
+// Returns the color of the module at the given coordinates, which must be in bounds.
+func (q QrCode) module(x, y int32) bool {
+ return q.modules[uint(y*q.size+x)]
+}
+
+// TODO: refactor to match closer to the semantics of rust counterpart
+// Returns a mutable reference to the module's color at the given coordinates, which must be in bounds.
+func (q *QrCode) moduleMut(x, y int32, mut bool) {
+ q.modules[uint(y*q.size+x)] = mut
+}
+
+/*---- Private helper methods for constructor: Drawing function modules ----*/
+
+// Reads this object's version field, and draws and marks all function modules.
+func (q *QrCode) drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ size := int(q.size)
+ for i := 0; i < size; i++ {
+ q.setFunctionModule(6, int32(i), i%2 == 0)
+ q.setFunctionModule(int32(i), 6, i%2 == 0)
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ q.drawFinderPattern(3, 3)
+ q.drawFinderPattern(q.size-4, 3)
+ q.drawFinderPattern(3, q.size-4)
+
+ // Draw numerous alignment patterns
+ alignpatpos := q.getAlignmentPatternPositions()
+ numalign := len(alignpatpos)
+ for i := 0; i < numalign; i++ {
+ for j := 0; j < numalign; j++ {
+ // Don't draw on the three finder corners
+ if !(i == 0 && j == 0 || i == 0 && j == numalign-1 || i == numalign-1 && j == 0) {
+ q.drawAlignmentPattern(alignpatpos[i], alignpatpos[j])
+ }
+ }
+ }
+
+ // Draw configuration data
+ q.drawFormatBits(mask.New(0)) // Dummy mask value; overwritten later in the constructor
+ q.drawVersion()
+}
+
+// Draws two copies of the format bits (with its own error correction code)
+// based on the given mask and this object's error correction level field.
+func (q *QrCode) drawFormatBits(mask Mask) {
+ // Calculate error correction code and pack bits
+ var bits uint32
+ {
+ // errorcorrectionlevel is uint2, mask is uint3
+ data := uint32(q.errorcorrectionlevel.FormatBits()<<3 | mask.Value())
+ rem := data
+ for i := 0; i < 10; i++ {
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537)
+ }
+ bits = (data<<10 | rem) ^ 0x5412 // uint15
+ }
+ if bits>>15 != 0 {
+ panic("bits>>15 != 0")
+ }
+
+ // Draw first copy
+ for i := int32(0); i < 6; i++ {
+ q.setFunctionModule(8, i, bitx.GetBit(bits, i))
+ }
+ q.setFunctionModule(8, 7, bitx.GetBit(bits, 6))
+ q.setFunctionModule(8, 8, bitx.GetBit(bits, 7))
+ q.setFunctionModule(7, 8, bitx.GetBit(bits, 8))
+ for i := int32(9); i < 15; i++ {
+ q.setFunctionModule(14-i, 8, bitx.GetBit(bits, i))
+ }
+
+ // Draw second copy
+ size := q.size
+ for i := int32(0); i < 8; i++ {
+ q.setFunctionModule(size-1-i, 8, bitx.GetBit(bits, i))
+ }
+ for i := int32(8); i < 15; i++ {
+ q.setFunctionModule(8, size-15+i, bitx.GetBit(bits, i))
+ }
+ q.setFunctionModule(8, size-8, true) // Always dark
+}
+
+// Draws two copies of the version bits (with its own error correction code),
+// based on this object's version field, iff 7 <= version <= 40.
+func (q *QrCode) drawVersion() {
+ if q.version < 7 {
+ return
+ }
+
+ // Calculate error correction code and pack bits
+ var bits uint32
+ {
+ data := uint32(q.version.Value()) // uint6, in the range [7, 40]
+ rem := data
+ for i := 0; i < 12; i++ {
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25)
+ }
+ bits = data<<12 | rem // uint18
+ }
+ if bits>>18 != 0 {
+ panic("bits>>18 != 0")
+ }
+
+ // Draw two copies
+ for i := int32(0); i < 18; i++ {
+ bit := bitx.GetBit(bits, i)
+ a := q.size - 11 + i%3
+ b := i / 3
+ q.setFunctionModule(a, b, bit)
+ q.setFunctionModule(b, a, bit)
+ }
+}
+
+// Draws a 9*9 finder pattern including the border separator,
+// with the center module at (x, y). Modules can be out of bounds.
+func (q *QrCode) drawFinderPattern(x, y int32) {
+ for dy := int32(-4); dy <= 4; dy++ {
+ for dx := int32(-4); dx <= 4; dx++ {
+ xx := x + dx
+ yy := y + dy
+ if 0 <= xx && xx < q.size && 0 <= yy && yy < q.size {
+ dist := mathx.MaxInt32(mathx.AbsInt32(dx), mathx.AbsInt32(dy)) // Chebyshev/infinity norm
+ q.setFunctionModule(xx, yy, dist != 2 && dist != 4)
+ }
+ }
+ }
+}
+
+// Draws a 5*5 alignment pattern, with the center module
+// at (x, y). All modules must be in bounds.
+func (q *QrCode) drawAlignmentPattern(x, y int32) {
+ for dy := int32(-2); dy <= 2; dy++ {
+ for dx := int32(-2); dx <= 2; dx++ {
+ q.setFunctionModule(x+dx, y+dy, mathx.MaxInt32(mathx.AbsInt32(dx), mathx.AbsInt32(dy)) != 1)
+ }
+ }
+}
+
+// Sets the color of a module and marks it as a function module.
+// Only used by the constructor. Coordinates must be in bounds.
+func (q *QrCode) setFunctionModule(x int32, y int32, isdark bool) {
+ q.moduleMut(x, y, isdark)
+ q.isfunction[(y*q.size + x)] = true
+}
+
+/*---- Private helper methods for constructor: Codewords and masking ----*/
+
+// Returns a new byte string representing the given data with the appropriate error correction
+// codewords appended to it, based on this object's version and error correction level.
+func (q *QrCode) addEccAndInterleave(data []uint8) []uint8 {
+ ver := q.version
+ ecl := q.errorcorrectionlevel
+ if len(data) != int(getNumDataCodewords(ver, ecl)) {
+ panic("Illegal argument")
+ }
+
+ // Calculate parameter numbers
+ numblocks := tableGet(NUM_ERROR_CORRECTION_BLOCKS, ver, ecl)
+ blockecclen := tableGet(ECC_CODEWORDS_PER_BLOCK, ver, ecl)
+ rawcodewords := getNumRawDataModules(ver) / 8
+ numshortblocks := numblocks - (rawcodewords % numblocks)
+ shortblocklen := rawcodewords / numblocks
+
+ // Split data into blocks and append ECC to each block
+ blocks := make([][]uint8, 0, numblocks)
+ rsdiv := reedSolomonComputeDivisor(blockecclen)
+
+ var k uint
+ for i, max := uint(0), numblocks; i < max; i++ {
+ datlen := shortblocklen - blockecclen + uint(mathx.BoolToUint8(i >= numshortblocks))
+ dat := make([]uint8, datlen)
+ _ = copy(dat, data[k:k+datlen])
+ k += datlen
+ ecc := reedSolomonComputeRemainder(dat, rsdiv)
+
+ if i < numshortblocks {
+ dat = append(dat, 0)
+ }
+ dat = append(dat, ecc...)
+ blocks = append(blocks, dat)
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ result := make([]uint8, 0, rawcodewords)
+ for i, max := uint(0), shortblocklen; i <= max; i++ {
+ for j, block := range blocks {
+ // Skip the padding byte in short blocks
+ if i != shortblocklen-blockecclen || uint(j) >= numshortblocks {
+ result = append(result, block[i])
+ }
+ }
+ }
+
+ return result
+}
+
+// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+// data area of this QR Code. Function modules need to be marked off before this is called.
+func (q *QrCode) drawCodewords(data []uint8) {
+ if uint(len(data)) != getNumRawDataModules(q.version)/8 {
+ panic("Illegal argument")
+ }
+
+ var i uint // Bit index into the data
+ // Do the funny zigzag scan
+ right := q.size - 1
+ for right >= 1 { // Index of right column in each column pair
+ if right == 6 {
+ right = 5
+ }
+ for vert := int32(0); vert < q.size; vert++ { // Vertical counter
+ for j := int32(0); j < 2; j++ {
+ x := right - j // Actual x coordinate
+ upward := (right+1)&2 == 0
+ var y int32
+ if upward {
+ y = q.size - 1 - vert
+ } else {
+ y = vert
+ }
+ if !q.isfunction[(y*q.size+x)] && i < uint(len(data)*8) {
+ q.moduleMut(x, y, bitx.GetBit(uint32(data[i>>3]), int32(7-(i&7))))
+ i += 1
+ }
+ // If this QR Code has any remainder bits (0 to 7), they were assigned as
+ // 0/false/light by the constructor and are left unchanged by this method
+ }
+ }
+ right -= 2
+ }
+
+ if i != uint(len(data)*8) {
+ panic("i != uint(len(data)*8)")
+ }
+}
+
+// XORs the codeword modules in this QR Code with the given mask pattern.
+// The function modules must be marked and the codeword bits must be drawn
+// before masking. Due to the arithmetic of XOR, calling apply_mask() with
+// the same mask value a second time will undo the mask. A final well-formed
+// QR Code needs exactly one (not zero, two, etc.) mask applied.
+func (q *QrCode) applyMask(mask Mask) {
+ for y := int32(0); y < q.size; y++ {
+ for x := int32(0); x < q.size; x++ {
+ var invert bool
+ switch mask.Value() {
+ case 0:
+ invert = (x+y)%2 == 0
+ case 1:
+ invert = y%2 == 0
+ case 2:
+ invert = x%3 == 0
+ case 3:
+ invert = (x+y)%3 == 0
+ case 4:
+ invert = (x/3+y/2)%2 == 0
+ case 5:
+ invert = x*y%2+x*y%3 == 0
+ case 6:
+ invert = (x*y%2+x*y%3)%2 == 0
+ case 7:
+ invert = ((x+y)%2+x*y%3)%2 == 0
+ default:
+ panic("unreachable")
+ }
+ newModule := q.module(x, y) != (invert && !q.isfunction[(y*q.size+x)])
+ q.moduleMut(x, y, newModule)
+ }
+ }
+}
+
+// Calculates and returns the penalty score based on state of this QR Code's current modules.
+// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
+func (q QrCode) getPenaltyScore() int32 {
+ var result int32
+ size := q.size
+
+ // Adjacent modules in row having same color, and finder-like patterns
+ for y := int32(0); y < size; y++ {
+ var runcolor bool
+ var runx int32
+ runhistory := newFinderPenalty(size)
+ for x := int32(0); x < size; x++ {
+ if q.module(x, y) == runcolor {
+ runx += 1
+ if runx == 5 {
+ result += PENALTY_N1
+ } else if runx > 5 {
+ result += 1
+ }
+ } else {
+ runhistory.addHistory(runx)
+ if !runcolor {
+ result += runhistory.countPatterns() * PENALTY_N3
+ }
+ runcolor = q.module(x, y)
+ runx = 1
+ }
+ }
+ result += runhistory.terminateAndCount(runcolor, runx) * PENALTY_N3
+ }
+
+ // Adjacent modules in column having same color, and finder-like patterns
+ for x := int32(0); x < size; x++ {
+ var runcolor bool
+ var runy int32
+ runhistory := newFinderPenalty(size)
+ for y := int32(0); y < size; y++ {
+ if q.module(x, y) == runcolor {
+ runy += 1
+ if runy == 5 {
+ result += PENALTY_N1
+ } else if runy > 5 {
+ result += 1
+ }
+ } else {
+ runhistory.addHistory(runy)
+ if !runcolor {
+ result += runhistory.countPatterns() * PENALTY_N3
+ }
+ runcolor = q.module(x, y)
+ runy = 1
+ }
+ }
+ result += runhistory.terminateAndCount(runcolor, runy) * PENALTY_N3
+ }
+
+ // 2*2 blocks of modules having same color
+ for y := int32(0); y < size-1; y++ {
+ for x := int32(0); x < size-1; x++ {
+ color := q.module(x, y)
+ if color == q.module(x+1, y) &&
+ color == q.module(x, y+1) &&
+ color == q.module(x+1, y+1) {
+ result += PENALTY_N2
+ }
+ }
+ }
+
+ // TODO: refactor to match closer to the semantics of rust counterpart for map().sum()
+ // Balance of dark and light modules
+ var dark int32
+ for _, mod := range q.modules {
+ dark += mathx.BoolToInt32(mod)
+ }
+ total := size * size // Note that size is odd, so dark/total != 1/2
+ // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
+ k := (mathx.AbsInt32((dark*20-total*10))+total-1)/total - 1
+ result += k * PENALTY_N4
+
+ return result
+}
+
+/*---- Private helper functions ----*/
+
+// Returns an ascending list of positions of alignment patterns for this version number.
+// Each position is in the range [0,177), and are used on both the x and y axes.
+// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
+func (q QrCode) getAlignmentPatternPositions() []int32 {
+ ver := q.version.Value()
+ if ver == 1 {
+ return []int32{}
+ } else {
+ numalign := int32(ver)/7 + 2
+ var step int32
+ if ver == 32 {
+ step = 26
+ } else {
+ step = (int32(ver)*4 + numalign*2 + 1) / (numalign*2 - 2) * 2
+ }
+ result := make([]int32, numalign)
+ for i := int32(0); i < numalign-1; i++ {
+ result[i] = q.size - 7 - i*step
+ }
+ result[numalign-1] = 6
+
+ // TODO: refactor to match closer to the semantics of rust counterpart, reverse()
+ invertedResult := make([]int32, numalign)
+ for i, val := range result {
+ invertedResult[numalign-1-int32(i)] = val
+ }
+
+ return invertedResult
+ }
+}
+
+// Returns the number of data bits that can be stored in a QR Code of the given version number, after
+// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
+// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
+func getNumRawDataModules(v Version) uint {
+ ver := uint(v.Value())
+ result := (16*ver+128)*ver + 64
+ if ver >= 2 {
+ numalign := ver/7 + 2
+ result -= (25*numalign-10)*numalign - 55
+ if ver >= 7 {
+ result -= 36
+ }
+ }
+ if result < 208 || result > 29648 {
+ panic("result < 208 || result > 29648")
+ }
+
+ return result
+}
+
+// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
+// QR Code of the given version number and error correction level, with remainder bits discarded.
+// This stateless pure function could be implemented as a (40*4)-cell lookup table.
+func getNumDataCodewords(ver Version, ecl QrCodeEcc) uint {
+ return getNumRawDataModules(ver)/8 - tableGet(ECC_CODEWORDS_PER_BLOCK, ver, ecl)*tableGet(NUM_ERROR_CORRECTION_BLOCKS, ver, ecl)
+}
+
+// Returns an entry from the given table based on the given values.
+func tableGet(table [4][41]int8, ver Version, ecl QrCodeEcc) uint {
+ return uint(table[ecl.Ordinal()][uint(ver.Value())])
+}
+
+// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
+// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
+func reedSolomonComputeDivisor(degree uint) []uint8 {
+ if degree < 1 || degree > 255 {
+ panic("Degree out of range")
+ }
+
+ // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
+ // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
+ result := make([]uint8, degree-1)
+ result = append(result, 1) // Start off with the monomial x^0
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // and drop the highest monomial term which is always 1x^degree.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ root := uint8(1)
+ for i := uint(0); i < degree; i++ { // Unused variable i
+ // Multiply the current product by (x - r^i)
+ for j := uint(0); j < degree; j++ {
+ result[j] = reedSolomonMultiply(result[j], root)
+ if j+1 < uint(len(result)) {
+ result[j] ^= result[j+1]
+ }
+ }
+ root = reedSolomonMultiply(root, 0x02)
+ }
+ return result
+}
+
+// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
+func reedSolomonComputeRemainder(data []uint8, divisor []uint8) []uint8 {
+ result := make([]uint8, len(divisor))
+ for _, b := range data { // Polynomial division
+ var pop uint8
+ pop, result = result[0], result[1:]
+ factor := b ^ pop
+ result = append(result, 0)
+
+ // TODO: refactor to match closer to the semantics of rust counterpart, zip()
+ iterLen := mathx.MinInt(len(result), len(divisor))
+ for i := 0; i < iterLen; i++ {
+ // x := result[i]
+ y := divisor[i]
+
+ result[i] ^= reedSolomonMultiply(y, factor)
+ }
+ }
+
+ return result
+}
+
+// Returns the product of the two given field elements modulo GF(2^8/0x11D).
+// All inputs are valid. This could be implemented as a 256*256 lookup table.
+func reedSolomonMultiply(x, y uint8) uint8 {
+ // Russian peasant multiplication
+ var z uint8
+ // TODO: refactor to match closer to the semantics of rust counterpart, rev()
+ for i := 7; i > -1; i-- {
+ z = (z << 1) ^ ((z >> 7) * 0x1D)
+ z ^= ((y >> i) & 1) * x
+ }
+
+ return z
+}
+
+/*---- Helper struct for get_penalty_score() ----*/
+
+type finderPenalty struct {
+ qrSize int32
+ runHistory [7]int32
+}
+
+func newFinderPenalty(size int32) *finderPenalty {
+ return &finderPenalty{
+ qrSize: size,
+ runHistory: [7]int32{},
+ }
+}
+
+// Pushes the given value to the front and drops the last value.
+func (p *finderPenalty) addHistory(currentrunlength int32) {
+ if p.runHistory[0] == 0 {
+ currentrunlength += p.qrSize // Add light border to initial run
+ }
+ rh := &p.runHistory
+ // TODO: refactor to match closer to the semantics of rust counterpart, rev()
+ for i := len(rh) - 1 - 1; i > -1; i-- {
+ p.runHistory[i+1] = rh[i]
+ }
+ rh[0] = currentrunlength
+}
+
+// Can only be called immediately after a light run is added, and returns either 0, 1, or 2.
+func (p finderPenalty) countPatterns() int32 {
+ rh := p.runHistory
+ n := rh[1]
+ if n > p.qrSize*3 {
+ panic("n > p.qrSize*3")
+ }
+ core := n > 0 && rh[2] == n && rh[3] == n*3 && rh[4] == n && rh[5] == n
+ return mathx.BoolToInt32(core && rh[0] >= n*4 && rh[6] >= n) + mathx.BoolToInt32(core && rh[6] >= n*4 && rh[0] >= n)
+}
+
+// Must be called at the end of a line (row or column) of modules.
+func (p *finderPenalty) terminateAndCount(currentruncolor bool, currentrunlength int32) int32 {
+ if currentruncolor { // Terminate dark run
+ p.addHistory(currentrunlength)
+ currentrunlength = 0
+ }
+ currentrunlength += p.qrSize // Add light border to final run
+ p.addHistory(currentrunlength)
+ return p.countPatterns()
+}
+
+/*---- Constants and tables ----*/
+
+// For use in getPenaltyScore(), when evaluating which mask is best.
+const (
+ PENALTY_N1 int32 = 3
+ PENALTY_N2 int32 = 3
+ PENALTY_N3 int32 = 40
+ PENALTY_N4 int32 = 10
+)
+
+var (
+ ECC_CODEWORDS_PER_BLOCK [4][41]int8 = [4][41]int8{
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
+ {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
+ {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
+ {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
+ }
+
+ NUM_ERROR_CORRECTION_BLOCKS [4][41]int8 = [4][41]int8{
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
+ {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
+ {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
+ {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
+ }
+)
diff --git a/golang/qrsegment/bitbuffer.go b/golang/qrsegment/bitbuffer.go
new file mode 100644
index 0000000..7a9db93
--- /dev/null
+++ b/golang/qrsegment/bitbuffer.go
@@ -0,0 +1,32 @@
+package qrsegment
+
+import "github.com/nayuki/qrcodegen/internal/bitx"
+
+/*---- Bit buffer functionality ----*/
+
+// BitBuffer is an appendable sequence of bits (0s and 1s).
+//
+// Mainly used by QrSegment.
+type BitBuffer []bool
+
+// AppendBits appends the given number of low-order bits of the given value to this buffer.
+//
+// Requires len ≤ 31 and val < 2len.
+func (b *BitBuffer) AppendBits(val uint32, len uint8) {
+ if len > 31 || (val>>len) != 0 {
+ panic("Value out of range")
+ }
+
+ // TODO: refactor to match closer to the semantics of rust counterpart, rev()
+ if len == 0 {
+ return
+ }
+ tmp := make([]bool, len)
+ for i := int32(len - 1); i > -1; i-- { // Append bit by bit
+ v := bitx.GetBit(val, i)
+ tmp[int32(len-1)-i] = v
+ }
+
+ res := append([]bool(*b), tmp...)
+ *b = BitBuffer(res)
+}
diff --git a/golang/qrsegment/mode.go b/golang/qrsegment/mode.go
new file mode 100644
index 0000000..f811eb0
--- /dev/null
+++ b/golang/qrsegment/mode.go
@@ -0,0 +1,59 @@
+package qrsegment
+
+import "github.com/nayuki/qrcodegen/version"
+
+/*---- QrSegmentMode functionality ----*/
+
+// QrSegmentMode describes how a segment's data bits are interpreted.
+type QrSegmentMode uint32
+
+const (
+ ModeNumeric QrSegmentMode = iota
+ ModeAlphanumeric
+ ModeByte
+ ModeKanji
+ ModeEci
+)
+
+// ModeBits returns an unsigned 4-bit integer value (range 0 to 15)
+// representing the mode indicator bits for this mode object.
+func (m QrSegmentMode) ModeBits() uint32 {
+ switch m {
+ case ModeNumeric:
+ return 0x1
+ case ModeAlphanumeric:
+ return 0x2
+ case ModeByte:
+ return 0x4
+ case ModeKanji:
+ return 0x8
+ case ModeEci:
+ return 0x7
+ default:
+ panic("unknown QrSegmentMode")
+ }
+}
+
+// NumCharCountBits returns the bit width of the character count field for a segment in this mode
+// in a QR Code at the given version number. The result is in the range [0, 16].
+func (m QrSegmentMode) NumCharCountBits(ver version.Version) uint8 {
+ var tmp [3]uint8
+
+ switch m {
+ case ModeNumeric:
+ tmp = [3]uint8{10, 12, 14}
+ case ModeAlphanumeric:
+ tmp = [3]uint8{9, 11, 13}
+ case ModeByte:
+ tmp = [3]uint8{8, 16, 16}
+ case ModeKanji:
+ tmp = [3]uint8{8, 10, 12}
+ case ModeEci:
+ tmp = [3]uint8{0, 0, 0}
+ default:
+ panic("unknown QrSegmentMode")
+ }
+
+ idx := (ver.Value() + 7) / 17
+ return tmp[idx]
+}
diff --git a/golang/qrsegment/qrsegment.go b/golang/qrsegment/qrsegment.go
new file mode 100644
index 0000000..990a5ea
--- /dev/null
+++ b/golang/qrsegment/qrsegment.go
@@ -0,0 +1,260 @@
+package qrsegment
+
+import (
+ "github.com/nayuki/qrcodegen/version"
+)
+
+// The set of all legal characters in alphanumeric mode,
+// where each character value maps to the index in the string.
+var (
+ ALPHANUMERIC_CHARSET = [45]rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ ' ', '$', '%', '*', '+', '-', '.', '/', ':'}
+ alphanumericCharset = make(map[rune]int, 45)
+)
+
+func init() {
+ for i, c := range ALPHANUMERIC_CHARSET {
+ alphanumericCharset[c] = i
+ }
+}
+
+/*---- QrSegment functionality ----*/
+
+// QrSegment is a segment of character/binary/control data in a QR Code symbol.
+//
+// Instances of this struct are immutable.
+//
+// The mid-level way to create a segment is to take the payload data
+// and call a static factory function such as `QrSegment::make_numeric()`.
+// The low-level way to create a segment is to custom-make the bit buffer
+// and call the `QrSegment::new()` constructor with appropriate values.
+//
+// This segment struct imposes no length restrictions, but QR Codes have restrictions.
+// Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
+// Any segment longer than this is meaningless for the purpose of generating QR Codes.
+type QrSegment struct {
+ // The mode indicator of this segment. Accessed through mode().
+ mode QrSegmentMode
+ // The length of this segment's unencoded data. Measured in characters for
+ // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
+ // Not the same as the data's bit length. Accessed through num_chars().
+ numchars uint
+ // The data bits of this segment. Accessed through data().
+ data []bool
+}
+
+/*---- Static factory functions (mid level) ----*/
+
+// MakeBytes returns a segment representing the given binary data encoded in byte mode.
+//
+// All input byte slices are acceptable.
+//
+// Any text string can be converted to UTF-8 bytes and encoded as a byte mode segment.
+func MakeBytes(data []uint8) QrSegment {
+ bb := make(BitBuffer, 0, len(data)*8)
+ for _, b := range data {
+ bb.AppendBits(uint32(b), 8)
+ }
+
+ return QrSegment{
+ mode: ModeByte,
+ numchars: uint(len(data)),
+ data: bb,
+ }
+}
+
+// MakeNumeric returns a segment representing the given string of decimal digits encoded in numeric mode.
+//
+// Panics if the string contains non-digit characters.
+func MakeNumeric(text []rune) QrSegment {
+ bb := make(BitBuffer, 0, len(text)*3+(len(text)+2)/3)
+ var accumdata uint32
+ var accumcount uint8
+ for _, c := range text {
+ if '0' > c || c > '9' {
+ panic("String contains non-numeric characters")
+ }
+ accumdata = accumdata*10 + uint32(c) - uint32('0')
+ accumcount += 1
+ if accumcount == 3 {
+ bb.AppendBits(accumdata, 10)
+ accumdata = 0
+ accumcount = 0
+ }
+ }
+ if accumcount > 0 { // 1 or 2 digits remaining
+ bb.AppendBits(accumdata, accumcount*3+1)
+ }
+
+ return QrSegment{
+ mode: ModeNumeric,
+ numchars: uint(len(text)),
+ data: bb,
+ }
+}
+
+// MakeAlphanumeric returns a segment representing the given text string encoded in alphanumeric mode.
+//
+// The characters allowed are: 0 to 9, A to Z (uppercase only), space,
+// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+//
+// Panics if the string contains non-encodable characters.
+func MakeAlphanumeric(text []rune) QrSegment {
+ bb := make(BitBuffer, 0, len(text)*5+(len(text)+1)/2)
+ var accumdata uint32
+ var accumcount uint32
+ for _, c := range text {
+ idx, ok := alphanumericCharset[c]
+ if !ok {
+ panic("String contains unencodable characters in alphanumeric mode")
+ }
+ accumdata = accumdata*45 + uint32(idx)
+ accumcount += 1
+ if accumcount == 2 {
+ bb.AppendBits(accumdata, 11)
+ accumdata = 0
+ accumcount = 0
+ }
+ }
+ if accumcount > 0 { // 1 character remaining
+ bb.AppendBits(accumdata, 6)
+ }
+
+ return QrSegment{
+ mode: ModeAlphanumeric,
+ numchars: uint(len(text)),
+ data: bb,
+ }
+}
+
+// MakeSegments returns a list of zero or more segments to represent the given Unicode text string.
+//
+// The result may use various segment modes and switch
+// modes to optimize the length of the bit stream.
+func MakeSegments(text []rune) []QrSegment {
+ if len(text) == 0 {
+ return []QrSegment{}
+ }
+
+ var seg QrSegment
+ if IsNumeric(text) {
+ seg = MakeNumeric(text)
+ } else if IsAlphanumeric(text) {
+ seg = MakeAlphanumeric(text)
+ } else {
+ seg = MakeBytes([]byte(string(text)))
+ }
+
+ return []QrSegment{seg}
+}
+
+// MakeEci returns a segment representing an Extended Channel Interpretation
+// (ECI) designator with the given assignment value.
+func MakeEci(assignval uint32) QrSegment {
+ bb := make(BitBuffer, 0, 24)
+ if assignval < (1 << 7) {
+ bb.AppendBits(assignval, 0)
+ } else if assignval < (1 << 14) {
+ bb.AppendBits(2, 2)
+ bb.AppendBits(assignval, 14)
+ } else if assignval < 1_000_000 {
+ bb.AppendBits(6, 3)
+ bb.AppendBits(assignval, 21)
+ } else {
+ panic("ECI assignment value out of range")
+ }
+
+ return QrSegment{
+ mode: ModeEci,
+ numchars: 0,
+ data: bb,
+ }
+}
+
+/*---- Constructor (low level) ----*/
+
+// New creates a new QR Code segment with the given attributes and data.
+//
+// The character count (numchars) must agree with the mode and
+// the bit buffer length, but the constraint isn't checked.
+func New(mode QrSegmentMode, numchars uint, data []bool) QrSegment {
+ return QrSegment{
+ mode: mode,
+ numchars: numchars,
+ data: data,
+ }
+}
+
+/*---- Instance field getters ----*/
+
+// Mode returns the mode indicator of this segment.
+func (s QrSegment) Mode() QrSegmentMode {
+ return s.mode
+}
+
+// NumChars returns the character count field of this segment.
+func (s QrSegment) NumChars() uint {
+ return s.numchars
+}
+
+// Data returns the data bits of this segment.
+func (s QrSegment) Data() []bool {
+ return s.data
+}
+
+/*---- Other static functions ----*/
+
+// GetTotalBits calculates and returns the number of bits needed to encode the given
+// segments at the given version. The result is None if a segment has too many
+// characters to fit its length field, or the total bits exceeds usize::MAX.
+func GetTotalBits(segs []QrSegment, ver version.Version) *uint {
+ var result uint
+ for _, seg := range segs {
+ ccbits := seg.mode.NumCharCountBits(ver)
+ // TODO: refactor to match closer to the semantics of rust counterpart to check overflow
+ // // ccbits can be as large as 16, but usize can be as small as 16
+ // if let Some(limit) = 1usize.checked_shl(u32::from(ccbits)) {
+ // if seg.numchars >= limit {
+ // return None; // The segment's length doesn't fit the field's bit width
+ // }
+ // }
+ limit := uint(1) << ccbits
+ if seg.numchars >= limit {
+ return nil // The segment's length doesn't fit the field's bit width
+ }
+
+ result += 4 + uint(ccbits)
+ result += uint(len(seg.data))
+ }
+
+ return &result
+}
+
+// IsNumeric tests whether the given string can be encoded as a segment in numeric mode.
+//
+// A string is encodable iff each character is in the range 0 to 9.
+func IsNumeric(text []rune) bool {
+ for _, c := range text {
+ if c < '0' || c > '9' {
+ return false
+ }
+ }
+
+ return true
+}
+
+// IsAlphanumeric tests whether the given string can be encoded as a segment in alphanumeric mode.
+//
+// A string is encodable iff each character is in the following set: 0 to 9, A to Z
+// (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+func IsAlphanumeric(text []rune) bool {
+ for _, c := range text {
+ _, ok := alphanumericCharset[c]
+ if !ok {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/golang/version/version.go b/golang/version/version.go
new file mode 100644
index 0000000..0671e9c
--- /dev/null
+++ b/golang/version/version.go
@@ -0,0 +1,27 @@
+package version
+
+// Version is a number between 1 and 40 (inclusive).
+type Version uint8
+
+const (
+ // Min is the minimum version number supported in the QR Code Model 2 standard.
+ Min = Version(1)
+ // Max is the maximum version number supported in the QR Code Model 2 standard.
+ Max = Version(40)
+)
+
+// New creates a version object from the given number.
+//
+// Panics if the number is outside the range [1, 40].
+func New(ver uint8) Version {
+ if ver < uint8(Min) || ver > uint8(Max) {
+ panic("Version number out of range")
+ }
+
+ return Version(ver)
+}
+
+// Value returns the value, which is in the range [1, 40].
+func (v Version) Value() uint8 {
+ return uint8(v)
+}