Browse Source

Initial commit

Tom Harwood 11 years ago
commit
6b7676c4bd
22 changed files with 7431 additions and 0 deletions
  1. 19 0
      LICENSE
  2. 0 0
      README
  3. 263 0
      bitset/bitset.go
  4. 321 0
      bitset/bitset_test.go
  5. 454 0
      encoder.go
  6. 311 0
      encoder_test.go
  7. 34 0
      example_test.go
  8. 454 0
      qrcode.go
  9. 227 0
      qrcode_decode_test.go
  10. 156 0
      qrcode_test.go
  11. 387 0
      reedsolomon/gf2_8.go
  12. 83 0
      reedsolomon/gf2_8_test.go
  13. 216 0
      reedsolomon/gf_poly.go
  14. 182 0
      reedsolomon/gf_poly_test.go
  15. 73 0
      reedsolomon/reed_solomon.go
  16. 89 0
      reedsolomon/reed_solomon_test.go
  17. 309 0
      regular_symbol.go
  18. 32 0
      regular_symbol_test.go
  19. 280 0
      symbol.go
  20. 333 0
      symbol_test.go
  21. 3050 0
      version.go
  22. 158 0
      version_test.go

+ 19 - 0
LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2014 Tom Harwood
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 0 - 0
README


+ 263 - 0
bitset/bitset.go

@@ -0,0 +1,263 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+// Package bitset implements an append only bit array.
+//
+// To create a Bitset and append some bits:
+//	                                  // Bitset Contents
+//	b := bitset.New()                 // {}
+//	b.AppendBools(true, true, false)  // {1, 1, 0}
+//	b.AppendBools(true)               // {1, 1, 0, 1}
+//	b.AppendValue(0x02, 4)            // {1, 1, 0, 1, 0, 0, 1, 0}
+//
+// To read values:
+//
+//	len := b.Len()                    // 8
+//	v := b.At(0)                      // 1
+//	v = b.At(1)                       // 1
+//	v = b.At(2)                       // 0
+//	v = b.At(8)                       // 0
+package bitset
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+)
+
+const (
+	b0 = false
+	b1 = true
+)
+
+// Bitset stores an array of bits.
+type Bitset struct {
+	// The number of bits stored.
+	numBits int
+
+	// Storage for individual bits.
+	bits []byte
+}
+
+// New returns an initialised Bitset with optional initial bits v.
+func New(v ...bool) *Bitset {
+	b := &Bitset{numBits: 0, bits: make([]byte, 0)}
+	b.AppendBools(v...)
+
+	return b
+}
+
+func Clone(from *Bitset) *Bitset {
+	return &Bitset{numBits: from.numBits, bits: from.bits[:]}
+}
+
+func (b *Bitset) Substr(start int, end int) *Bitset {
+	if start > end || end > b.numBits {
+		log.Panicf("Out of range start=%d end=%d numBits=%d", start, end, b.numBits)
+	}
+
+	result := New()
+	result.ensureCapacity(end - start)
+
+	for i := start; i < end; i++ {
+		if b.At(i) {
+			result.bits[result.numBits/8] |= 0x80 >> uint(result.numBits%8)
+		}
+		result.numBits++
+	}
+
+	return result
+}
+
+func NewFromBase2String(b2string string) *Bitset {
+	b := &Bitset{numBits: 0, bits: make([]byte, 0)}
+
+	for _, c := range b2string {
+		switch c {
+		case '1':
+			b.AppendBools(true)
+		case '0':
+			b.AppendBools(false)
+		case ' ':
+		default:
+			log.Panicf("Invalid char %c in NewFromBase2String", c)
+		}
+	}
+
+	return b
+}
+
+// AppendBytes appends a list of whole bytes.
+func (b *Bitset) AppendBytes(data []byte) {
+	for _, d := range data {
+		b.AppendByte(d, 8)
+	}
+}
+
+// AppendBytes appends the |numBits| least significant bits from |byte|.
+func (b *Bitset) AppendByte(bits byte, numBits int) {
+	b.ensureCapacity(numBits)
+
+	if numBits > 8 {
+		log.Panicf("numBits %d out of range 0-8", numBits)
+	}
+
+	for i := numBits - 1; i >= 0; i-- {
+		if bits&(1<<uint(i)) != 0 {
+			b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
+		}
+
+		b.numBits++
+	}
+}
+
+// AppendValue appends the |numBits| least significant bits from |value|.
+func (b *Bitset) AppendUint32(value uint32, numBits int) {
+	b.ensureCapacity(numBits)
+
+	if numBits > 32 {
+		log.Panicf("numBits %d out of range 0-32", numBits)
+	}
+
+	for i := numBits - 1; i >= 0; i-- {
+		if value&(1<<uint(i)) != 0 {
+			b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
+		}
+
+		b.numBits++
+	}
+}
+
+// ensureCapacity ensures the Bitset can store an additional |numBits|.
+//
+// The underlying array is expanded if necessary. To prevent frequent
+// reallocation, expanding the underlying array at least doubles its capacity.
+func (b *Bitset) ensureCapacity(numBits int) {
+	numBits += b.numBits
+
+	newNumBytes := numBits / 8
+	if numBits%8 != 0 {
+		newNumBytes++
+	}
+
+	if len(b.bits) >= newNumBytes {
+		return
+	}
+
+	b.bits = append(b.bits, make([]byte, newNumBytes+2*len(b.bits))...)
+}
+
+// Append bits copied from |other|.
+//
+// The new length is b.Len() + other.Len().
+func (b *Bitset) Append(other *Bitset) {
+	b.ensureCapacity(other.numBits)
+
+	for i := 0; i < other.numBits; i++ {
+		if other.At(i) {
+			b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
+		}
+		b.numBits++
+	}
+}
+
+// AppendBools appends bits to the Bitset.
+func (b *Bitset) AppendBools(bits ...bool) {
+	b.ensureCapacity(len(bits))
+
+	for _, v := range bits {
+		if v {
+			b.bits[b.numBits/8] |= 0x80 >> uint(b.numBits%8)
+		}
+		b.numBits++
+	}
+}
+
+// AppendBools appends bits to the Bitset.
+func (b *Bitset) AppendNumBools(num int, value bool) {
+	for i := 0; i < num; i++ {
+		b.AppendBools(value)
+	}
+}
+
+// String returns a human readable representation of the Bitset's contents.
+func (b *Bitset) String() string {
+	var bitString string
+	for i := 0; i < b.numBits; i++ {
+		if (i % 8) == 0 {
+			bitString += " "
+		}
+
+		if (b.bits[i/8] & (0x80 >> byte(i%8))) != 0 {
+			bitString += "1"
+		} else {
+			bitString += "0"
+		}
+	}
+
+	return fmt.Sprintf("numBits=%d, bits=%s", b.numBits, bitString)
+}
+
+// Len returns the length of the Bitset in bits.
+func (b *Bitset) Len() int {
+	return b.numBits
+}
+
+// Bits returns the contents of the Bitset.
+func (b *Bitset) Bits() []bool {
+	result := make([]bool, b.numBits)
+
+	var i int
+	for i = 0; i < b.numBits; i++ {
+		result[i] = (b.bits[i/8] & (0x80 >> byte(i%8))) != 0
+	}
+
+	return result
+}
+
+// At returns the value of the bit at |index|.
+func (b *Bitset) At(index int) bool {
+	if index >= b.numBits {
+		log.Panicf("Index %d out of range", index)
+	}
+
+	return (b.bits[index/8] & (0x80 >> byte(index%8))) != 0
+}
+
+func (b *Bitset) Equals(other *Bitset) bool {
+	if b.numBits != other.numBits {
+		return false
+	}
+
+	if !bytes.Equal(b.bits[0:b.numBits/8], other.bits[0:b.numBits/8]) {
+		return false
+	}
+
+	for i := 8 * (b.numBits / 8); i < b.numBits; i++ {
+		a := (b.bits[i/8] & (0x80 >> byte(i%8)))
+		b := (other.bits[i/8] & (0x80 >> byte(i%8)))
+
+		if a != b {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (b *Bitset) ByteAt(index int) byte {
+	if index >= b.numBits {
+		log.Panicf("Index %d out of range", index)
+	}
+
+	var result byte = 0
+
+	for i := index; i < index+8 && i < b.numBits; i++ {
+		result <<= 1
+		if b.At(i) {
+			result |= 1
+		}
+	}
+
+	return result
+}

+ 321 - 0
bitset/bitset_test.go

@@ -0,0 +1,321 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package bitset
+
+import (
+	rand "math/rand"
+	"testing"
+)
+
+func TestNewBitset(t *testing.T) {
+	tests := [][]bool{
+		[]bool{},
+		[]bool{b1},
+		[]bool{b0},
+		[]bool{b1, b0},
+		[]bool{b1, b0, b1},
+		[]bool{b0, b0, b1},
+	}
+
+	for _, v := range tests {
+		result := New(v...)
+
+		if !equal(result.Bits(), v) {
+			t.Errorf("%s", result.String())
+			t.Errorf("%v => %v, want %v", v, result.Bits(), v)
+		}
+	}
+}
+
+func TestAppend(t *testing.T) {
+	randomBools := make([]bool, 128)
+
+	rng := rand.New(rand.NewSource(1))
+
+	for i := 0; i < len(randomBools); i++ {
+		randomBools[i] = rng.Intn(2) == 1
+	}
+
+	for i := 0; i < len(randomBools)-1; i++ {
+		a := New(randomBools[0:i]...)
+		b := New(randomBools[i:]...)
+
+		a.Append(b)
+
+		if !equal(a.Bits(), randomBools) {
+			t.Errorf("got %v, want %v", a.Bits(), randomBools)
+		}
+	}
+}
+
+func TestAppendByte(t *testing.T) {
+	tests := []struct {
+		initial  *Bitset
+		value    byte
+		numBits  int
+		expected *Bitset
+	}{
+		{
+			New(),
+			0x01,
+			1,
+			New(b1),
+		},
+		{
+			New(b1),
+			0x01,
+			1,
+			New(b1, b1),
+		},
+		{
+			New(b0),
+			0x01,
+			1,
+			New(b0, b1),
+		},
+		{
+			New(b1, b0, b1, b0, b1, b0, b1),
+			0xAA, // 0b10101010
+			2,
+			New(b1, b0, b1, b0, b1, b0, b1, b1, b0),
+		},
+		{
+			New(b1, b0, b1, b0, b1, b0, b1),
+			0xAA, // 0b10101010
+			8,
+			New(b1, b0, b1, b0, b1, b0, b1, b1, b0, b1, b0, b1, b0, b1, b0),
+		},
+	}
+
+	for _, test := range tests {
+		test.initial.AppendByte(test.value, test.numBits)
+		if !equal(test.initial.Bits(), test.expected.Bits()) {
+			t.Errorf("Got %v, expected %v", test.initial.Bits(),
+				test.expected.Bits())
+		}
+	}
+}
+
+func TestAppendUint32(t *testing.T) {
+	tests := []struct {
+		initial  *Bitset
+		value    uint32
+		numBits  int
+		expected *Bitset
+	}{
+		{
+			New(),
+			0xAAAAAAAF,
+			4,
+			New(b1, b1, b1, b1),
+		},
+		{
+			New(),
+			0xFFFFFFFF,
+			32,
+			New(b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1,
+				b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1),
+		},
+		{
+			New(),
+			0x0,
+			32,
+			New(b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0,
+				b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0),
+		},
+		{
+			New(),
+			0xAAAAAAAA,
+			32,
+			New(b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1,
+				b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0),
+		},
+		{
+			New(),
+			0xAAAAAAAA,
+			31,
+			New(b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1,
+				b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0, b1, b0),
+		},
+	}
+
+	for _, test := range tests {
+		test.initial.AppendUint32(test.value, test.numBits)
+		if !equal(test.initial.Bits(), test.expected.Bits()) {
+			t.Errorf("Got %v, expected %v", test.initial.Bits(),
+				test.expected.Bits())
+		}
+	}
+}
+
+func TestAppendBools(t *testing.T) {
+	randomBools := make([]bool, 128)
+
+	rng := rand.New(rand.NewSource(1))
+
+	for i := 0; i < len(randomBools); i++ {
+		randomBools[i] = rng.Intn(2) == 1
+	}
+
+	for i := 0; i < len(randomBools)-1; i++ {
+		result := New(randomBools[0:i]...)
+		result.AppendBools(randomBools[i:]...)
+
+		if !equal(result.Bits(), randomBools) {
+			t.Errorf("got %v, want %v", result.Bits(), randomBools)
+		}
+	}
+}
+
+func BenchmarkShortAppend(b *testing.B) {
+	bitset := New()
+
+	for i := 0; i < b.N; i++ {
+		bitset.AppendBools(b0, b1, b0, b1, b0, b1, b0)
+	}
+}
+
+func TestLen(t *testing.T) {
+	randomBools := make([]bool, 128)
+
+	rng := rand.New(rand.NewSource(1))
+
+	for i := 0; i < len(randomBools); i++ {
+		randomBools[i] = rng.Intn(2) == 1
+	}
+
+	for i := 0; i < len(randomBools)-1; i++ {
+		result := New(randomBools[0:i]...)
+
+		if result.Len() != i {
+			t.Errorf("Len = %d, want %d", result.Len(), i)
+		}
+	}
+}
+
+func TestAt(t *testing.T) {
+	test := []bool{b0, b1, b0, b1, b0, b1, b1, b0, b1}
+
+	bitset := New(test...)
+	for i, v := range test {
+		result := bitset.At(i)
+
+		if result != test[i] {
+			t.Errorf("bitset[%d] => %t, want %t", i, result, v)
+		}
+	}
+}
+
+func equal(a []bool, b []bool) bool {
+	if len(a) != len(b) {
+		return false
+	}
+
+	for i := 0; i < len(a); i++ {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+
+	return true
+}
+
+func TestExample(t *testing.T) {
+	b := New()                       // {}
+	b.AppendBools(true, true, false) // {1, 1, 0}
+	b.AppendBools(true)              // {1, 1, 0, 1}
+	b.AppendByte(0x02, 4)            // {1, 1, 0, 1, 0, 0, 1, 0}
+
+	expected := []bool{b1, b1, b0, b1, b0, b0, b1, b0}
+
+	if !equal(b.Bits(), expected) {
+		t.Errorf("Got %v, expected %v", b.Bits(), expected)
+	}
+}
+
+func TestByteAt(t *testing.T) {
+	data := []bool{b0, b1, b0, b1, b0, b1, b1, b0, b1}
+
+	tests := []struct {
+		index    int
+		expected byte
+	}{
+		{
+			0,
+			0x56,
+		},
+		{
+			1,
+			0xad,
+		},
+		{
+			2,
+			0x2d,
+		},
+		{
+			5,
+			0x0d,
+		},
+		{
+			8,
+			0x01,
+		},
+	}
+
+	for _, test := range tests {
+		b := New()
+		b.AppendBools(data...)
+
+		result := b.ByteAt(test.index)
+
+		if result != test.expected {
+			t.Errorf("Got %#x, expected %#x", result, test.expected)
+		}
+	}
+}
+
+func TestSubstr(t *testing.T) {
+	data := []bool{b0, b1, b0, b1, b0, b1, b1, b0}
+
+	tests := []struct {
+		start    int
+		end      int
+		expected []bool
+	}{
+		{
+			0,
+			8,
+			[]bool{b0, b1, b0, b1, b0, b1, b1, b0},
+		},
+		{
+			0,
+			0,
+			[]bool{},
+		},
+		{
+			0,
+			1,
+			[]bool{b0},
+		},
+		{
+			2,
+			4,
+			[]bool{b0, b1},
+		},
+	}
+
+	for _, test := range tests {
+		b := New()
+		b.AppendBools(data...)
+
+		result := b.Substr(test.start, test.end)
+
+		expected := New()
+		expected.AppendBools(test.expected...)
+
+		if !result.Equals(expected) {
+			t.Errorf("Got %s, expected %s", result.String(), expected.String())
+		}
+	}
+}

+ 454 - 0
encoder.go

@@ -0,0 +1,454 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"errors"
+	"log"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+// Data encoding.
+//
+// The main data portion of a QR Code consists of one or more segments of data.
+// A segment consists of:
+//
+// - The segment Data Mode: numeric, alphanumeric, or byte.
+// - The length of segment in bits.
+// - Encoded data.
+//
+// For example, the string "123ZZ#!#!" may be represented as:
+//
+// [numeric, 3, "123"] [alphanumeric, 2, "ZZ"] [byte, 4, "#!#!"]
+//
+// Multiple data modes exist to minimise the size of encoded data. For example,
+// 8-bit bytes require 8 bits to encode each, but base 10 numeric data can be
+// encoded at a higher density of 3 numbers (e.g. 123) per 10 bits.
+//
+// Some data can be represented in multiple modes. Numeric data can be
+// represented in all three modes, whereas alphanumeric data (e.g. 'A') can be
+// represented in alphanumeric and byte mode.
+//
+// The cost to start a new segment (to use a different Data Mode) has a cost,
+// the bits to state the new segment Data Mode and length. To minimise each QR
+// Code's symbol size, an optimisation routine coalesces segment types
+// where possible, to reduce the encoded data length.
+//
+// There are several other data modes available (e.g. Kanji mode) which are not
+// implemented here.
+
+// A segment encoding mode.
+type dataMode uint8
+
+const (
+	// Each dataMode is a subset of the subsequent dataMode:
+	// dataModeNone < dataModeNumeric < dataModeAlphanumeric < dataModeByte
+	//
+	// This ordering is important for determining which data modes a character can
+	// be encoded with. E.g. 'E' can be encoded in both dataModeAlphanumeric and
+	// dataModeByte.
+	dataModeNone dataMode = 1 << iota
+	dataModeNumeric
+	dataModeAlphanumeric
+	dataModeByte
+)
+
+// dataModeString returns d as a short printable string.
+func dataModeString(d dataMode) string {
+	switch d {
+	case dataModeNone:
+		return "none"
+	case dataModeNumeric:
+		return "numeric"
+	case dataModeAlphanumeric:
+		return "alphanumeric"
+	case dataModeByte:
+		return "byte"
+	}
+
+	return "unknown"
+}
+
+type dataEncoderType uint8
+
+const (
+	dataEncoderType1To9 dataEncoderType = iota
+	dataEncoderType10To26
+	dataEncoderType27To40
+)
+
+// segment is a single segment of data.
+type segment struct {
+	// Data Mode (e.g. numeric).
+	dataMode dataMode
+
+	// segment data (e.g. "abc").
+	data []byte
+}
+
+// A dataEncoder encodes data for a particular QR Code version.
+type dataEncoder struct {
+	// Minimum & maximum versions supported.
+	minVersion int
+	maxVersion int
+
+	// Mode indicator bit sequences.
+	numericModeIndicator      *bitset.Bitset
+	alphanumericModeIndicator *bitset.Bitset
+	byteModeIndicator         *bitset.Bitset
+
+	// Character count lengths.
+	numNumericCharCountBits      int
+	numAlphanumericCharCountBits int
+	numByteCharCountBits         int
+
+	// The raw input data.
+	data []byte
+
+	// The data classified into unoptimised segments.
+	actual []segment
+
+	// The data classified into optimised segments.
+	optimised []segment
+}
+
+// newDataEncoder constructs a dataEncoder.
+func newDataEncoder(t dataEncoderType) *dataEncoder {
+	var d *dataEncoder = &dataEncoder{}
+
+	switch t {
+	case dataEncoderType1To9:
+		d = &dataEncoder{
+			minVersion:                   1,
+			maxVersion:                   9,
+			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
+			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
+			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
+			numNumericCharCountBits:      10,
+			numAlphanumericCharCountBits: 9,
+			numByteCharCountBits:         8,
+		}
+	case dataEncoderType10To26:
+		d = &dataEncoder{
+			minVersion:                   10,
+			maxVersion:                   26,
+			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
+			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
+			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
+			numNumericCharCountBits:      12,
+			numAlphanumericCharCountBits: 11,
+			numByteCharCountBits:         16,
+		}
+	case dataEncoderType27To40:
+		d = &dataEncoder{
+			minVersion:                   27,
+			maxVersion:                   40,
+			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
+			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
+			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
+			numNumericCharCountBits:      14,
+			numAlphanumericCharCountBits: 13,
+			numByteCharCountBits:         16,
+		}
+	default:
+		log.Panic("Unknown dataEncoderType")
+	}
+
+	return d
+}
+
+// encode data as one or more segments and return the encoded data.
+//
+// The returned data does not include the terminator bit sequence.
+func (d *dataEncoder) encode(data []byte) (*bitset.Bitset, error) {
+	d.data = data
+	d.actual = nil
+	d.optimised = nil
+
+	if len(data) == 0 {
+		return nil, errors.New("No data to encode")
+	}
+
+	// Classify data into unoptimised segments.
+	d.classifyDataModes()
+
+	// Optimise segments.
+	err := d.optimiseDataModes()
+	if err != nil {
+		return nil, err
+	}
+
+	// Encode data.
+	var encoded *bitset.Bitset = bitset.New()
+	for _, s := range d.optimised {
+		d.encodeDataRaw(s.data, s.dataMode, encoded)
+	}
+
+	return encoded, nil
+}
+
+// classifyDataModes classifies the raw data into unoptimised segments.
+// e.g. "123ZZ#!#!" =>
+// [numeric, 3, "123"] [alphanumeric, 2, "ZZ"] [byte, 4, "#!#!"].
+func (d *dataEncoder) classifyDataModes() {
+	var start int = 0
+	var mode dataMode = dataModeNone
+
+	for i, v := range d.data {
+		newMode := dataModeNone
+		switch {
+		case v >= 0x30 && v <= 0x39:
+			newMode = dataModeNumeric
+		case v == 0x20 || v == 0x24 || v == 0x25 || v == 0x2a || v == 0x2b || v ==
+			0x2d || v == 0x2e || v == 0x2f || v == 0x3a || (v >= 0x41 && v <= 0x5a):
+			newMode = dataModeAlphanumeric
+		default:
+			newMode = dataModeByte
+		}
+
+		if newMode != mode {
+			if i > 0 {
+				d.actual = append(d.actual, segment{dataMode: mode, data: d.data[start:i]})
+
+				start = i
+			}
+
+			mode = newMode
+		}
+	}
+
+	d.actual = append(d.actual, segment{dataMode: mode, data: d.data[start:len(d.data)]})
+}
+
+// optimiseDataModes optimises the list of segments to reduce the overall output
+// encoded data length.
+//
+// The algorithm coalesces adjacent segments. segments are only coalesced when
+// the Data Modes are compatible, and when the coalesced segment has a shorter
+// encoded length than separate segments.
+//
+// Multiple segments may be coalesced. For example a string of alternating
+// alphanumeric/numeric segments ANANANANA can be optimised to just A.
+func (d *dataEncoder) optimiseDataModes() error {
+	for i := 0; i < len(d.actual); {
+		mode := d.actual[i].dataMode
+		numChars := len(d.actual[i].data)
+
+		j := i + 1
+		for j < len(d.actual) {
+			nextNumChars := len(d.actual[j].data)
+			nextMode := d.actual[j].dataMode
+
+			if nextMode > mode {
+				break
+			}
+
+			coalescedLength, err := d.encodedLength(mode, numChars+nextNumChars)
+
+			if err != nil {
+				return err
+			}
+
+			seperateLength1, err := d.encodedLength(mode, numChars)
+
+			if err != nil {
+				return err
+			}
+
+			seperateLength2, err := d.encodedLength(nextMode, nextNumChars)
+
+			if err != nil {
+				return err
+			}
+
+			if coalescedLength < seperateLength1+seperateLength2 {
+				j++
+				numChars += nextNumChars
+			} else {
+				break
+			}
+		}
+
+		var optimised segment = segment{dataMode: mode,
+			data: make([]byte, 0, numChars)}
+
+		for k := i; k < j; k++ {
+			optimised.data = append(optimised.data, d.actual[k].data...)
+		}
+
+		d.optimised = append(d.optimised, optimised)
+
+		i = j
+	}
+
+	return nil
+}
+
+// encodeDataRaw encodes data in dataMode. The encoded data is appended to
+// encoded.
+func (d *dataEncoder) encodeDataRaw(data []byte, dataMode dataMode, encoded *bitset.Bitset) {
+	var modeIndicator *bitset.Bitset = d.modeIndicator(dataMode)
+	var charCountBits int = d.charCountBits(dataMode)
+
+	// Append mode indicator.
+	encoded.Append(modeIndicator)
+
+	// Append character count.
+	encoded.AppendUint32(uint32(len(data)), charCountBits)
+
+	// Append data.
+	switch dataMode {
+	case dataModeNumeric:
+		for i := 0; i < len(data); i += 3 {
+			charsRemaining := len(data) - i
+
+			var value uint32 = 0
+			var bitsUsed int = 1
+			for j := 0; j < charsRemaining && j < 3; j++ {
+				value *= 10
+				value += uint32(data[i+j] - 0x30)
+				bitsUsed += 3
+			}
+			encoded.AppendUint32(value, bitsUsed)
+		}
+	case dataModeAlphanumeric:
+		for i := 0; i < len(data); i += 2 {
+			charsRemaining := len(data) - i
+
+			var value uint32 = 0
+			for j := 0; j < charsRemaining && j < 2; j++ {
+				value *= 45
+				value += encodeAlphanumericCharacter(data[i+j])
+			}
+
+			var bitsUsed int = 6
+			if charsRemaining > 1 {
+				bitsUsed = 11
+			}
+
+			encoded.AppendUint32(value, bitsUsed)
+		}
+	case dataModeByte:
+		for _, b := range data {
+			encoded.AppendByte(b, 8)
+		}
+	}
+}
+
+// modeIndicator returns the segment header bits for a segment of type dataMode.
+func (d *dataEncoder) modeIndicator(dataMode dataMode) *bitset.Bitset {
+	switch dataMode {
+	case dataModeNumeric:
+		return d.numericModeIndicator
+	case dataModeAlphanumeric:
+		return d.alphanumericModeIndicator
+	case dataModeByte:
+		return d.byteModeIndicator
+	default:
+		log.Panic("Unknown data mode")
+	}
+
+	return nil
+}
+
+// charCountBits returns the number of bits used to encode the length of a data
+// segment of type dataMode.
+func (d *dataEncoder) charCountBits(dataMode dataMode) int {
+	switch dataMode {
+	case dataModeNumeric:
+		return d.numNumericCharCountBits
+	case dataModeAlphanumeric:
+		return d.numAlphanumericCharCountBits
+	case dataModeByte:
+		return d.numByteCharCountBits
+	default:
+		log.Panic("Unknown data mode")
+	}
+
+	return 0
+}
+
+// encodedLength returns the number of bits required to encode n symbols in
+// dataMode.
+//
+// The number of bits required is affected by:
+//	- QR code type - Mode Indicator length.
+//	- Data mode - number of bits used to represent data length.
+//	- Data mode - how the data is encoded.
+//	- Number of symbols encoded.
+//
+// An error is returned if the mode is not supported, or the length requested is
+// too long to be represented.
+func (d *dataEncoder) encodedLength(dataMode dataMode, n int) (int, error) {
+	var modeIndicator *bitset.Bitset = d.modeIndicator(dataMode)
+	var charCountBits int = d.charCountBits(dataMode)
+
+	if modeIndicator == nil {
+		return 0, errors.New("Mode not supported")
+	}
+
+	maxLength := (1 << uint8(charCountBits)) - 1
+
+	if n > maxLength {
+		return 0, errors.New("Length too long to be represented")
+	}
+
+	var length int = modeIndicator.Len() + charCountBits
+
+	switch dataMode {
+	case dataModeNumeric:
+		length += 10 * (n / 3)
+
+		if n%3 != 0 {
+			length += 1 + 3*(n%3)
+		}
+	case dataModeAlphanumeric:
+		length += 11 * (n / 2)
+		length += 6 * (n % 2)
+	case dataModeByte:
+		length += 8 * n
+	}
+
+	return length, nil
+}
+
+// encodeAlphanumericChar returns the QR Code encoded value of v.
+//
+// v must be a QR Code defined alphanumeric character: 0-9, A-Z, SP, $%*+-./ or
+// :. The characters are mapped to values in the range 0-44 respectively.
+func encodeAlphanumericCharacter(v byte) uint32 {
+	c := uint32(v)
+
+	switch {
+	case c >= '0' && c <= '9':
+		// 0-9 encoded as 0-9.
+		return c - '0'
+	case c >= 'A' && c <= 'Z':
+		// A-Z encoded as 10-35.
+		return c - 'A' + 10
+	case c == ' ':
+		return 36
+	case c == '$':
+		return 37
+	case c == '%':
+		return 38
+	case c == '*':
+		return 39
+	case c == '+':
+		return 40
+	case c == '-':
+		return 41
+	case c == '.':
+		return 42
+	case c == '/':
+		return 43
+	case c == ':':
+		return 44
+	default:
+		log.Panicf("encodeAlphanumericCharacter() with non alphanumeric char %v.", v)
+	}
+
+	return 0
+}

+ 311 - 0
encoder_test.go

@@ -0,0 +1,311 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+func TestClassifyDataMode(t *testing.T) {
+	type Test struct {
+	}
+
+	tests := []struct {
+		data   []byte
+		actual []segment
+	}{
+		{
+			[]byte{0x30},
+			[]segment{
+				{
+					dataModeNumeric,
+					[]byte{0x30},
+				},
+			},
+		},
+		{
+			[]byte{0x30, 0x41, 0x42, 0x43, 0x20, 0x00, 0xf0, 0xf1, 0xf2, 0x31},
+			[]segment{
+				{
+					dataModeNumeric,
+					[]byte{0x30},
+				},
+				{
+					dataModeAlphanumeric,
+					[]byte{0x41, 0x42, 0x43, 0x20},
+				},
+				{
+					dataModeByte,
+					[]byte{0x00, 0xf0, 0xf1, 0xf2},
+				},
+				{
+					dataModeNumeric,
+					[]byte{0x31},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		encoder := newDataEncoder(dataEncoderType1To9)
+		encoder.encode(test.data)
+
+		if !reflect.DeepEqual(test.actual, encoder.actual) {
+			t.Errorf("Got %v, expected %v", encoder.actual, test.actual)
+		}
+	}
+}
+
+func TestByteModeLengthCalculations(t *testing.T) {
+	tests := []struct {
+		dataEncoderType dataEncoderType
+		dataMode        dataMode
+		numSymbols      int
+		expectedLength  int
+	}{}
+
+	for i, test := range tests {
+		var encoder *dataEncoder = newDataEncoder(test.dataEncoderType)
+		var resultLength int
+
+		resultLength, err := encoder.encodedLength(test.dataMode, test.numSymbols)
+
+		if test.expectedLength == -1 {
+			if err == nil {
+				t.Errorf("Test %d: got length %d, expected error", i, resultLength)
+			}
+		} else if resultLength != test.expectedLength {
+			t.Errorf("Test %d: got length %d, expected length %d", i, resultLength,
+				test.expectedLength)
+		}
+	}
+}
+
+func TestSingleModeEncodings(t *testing.T) {
+	tests := []struct {
+		dataEncoderType dataEncoderType
+		dataMode        dataMode
+		data            string
+		expected        *bitset.Bitset
+	}{
+		{
+			dataEncoderType1To9,
+			dataModeNumeric,
+			"01234567",
+			bitset.NewFromBase2String("0001 0000001000 0000001100 0101011001 1000011"),
+		},
+		{
+			dataEncoderType1To9,
+			dataModeAlphanumeric,
+			"AC-42",
+			bitset.NewFromBase2String("0010 000000101 00111001110 11100111001 000010"),
+		},
+		{
+			dataEncoderType1To9,
+			dataModeByte,
+			"123",
+			bitset.NewFromBase2String("0100 00000011 00110001 00110010 00110011"),
+		},
+		{
+			dataEncoderType10To26,
+			dataModeByte,
+			"123",
+			bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
+		},
+		{
+			dataEncoderType27To40,
+			dataModeByte,
+			"123",
+			bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
+		},
+	}
+
+	for _, test := range tests {
+		var encoder *dataEncoder = newDataEncoder(test.dataEncoderType)
+
+		var encoded *bitset.Bitset = bitset.New()
+		encoder.encodeDataRaw([]byte(test.data), test.dataMode, encoded)
+
+		if !test.expected.Equals(encoded) {
+			t.Errorf("For %s got %s, expected %s", test.data, encoded.String(),
+				test.expected.String())
+		}
+	}
+}
+
+type testModeSegment struct {
+	dataMode dataMode
+	numChars int
+}
+
+func TestOptimiseEncoding(t *testing.T) {
+
+	tests := []struct {
+		dataEncoderType dataEncoderType
+		actual          []testModeSegment
+		optimised       []testModeSegment
+	}{
+		// Coalescing multiple segments.
+		{
+			dataEncoderType1To9,
+			[]testModeSegment{
+				{dataModeAlphanumeric, 1}, // length = 4 + 9 + 6 = 19 bits
+				{dataModeNumeric, 1},      // length = 4 + 10 + 4 = 18 bits
+				{dataModeAlphanumeric, 1}, // 19 bits.
+				{dataModeNumeric, 1},      // 18 bits.
+				{dataModeAlphanumeric, 1}, // 19 bits.
+				// total = 93 bits.
+			},
+			[]testModeSegment{
+				{dataModeAlphanumeric, 5}, // length = 4 + 9 + 22 + 6 = 41.
+			},
+		},
+		// Coalesing not necessary.
+		{
+			dataEncoderType1To9,
+			[]testModeSegment{
+				{dataModeAlphanumeric, 1},
+				{dataModeNumeric, 20},
+			},
+			[]testModeSegment{
+				{dataModeAlphanumeric, 1},
+				{dataModeNumeric, 20},
+			},
+		},
+		// Switch to more general dataMode.
+		{
+			dataEncoderType1To9,
+			[]testModeSegment{
+				{dataModeAlphanumeric, 1},
+				{dataModeByte, 1},
+				{dataModeNumeric, 1},
+			},
+			[]testModeSegment{
+				{dataModeAlphanumeric, 1},
+				{dataModeByte, 2},
+			},
+		},
+		// https://www.google.com/123
+		// BBBBBAAABBBABBBBBBABBBANNN
+		{
+			dataEncoderType1To9,
+			[]testModeSegment{
+				{dataModeByte, 5},
+				{dataModeAlphanumeric, 3},
+				{dataModeByte, 3},
+				{dataModeAlphanumeric, 1},
+				{dataModeByte, 6},
+				{dataModeAlphanumeric, 1},
+				{dataModeAlphanumeric, 4},
+				{dataModeNumeric, 3},
+			},
+			[]testModeSegment{
+				{dataModeByte, 23},
+				{dataModeNumeric, 3},
+			},
+		},
+		// HTTPS://WWW.GOOGLE.COM/123
+		// AAAAAAAAAAAAAAAAAAAAAAANNN
+		{
+			dataEncoderType1To9,
+			[]testModeSegment{
+				{dataModeAlphanumeric, 23},
+				{dataModeNumeric, 3},
+			},
+			[]testModeSegment{
+				{dataModeAlphanumeric, 26},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		numTotalChars := 0
+		for _, v := range test.actual {
+			numTotalChars += v.numChars
+		}
+
+		var data []byte = make([]byte, numTotalChars)
+
+		var i int = 0
+		for _, v := range test.actual {
+			for j := 0; j < v.numChars; j++ {
+				switch v.dataMode {
+				case dataModeNumeric:
+					data[i] = '1'
+				case dataModeAlphanumeric:
+					data[i] = 'A'
+				case dataModeByte:
+					data[i] = '#'
+				default:
+					t.Fatal("Unrecognised data mode")
+				}
+
+				i++
+			}
+		}
+
+		var encoder *dataEncoder = newDataEncoder(test.dataEncoderType)
+
+		_, err := encoder.encode(data)
+
+		if err != nil {
+			t.Errorf("Got %s, expected valid encoding", err.Error())
+		} else {
+			var ok bool = true
+
+			if len(encoder.optimised) != len(test.optimised) {
+				ok = false
+			} else {
+				for i, s := range test.optimised {
+					if encoder.optimised[i].dataMode != s.dataMode ||
+						len(encoder.optimised[i].data) != s.numChars {
+						ok = false
+						break
+					}
+				}
+			}
+
+			if !ok {
+				t.Errorf("got %s, expected %s", segmentsString(encoder.optimised),
+					testModeSegmentsString(test.optimised))
+			}
+		}
+	}
+}
+
+func testModeSegmentsString(segments []testModeSegment) string {
+	var result string = "["
+	for i, segment := range segments {
+		if i > 0 {
+			result += ", "
+		}
+
+		result += fmt.Sprintf("%d*%s", segment.numChars,
+			dataModeString(segment.dataMode))
+	}
+
+	result += "]"
+
+	return result
+}
+
+func segmentsString(segments []segment) string {
+	var result string = "["
+	for i, segment := range segments {
+		if i > 0 {
+			result += ", "
+		}
+
+		result += fmt.Sprintf("%d*%s", len(segment.data),
+			dataModeString(segment.dataMode))
+	}
+
+	result += "]"
+
+	return result
+}

+ 34 - 0
example_test.go

@@ -0,0 +1,34 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"fmt"
+	"os"
+)
+
+func ExampleEncode() {
+	var png []byte
+	png, err := Encode("https://example.org", Medium, 256)
+
+	if err != nil {
+		fmt.Printf("Error: %s", err.Error())
+	} else {
+		fmt.Println("PNG is %d bytes long", len(png))
+	}
+}
+
+func ExampleWriteFile() {
+	filename := "example.png"
+
+	err := WriteFile("https://example.org", Medium, 256, filename)
+
+	if err != nil {
+		err = os.Remove(filename)
+	}
+
+	if err != nil {
+		fmt.Printf("Error: %s", err.Error())
+	}
+}

+ 454 - 0
qrcode.go

@@ -0,0 +1,454 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+/*
+Package qrcode implements a QR Code encoder.
+
+A QR Code is a matrix (two-dimensional) barcode. Arbitrary content may be
+encoded.
+
+A QR Code contains error recovery information to aid reading damaged or
+obscured codes. There are four levels of error recovery: qrcode.{Low, Medium,
+High, Highest}. QR Codes with a higher recovery level are more robust to damage,
+at the cost of being physically larger.
+
+Two functions cover most use cases:
+
+- Create a PNG image:
+
+	var png []byte
+	png, err := qrcode.Encode("https://example.org", qrcode.Medium, 256)
+
+- Create a PNG image and write to a file:
+
+	err := qrcode.WriteFile("https://example.org", qrcode.Medium, 256, "qr.png")
+
+Both examples use the qrcode.Medium error Recovery Level and create a 256x256
+pixel, black on white QR Code.
+
+The maximum capacity of a QR Code varies according to the content encoded and
+the error recovery level. The maximum capacity is 2,953 bytes, 4,296
+alphanumeric characters, 7,089 numeric digits, or a combination of these.
+
+This package implements a subset of QR Code 2005, as defined in ISO/IEC
+18004:2006.
+*/
+package qrcode
+
+import (
+	"bytes"
+	"errors"
+	"image"
+	"image/color"
+	"image/png"
+	"io/ioutil"
+	"log"
+	"os"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+	reedsolomon "code.google.com/p/go-qrcode/reedsolomon"
+)
+
+// Encode a QR Code and return a raw PNG image.
+//
+// size is both the image width and height in pixels. If size is too small then
+// a larger image is silently returned.
+//
+// To serve over HTTP, remember to send a Content-Type: image/png header.
+func Encode(content string, level RecoveryLevel, size int) ([]byte, error) {
+	var q *QRCode
+
+	q, err := New(content, level)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return q.PNG(size)
+}
+
+// WriteFile encodes, then writes a QR Code to the given filename in PNG format.
+//
+// size is both the width and height in pixels. If size is too small then a
+// larger image is silently written.
+func WriteFile(content string, level RecoveryLevel, size int, filename string) error {
+	var q *QRCode
+
+	q, err := New(content, level)
+
+	if err != nil {
+		return err
+	}
+
+	return q.WriteFile(size, filename)
+}
+
+// A QRCode represents a valid encoded QRCode.
+type QRCode struct {
+	// Original content encoded.
+	Content string
+
+	// QR Code type.
+	Level         RecoveryLevel
+	VersionNumber int
+
+	// User settable drawing options.
+	ForegroundColor color.Color
+	BackgroundColor color.Color
+
+	encoder *dataEncoder
+	version qrCodeVersion
+
+	data   *bitset.Bitset
+	symbol *symbol
+}
+
+// New constructs a QRCode.
+//
+//	var q *qrcode.QRCode
+//	q, err := qrcode.New("my content", qrcode.Medium)
+//
+// An error occurs if the content is too long.
+func New(content string, level RecoveryLevel) (*QRCode, error) {
+	encoders := []dataEncoderType{dataEncoderType1To9, dataEncoderType10To26,
+		dataEncoderType27To40}
+
+	var encoder *dataEncoder
+	var encoded *bitset.Bitset
+	var chosenVersion *qrCodeVersion
+	var err error
+
+	for _, t := range encoders {
+		encoder = newDataEncoder(t)
+		encoded, err = encoder.encode([]byte(content))
+
+		if err != nil {
+			continue
+		}
+
+		chosenVersion = chooseQRCodeVersion(level, encoder, encoded.Len())
+
+		if chosenVersion != nil {
+			break
+		}
+	}
+
+	if err != nil {
+		return nil, err
+	} else if chosenVersion == nil {
+		return nil, errors.New("Content too long to encode")
+	}
+
+	var q *QRCode = &QRCode{
+		Content: content,
+
+		Level:         level,
+		VersionNumber: chosenVersion.version,
+
+		ForegroundColor: color.Black,
+		BackgroundColor: color.White,
+
+		encoder: encoder,
+		data:    encoded,
+		version: *chosenVersion,
+	}
+
+	q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
+
+	return q, nil
+}
+
+func newWithForcedVersion(content string, version int, level RecoveryLevel) (*QRCode, error) {
+	var encoder *dataEncoder
+
+	switch {
+	case version >= 1 && version <= 9:
+		encoder = newDataEncoder(dataEncoderType1To9)
+	case version >= 10 && version <= 26:
+		encoder = newDataEncoder(dataEncoderType10To26)
+	case version >= 27 && version <= 40:
+		encoder = newDataEncoder(dataEncoderType27To40)
+	default:
+		log.Fatalf("Invalid version %d (expected 1-40 inclusive)", version)
+	}
+
+	var encoded *bitset.Bitset
+	encoded, err := encoder.encode([]byte(content))
+
+	if err != nil {
+		return nil, err
+	}
+
+	var chosenVersion *qrCodeVersion = getQRCodeVersion(level, version)
+
+	if chosenVersion == nil {
+		return nil, errors.New("Cannot find QR Code version")
+	}
+
+	var q *QRCode = &QRCode{
+		Content: content,
+
+		Level:         level,
+		VersionNumber: chosenVersion.version,
+
+		ForegroundColor: color.Black,
+		BackgroundColor: color.White,
+
+		encoder: encoder,
+		data:    encoded,
+		version: *chosenVersion,
+	}
+
+	q.encode(chosenVersion.numTerminatorBitsRequired(encoded.Len()))
+
+	return q, nil
+}
+
+// Bitmap returns the QR Code as a 2D array of 1-bit pixels.
+//
+// bitmap[y][x] is true if the pixel at (x, y) is set.
+//
+// The bitmap includes the required "quiet zone" around the QR Code to aid
+// decoding.
+func (q *QRCode) Bitmap() [][]bool {
+	return q.symbol.bitmap()
+}
+
+// Image returns the QR Code as an image.Image.
+//
+// size is both the width and height in pixels.
+func (q *QRCode) Image(size int) image.Image {
+	// Minimum pixels (both width and height) required.
+	realSize := q.symbol.size
+
+	// Actual pixels available to draw the symbol. Automatically increase the
+	// image size if it's not large enough.
+	if size < realSize {
+		size = realSize
+	}
+
+	// Size of each module drawn.
+	pixelsPerModule := size / realSize
+
+	// Center the symbol within the image.
+	offset := (size - realSize*pixelsPerModule) / 2
+
+	var rect image.Rectangle = image.Rectangle{Min: image.Point{0, 0}, Max: image.Point{size, size}}
+
+	var img *image.RGBA = image.NewRGBA(rect)
+
+	for i := 0; i < size; i++ {
+		for j := 0; j < size; j++ {
+			img.Set(i, j, q.BackgroundColor)
+		}
+	}
+
+	var bitmap [][]bool = q.symbol.bitmap()
+	for y, row := range bitmap {
+		for x, v := range row {
+			if v {
+				startX := x*pixelsPerModule + offset
+				startY := y*pixelsPerModule + offset
+				for i := startX; i < startX+pixelsPerModule; i++ {
+					for j := startY; j < startY+pixelsPerModule; j++ {
+						img.Set(i, j, q.ForegroundColor)
+					}
+				}
+			}
+		}
+	}
+
+	return img
+}
+
+// PNG returns the QR Code as a PNG image.
+//
+// size is both the image width and height in pixels. If size is too small then
+// a larger image is silently returned.
+func (q *QRCode) PNG(size int) ([]byte, error) {
+	var img image.Image = q.Image(size)
+
+	var b bytes.Buffer
+	err := png.Encode(&b, img)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return b.Bytes(), nil
+}
+
+// WriteFile writes the QR Code as a PNG image to the specified file.
+//
+// size is both the image width and height in pixels. If size is too small then
+// a larger image is silently written.
+func (q *QRCode) WriteFile(size int, filename string) error {
+	var png []byte
+
+	png, err := q.PNG(size)
+
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(filename, png, os.FileMode(0644))
+}
+
+// encode completes the steps required to encode the QR Code. These include
+// adding the terminator bits and padding, splitting the data into blocks and
+// applying the error correction, and selecting the best data mask.
+func (q *QRCode) encode(numTerminatorBits int) {
+	q.addTerminatorBits(numTerminatorBits)
+	q.addPadding()
+
+	var encoded *bitset.Bitset = q.encodeBlocks()
+
+	var numMasks int = 8
+	var penalty int = 0
+
+	for mask := 0; mask < numMasks; mask++ {
+		var s *symbol
+		var err error
+
+		s, err = buildRegularSymbol(q.version, mask, encoded)
+
+		if err != nil {
+			log.Panic(err.Error())
+		}
+
+		var p int = s.penaltyScore()
+
+		if q.symbol == nil || p < penalty {
+			q.symbol = s
+			penalty = p
+		}
+	}
+}
+
+// addTerminatorBits adds final terminator bits to the encoded data.
+//
+// The number of terminator bits required is determined when the QR Code version
+// is chosen (which itself depends on the length of the data encoded). The
+// terminator bits are thus added after the QR Code version
+// is chosen, rather than at the data encoding stage.
+func (q *QRCode) addTerminatorBits(numTerminatorBits int) {
+	q.data.AppendNumBools(numTerminatorBits, false)
+}
+
+// encodeBlocks takes the completed (terminated & padded) encoded data, splits
+// the data into blocks (as specified by the QR Code version), applies error
+// correction to each block, then interleaves the blocks together.
+//
+// The QR Code's final data sequence is returned.
+func (q *QRCode) encodeBlocks() *bitset.Bitset {
+	// Split into blocks.
+	type dataBlock struct {
+		data          *bitset.Bitset
+		ecStartOffset int
+	}
+
+	var block []dataBlock = make([]dataBlock, q.version.numBlocks())
+
+	var start int = 0
+	var end int = 0
+	var blockID int = 0
+	for _, b := range q.version.block {
+		for j := 0; j < b.numBlocks; j++ {
+			start = end
+			end = start + b.numDataCodewords*8
+
+			// Apply error correction to each block.
+			var numErrorCodewords int = b.numCodewords - b.numDataCodewords
+			block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords)
+			block[blockID].ecStartOffset = end - start
+
+			blockID++
+		}
+	}
+
+	// Interleave the blocks.
+
+	// A single block doesn't need interleaving.
+	if len(block) == 1 {
+		return block[0].data
+	}
+
+	result := bitset.New()
+
+	// Combine data blocks.
+	var working bool = true
+	for i := 0; working; i += 8 {
+		working = false
+
+		for j, b := range block {
+			if i >= block[j].ecStartOffset {
+				continue
+			}
+
+			result.Append(b.data.Substr(i, i+8))
+
+			working = true
+		}
+	}
+
+	// Combine error correction blocks.
+	working = true
+	for i := 0; working; i += 8 {
+		working = false
+
+		for j, b := range block {
+			var offset int = i + block[j].ecStartOffset
+			if offset >= block[j].data.Len() {
+				continue
+			}
+
+			result.Append(b.data.Substr(offset, offset+8))
+
+			working = true
+		}
+	}
+
+	// Append remainder bits.
+	result.AppendNumBools(q.version.numRemainderBits, false)
+
+	return result
+}
+
+// max returns the maximum of a and b.
+func max(a int, b int) int {
+	if a > b {
+		return a
+	} else {
+		return b
+	}
+}
+
+// addPadding pads the encoded data upto the full length required.
+func (q *QRCode) addPadding() {
+	numDataBits := q.version.numDataBits()
+
+	if q.data.Len() == numDataBits {
+		return
+	}
+
+	// Pad to the nearest codeword boundary.
+	q.data.AppendNumBools(q.version.numBitsToPadToCodeword(q.data.Len()), false)
+
+	// Pad codewords 0b11101100 and 0b00010001.
+	var padding [2]*bitset.Bitset = [2]*bitset.Bitset{
+		bitset.New(true, true, true, false, true, true, false, false),
+		bitset.New(false, false, false, true, false, false, false, true),
+	}
+
+	// Insert pad codewords alternately.
+	i := 0
+	for numDataBits-q.data.Len() >= 8 {
+		q.data.Append(padding[i])
+
+		i = 1 - i // Alternate between 0 and 1.
+	}
+
+	if q.data.Len() != numDataBits {
+		log.Panicf("BUG: got len %d, expected %d", q.data.Len(), numDataBits)
+	}
+}

+ 227 - 0
qrcode_decode_test.go

@@ -0,0 +1,227 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"math/rand"
+	"os/exec"
+	"strings"
+	"testing"
+)
+
+// These tests use zbarimg to decode generated QR Codes to ensure they are
+// readable. sudo apt-get install zbar-tools, or download from
+// http://zbar.sourceforge.net.
+//
+// By default these tests are disabled to avoid a dependency on zbarimg if
+// you're not running the tests. Use the -test-decode flag (go test
+// -test-decode) to enable.
+
+var testDecode *bool = flag.Bool("test-decode",
+	false,
+	"Enable decode tests. Requires zbarimg installed.")
+
+var testDecodeFuzz *bool = flag.Bool("test-decode-fuzz",
+	false,
+	"Enable decode fuzz tests. Requires zbarimg installed.")
+
+func TestDecodeBasic(t *testing.T) {
+	if !*testDecode {
+		t.Skip("Decode tests not enabled")
+	}
+
+	tests := []struct {
+		content        string
+		numRepetitions int
+		level          RecoveryLevel
+	}{
+		{
+			"A",
+			1,
+			Low,
+		},
+		{
+			"A",
+			1,
+			Medium,
+		},
+		{
+			"A",
+			1,
+			High,
+		},
+		{
+			"A",
+			1,
+			Highest,
+		},
+	}
+
+	for _, test := range tests {
+		content := strings.Repeat(test.content, test.numRepetitions)
+
+		q, err := New(content, test.level)
+		if err != nil {
+			t.Error(err.Error())
+		}
+
+		err = zbarimgCheck(q)
+
+		if err != nil {
+			t.Error(err.Error())
+		}
+	}
+}
+
+func TestDecodeAllVersionLevels(t *testing.T) {
+	if !*testDecode {
+		t.Skip("Decode tests not enabled")
+	}
+
+	for version := 1; version <= 40; version++ {
+		for _, level := range []RecoveryLevel{Low, Medium, High, Highest} {
+			t.Logf("Version=%d Level=%d",
+				version,
+				level)
+
+			q, err := newWithForcedVersion(
+				fmt.Sprintf("v-%d l-%d", version, level), version, level)
+			if err != nil {
+				t.Fatal(err.Error())
+				return
+			}
+
+			err = zbarimgCheck(q)
+
+			if err != nil {
+				t.Errorf("Version=%d Level=%d, err=%s, expected success",
+					version,
+					level,
+					err.Error())
+				continue
+			}
+		}
+	}
+}
+
+func TestDecodeAllCharacters(t *testing.T) {
+	if !*testDecode {
+		t.Skip("Decode tests not enabled")
+	}
+
+	var content string
+
+	// zbarimg has trouble with null bytes, hence start from ASCII 1.
+	for i := 1; i < 256; i++ {
+		content += string(i)
+	}
+
+	q, err := New(content, Low)
+	if err != nil {
+		t.Error(err.Error())
+	}
+
+	err = zbarimgCheck(q)
+
+	if err != nil {
+		t.Error(err.Error())
+	}
+}
+
+func TestDecodeFuzz(t *testing.T) {
+	if !*testDecodeFuzz {
+		t.Skip("Decode fuzz tests not enabled")
+	}
+
+	var r *rand.Rand = rand.New(rand.NewSource(0))
+
+	const kIterations int = 32
+	const kMaxLength int = 128
+
+	for i := 0; i < kIterations; i++ {
+		len := r.Intn(kMaxLength-1) + 1
+
+		var content string
+		for j := 0; j < len; j++ {
+			// zbarimg has trouble with null bytes, hence start from ASCII 1.
+			content += string(1+r.Intn(254))
+		}
+
+		for _, level := range []RecoveryLevel{Low, Medium, High, Highest} {
+			q, err := New(content, level)
+			if err != nil {
+				t.Error(err.Error())
+			}
+
+			err = zbarimgCheck(q)
+
+			if err != nil {
+				t.Error(err.Error())
+			}
+		}
+	}
+}
+
+func zbarimgCheck(q *QRCode) error {
+	s, err := zbarimgDecode(q)
+	if err != nil {
+		return err
+	}
+
+	if s != q.Content {
+		q.WriteFile(256, fmt.Sprintf("%x.png", q.Content))
+		return fmt.Errorf("Got '%s' (%x) expected '%s' (%x)", s, s, q.Content, q.Content)
+	}
+
+	return nil
+}
+
+func zbarimgDecode(q *QRCode) (string, error) {
+	var png []byte
+
+	// 512x512px
+	png, err := q.PNG(512)
+	if err != nil {
+		return "", err
+	}
+
+	var cmd *exec.Cmd = exec.Command("zbarimg", "--quiet", "-Sdisable",
+		"-Sqrcode.enable", "/dev/stdin")
+
+	var out bytes.Buffer
+
+	cmd.Stdin = bytes.NewBuffer(png)
+	cmd.Stdout = &out
+
+	err = cmd.Run()
+
+	if err != nil {
+		return "", err
+	}
+
+	return strings.TrimSuffix(strings.TrimPrefix(out.String(), "QR-Code:"), "\n"), nil
+}
+
+func BenchmarkDecodeTest(b *testing.B) {
+	if !*testDecode {
+		b.Skip("Decode benchmarks not enabled")
+	}
+
+	for n := 0; n < b.N; n++ {
+		q, err := New("content", Medium)
+		if err != nil {
+			b.Error(err.Error())
+		}
+
+		err = zbarimgCheck(q)
+
+		if err != nil {
+			b.Error(err.Error())
+		}
+	}
+}
+

+ 156 - 0
qrcode_test.go

@@ -0,0 +1,156 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestQRCodeMaxCapacity(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping TestQRCodeCapacity")
+	}
+
+	tests := []struct {
+		char     byte
+		maxChars int
+	}{
+		{
+			'0',
+			7089,
+		},
+		{
+			'A',
+			4296,
+		},
+		{
+			'#',
+			2953,
+		},
+	}
+
+	for _, test := range tests {
+		_, err := New(strings.Repeat(string(test.char), test.maxChars), Low)
+
+		if err != nil {
+			t.Errorf("%d x '%c' got %s expected success", test.maxChars, test.char, err.Error())
+		}
+	}
+
+	for _, test := range tests {
+		_, err := New(strings.Repeat(string(test.char), test.maxChars+1), Low)
+
+		if err == nil {
+			t.Errorf("%d x '%c' chars encodable, expected not encodable",
+				test.maxChars+1, test.char)
+		}
+	}
+}
+
+func TestQRCodeVersionCapacity(t *testing.T) {
+	tests := []struct {
+		version         int
+		level           RecoveryLevel
+		maxNumeric      int
+		maxAlphanumeric int
+		maxByte         int
+	}{
+		{
+			1,
+			Low,
+			41,
+			25,
+			17,
+		},
+		{
+			2,
+			Low,
+			77,
+			47,
+			32,
+		},
+		{
+			2,
+			Highest,
+			34,
+			20,
+			14,
+		},
+		{
+			40,
+			Low,
+			7089,
+			4296,
+			2953,
+		},
+		{
+			40,
+			Highest,
+			3057,
+			1852,
+			1273,
+		},
+	}
+
+	for i, test := range tests {
+		numericData := strings.Repeat("1", test.maxNumeric)
+		alphanumericData := strings.Repeat("A", test.maxAlphanumeric)
+		byteData := strings.Repeat("#", test.maxByte)
+
+		var n *QRCode
+		var a *QRCode
+		var b *QRCode
+		var err error
+
+		n, err = New(numericData, test.level)
+		if err != nil {
+			t.Fatal(err.Error())
+		}
+
+		a, err = New(alphanumericData, test.level)
+		if err != nil {
+			t.Fatal(err.Error())
+		}
+
+		b, err = New(byteData, test.level)
+		if err != nil {
+			t.Fatal(err.Error())
+		}
+
+		if n.VersionNumber != test.version {
+			t.Fatalf("Test #%d numeric has version #%d, expected #%d", i,
+				n.VersionNumber, test.version)
+		}
+
+		if a.VersionNumber != test.version {
+			t.Fatalf("Test #%d alphanumeric has version #%d, expected #%d", i,
+				a.VersionNumber, test.version)
+		}
+
+		if b.VersionNumber != test.version {
+			t.Fatalf("Test #%d byte has version #%d, expected #%d", i,
+				b.VersionNumber, test.version)
+		}
+	}
+}
+
+func BenchmarkQRCodeMinimumSize(b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		New("1", Low)
+	}
+}
+
+func BenchmarkQRCodeURLSize(b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		New("http://www.example.org", Medium)
+	}
+}
+
+func BenchmarkQRCodeMaximumSize(b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		// 7089 is the maximum encodable number of numeric digits.
+		New(strings.Repeat("0", 7089), Low)
+	}
+}

+ 387 - 0
reedsolomon/gf2_8.go

@@ -0,0 +1,387 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package reedsolomon
+
+// Addition, subtraction, multiplication, and division in GF(2^8).
+// Operations are performed modulo x^8 + x^4 + x^3 + x^2 + 1.
+
+// http://en.wikipedia.org/wiki/Finite_field_arithmetic
+
+import "log"
+
+const (
+	gfZero = gfElement(0)
+	gfOne  = gfElement(1)
+)
+
+var (
+	gfExpTable = [256]gfElement{
+		/*   0 -   9 */ 1, 2, 4, 8, 16, 32, 64, 128, 29, 58,
+		/*  10 -  19 */ 116, 232, 205, 135, 19, 38, 76, 152, 45, 90,
+		/*  20 -  29 */ 180, 117, 234, 201, 143, 3, 6, 12, 24, 48,
+		/*  30 -  39 */ 96, 192, 157, 39, 78, 156, 37, 74, 148, 53,
+		/*  40 -  49 */ 106, 212, 181, 119, 238, 193, 159, 35, 70, 140,
+		/*  50 -  59 */ 5, 10, 20, 40, 80, 160, 93, 186, 105, 210,
+		/*  60 -  69 */ 185, 111, 222, 161, 95, 190, 97, 194, 153, 47,
+		/*  70 -  79 */ 94, 188, 101, 202, 137, 15, 30, 60, 120, 240,
+		/*  80 -  89 */ 253, 231, 211, 187, 107, 214, 177, 127, 254, 225,
+		/*  90 -  99 */ 223, 163, 91, 182, 113, 226, 217, 175, 67, 134,
+		/* 100 - 109 */ 17, 34, 68, 136, 13, 26, 52, 104, 208, 189,
+		/* 110 - 119 */ 103, 206, 129, 31, 62, 124, 248, 237, 199, 147,
+		/* 120 - 129 */ 59, 118, 236, 197, 151, 51, 102, 204, 133, 23,
+		/* 130 - 139 */ 46, 92, 184, 109, 218, 169, 79, 158, 33, 66,
+		/* 140 - 149 */ 132, 21, 42, 84, 168, 77, 154, 41, 82, 164,
+		/* 150 - 159 */ 85, 170, 73, 146, 57, 114, 228, 213, 183, 115,
+		/* 160 - 169 */ 230, 209, 191, 99, 198, 145, 63, 126, 252, 229,
+		/* 170 - 179 */ 215, 179, 123, 246, 241, 255, 227, 219, 171, 75,
+		/* 180 - 189 */ 150, 49, 98, 196, 149, 55, 110, 220, 165, 87,
+		/* 190 - 199 */ 174, 65, 130, 25, 50, 100, 200, 141, 7, 14,
+		/* 200 - 209 */ 28, 56, 112, 224, 221, 167, 83, 166, 81, 162,
+		/* 210 - 219 */ 89, 178, 121, 242, 249, 239, 195, 155, 43, 86,
+		/* 220 - 229 */ 172, 69, 138, 9, 18, 36, 72, 144, 61, 122,
+		/* 230 - 239 */ 244, 245, 247, 243, 251, 235, 203, 139, 11, 22,
+		/* 240 - 249 */ 44, 88, 176, 125, 250, 233, 207, 131, 27, 54,
+		/* 250 - 255 */ 108, 216, 173, 71, 142, 1}
+
+	gfLogTable = [256]int{
+		/*   0 -   9 */ -1, 0, 1, 25, 2, 50, 26, 198, 3, 223,
+		/*  10 -  19 */ 51, 238, 27, 104, 199, 75, 4, 100, 224, 14,
+		/*  20 -  29 */ 52, 141, 239, 129, 28, 193, 105, 248, 200, 8,
+		/*  30 -  39 */ 76, 113, 5, 138, 101, 47, 225, 36, 15, 33,
+		/*  40 -  49 */ 53, 147, 142, 218, 240, 18, 130, 69, 29, 181,
+		/*  50 -  59 */ 194, 125, 106, 39, 249, 185, 201, 154, 9, 120,
+		/*  60 -  69 */ 77, 228, 114, 166, 6, 191, 139, 98, 102, 221,
+		/*  70 -  79 */ 48, 253, 226, 152, 37, 179, 16, 145, 34, 136,
+		/*  80 -  89 */ 54, 208, 148, 206, 143, 150, 219, 189, 241, 210,
+		/*  90 -  99 */ 19, 92, 131, 56, 70, 64, 30, 66, 182, 163,
+		/* 100 - 109 */ 195, 72, 126, 110, 107, 58, 40, 84, 250, 133,
+		/* 110 - 119 */ 186, 61, 202, 94, 155, 159, 10, 21, 121, 43,
+		/* 120 - 129 */ 78, 212, 229, 172, 115, 243, 167, 87, 7, 112,
+		/* 130 - 139 */ 192, 247, 140, 128, 99, 13, 103, 74, 222, 237,
+		/* 140 - 149 */ 49, 197, 254, 24, 227, 165, 153, 119, 38, 184,
+		/* 150 - 159 */ 180, 124, 17, 68, 146, 217, 35, 32, 137, 46,
+		/* 160 - 169 */ 55, 63, 209, 91, 149, 188, 207, 205, 144, 135,
+		/* 170 - 179 */ 151, 178, 220, 252, 190, 97, 242, 86, 211, 171,
+		/* 180 - 189 */ 20, 42, 93, 158, 132, 60, 57, 83, 71, 109,
+		/* 190 - 199 */ 65, 162, 31, 45, 67, 216, 183, 123, 164, 118,
+		/* 200 - 209 */ 196, 23, 73, 236, 127, 12, 111, 246, 108, 161,
+		/* 210 - 219 */ 59, 82, 41, 157, 85, 170, 251, 96, 134, 177,
+		/* 220 - 229 */ 187, 204, 62, 90, 203, 89, 95, 176, 156, 169,
+		/* 230 - 239 */ 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
+		/* 240 - 249 */ 79, 174, 213, 233, 230, 231, 173, 232, 116, 214,
+		/* 250 - 255 */ 244, 234, 168, 80, 88, 175}
+)
+
+// gfElement is an element in GF(2^8).
+type gfElement uint8
+
+// newGFElement creates and returns a new gfElement.
+func newGFElement(data byte) gfElement {
+	return gfElement(data)
+}
+
+// gfAdd returns a + b.
+func gfAdd(a, b gfElement) gfElement {
+	return a ^ b
+}
+
+// gfSub returns a - b.
+//
+// Note addition is equivalent to subtraction in GF(2).
+func gfSub(a, b gfElement) gfElement {
+	return a ^ b
+}
+
+// gfMultiply returns a * b.
+func gfMultiply(a, b gfElement) gfElement {
+	if a == gfZero || b == gfZero {
+		return gfZero
+	}
+
+	return gfExpTable[(gfLogTable[a]+gfLogTable[b])%255]
+}
+
+// gfDivide returns a / b.
+//
+// Divide by zero results in a panic.
+func gfDivide(a, b gfElement) gfElement {
+	if a == gfZero {
+		return gfZero
+	} else if b == gfZero {
+		log.Panicln("Divide by zero")
+	}
+
+	return gfMultiply(a, gfInverse(b))
+}
+
+// gfInverse returns the multiplicative inverse of a, a^-1.
+//
+// a * a^-1 = 1
+func gfInverse(a gfElement) gfElement {
+	if a == gfZero {
+		log.Panicln("No multiplicative inverse of 0")
+	}
+
+	return gfExpTable[255-gfLogTable[a]]
+}
+
+// a^i   | bits      | polynomial                                   | decimal
+// --------------------------------------------------------------------------
+// 0     | 000000000 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 0
+// a^0   | 000000001 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 1
+// a^1   | 000000010 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 2
+// a^2   | 000000100 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 4
+// a^3   | 000001000 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 8
+// a^4   | 000010000 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 16
+// a^5   | 000100000 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 32
+// a^6   | 001000000 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 64
+// a^7   | 010000000 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 128
+// a^8   | 000011101 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 29
+// a^9   | 000111010 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 58
+// a^10  | 001110100 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 116
+// a^11  | 011101000 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 232
+// a^12  | 011001101 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 205
+// a^13  | 010000111 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 135
+// a^14  | 000010011 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 19
+// a^15  | 000100110 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 38
+// a^16  | 001001100 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 76
+// a^17  | 010011000 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 152
+// a^18  | 000101101 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 45
+// a^19  | 001011010 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 90
+// a^20  | 010110100 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 180
+// a^21  | 001110101 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 117
+// a^22  | 011101010 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 234
+// a^23  | 011001001 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 201
+// a^24  | 010001111 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 143
+// a^25  | 000000011 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 3
+// a^26  | 000000110 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 6
+// a^27  | 000001100 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 12
+// a^28  | 000011000 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 24
+// a^29  | 000110000 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 48
+// a^30  | 001100000 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 96
+// a^31  | 011000000 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 192
+// a^32  | 010011101 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 157
+// a^33  | 000100111 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 39
+// a^34  | 001001110 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 78
+// a^35  | 010011100 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 156
+// a^36  | 000100101 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 37
+// a^37  | 001001010 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 74
+// a^38  | 010010100 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 148
+// a^39  | 000110101 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 53
+// a^40  | 001101010 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 106
+// a^41  | 011010100 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 212
+// a^42  | 010110101 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 181
+// a^43  | 001110111 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 119
+// a^44  | 011101110 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 238
+// a^45  | 011000001 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 193
+// a^46  | 010011111 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 159
+// a^47  | 000100011 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 35
+// a^48  | 001000110 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 70
+// a^49  | 010001100 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 140
+// a^50  | 000000101 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 5
+// a^51  | 000001010 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 10
+// a^52  | 000010100 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 20
+// a^53  | 000101000 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 40
+// a^54  | 001010000 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 80
+// a^55  | 010100000 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 160
+// a^56  | 001011101 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 93
+// a^57  | 010111010 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 186
+// a^58  | 001101001 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 105
+// a^59  | 011010010 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 210
+// a^60  | 010111001 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 185
+// a^61  | 001101111 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 111
+// a^62  | 011011110 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 222
+// a^63  | 010100001 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 161
+// a^64  | 001011111 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 95
+// a^65  | 010111110 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 190
+// a^66  | 001100001 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 97
+// a^67  | 011000010 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 194
+// a^68  | 010011001 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 153
+// a^69  | 000101111 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 47
+// a^70  | 001011110 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 94
+// a^71  | 010111100 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 188
+// a^72  | 001100101 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 101
+// a^73  | 011001010 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 202
+// a^74  | 010001001 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 137
+// a^75  | 000001111 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 15
+// a^76  | 000011110 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 30
+// a^77  | 000111100 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 60
+// a^78  | 001111000 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 120
+// a^79  | 011110000 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 240
+// a^80  | 011111101 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 253
+// a^81  | 011100111 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 231
+// a^82  | 011010011 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 211
+// a^83  | 010111011 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 187
+// a^84  | 001101011 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 107
+// a^85  | 011010110 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 214
+// a^86  | 010110001 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 177
+// a^87  | 001111111 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 127
+// a^88  | 011111110 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 254
+// a^89  | 011100001 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 225
+// a^90  | 011011111 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 223
+// a^91  | 010100011 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 163
+// a^92  | 001011011 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 91
+// a^93  | 010110110 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 182
+// a^94  | 001110001 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 113
+// a^95  | 011100010 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 226
+// a^96  | 011011001 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 217
+// a^97  | 010101111 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 175
+// a^98  | 001000011 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 67
+// a^99  | 010000110 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 134
+// a^100 | 000010001 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 17
+// a^101 | 000100010 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 34
+// a^102 | 001000100 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 68
+// a^103 | 010001000 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 136
+// a^104 | 000001101 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 13
+// a^105 | 000011010 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 26
+// a^106 | 000110100 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 52
+// a^107 | 001101000 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 104
+// a^108 | 011010000 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 208
+// a^109 | 010111101 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 189
+// a^110 | 001100111 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 103
+// a^111 | 011001110 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 206
+// a^112 | 010000001 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 129
+// a^113 | 000011111 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 31
+// a^114 | 000111110 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 62
+// a^115 | 001111100 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 124
+// a^116 | 011111000 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 248
+// a^117 | 011101101 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 237
+// a^118 | 011000111 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 199
+// a^119 | 010010011 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 147
+// a^120 | 000111011 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 59
+// a^121 | 001110110 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 118
+// a^122 | 011101100 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 236
+// a^123 | 011000101 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 197
+// a^124 | 010010111 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 151
+// a^125 | 000110011 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 51
+// a^126 | 001100110 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 102
+// a^127 | 011001100 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 204
+// a^128 | 010000101 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 133
+// a^129 | 000010111 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 23
+// a^130 | 000101110 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 46
+// a^131 | 001011100 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 92
+// a^132 | 010111000 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 184
+// a^133 | 001101101 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 109
+// a^134 | 011011010 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 218
+// a^135 | 010101001 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 169
+// a^136 | 001001111 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 79
+// a^137 | 010011110 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 158
+// a^138 | 000100001 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 33
+// a^139 | 001000010 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 66
+// a^140 | 010000100 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 132
+// a^141 | 000010101 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 21
+// a^142 | 000101010 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 42
+// a^143 | 001010100 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 84
+// a^144 | 010101000 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 168
+// a^145 | 001001101 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 77
+// a^146 | 010011010 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 154
+// a^147 | 000101001 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 41
+// a^148 | 001010010 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 82
+// a^149 | 010100100 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 164
+// a^150 | 001010101 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 85
+// a^151 | 010101010 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 170
+// a^152 | 001001001 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 73
+// a^153 | 010010010 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 146
+// a^154 | 000111001 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 57
+// a^155 | 001110010 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 114
+// a^156 | 011100100 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 228
+// a^157 | 011010101 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 213
+// a^158 | 010110111 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 183
+// a^159 | 001110011 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 115
+// a^160 | 011100110 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 230
+// a^161 | 011010001 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 209
+// a^162 | 010111111 | 0x^8 1x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 191
+// a^163 | 001100011 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 99
+// a^164 | 011000110 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 198
+// a^165 | 010010001 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 145
+// a^166 | 000111111 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 63
+// a^167 | 001111110 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 0x^0 | 126
+// a^168 | 011111100 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 252
+// a^169 | 011100101 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 229
+// a^170 | 011010111 | 0x^8 1x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 215
+// a^171 | 010110011 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 179
+// a^172 | 001111011 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 123
+// a^173 | 011110110 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 246
+// a^174 | 011110001 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 241
+// a^175 | 011111111 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 1x^2 1x^1 1x^0 | 255
+// a^176 | 011100011 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 227
+// a^177 | 011011011 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 219
+// a^178 | 010101011 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 171
+// a^179 | 001001011 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 75
+// a^180 | 010010110 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 150
+// a^181 | 000110001 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 49
+// a^182 | 001100010 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 98
+// a^183 | 011000100 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 196
+// a^184 | 010010101 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 149
+// a^185 | 000110111 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 55
+// a^186 | 001101110 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 110
+// a^187 | 011011100 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 220
+// a^188 | 010100101 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 165
+// a^189 | 001010111 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 87
+// a^190 | 010101110 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 174
+// a^191 | 001000001 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 65
+// a^192 | 010000010 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 130
+// a^193 | 000011001 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 25
+// a^194 | 000110010 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 50
+// a^195 | 001100100 | 0x^8 0x^7 1x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 100
+// a^196 | 011001000 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 200
+// a^197 | 010001101 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 141
+// a^198 | 000000111 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 7
+// a^199 | 000001110 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 14
+// a^200 | 000011100 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 1x^2 0x^1 0x^0 | 28
+// a^201 | 000111000 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 56
+// a^202 | 001110000 | 0x^8 0x^7 1x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 112
+// a^203 | 011100000 | 0x^8 1x^7 1x^6 1x^5 0x^4 0x^3 0x^2 0x^1 0x^0 | 224
+// a^204 | 011011101 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 221
+// a^205 | 010100111 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 167
+// a^206 | 001010011 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 83
+// a^207 | 010100110 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 1x^2 1x^1 0x^0 | 166
+// a^208 | 001010001 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 0x^2 0x^1 1x^0 | 81
+// a^209 | 010100010 | 0x^8 1x^7 0x^6 1x^5 0x^4 0x^3 0x^2 1x^1 0x^0 | 162
+// a^210 | 001011001 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 89
+// a^211 | 010110010 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 178
+// a^212 | 001111001 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 121
+// a^213 | 011110010 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 242
+// a^214 | 011111001 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 0x^1 1x^0 | 249
+// a^215 | 011101111 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 239
+// a^216 | 011000011 | 0x^8 1x^7 1x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 195
+// a^217 | 010011011 | 0x^8 1x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 155
+// a^218 | 000101011 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 43
+// a^219 | 001010110 | 0x^8 0x^7 1x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 86
+// a^220 | 010101100 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 172
+// a^221 | 001000101 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 0x^1 1x^0 | 69
+// a^222 | 010001010 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 0x^0 | 138
+// a^223 | 000001001 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 9
+// a^224 | 000010010 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 0x^2 1x^1 0x^0 | 18
+// a^225 | 000100100 | 0x^8 0x^7 0x^6 1x^5 0x^4 0x^3 1x^2 0x^1 0x^0 | 36
+// a^226 | 001001000 | 0x^8 0x^7 1x^6 0x^5 0x^4 1x^3 0x^2 0x^1 0x^0 | 72
+// a^227 | 010010000 | 0x^8 1x^7 0x^6 0x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 144
+// a^228 | 000111101 | 0x^8 0x^7 0x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 61
+// a^229 | 001111010 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 122
+// a^230 | 011110100 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 0x^0 | 244
+// a^231 | 011110101 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 0x^1 1x^0 | 245
+// a^232 | 011110111 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 1x^2 1x^1 1x^0 | 247
+// a^233 | 011110011 | 0x^8 1x^7 1x^6 1x^5 1x^4 0x^3 0x^2 1x^1 1x^0 | 243
+// a^234 | 011111011 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 251
+// a^235 | 011101011 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 235
+// a^236 | 011001011 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 203
+// a^237 | 010001011 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 139
+// a^238 | 000001011 | 0x^8 0x^7 0x^6 0x^5 0x^4 1x^3 0x^2 1x^1 1x^0 | 11
+// a^239 | 000010110 | 0x^8 0x^7 0x^6 0x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 22
+// a^240 | 000101100 | 0x^8 0x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 44
+// a^241 | 001011000 | 0x^8 0x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 88
+// a^242 | 010110000 | 0x^8 1x^7 0x^6 1x^5 1x^4 0x^3 0x^2 0x^1 0x^0 | 176
+// a^243 | 001111101 | 0x^8 0x^7 1x^6 1x^5 1x^4 1x^3 1x^2 0x^1 1x^0 | 125
+// a^244 | 011111010 | 0x^8 1x^7 1x^6 1x^5 1x^4 1x^3 0x^2 1x^1 0x^0 | 250
+// a^245 | 011101001 | 0x^8 1x^7 1x^6 1x^5 0x^4 1x^3 0x^2 0x^1 1x^0 | 233
+// a^246 | 011001111 | 0x^8 1x^7 1x^6 0x^5 0x^4 1x^3 1x^2 1x^1 1x^0 | 207
+// a^247 | 010000011 | 0x^8 1x^7 0x^6 0x^5 0x^4 0x^3 0x^2 1x^1 1x^0 | 131
+// a^248 | 000011011 | 0x^8 0x^7 0x^6 0x^5 1x^4 1x^3 0x^2 1x^1 1x^0 | 27
+// a^249 | 000110110 | 0x^8 0x^7 0x^6 1x^5 1x^4 0x^3 1x^2 1x^1 0x^0 | 54
+// a^250 | 001101100 | 0x^8 0x^7 1x^6 1x^5 0x^4 1x^3 1x^2 0x^1 0x^0 | 108
+// a^251 | 011011000 | 0x^8 1x^7 1x^6 0x^5 1x^4 1x^3 0x^2 0x^1 0x^0 | 216
+// a^252 | 010101101 | 0x^8 1x^7 0x^6 1x^5 0x^4 1x^3 1x^2 0x^1 1x^0 | 173
+// a^253 | 001000111 | 0x^8 0x^7 1x^6 0x^5 0x^4 0x^3 1x^2 1x^1 1x^0 | 71
+// a^254 | 010001110 | 0x^8 1x^7 0x^6 0x^5 0x^4 1x^3 1x^2 1x^1 0x^0 | 142
+// a^255 | 000000001 | 0x^8 0x^7 0x^6 0x^5 0x^4 0x^3 0x^2 0x^1 1x^0 | 1

+ 83 - 0
reedsolomon/gf2_8_test.go

@@ -0,0 +1,83 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package reedsolomon
+
+import "testing"
+
+func TestGFMultiplicationIdentities(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		value := gfElement(i)
+		if gfMultiply(gfZero, value) != gfZero {
+			t.Errorf("0 . %d != 0", value)
+		}
+
+		if gfMultiply(value, gfOne) != value {
+			t.Errorf("%d . 1 == %d, want %d", value, gfMultiply(value, gfOne), value)
+		}
+	}
+}
+
+func TestGFMultiplicationAndDivision(t *testing.T) {
+	// a * b == result
+	var tests = []struct {
+		a      gfElement
+		b      gfElement
+		result gfElement
+	}{
+		{0, 29, 0},
+		{1, 1, 1},
+		{1, 32, 32},
+		{2, 4, 8},
+		{16, 128, 232},
+		{17, 17, 28},
+		{27, 9, 195},
+	}
+
+	for _, test := range tests {
+		result := gfMultiply(test.a, test.b)
+
+		if result != test.result {
+			t.Errorf("%d * %d = %d, want %d", test.a, test.b, result, test.result)
+		}
+
+		if test.b != gfZero && test.result != gfZero {
+			b := gfDivide(test.result, test.a)
+
+			if b != test.b {
+				t.Errorf("%d / %d = %d, want %d", test.result, test.a, b, test.b)
+			}
+		}
+	}
+}
+
+func TestGFInverse(t *testing.T) {
+	for i := 1; i < 256; i++ {
+		a := gfElement(i)
+		inverse := gfInverse(a)
+
+		result := gfMultiply(a, inverse)
+
+		if result != gfOne {
+			t.Errorf("%d * %d^-1 == %d, want %d", a, inverse, result, gfOne)
+		}
+	}
+}
+
+func TestGFDivide(t *testing.T) {
+	for i := 1; i < 256; i++ {
+		for j := 1; j < 256; j++ {
+			// a * b == product
+			a := gfElement(i)
+			b := gfElement(j)
+			product := gfMultiply(a, b)
+
+			// product / b == a
+			result := gfDivide(product, b)
+
+			if result != a {
+				t.Errorf("%d / %d == %d, want %d", product, b, result, a)
+			}
+		}
+	}
+}

+ 216 - 0
reedsolomon/gf_poly.go

@@ -0,0 +1,216 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package reedsolomon
+
+import (
+	"fmt"
+	"log"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+// gfPoly is a polynomial over GF(2^8).
+type gfPoly struct {
+	// The ith value is the coefficient of the ith degree of x.
+	// term[0]*(x^0) + term[1]*(x^1) + term[2]*(x^2) ...
+	term []gfElement
+}
+
+// newGFPolyFromData returns |data| as a polynomial over GF(2^8).
+//
+// Each data byte becomes the coefficient of an x term.
+//
+// For an n byte input the polynomial is:
+// data[n-1]*(x^n-1) + data[n-2]*(x^n-2) ... + data[0]*(x^0).
+func newGFPolyFromData(data *bitset.Bitset) gfPoly {
+	numTotalBytes := data.Len() / 8
+	if data.Len()%8 != 0 {
+		numTotalBytes++
+	}
+
+	result := gfPoly{term: make([]gfElement, numTotalBytes)}
+
+	i := numTotalBytes - 1
+	for j := 0; j < data.Len(); j += 8 {
+		result.term[i] = gfElement(data.ByteAt(j))
+		i--
+	}
+
+	return result
+}
+
+// newGFPolyMonomial returns term*(x^degree).
+func newGFPolyMonomial(term gfElement, degree int) gfPoly {
+	if term == gfZero {
+		return gfPoly{}
+	}
+
+	result := gfPoly{term: make([]gfElement, degree+1)}
+	result.term[degree] = term
+
+	return result
+}
+
+func (e gfPoly) data(numTerms int) []byte {
+	result := make([]byte, numTerms)
+
+	i := numTerms - len(e.term)
+	for j := len(e.term) - 1; j >= 0; j-- {
+		result[i] = byte(e.term[j])
+		i++
+	}
+
+	return result
+}
+
+// numTerms returns the number of
+func (e gfPoly) numTerms() int {
+	return len(e.term)
+}
+
+// gfPolyMultiply returns a * b.
+func gfPolyMultiply(a, b gfPoly) gfPoly {
+	numATerms := a.numTerms()
+	numBTerms := b.numTerms()
+
+	result := gfPoly{term: make([]gfElement, numATerms+numBTerms)}
+
+	for i := 0; i < numATerms; i++ {
+		for j := 0; j < numBTerms; j++ {
+			if a.term[i] != 0 && b.term[j] != 0 {
+				monomial := gfPoly{term: make([]gfElement, i+j+1)}
+				monomial.term[i+j] = gfMultiply(a.term[i], b.term[j])
+
+				result = gfPolyAdd(result, monomial)
+			}
+		}
+	}
+
+	return result.normalised()
+}
+
+// gfPolyRemainder return the remainder of numerator / denominator.
+func gfPolyRemainder(numerator, denominator gfPoly) gfPoly {
+	if denominator.equals(gfPoly{}) {
+		log.Panicln("Remainder by zero")
+	}
+
+	remainder := numerator
+
+	for remainder.numTerms() >= denominator.numTerms() {
+		degree := remainder.numTerms() - denominator.numTerms()
+		coefficient := gfDivide(remainder.term[remainder.numTerms()-1],
+			denominator.term[denominator.numTerms()-1])
+
+		divisor := gfPolyMultiply(denominator,
+			newGFPolyMonomial(coefficient, degree))
+
+		remainder = gfPolyAdd(remainder, divisor)
+	}
+
+	return remainder.normalised()
+}
+
+// gfPolyAdd returns a + b.
+func gfPolyAdd(a, b gfPoly) gfPoly {
+	numATerms := a.numTerms()
+	numBTerms := b.numTerms()
+
+	numTerms := numATerms
+	if numBTerms > numTerms {
+		numTerms = numBTerms
+	}
+
+	result := gfPoly{term: make([]gfElement, numTerms)}
+
+	for i := 0; i < numTerms; i++ {
+		switch {
+		case numATerms > i && numBTerms > i:
+			result.term[i] = gfAdd(a.term[i], b.term[i])
+		case numATerms > i:
+			result.term[i] = a.term[i]
+		default:
+			result.term[i] = b.term[i]
+		}
+	}
+
+	return result.normalised()
+}
+
+func (e gfPoly) normalised() gfPoly {
+	numTerms := e.numTerms()
+	maxNonzeroTerm := numTerms - 1
+
+	for i := numTerms - 1; i >= 0; i-- {
+		if e.term[i] != 0 {
+			break
+		}
+
+		maxNonzeroTerm = i - 1
+	}
+
+	if maxNonzeroTerm < 0 {
+		return gfPoly{}
+	} else if maxNonzeroTerm < numTerms-1 {
+		e.term = e.term[0 : maxNonzeroTerm+1]
+	}
+
+	return e
+}
+
+func (e gfPoly) string(useIndexForm bool) string {
+	var str string
+	numTerms := e.numTerms()
+
+	for i := numTerms - 1; i >= 0; i-- {
+		if e.term[i] > 0 {
+			if len(str) > 0 {
+				str += " + "
+			}
+
+			if !useIndexForm {
+				str += fmt.Sprintf("%dx^%d", e.term[i], i)
+			} else {
+				str += fmt.Sprintf("a^%dx^%d", gfLogTable[e.term[i]], i)
+			}
+		}
+	}
+
+	if len(str) == 0 {
+		str = "0"
+	}
+
+	return str
+}
+
+// equals returns true if e == other.
+func (e gfPoly) equals(other gfPoly) bool {
+	var minecPoly *gfPoly
+	var maxecPoly *gfPoly
+
+	if e.numTerms() > other.numTerms() {
+		minecPoly = &other
+		maxecPoly = &e
+	} else {
+		minecPoly = &e
+		maxecPoly = &other
+	}
+
+	numMinTerms := minecPoly.numTerms()
+	numMaxTerms := maxecPoly.numTerms()
+
+	for i := 0; i < numMinTerms; i++ {
+		if e.term[i] != other.term[i] {
+			return false
+		}
+	}
+
+	for i := numMinTerms; i < numMaxTerms; i++ {
+		if maxecPoly.term[i] != 0 {
+			return false
+		}
+	}
+
+	return true
+}

+ 182 - 0
reedsolomon/gf_poly_test.go

@@ -0,0 +1,182 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package reedsolomon
+
+import (
+	"testing"
+)
+
+func TestGFPolyAdd(t *testing.T) {
+	// a + b == result
+	var tests = []struct {
+		a      gfPoly
+		b      gfPoly
+		result gfPoly
+	}{
+		{
+			gfPoly{[]gfElement{0, 0, 0}},
+			gfPoly{[]gfElement{0}},
+			gfPoly{[]gfElement{}},
+		},
+		{
+			gfPoly{[]gfElement{1, 0}},
+			gfPoly{[]gfElement{1, 0}},
+			gfPoly{[]gfElement{0, 0}},
+		},
+		{
+			gfPoly{[]gfElement{0xA0, 0x80, 0xFF, 0x00}},
+			gfPoly{[]gfElement{0x0A, 0x82}},
+			gfPoly{[]gfElement{0xAA, 0x02, 0xFF}},
+		},
+	}
+
+	for _, test := range tests {
+		result := gfPolyAdd(test.a, test.b)
+
+		if !test.result.equals(result) {
+			t.Errorf("%s * %s != %s (got %s)\n", test.a.string(false), test.b.string(false),
+				test.result.string(false), result.string(false))
+		}
+
+		if len(result.term) > 0 && result.term[len(result.term)-1] == 0 {
+			t.Errorf("Result's maximum term coefficient is zero")
+		}
+	}
+}
+
+func TestGFPolyequals(t *testing.T) {
+	// a == b if isEqual
+	var tests = []struct {
+		a       gfPoly
+		b       gfPoly
+		isEqual bool
+	}{
+		{
+			gfPoly{[]gfElement{0}},
+			gfPoly{[]gfElement{0}},
+			true,
+		},
+		{
+			gfPoly{[]gfElement{1}},
+			gfPoly{[]gfElement{0}},
+			false,
+		},
+		{
+			gfPoly{[]gfElement{1, 0, 1, 0, 1}},
+			gfPoly{[]gfElement{1, 0, 1, 0, 1}},
+			true,
+		},
+		{
+			gfPoly{[]gfElement{1, 0, 1}},
+			gfPoly{[]gfElement{1, 0, 1, 0, 0}},
+			true,
+		},
+	}
+
+	for _, test := range tests {
+		var isEqual bool = test.a.equals(test.b)
+
+		if isEqual != test.isEqual {
+			t.Errorf("%s and %s equality is %t (got %t)\n", test.a.string(false), test.b.string(false),
+				test.isEqual, isEqual)
+		}
+	}
+}
+
+func TestGFPolyMultiply(t *testing.T) {
+	// a * b == result
+	var tests = []struct {
+		a      gfPoly
+		b      gfPoly
+		result gfPoly
+	}{
+		{
+			gfPoly{[]gfElement{0, 0, 1}},
+			gfPoly{[]gfElement{9}},
+			gfPoly{[]gfElement{0, 0, 9}},
+		},
+		{
+			gfPoly{[]gfElement{0, 16, 1}},
+			gfPoly{[]gfElement{128, 2}},
+			gfPoly{[]gfElement{0, 232, 160, 2}},
+		},
+		{
+			gfPoly{[]gfElement{254, 120, 88, 44, 11, 1}},
+			gfPoly{[]gfElement{16, 2, 0, 51, 44}},
+			gfPoly{[]gfElement{91, 50, 25, 184, 194, 105, 45, 244, 58, 44}},
+		},
+	}
+
+	for _, test := range tests {
+		result := gfPolyMultiply(test.a, test.b)
+
+		if !test.result.equals(result) {
+			t.Errorf("%s * %s = %s (got %s)\n",
+				test.a.string(false),
+				test.b.string(false),
+				test.result.string(false),
+				result.string(false))
+		}
+	}
+}
+
+func TestGFPolyRemainder(t *testing.T) {
+	// numerator / denominator == quotient + remainder.
+	var tests = []struct {
+		numerator   gfPoly
+		denominator gfPoly
+		remainder   gfPoly
+	}{
+		{
+			gfPoly{[]gfElement{1}},
+			gfPoly{[]gfElement{1}},
+			gfPoly{[]gfElement{0}},
+		},
+		{
+			gfPoly{[]gfElement{1, 0}},
+			gfPoly{[]gfElement{1}},
+			gfPoly{[]gfElement{0}},
+		},
+		{
+			gfPoly{[]gfElement{1}},
+			gfPoly{[]gfElement{1, 0}},
+			gfPoly{[]gfElement{1}},
+		},
+		{
+			gfPoly{[]gfElement{1, 0, 1}},
+			gfPoly{[]gfElement{0, 1}},
+			gfPoly{[]gfElement{1}},
+		},
+		// (x^12 + x^10) / (x^10 + x^8 + x^5 + x^4 + x^2 + x^1 + x^0) =
+		//  (x^10 + x^8 + x^5 + x^4 + x^2 + x^1 + x^0) * x^2 +
+		//  (x^7 + x^6 + x^4 + x^3 + x^2) (the remainder)
+		{
+			gfPoly{[]gfElement{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}},
+			gfPoly{[]gfElement{1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1}},
+			gfPoly{[]gfElement{0, 0, 1, 1, 1, 0, 1, 1}},
+		},
+		{
+			gfPoly{[]gfElement{91, 50, 25, 184, 194, 105, 45, 244, 58, 44}},
+			gfPoly{[]gfElement{254, 120, 88, 44, 11, 1}},
+			gfPoly{[]gfElement{}},
+		},
+		{
+			gfPoly{[]gfElement{0, 0, 0, 0, 0, 0, 195, 172, 24, 64}},
+			gfPoly{[]gfElement{116, 147, 63, 198, 31, 1}},
+			gfPoly{[]gfElement{48, 174, 34, 13, 134}},
+		},
+	}
+
+	for _, test := range tests {
+		remainder := gfPolyRemainder(test.numerator, test.denominator)
+
+		if !test.remainder.equals(remainder) {
+			t.Errorf("%s / %s, remainder = %s (got %s)\n",
+				test.numerator.string(false),
+				test.denominator.string(false),
+				test.remainder.string(false),
+				remainder.string(false))
+		}
+	}
+}

+ 73 - 0
reedsolomon/reed_solomon.go

@@ -0,0 +1,73 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+// Reed-Solomon error correction for QR Code 2005.
+//
+// QR Code 2005 uses a Reed-Solomon error correcting code to detect and correct
+// errors encountered during decoding.
+//
+// The generated RS codes are systematic, and consist of the input data with
+// error correction bytes appended.
+package reedsolomon
+
+import (
+	"log"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+// Encode data for QR Code 2005 using the appropriate Reed-Solomon code.
+//
+// numECBytes is the number of error correction bytes to append, and is
+// determined by the target QR Code's version and error correction level.
+//
+// ISO/IEC 18004 table 9 specifies the numECBytes required. e.g. a 1-L code has
+// numECBytes=7.
+func Encode(data *bitset.Bitset, numECBytes int) *bitset.Bitset {
+	// Create a polynomial representing |data|.
+	//
+	// The bytes are interpreted as the sequence of coefficients of a polynomial.
+	// The last byte's value becomes the x^0 coefficient, the second to last
+	// becomes the x^1 coefficient and so on.
+	ecpoly := newGFPolyFromData(data)
+	ecpoly = gfPolyMultiply(ecpoly, newGFPolyMonomial(gfOne, numECBytes))
+
+	// Pick the generator polynomial.
+	generator := rsGeneratorPoly(numECBytes)
+
+	// Generate the error correction bytes.
+	remainder := gfPolyRemainder(ecpoly, generator)
+
+	// Combine the data & error correcting bytes.
+	// The mathematically correct answer is:
+	//
+	//	result := gfPolyAdd(ecpoly, remainder).
+	//
+	// The encoding used by QR Code 2005 is slightly different this result: To
+	// preserve the original |data| bit sequence exactly, the data and remainder
+	// are combined manually below. This ensures any most significant zero bits
+	// are preserved (and not optimised away).
+	result := bitset.Clone(data)
+	result.AppendBytes(remainder.data(numECBytes))
+
+	return result
+}
+
+// rsGeneratorPoly returns the Reed-Solomon generator polynomial with |degree|.
+//
+// The generator polynomial is calculated as:
+// (x + a^0)(x + a^1)...(x + a^degree-1)
+func rsGeneratorPoly(degree int) gfPoly {
+	if degree < 2 {
+		log.Panic("degree < 2")
+	}
+
+	generator := gfPoly{term: []gfElement{1}}
+
+	for i := 0; i < degree; i++ {
+		nextPoly := gfPoly{term: []gfElement{gfExpTable[i], 1}}
+		generator = gfPolyMultiply(generator, nextPoly)
+	}
+
+	return generator
+}

+ 89 - 0
reedsolomon/reed_solomon_test.go

@@ -0,0 +1,89 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package reedsolomon
+
+import (
+	"testing"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+func TestGeneratorPoly(t *testing.T) {
+	var tests = []struct {
+		degree    int
+		generator gfPoly
+	}{
+		// x^2 + 3x^1 + 2x^0 (the shortest generator poly)
+		{
+			2,
+			gfPoly{term: []gfElement{2, 3, 1}},
+		},
+		// x^5 + 31x^4 + 198x^3 + 63x^2 + 147x^1 + 116x^0
+		{
+			5,
+			gfPoly{term: []gfElement{116, 147, 63, 198, 31, 1}},
+		},
+		// x^68 + 131x^67 + 115x^66 + 9x^65 + 39x^64 + 18x^63 + 182x^62 + 60x^61 +
+		// 94x^60 + 223x^59 + 230x^58 + 157x^57 + 142x^56 + 119x^55 + 85x^54 +
+		// 107x^53 + 34x^52 + 174x^51 + 167x^50 + 109x^49 + 20x^48 + 185x^47 +
+		// 112x^46 + 145x^45 + 172x^44 + 224x^43 + 170x^42 + 182x^41 + 107x^40 +
+		// 38x^39 + 107x^38 + 71x^37 + 246x^36 + 230x^35 + 225x^34 + 144x^33 +
+		// 20x^32 + 14x^31 + 175x^30 + 226x^29 + 245x^28 + 20x^27 + 219x^26 +
+		// 212x^25 + 51x^24 + 158x^23 + 88x^22 + 63x^21 + 36x^20 + 199x^19 + 4x^18 +
+		// 80x^17 + 157x^16 + 211x^15 + 239x^14 + 255x^13 + 7x^12 + 119x^11 + 11x^10
+		// + 235x^9 + 12x^8 + 34x^7 + 149x^6 + 204x^5 + 8x^4 + 32x^3 + 29x^2 + 99x^1
+		// + 11x^0 (the longest generator poly)
+		{
+			68,
+			gfPoly{term: []gfElement{11, 99, 29, 32, 8, 204, 149, 34, 12,
+				235, 11, 119, 7, 255, 239, 211, 157, 80, 4, 199, 36, 63, 88, 158, 51, 212,
+				219, 20, 245, 226, 175, 14, 20, 144, 225, 230, 246, 71, 107, 38, 107, 182,
+				170, 224, 172, 145, 112, 185, 20, 109, 167, 174, 34, 107, 85, 119, 142,
+				157, 230, 223, 94, 60, 182, 18, 39, 9, 115, 131, 1}},
+		},
+	}
+
+	for _, test := range tests {
+		generator := rsGeneratorPoly(test.degree)
+
+		if !generator.equals(test.generator) {
+			t.Errorf("degree=%d generator=%s, want %s", test.degree,
+				generator.string(true), test.generator.string(true))
+		}
+	}
+}
+
+func TestEncode(t *testing.T) {
+	var tests = []struct {
+		numECBytes int
+		data       string
+		rsCode     string
+	}{
+		{
+			5,
+			"01000000 00011000 10101100 11000011 00000000",
+			"01000000 00011000 10101100 11000011 00000000 10000110 00001101 00100010 10101110 00110000",
+		},
+		{
+			10,
+			"00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001",
+			"00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 11101100 00010001 10100101 00100100 11010100 11000001 11101101 00110110 11000111 10000111 00101100 01010101",
+		},
+	}
+
+	for _, test := range tests {
+		var data *bitset.Bitset = bitset.NewFromBase2String(test.data)
+		var rsCode *bitset.Bitset = bitset.NewFromBase2String(test.rsCode)
+
+		var result *bitset.Bitset = Encode(data, test.numECBytes)
+
+		if !rsCode.Equals(result) {
+			t.Errorf("data=%s, numECBytes=%d, encoded=%s, want %s",
+				data.String(),
+				test.numECBytes,
+				result.String(),
+				rsCode)
+		}
+	}
+}

+ 309 - 0
regular_symbol.go

@@ -0,0 +1,309 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+type regularSymbol struct {
+	version qrCodeVersion
+	mask    int
+
+	data *bitset.Bitset
+
+	symbol *symbol
+	size   int
+}
+
+// Abbreviated true/false.
+const (
+	b0 = false
+	b1 = true
+)
+
+var (
+	alignmentPatternCenter = [][]int{
+		{}, // Version 0 doesn't exist.
+		{}, // Version 1 doesn't use alignment patterns.
+		{6, 18},
+		{6, 22},
+		{6, 26},
+		{6, 30},
+		{6, 34},
+		{6, 22, 38},
+		{6, 24, 42},
+		{6, 26, 46},
+		{6, 28, 50},
+		{6, 30, 54},
+		{6, 32, 58},
+		{6, 34, 62},
+		{6, 26, 46, 66},
+		{6, 26, 48, 70},
+		{6, 26, 50, 74},
+		{6, 30, 54, 78},
+		{6, 30, 56, 82},
+		{6, 30, 58, 86},
+		{6, 34, 62, 90},
+		{6, 28, 50, 72, 94},
+		{6, 26, 50, 74, 98},
+		{6, 30, 54, 78, 102},
+		{6, 28, 54, 80, 106},
+		{6, 32, 58, 84, 110},
+		{6, 30, 58, 86, 114},
+		{6, 34, 62, 90, 118},
+		{6, 26, 50, 74, 98, 122},
+		{6, 30, 54, 78, 102, 126},
+		{6, 26, 52, 78, 104, 130},
+		{6, 30, 56, 82, 108, 134},
+		{6, 34, 60, 86, 112, 138},
+		{6, 30, 58, 86, 114, 142},
+		{6, 34, 62, 90, 118, 146},
+		{6, 30, 54, 78, 102, 126, 150},
+		{6, 24, 50, 76, 102, 128, 154},
+		{6, 28, 54, 80, 106, 132, 158},
+		{6, 32, 58, 84, 110, 136, 162},
+		{6, 26, 54, 82, 110, 138, 166},
+		{6, 30, 58, 86, 114, 142, 170},
+	}
+
+	finderPattern = [][]bool{
+		{b1, b1, b1, b1, b1, b1, b1},
+		{b1, b0, b0, b0, b0, b0, b1},
+		{b1, b0, b1, b1, b1, b0, b1},
+		{b1, b0, b1, b1, b1, b0, b1},
+		{b1, b0, b1, b1, b1, b0, b1},
+		{b1, b0, b0, b0, b0, b0, b1},
+		{b1, b1, b1, b1, b1, b1, b1},
+	}
+
+	finderPatternSize = 7
+
+	finderPatternHorizontalBorder = [][]bool{
+		{b0, b0, b0, b0, b0, b0, b0, b0},
+	}
+
+	finderPatternVerticalBorder = [][]bool{
+		{b0},
+		{b0},
+		{b0},
+		{b0},
+		{b0},
+		{b0},
+		{b0},
+		{b0},
+	}
+
+	alignmentPattern = [][]bool{
+		{b1, b1, b1, b1, b1},
+		{b1, b0, b0, b0, b1},
+		{b1, b0, b1, b0, b1},
+		{b1, b0, b0, b0, b1},
+		{b1, b1, b1, b1, b1},
+	}
+)
+
+func buildRegularSymbol(version qrCodeVersion, mask int,
+	data *bitset.Bitset) (*symbol, error) {
+	var m *regularSymbol = &regularSymbol{
+		version: version,
+		mask:    mask,
+		data:    data,
+
+		symbol: newSymbol(version.symbolSize(), version.quietZoneSize()),
+		size:   version.symbolSize(),
+	}
+
+	m.addFinderPatterns()
+	m.addAlignmentPatterns()
+	m.addTimingPatterns()
+	m.addFormatInfo()
+	m.addVersionInfo()
+
+	ok, err := m.addData()
+	if !ok {
+		return nil, err
+	}
+
+	return m.symbol, nil
+}
+
+func (m *regularSymbol) addFinderPatterns() {
+	var fpSize int = finderPatternSize
+	var fp [][]bool = finderPattern
+	var fpHBorder [][]bool = finderPatternHorizontalBorder
+	var fpVBorder [][]bool = finderPatternVerticalBorder
+
+	// Top left Finder Pattern.
+	m.symbol.set2dPattern(0, 0, fp)
+	m.symbol.set2dPattern(0, fpSize, fpHBorder)
+	m.symbol.set2dPattern(fpSize, 0, fpVBorder)
+
+	// Top right Finder Pattern.
+	m.symbol.set2dPattern(m.size-fpSize, 0, fp)
+	m.symbol.set2dPattern(m.size-fpSize-1, fpSize, fpHBorder)
+	m.symbol.set2dPattern(m.size-fpSize-1, 0, fpVBorder)
+
+	// Bottom left Finder Pattern.
+	m.symbol.set2dPattern(0, m.size-fpSize, fp)
+	m.symbol.set2dPattern(0, m.size-fpSize-1, fpHBorder)
+	m.symbol.set2dPattern(fpSize, m.size-fpSize-1, fpVBorder)
+}
+
+func (m *regularSymbol) addAlignmentPatterns() {
+	for _, x := range alignmentPatternCenter[m.version.version] {
+		for _, y := range alignmentPatternCenter[m.version.version] {
+			if !m.symbol.empty(x, y) {
+				continue
+			}
+
+			m.symbol.set2dPattern(x-2, y-2, alignmentPattern)
+		}
+	}
+}
+
+func (m *regularSymbol) addTimingPatterns() {
+	var value bool = true
+
+	for i := finderPatternSize + 1; i < m.size-finderPatternSize; i++ {
+		m.symbol.set(i, finderPatternSize-1, value)
+		m.symbol.set(finderPatternSize-1, i, value)
+
+		value = !value
+	}
+}
+
+func (m *regularSymbol) addFormatInfo() {
+	var fpSize int = finderPatternSize
+	var l int = formatInfoLengthBits - 1
+
+	var f *bitset.Bitset = m.version.formatInfo(m.mask)
+
+	// Bits 0-7, under the top right finder pattern.
+	for i := 0; i <= 7; i++ {
+		m.symbol.set(m.size-i-1, fpSize+1, f.At(l-i))
+	}
+
+	// Bits 0-5, right of the top left finder pattern.
+	for i := 0; i <= 5; i++ {
+		m.symbol.set(fpSize+1, i, f.At(l-i))
+	}
+
+	// Bits 6-8 on the corner of the top left finder pattern.
+	m.symbol.set(fpSize+1, fpSize, f.At(l-6))
+	m.symbol.set(fpSize+1, fpSize+1, f.At(l-7))
+	m.symbol.set(fpSize, fpSize+1, f.At(l-8))
+
+	// Bits 9-14 on the underside of the top left finder pattern.
+	for i := 9; i <= 14; i++ {
+		m.symbol.set(14-i, fpSize+1, f.At(l-i))
+	}
+
+	// Bits 8-14 on the right side of the bottom left finder pattern.
+	for i := 8; i <= 14; i++ {
+		m.symbol.set(fpSize+1, m.size-fpSize+i-8, f.At(l-i))
+	}
+
+	// Always dark symbol.
+	m.symbol.set(fpSize+1, m.size-fpSize-1, true)
+}
+
+func (m *regularSymbol) addVersionInfo() {
+	var fpSize int = finderPatternSize
+
+	var v *bitset.Bitset = m.version.versionInfo()
+	var l int = versionInfoLengthBits - 1
+
+	if v == nil {
+		return
+	}
+
+	for i := 0; i < v.Len(); i++ {
+		// Above the bottom left finder pattern.
+		m.symbol.set(i/3, m.size-fpSize-4+i%3, v.At(l-i))
+
+		// Left of the top right finder pattern.
+		m.symbol.set(m.size-fpSize-4+i%3, i/3, v.At(l-i))
+	}
+}
+
+type direction uint8
+
+const (
+	up direction = iota
+	down
+)
+
+func (m *regularSymbol) addData() (bool, error) {
+	var xOffset int = 1
+	var dir direction = up
+
+	var x int = m.size - 2
+	var y int = m.size - 1
+
+	for i := 0; i < m.data.Len(); i++ {
+		var mask bool
+		switch m.mask {
+		case 0:
+			mask = (y+x+xOffset)%2 == 0
+		case 1:
+			mask = y%2 == 0
+		case 2:
+			mask = (x+xOffset)%3 == 0
+		case 3:
+			mask = (y+x+xOffset)%3 == 0
+		case 4:
+			mask = (y/2+(x+xOffset)/3)%2 == 0
+		case 5:
+			mask = (y*(x+xOffset))%2+(y*(x+xOffset))%3 == 0
+		case 6:
+			mask = ((y*(x+xOffset))%2+((y*(x+xOffset))%3))%2 == 0
+		case 7:
+			mask = ((y+x+xOffset)%2+((y*(x+xOffset))%3))%2 == 0
+		}
+
+		// != is equivalent to XOR.
+		m.symbol.set(x+xOffset, y, mask != m.data.At(i))
+
+		if i == m.data.Len()-1 {
+			break
+		}
+
+		// Find next free bit in the symbol.
+		for {
+			if xOffset == 1 {
+				xOffset = 0
+			} else {
+				xOffset = 1
+
+				if dir == up {
+					if y > 0 {
+						y--
+					} else {
+						dir = down
+						x -= 2
+					}
+				} else {
+					if y < m.size-1 {
+						y++
+					} else {
+						dir = up
+						x -= 2
+					}
+				}
+			}
+
+			// Skip over the vertical timing pattern entirely.
+			if x == 5 {
+				x--
+			}
+
+			if m.symbol.empty(x+xOffset, y) {
+				break
+			}
+		}
+	}
+
+	return true, nil
+}

+ 32 - 0
regular_symbol_test.go

@@ -0,0 +1,32 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"fmt"
+	"testing"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+func TestBuildRegularSymbol(t *testing.T) {
+	for k := 0; k <= 7; k++ {
+		var v *qrCodeVersion = getQRCodeVersion(Low, 1)
+		var s *symbol
+
+		var data *bitset.Bitset = bitset.New()
+		for i := 0; i < 26; i++ {
+			data.AppendNumBools(8, false)
+		}
+
+		s, err := buildRegularSymbol(*v, k, data)
+
+		if err != nil {
+			fmt.Println(err.Error())
+		} else {
+			_ = s
+			//fmt.Print(m.string())
+		}
+	}
+}

+ 280 - 0
symbol.go

@@ -0,0 +1,280 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+// symbol is a 2D array of bits representing a QR Code symbol.
+//
+// A symbol consists of size*size modules, with each module normally drawn as a
+// black or white square. The symbol also has a border of quietZoneSize modules.
+//
+// A (fictional) size=2, quietZoneSize=1 QR Code looks like:
+//
+// +----+
+// |    |
+// | ab |
+// | cd |
+// |    |
+// +----+
+//
+// For ease of implementation, the functions to set/get bits ignore the border,
+// so (0,0)=a, (0,1)=b, (1,0)=c, and (1,1)=d. The entire symbol (including the
+// border) is returned by bitmap().
+//
+type symbol struct {
+	// Value of module at [y][x]. True is set.
+	module [][]bool
+
+	// True if the module at [y][x] is used (to either true or false).
+	// Used to identify unused modules.
+	isUsed [][]bool
+
+	// Combined width/height of the symbol and quiet zones.
+	//
+	// size = symbolSize + 2*quietZoneSize.
+	size int
+
+	// Width/height of the symbol only.
+	symbolSize int
+
+	// Width/height of a single quiet zone.
+	quietZoneSize int
+}
+
+// newSymbol constructs a symbol of size size*size, with a border of
+// quietZoneSize.
+func newSymbol(size int, quietZoneSize int) *symbol {
+	var m symbol
+
+	m.module = make([][]bool, size+2*quietZoneSize)
+	m.isUsed = make([][]bool, size+2*quietZoneSize)
+
+	for i := range m.module {
+		m.module[i] = make([]bool, size+2*quietZoneSize)
+		m.isUsed[i] = make([]bool, size+2*quietZoneSize)
+	}
+
+	m.size = size + 2*quietZoneSize
+	m.symbolSize = size
+	m.quietZoneSize = quietZoneSize
+
+	return &m
+}
+
+// get returns the module value at (x, y).
+func (m *symbol) get(x int, y int) (v bool) {
+	v = m.module[y+m.quietZoneSize][x+m.quietZoneSize]
+	return
+}
+
+// empty returns true if the module at (x, y) has not been set (to either true
+// or false).
+func (m *symbol) empty(x int, y int) bool {
+	return !m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize]
+}
+
+// set sets the module at (x, y) to v.
+func (m *symbol) set(x int, y int, v bool) {
+	m.module[y+m.quietZoneSize][x+m.quietZoneSize] = v
+	m.isUsed[y+m.quietZoneSize][x+m.quietZoneSize] = true
+}
+
+// set2dPattern sets a 2D array of modules, starting at (x, y).
+func (m *symbol) set2dPattern(x int, y int, v [][]bool) {
+	for j, row := range v {
+		for i, value := range row {
+			m.set(x+i, y+j, value)
+		}
+	}
+}
+
+// bitmap returns the entire symbol, including the quiet zone.
+func (m *symbol) bitmap() [][]bool {
+	var module [][]bool = make([][]bool, len(m.module))
+
+	for i, _ := range m.module {
+		module[i] = m.module[i][:]
+	}
+
+	return module
+}
+
+// string returns a pictorial representation of the symbol, suitable for
+// printing in a TTY.
+func (m *symbol) string() string {
+	var result string
+
+	for _, row := range m.module {
+		for _, value := range row {
+			switch value {
+			case true:
+				result += "  "
+			case false:
+				// Unicode 'FULL BLOCK' (U+2588).
+				result += "██"
+			}
+		}
+		result += "\n"
+	}
+
+	return result
+}
+
+// Constants used to weight penalty calculations. Specified by ISO/IEC
+// 18004:2006.
+const (
+	penaltyWeight1 = 3
+	penaltyWeight2 = 3
+	penaltyWeight3 = 40
+	penaltyWeight4 = 10
+)
+
+// penaltyScore returns the penalty score of the symbol. The penalty score
+// consists of the sum of the four individual penalty types.
+func (m *symbol) penaltyScore() int {
+	return m.penalty1() + m.penalty2() + m.penalty3() + m.penalty4()
+}
+
+// penalty1 returns the penalty score for "adjacent modules in row/column with
+// same colour".
+//
+// The numbers of adjacent matching modules and scores are:
+// 0-5: score = 0
+// 6+ : score = penaltyWeight1 + (numAdjacentModules - 5)
+func (m *symbol) penalty1() int {
+	var penalty int = 0
+
+	for x := 0; x < m.symbolSize; x++ {
+		lastValue := m.get(x, 0)
+		count := 1
+
+		for y := 1; y < m.symbolSize; y++ {
+			v := m.get(x, y)
+
+			if v != lastValue {
+				count = 1
+				lastValue = v
+			} else {
+				count++
+				if count == 6 {
+					penalty += penaltyWeight1 + 1
+				} else if count > 6 {
+					penalty += 1
+				}
+			}
+		}
+	}
+
+	for y := 0; y < m.symbolSize; y++ {
+		lastValue := m.get(0, y)
+		count := 1
+
+		for x := 1; x < m.symbolSize; x++ {
+			v := m.get(x, y)
+
+			if v != lastValue {
+				count = 1
+				lastValue = v
+			} else {
+				count++
+				if count == 6 {
+					penalty += penaltyWeight1 + 1
+				} else if count > 6 {
+					penalty += 1
+				}
+			}
+		}
+	}
+
+	return penalty
+}
+
+// penalty2 returns the penalty score for "block of modules in the same colour".
+//
+// m*n: score = penaltyWeight2 * (m-1) * (n-1).
+func (m *symbol) penalty2() int {
+	var penalty int = 0
+
+	for y := 1; y < m.symbolSize; y++ {
+		for x := 1; x < m.symbolSize; x++ {
+			topLeft := m.get(x-1, y-1)
+			above := m.get(x, y-1)
+			left := m.get(x-1, y)
+			current := m.get(x, y)
+
+			if current == left && current == above && current == topLeft {
+				penalty++
+			}
+		}
+	}
+
+	return penalty * penaltyWeight2
+}
+
+// penalty3 returns the penalty score for "1:1:3:1:1 ratio
+// (dark:light:dark:light:dark) pattern in row/column, preceded or followed by
+// light area 4 modules wide".
+//
+// Existence of the pattern scores penaltyWeight3.
+func (m *symbol) penalty3() int {
+	var penalty int = 0
+
+	for y := 0; y < m.symbolSize; y++ {
+		var bitBuffer int16 = 0xFF
+
+		for x := 0; x < m.symbolSize; x++ {
+			bitBuffer <<= 1
+			if v := m.get(x, y); v {
+				bitBuffer |= 1
+			}
+
+			switch bitBuffer & 0x7ff {
+			// 0b000 0101 1101 or 0b10111010000
+			// 0x05d           or 0x5d0
+			case 0x05d, 0x5d0:
+				penalty += penaltyWeight3
+			}
+		}
+	}
+
+	for x := 0; x < m.symbolSize; x++ {
+		var bitBuffer int16 = 0xFF
+
+		for y := 0; y < m.symbolSize; y++ {
+			bitBuffer <<= 1
+			if v := m.get(x, y); v {
+				bitBuffer |= 1
+			}
+
+			switch bitBuffer & 0x7ff {
+			// 0b000 0101 1101 or 0b10111010000
+			// 0x05d           or 0x5d0
+			case 0x05d, 0x5d0:
+				penalty += penaltyWeight3
+			}
+		}
+	}
+
+	return penalty
+}
+
+// penalty4 returns the penalty score...
+func (m *symbol) penalty4() int {
+	var numModules int = m.symbolSize * m.symbolSize
+	var numDarkModules int = 0
+
+	for x := 0; x < m.symbolSize; x++ {
+		for y := 0; y < m.symbolSize; y++ {
+			if v := m.get(x, y); v {
+				numDarkModules++
+			}
+		}
+	}
+
+	var numDarkModuleDeviation int = numModules/2 - numDarkModules
+	if numDarkModuleDeviation < 0 {
+		numDarkModuleDeviation *= -1
+	}
+
+	return penaltyWeight4 * (numDarkModuleDeviation / (numModules / 20))
+}

+ 333 - 0
symbol_test.go

@@ -0,0 +1,333 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import "testing"
+
+func TestSymbolBasic(t *testing.T) {
+	var size int = 10
+	var quietZoneSize int = 4
+
+	var m *symbol = newSymbol(size, quietZoneSize)
+
+	if m.size != size+quietZoneSize*2 {
+		t.Errorf("Symbol size is %d, expected %d", m.size, size+quietZoneSize*2)
+	}
+
+	for i := 0; i < size; i++ {
+		for j := 0; j < size; j++ {
+
+			v := m.get(i, j)
+
+			if v != false {
+				t.Errorf("New symbol not empty")
+			}
+
+			if !m.empty(i, j) {
+				t.Errorf("New symbol is not empty")
+			}
+
+			var value bool = i*j%2 == 0
+			m.set(i, j, value)
+
+			v = m.get(i, j)
+
+			if v != value {
+				t.Errorf("Symbol ignores set bits")
+			}
+
+			if m.empty(i, j) {
+				t.Errorf("Symbol ignores set bits")
+			}
+		}
+	}
+}
+
+func TestSymbolPenalties(t *testing.T) {
+	tests := []struct {
+		pattern          [][]bool
+		expectedPenalty1 int
+		expectedPenalty2 int
+		expectedPenalty3 int
+		expectedPenalty4 int
+	}{
+		{
+			[][]bool{
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+			},
+			0, // No adjacent modules of same color.
+			0, // No 2x2+ sized blocks.
+			0, // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+			},
+			0, // 5 adjacent modules of same colour, score = 0.
+			0, // No 2x2+ sized blocks.
+			0, // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+			},
+			4, // 6 adjacent modules of same colour, score = 3 + (6-5)
+			0, // No 2x2+ sized blocks.
+			0, // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0},
+				{b1, b0, b1, b0, b1, b0, b1},
+				{b1, b0, b0, b0, b0, b0, b1},
+				{b1, b0, b1, b0, b1, b0, b1},
+				{b1, b0, b0, b0, b0, b0, b1},
+				{b1, b0, b1, b0, b1, b0, b1},
+				{b1, b0, b0, b0, b0, b0, b0},
+			},
+			28, // 3+(7-5) + 3+(6-5) + 3+(6-5) + 3+(6-5) + 3+(7-5) + 3+(7-5) = 28
+			0,  // No 2x2+ sized blocks.
+			0,  // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b1, b0, b1},
+				{b0, b0, b1, b0, b1, b0},
+				{b0, b1, b0, b1, b0, b1},
+				{b1, b0, b1, b1, b1, b0},
+				{b0, b1, b1, b1, b0, b1},
+				{b1, b0, b1, b0, b1, b0},
+			},
+			-1,
+			6, // 3*(2-1)*(2-1) + 3(2-1)*(2-1)
+			0, // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+			},
+			-1,
+			60, // 3 * (5-1) * (6-1)
+			0,  // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b1},
+				{b0, b0, b0, b0, b0, b1},
+				{b1, b1, b0, b1, b0, b1},
+				{b1, b1, b0, b1, b0, b1},
+				{b1, b1, b0, b1, b0, b1},
+				{b1, b1, b0, b1, b0, b1},
+			},
+			-1,
+			21, // 3*(5-1)*(2-1) + 3*(2-1)*(4-1) = 3*4 + 3*3
+			0,  // No 1:1:3:1:1 pattern.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+				{b0, b0, b0, b0, b1, b0, b1, b1, b1, b0, b1, b0},
+			},
+			-1,
+			-1,
+			480, // 12* 1:1:3:1:1 patterns, 12 * 40.
+			-1,
+		},
+		{
+			[][]bool{
+				{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b1, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+			},
+			-1,
+			-1,
+			80, // 2* 1:1:3:1:1 patterns, 2 * 40.
+			-1,
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+			},
+			-1,
+			-1,
+			-1,
+			100, // 10 * (10 steps of 5% deviation from 50% black/white).
+		},
+		{
+			[][]bool{
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+			},
+			-1,
+			-1,
+			-1,
+			100, // 10 * (10 steps of 5% deviation from 50% black/white).
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+			},
+			-1,
+			-1,
+			-1,
+			0, // Exactly 50%/50% black/white.
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+			},
+			-1,
+			-1,
+			-1,
+			20, // 10 * (2 steps of 5% deviation towards white).
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+			},
+			-1,
+			-1,
+			-1,
+			30, // 10 * (3 steps of 5% deviation towards white).
+		},
+		{
+			[][]bool{
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b0},
+				{b0, b0, b0, b0, b0, b0, b0, b0, b0, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+				{b1, b1, b1, b1, b1, b1, b1, b1, b1, b1},
+			},
+			-1,
+			-1,
+			-1,
+			30, // 10 * (3 steps of 5% deviation towards white).
+		},
+	}
+
+	for i, test := range tests {
+		var s *symbol = newSymbol(len(test.pattern[0]), 4)
+		s.set2dPattern(0, 0, test.pattern)
+
+		penalty1 := s.penalty1()
+		penalty2 := s.penalty2()
+		penalty3 := s.penalty3()
+		penalty4 := s.penalty4()
+
+		var ok bool = true
+		if test.expectedPenalty1 != -1 && test.expectedPenalty1 != penalty1 {
+			ok = false
+		}
+		if test.expectedPenalty2 != -1 && test.expectedPenalty2 != penalty2 {
+			ok = false
+		}
+		if test.expectedPenalty3 != -1 && test.expectedPenalty3 != penalty3 {
+			ok = false
+		}
+		if test.expectedPenalty4 != -1 && test.expectedPenalty4 != penalty4 {
+			ok = false
+		}
+
+		if !ok {
+			t.Fatalf("Penalty test #%d p1=%d, p2=%d, p3=%d, p4=%d (expected p1=%d, p2=%d, p3=%d, p4=%d)", i, penalty1, penalty2, penalty3, penalty4,
+				test.expectedPenalty1, test.expectedPenalty2, test.expectedPenalty3,
+				test.expectedPenalty4)
+		}
+	}
+}

+ 3050 - 0
version.go

@@ -0,0 +1,3050 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"log"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+// Error detection/recovery capacity.
+//
+// There are several levels of error detection/recovery capacity. Higher levels
+// of error recovery are able to correct more errors, with the trade-off of
+// increased symbol size.
+type RecoveryLevel int
+
+const (
+	// Level L: 7% error recovery.
+	Low RecoveryLevel = iota
+
+	// Level M: 15% error recovery. Good default choice.
+	Medium
+
+	// Level Q: 25% error recovery.
+	High
+
+	// Level H: 30% error recovery.
+	Highest
+)
+
+// qrCodeVersion describes the data length and encoding order of a single QR
+// Code version. There are 40 versions numbers x 4 recovery levels == 160
+// possible qrCodeVersion structures.
+type qrCodeVersion struct {
+	// Version number (1-40 inclusive).
+	version int
+
+	// Error recovery level.
+	level RecoveryLevel
+
+	dataEncoderType dataEncoderType
+
+	// Encoded data can be split into multiple blocks. Each block contains data
+	// and error recovery bytes.
+	//
+	// Larger QR Codes contain more blocks.
+	block []block
+
+	// Number of bits required to pad the combined data & error correction bit
+	// stream up to the symbol's full capacity.
+	numRemainderBits int
+}
+
+type block struct {
+	numBlocks int
+
+	// Total codewords (numCodewords == numErrorCodewords+numDataCodewords).
+	numCodewords int
+
+	// Number of data codewords.
+	numDataCodewords int
+}
+
+var (
+	versions = []qrCodeVersion{
+		{
+			1,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					26,
+					19,
+				},
+			},
+			0,
+		},
+		{
+			1,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					26,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			1,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					26,
+					13,
+				},
+			},
+			0,
+		},
+		{
+			1,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					26,
+					9,
+				},
+			},
+			0,
+		},
+		{
+			2,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					44,
+					34,
+				},
+			},
+			7,
+		},
+		{
+			2,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					44,
+					28,
+				},
+			},
+			7,
+		},
+		{
+			2,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					44,
+					22,
+				},
+			},
+			7,
+		},
+		{
+			2,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					44,
+					16,
+				},
+			},
+			7,
+		},
+		{
+			3,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					70,
+					55,
+				},
+			},
+			7,
+		},
+		{
+			3,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					70,
+					44,
+				},
+			},
+			7,
+		},
+		{
+			3,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					35,
+					17,
+				},
+			},
+			7,
+		},
+		{
+			3,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					35,
+					13,
+				},
+			},
+			7,
+		},
+		{
+			4,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					100,
+					80,
+				},
+			},
+			7,
+		},
+		{
+			4,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					50,
+					32,
+				},
+			},
+			7,
+		},
+		{
+			4,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					50,
+					24,
+				},
+			},
+			7,
+		},
+		{
+			4,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					25,
+					9,
+				},
+			},
+			7,
+		},
+		{
+			5,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					1,
+					134,
+					108,
+				},
+			},
+			7,
+		},
+		{
+			5,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					67,
+					43,
+				},
+			},
+			7,
+		},
+		{
+			5,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					33,
+					15,
+				},
+				{
+					2,
+					34,
+					16,
+				},
+			},
+			7,
+		},
+		{
+			5,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					33,
+					11,
+				},
+				{
+					2,
+					34,
+					12,
+				},
+			},
+			7,
+		},
+		{
+			6,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					86,
+					68,
+				},
+			},
+			7,
+		},
+		{
+			6,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					43,
+					27,
+				},
+			},
+			7,
+		},
+		{
+			6,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					43,
+					19,
+				},
+			},
+			7,
+		},
+		{
+			6,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					43,
+					15,
+				},
+			},
+			7,
+		},
+		{
+			7,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					98,
+					78,
+				},
+			},
+			0,
+		},
+		{
+			7,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					49,
+					31,
+				},
+			},
+			0,
+		},
+		{
+			7,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					32,
+					14,
+				},
+				{
+					4,
+					33,
+					15,
+				},
+			},
+			0,
+		},
+		{
+			7,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					39,
+					13,
+				},
+				{
+					1,
+					40,
+					14,
+				},
+			},
+			0,
+		},
+		{
+			8,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					121,
+					97,
+				},
+			},
+			0,
+		},
+		{
+			8,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					60,
+					38,
+				},
+				{
+					2,
+					61,
+					39,
+				},
+			},
+			0,
+		},
+		{
+			8,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					40,
+					18,
+				},
+				{
+					2,
+					41,
+					19,
+				},
+			},
+			0,
+		},
+		{
+			8,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					40,
+					14,
+				},
+				{
+					2,
+					41,
+					15,
+				},
+			},
+			0,
+		},
+		{
+			9,
+			Low,
+			dataEncoderType1To9,
+			[]block{
+				{
+					2,
+					146,
+					116,
+				},
+			},
+			0,
+		},
+		{
+			9,
+			Medium,
+			dataEncoderType1To9,
+			[]block{
+				{
+					3,
+					58,
+					36,
+				},
+				{
+					2,
+					59,
+					37,
+				},
+			},
+			0,
+		},
+		{
+			9,
+			High,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					36,
+					16,
+				},
+				{
+					4,
+					37,
+					17,
+				},
+			},
+			0,
+		},
+		{
+			9,
+			Highest,
+			dataEncoderType1To9,
+			[]block{
+				{
+					4,
+					36,
+					12,
+				},
+				{
+					4,
+					37,
+					13,
+				},
+			},
+			0,
+		},
+		{
+			10,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					2,
+					86,
+					68,
+				},
+				{
+					2,
+					87,
+					69,
+				},
+			},
+			0,
+		},
+		{
+			10,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					69,
+					43,
+				},
+				{
+					1,
+					70,
+					44,
+				},
+			},
+			0,
+		},
+		{
+			10,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					6,
+					43,
+					19,
+				},
+				{
+					2,
+					44,
+					20,
+				},
+			},
+			0,
+		},
+		{
+			10,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					6,
+					43,
+					15,
+				},
+				{
+					2,
+					44,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			11,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					101,
+					81,
+				},
+			},
+			0,
+		},
+		{
+			11,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					1,
+					80,
+					50,
+				},
+				{
+					4,
+					81,
+					51,
+				},
+			},
+			0,
+		},
+		{
+			11,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					50,
+					22,
+				},
+				{
+					4,
+					51,
+					23,
+				},
+			},
+			0,
+		},
+		{
+			11,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					36,
+					12,
+				},
+				{
+					8,
+					37,
+					13,
+				},
+			},
+			0,
+		},
+		{
+			12,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					2,
+					116,
+					92,
+				},
+				{
+					2,
+					117,
+					93,
+				},
+			},
+			0,
+		},
+		{
+			12,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					6,
+					58,
+					36,
+				},
+				{
+					2,
+					59,
+					37,
+				},
+			},
+			0,
+		},
+		{
+			12,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					46,
+					20,
+				},
+				{
+					6,
+					47,
+					21,
+				},
+			},
+			0,
+		},
+		{
+			12,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					7,
+					42,
+					14,
+				},
+				{
+					4,
+					43,
+					15,
+				},
+			},
+			0,
+		},
+		{
+			13,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					133,
+					107,
+				},
+			},
+			0,
+		},
+		{
+			13,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					8,
+					59,
+					37,
+				},
+				{
+					1,
+					60,
+					38,
+				},
+			},
+			0,
+		},
+		{
+			13,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					8,
+					44,
+					20,
+				},
+				{
+					4,
+					45,
+					21,
+				},
+			},
+			0,
+		},
+		{
+			13,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					12,
+					33,
+					11,
+				},
+				{
+					4,
+					34,
+					12,
+				},
+			},
+			0,
+		},
+		{
+			14,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					145,
+					115,
+				},
+				{
+					1,
+					146,
+					116,
+				},
+			},
+			3,
+		},
+		{
+			14,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					64,
+					40,
+				},
+				{
+					5,
+					65,
+					41,
+				},
+			},
+			3,
+		},
+		{
+			14,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					11,
+					36,
+					16,
+				},
+				{
+					5,
+					37,
+					17,
+				},
+			},
+			3,
+		},
+		{
+			14,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					11,
+					36,
+					12,
+				},
+				{
+					5,
+					37,
+					13,
+				},
+			},
+			3,
+		},
+		{
+			15,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					5,
+					109,
+					87,
+				},
+				{
+					1,
+					110,
+					88,
+				},
+			},
+			3,
+		},
+		{
+			15,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					5,
+					65,
+					41,
+				},
+				{
+					5,
+					66,
+					42,
+				},
+			},
+			3,
+		},
+		{
+			15,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					5,
+					54,
+					24,
+				},
+				{
+					7,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			15,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					11,
+					36,
+					12,
+				},
+				{
+					7,
+					37,
+					13,
+				},
+			},
+			3,
+		},
+		{
+			16,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					5,
+					122,
+					98,
+				},
+				{
+					1,
+					123,
+					99,
+				},
+			},
+			3,
+		},
+		{
+			16,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					7,
+					73,
+					45,
+				},
+				{
+					3,
+					74,
+					46,
+				},
+			},
+			3,
+		},
+		{
+			16,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					15,
+					43,
+					19,
+				},
+				{
+					2,
+					44,
+					20,
+				},
+			},
+			3,
+		},
+		{
+			16,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					45,
+					15,
+				},
+				{
+					13,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			17,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					1,
+					135,
+					107,
+				},
+				{
+					5,
+					136,
+					108,
+				},
+			},
+			3,
+		},
+		{
+			17,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					10,
+					74,
+					46,
+				},
+				{
+					1,
+					75,
+					47,
+				},
+			},
+			3,
+		},
+		{
+			17,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					1,
+					50,
+					22,
+				},
+				{
+					15,
+					51,
+					23,
+				},
+			},
+			3,
+		},
+		{
+			17,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					2,
+					42,
+					14,
+				},
+				{
+					17,
+					43,
+					15,
+				},
+			},
+			3,
+		},
+		{
+			18,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					5,
+					150,
+					120,
+				},
+				{
+					1,
+					151,
+					121,
+				},
+			},
+			3,
+		},
+		{
+			18,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					9,
+					69,
+					43,
+				},
+				{
+					4,
+					70,
+					44,
+				},
+			},
+			3,
+		},
+		{
+			18,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					17,
+					50,
+					22,
+				},
+				{
+					1,
+					51,
+					23,
+				},
+			},
+			3,
+		},
+		{
+			18,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					2,
+					42,
+					14,
+				},
+				{
+					19,
+					43,
+					15,
+				},
+			},
+			3,
+		},
+		{
+			19,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					141,
+					113,
+				},
+				{
+					4,
+					142,
+					114,
+				},
+			},
+			3,
+		},
+		{
+			19,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					70,
+					44,
+				},
+				{
+					11,
+					71,
+					45,
+				},
+			},
+			3,
+		},
+		{
+			19,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					17,
+					47,
+					21,
+				},
+				{
+					4,
+					48,
+					22,
+				},
+			},
+			3,
+		},
+		{
+			19,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					9,
+					39,
+					13,
+				},
+				{
+					16,
+					40,
+					14,
+				},
+			},
+			3,
+		},
+		{
+			20,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					135,
+					107,
+				},
+				{
+					5,
+					136,
+					108,
+				},
+			},
+			3,
+		},
+		{
+			20,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					3,
+					67,
+					41,
+				},
+				{
+					13,
+					68,
+					42,
+				},
+			},
+			3,
+		},
+		{
+			20,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					15,
+					54,
+					24,
+				},
+				{
+					5,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			20,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					15,
+					43,
+					15,
+				},
+				{
+					10,
+					44,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			21,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					144,
+					116,
+				},
+				{
+					4,
+					145,
+					117,
+				},
+			},
+			4,
+		},
+		{
+			21,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					17,
+					68,
+					42,
+				},
+			},
+			4,
+		},
+		{
+			21,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					17,
+					50,
+					22,
+				},
+				{
+					6,
+					51,
+					23,
+				},
+			},
+			4,
+		},
+		{
+			21,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					19,
+					46,
+					16,
+				},
+				{
+					6,
+					47,
+					17,
+				},
+			},
+			4,
+		},
+		{
+			22,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					2,
+					139,
+					111,
+				},
+				{
+					7,
+					140,
+					112,
+				},
+			},
+			4,
+		},
+		{
+			22,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					17,
+					74,
+					46,
+				},
+			},
+			4,
+		},
+		{
+			22,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					7,
+					54,
+					24,
+				},
+				{
+					16,
+					55,
+					25,
+				},
+			},
+			4,
+		},
+		{
+			22,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					34,
+					37,
+					13,
+				},
+			},
+			4,
+		},
+		{
+			23,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					151,
+					121,
+				},
+				{
+					5,
+					152,
+					122,
+				},
+			},
+			4,
+		},
+		{
+			23,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					4,
+					75,
+					47,
+				},
+				{
+					14,
+					76,
+					48,
+				},
+			},
+			4,
+		},
+		{
+			23,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					11,
+					54,
+					24,
+				},
+				{
+					14,
+					55,
+					25,
+				},
+			},
+			4,
+		},
+		{
+			23,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					16,
+					45,
+					15,
+				},
+				{
+					14,
+					46,
+					16,
+				},
+			},
+			4,
+		},
+		{
+			24,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					6,
+					147,
+					117,
+				},
+				{
+					4,
+					148,
+					118,
+				},
+			},
+			4,
+		},
+		{
+			24,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					6,
+					73,
+					45,
+				},
+				{
+					14,
+					74,
+					46,
+				},
+			},
+			4,
+		},
+		{
+			24,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					11,
+					54,
+					24,
+				},
+				{
+					16,
+					55,
+					25,
+				},
+			},
+			4,
+		},
+		{
+			24,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					30,
+					46,
+					16,
+				},
+				{
+					2,
+					47,
+					17,
+				},
+			},
+			4,
+		},
+		{
+			25,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					8,
+					132,
+					106,
+				},
+				{
+					4,
+					133,
+					107,
+				},
+			},
+			4,
+		},
+		{
+			25,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					8,
+					75,
+					47,
+				},
+				{
+					13,
+					76,
+					48,
+				},
+			},
+			4,
+		},
+		{
+			25,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					7,
+					54,
+					24,
+				},
+				{
+					22,
+					55,
+					25,
+				},
+			},
+			4,
+		},
+		{
+			25,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					22,
+					45,
+					15,
+				},
+				{
+					13,
+					46,
+					16,
+				},
+			},
+			4,
+		},
+		{
+			26,
+			Low,
+			dataEncoderType10To26,
+			[]block{
+				{
+					10,
+					142,
+					114,
+				},
+				{
+					2,
+					143,
+					115,
+				},
+			},
+			4,
+		},
+		{
+			26,
+			Medium,
+			dataEncoderType10To26,
+			[]block{
+				{
+					19,
+					74,
+					46,
+				},
+				{
+					4,
+					75,
+					47,
+				},
+			},
+			4,
+		},
+		{
+			26,
+			High,
+			dataEncoderType10To26,
+			[]block{
+				{
+					28,
+					50,
+					22,
+				},
+				{
+					6,
+					51,
+					23,
+				},
+			},
+			4,
+		},
+		{
+			26,
+			Highest,
+			dataEncoderType10To26,
+			[]block{
+				{
+					33,
+					46,
+					16,
+				},
+				{
+					4,
+					47,
+					17,
+				},
+			},
+			4,
+		},
+		{
+			27,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					8,
+					152,
+					122,
+				},
+				{
+					4,
+					153,
+					123,
+				},
+			},
+			4,
+		},
+		{
+			27,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					22,
+					73,
+					45,
+				},
+				{
+					3,
+					74,
+					46,
+				},
+			},
+			4,
+		},
+		{
+			27,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					8,
+					53,
+					23,
+				},
+				{
+					26,
+					54,
+					24,
+				},
+			},
+			4,
+		},
+		{
+			27,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					12,
+					45,
+					15,
+				},
+				{
+					28,
+					46,
+					16,
+				},
+			},
+			4,
+		},
+		{
+			28,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					3,
+					147,
+					117,
+				},
+				{
+					10,
+					148,
+					118,
+				},
+			},
+			3,
+		},
+		{
+			28,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					3,
+					73,
+					45,
+				},
+				{
+					23,
+					74,
+					46,
+				},
+			},
+			3,
+		},
+		{
+			28,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					4,
+					54,
+					24,
+				},
+				{
+					31,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			28,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					11,
+					45,
+					15,
+				},
+				{
+					31,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			29,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					7,
+					146,
+					116,
+				},
+				{
+					7,
+					147,
+					117,
+				},
+			},
+			3,
+		},
+		{
+			29,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					21,
+					73,
+					45,
+				},
+				{
+					7,
+					74,
+					46,
+				},
+			},
+			3,
+		},
+		{
+			29,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					1,
+					53,
+					23,
+				},
+				{
+					37,
+					54,
+					24,
+				},
+			},
+			3,
+		},
+		{
+			29,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					19,
+					45,
+					15,
+				},
+				{
+					26,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			30,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					5,
+					145,
+					115,
+				},
+				{
+					10,
+					146,
+					116,
+				},
+			},
+			3,
+		},
+		{
+			30,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					19,
+					75,
+					47,
+				},
+				{
+					10,
+					76,
+					48,
+				},
+			},
+			3,
+		},
+		{
+			30,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					15,
+					54,
+					24,
+				},
+				{
+					25,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			30,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					23,
+					45,
+					15,
+				},
+				{
+					25,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			31,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					13,
+					145,
+					115,
+				},
+				{
+					3,
+					146,
+					116,
+				},
+			},
+			3,
+		},
+		{
+			31,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					2,
+					74,
+					46,
+				},
+				{
+					29,
+					75,
+					47,
+				},
+			},
+			3,
+		},
+		{
+			31,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					42,
+					54,
+					24,
+				},
+				{
+					1,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			31,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					23,
+					45,
+					15,
+				},
+				{
+					28,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			32,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					17,
+					145,
+					115,
+				},
+			},
+			3,
+		},
+		{
+			32,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					10,
+					74,
+					46,
+				},
+				{
+					23,
+					75,
+					47,
+				},
+			},
+			3,
+		},
+		{
+			32,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					10,
+					54,
+					24,
+				},
+				{
+					35,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			32,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					19,
+					45,
+					15,
+				},
+				{
+					35,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			33,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					17,
+					145,
+					115,
+				},
+				{
+					1,
+					146,
+					116,
+				},
+			},
+			3,
+		},
+		{
+			33,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					14,
+					74,
+					46,
+				},
+				{
+					21,
+					75,
+					47,
+				},
+			},
+			3,
+		},
+		{
+			33,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					29,
+					54,
+					24,
+				},
+				{
+					19,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			33,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					11,
+					45,
+					15,
+				},
+				{
+					46,
+					46,
+					16,
+				},
+			},
+			3,
+		},
+		{
+			34,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					13,
+					145,
+					115,
+				},
+				{
+					6,
+					146,
+					116,
+				},
+			},
+			3,
+		},
+		{
+			34,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					14,
+					74,
+					46,
+				},
+				{
+					23,
+					75,
+					47,
+				},
+			},
+			3,
+		},
+		{
+			34,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					44,
+					54,
+					24,
+				},
+				{
+					7,
+					55,
+					25,
+				},
+			},
+			3,
+		},
+		{
+			34,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					59,
+					46,
+					16,
+				},
+				{
+					1,
+					47,
+					17,
+				},
+			},
+			3,
+		},
+		{
+			35,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					12,
+					151,
+					121,
+				},
+				{
+					7,
+					152,
+					122,
+				},
+			},
+			0,
+		},
+		{
+			35,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					12,
+					75,
+					47,
+				},
+				{
+					26,
+					76,
+					48,
+				},
+			},
+			0,
+		},
+		{
+			35,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					39,
+					54,
+					24,
+				},
+				{
+					14,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			35,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					22,
+					45,
+					15,
+				},
+				{
+					41,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			36,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					6,
+					151,
+					121,
+				},
+				{
+					14,
+					152,
+					122,
+				},
+			},
+			0,
+		},
+		{
+			36,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					6,
+					75,
+					47,
+				},
+				{
+					34,
+					76,
+					48,
+				},
+			},
+			0,
+		},
+		{
+			36,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					46,
+					54,
+					24,
+				},
+				{
+					10,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			36,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					2,
+					45,
+					15,
+				},
+				{
+					64,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			37,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					17,
+					152,
+					122,
+				},
+				{
+					4,
+					153,
+					123,
+				},
+			},
+			0,
+		},
+		{
+			37,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					29,
+					74,
+					46,
+				},
+				{
+					14,
+					75,
+					47,
+				},
+			},
+			0,
+		},
+		{
+			37,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					49,
+					54,
+					24,
+				},
+				{
+					10,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			37,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					24,
+					45,
+					15,
+				},
+				{
+					46,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			38,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					4,
+					152,
+					122,
+				},
+				{
+					18,
+					153,
+					123,
+				},
+			},
+			0,
+		},
+		{
+			38,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					13,
+					74,
+					46,
+				},
+				{
+					32,
+					75,
+					47,
+				},
+			},
+			0,
+		},
+		{
+			38,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					48,
+					54,
+					24,
+				},
+				{
+					14,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			38,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					42,
+					45,
+					15,
+				},
+				{
+					32,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			39,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					20,
+					147,
+					117,
+				},
+				{
+					4,
+					148,
+					118,
+				},
+			},
+			0,
+		},
+		{
+			39,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					40,
+					75,
+					47,
+				},
+				{
+					7,
+					76,
+					48,
+				},
+			},
+			0,
+		},
+		{
+			39,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					43,
+					54,
+					24,
+				},
+				{
+					22,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			39,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					10,
+					45,
+					15,
+				},
+				{
+					67,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+		{
+			40,
+			Low,
+			dataEncoderType27To40,
+			[]block{
+				{
+					19,
+					148,
+					118,
+				},
+				{
+					6,
+					149,
+					119,
+				},
+			},
+			0,
+		},
+		{
+			40,
+			Medium,
+			dataEncoderType27To40,
+			[]block{
+				{
+					18,
+					75,
+					47,
+				},
+				{
+					31,
+					76,
+					48,
+				},
+			},
+			0,
+		},
+		{
+			40,
+			High,
+			dataEncoderType27To40,
+			[]block{
+				{
+					34,
+					54,
+					24,
+				},
+				{
+					34,
+					55,
+					25,
+				},
+			},
+			0,
+		},
+		{
+			40,
+			Highest,
+			dataEncoderType27To40,
+			[]block{
+				{
+					20,
+					45,
+					15,
+				},
+				{
+					61,
+					46,
+					16,
+				},
+			},
+			0,
+		},
+	}
+)
+
+var (
+	// Each QR Code contains a 15-bit Format Information value.  The 15 bits
+	// consist of 5 data bits concatenated with 10 error correction bits.
+	//
+	// The 5 data bits consist of:
+	// - 2 bits for the error correction level (L=01, M=00, G=11, H=10).
+	// - 3 bits for the data mask pattern identifier.
+	//
+	// formatBitSequence is a mapping from the 5 data bits to the completed 15-bit
+	// Format Information value.
+	//
+	// For example, a QR Code using error correction level L, and data mask
+	// pattern identifier 001:
+	//
+	// 01 | 001 = 01001 = 0x9
+	// formatBitSequence[0x9].qrCode = 0x72f3 = 111001011110011
+	formatBitSequence = []struct {
+		regular uint32
+		micro   uint32
+	}{
+		{0x5412, 0x4445},
+		{0x5125, 0x4172},
+		{0x5e7c, 0x4e2b},
+		{0x5b4b, 0x4b1c},
+		{0x45f9, 0x55ae},
+		{0x40ce, 0x5099},
+		{0x4f97, 0x5fc0},
+		{0x4aa0, 0x5af7},
+		{0x77c4, 0x6793},
+		{0x72f3, 0x62a4},
+		{0x7daa, 0x6dfd},
+		{0x789d, 0x68ca},
+		{0x662f, 0x7678},
+		{0x6318, 0x734f},
+		{0x6c41, 0x7c16},
+		{0x6976, 0x7921},
+		{0x1689, 0x06de},
+		{0x13be, 0x03e9},
+		{0x1ce7, 0x0cb0},
+		{0x19d0, 0x0987},
+		{0x0762, 0x1735},
+		{0x0255, 0x1202},
+		{0x0d0c, 0x1d5b},
+		{0x083b, 0x186c},
+		{0x355f, 0x2508},
+		{0x3068, 0x203f},
+		{0x3f31, 0x2f66},
+		{0x3a06, 0x2a51},
+		{0x24b4, 0x34e3},
+		{0x2183, 0x31d4},
+		{0x2eda, 0x3e8d},
+		{0x2bed, 0x3bba},
+	}
+
+	// QR Codes version 7 and higher contain an 18-bit Version Information value,
+	// consisting of a 6 data bits and 12 error correction bits.
+	//
+	// versionBitSequence is a mapping from QR Code version to the completed
+	// 18-bit Version Information value.
+	//
+	// For example, a QR code of version 7:
+	// versionBitSequence[0x7] = 0x07c94 = 000111110010010100
+	versionBitSequence = []uint32{
+		0x00000,
+		0x00000,
+		0x00000,
+		0x00000,
+		0x00000,
+		0x00000,
+		0x00000,
+		0x07c94,
+		0x085bc,
+		0x09a99,
+		0x0a4d3,
+		0x0bbf6,
+		0x0c762,
+		0x0d847,
+		0x0e60d,
+		0x0f928,
+		0x10b78,
+		0x1145d,
+		0x12a17,
+		0x13532,
+		0x149a6,
+		0x15683,
+		0x168c9,
+		0x177ec,
+		0x18ec4,
+		0x191e1,
+		0x1afab,
+		0x1b08e,
+		0x1cc1a,
+		0x1d33f,
+		0x1ed75,
+		0x1f250,
+		0x209d5,
+		0x216f0,
+		0x228ba,
+		0x2379f,
+		0x24b0b,
+		0x2542e,
+		0x26a64,
+		0x27541,
+		0x28c69,
+	}
+)
+
+const (
+	formatInfoLengthBits  = 15
+	versionInfoLengthBits = 18
+)
+
+// formatInfo returns the 15-bit Format Information value for a QR
+// code.
+func (v qrCodeVersion) formatInfo(maskPattern int) *bitset.Bitset {
+	formatID := 0
+
+	switch v.level {
+	case Low:
+		formatID = 0x08 // 0b01000
+	case Medium:
+		formatID = 0x00 // 0b00000
+	case High:
+		formatID = 0x18 // 0b11000
+	case Highest:
+		formatID = 0x10 // 0b10000
+	default:
+		log.Panicf("Invalid level %d", v.level)
+	}
+
+	if maskPattern < 0 || maskPattern > 7 {
+		log.Panicf("Invalid maskPattern %d", maskPattern)
+	}
+
+	formatID |= maskPattern & 0x7
+
+	result := bitset.New()
+
+	result.AppendUint32(formatBitSequence[formatID].regular, formatInfoLengthBits)
+
+	return result
+}
+
+// versionInfo returns the 18-bit Version Information value for a QR Code.
+//
+// Version Information is applicable only to QR Codes versions 7-40 inclusive.
+// nil is returned if Version Information is not required.
+func (v qrCodeVersion) versionInfo() *bitset.Bitset {
+	if v.version < 7 {
+		return nil
+	}
+
+	result := bitset.New()
+	result.AppendUint32(versionBitSequence[v.version], 18)
+
+	return result
+}
+
+// numDataBits returns the data capacity in bits.
+func (v qrCodeVersion) numDataBits() int {
+	numDataBits := 0
+	for _, b := range v.block {
+		numDataBits += 8 * b.numBlocks * b.numDataCodewords // 8 bits in a byte
+	}
+
+	return numDataBits
+}
+
+// chooseQRCodeVersion chooses the most suitable QR Code version for a stated
+// data length in bits, the error recovery level required, and the data encoder
+// used.
+//
+// The chosen QR Code version is the smallest version able to fit numDataBits
+// and the optional terminator bits required by the specified encoder.
+//
+// On success the chosen QR Code version is returned.
+func chooseQRCodeVersion(level RecoveryLevel, encoder *dataEncoder, numDataBits int) *qrCodeVersion {
+	var chosenVersion *qrCodeVersion = nil
+
+	for _, v := range versions {
+		if v.level != level {
+			continue
+		} else if v.version < encoder.minVersion {
+			continue
+		} else if v.version > encoder.maxVersion {
+			break
+		}
+
+		numFreeBits := v.numDataBits() - numDataBits
+
+		if numFreeBits >= 0 {
+			chosenVersion = &v
+			break
+		}
+	}
+
+	return chosenVersion
+}
+
+func (v qrCodeVersion) numTerminatorBitsRequired(numDataBits int) int {
+	numFreeBits := v.numDataBits() - numDataBits
+
+	var numTerminatorBits int
+
+	switch {
+	case numFreeBits >= 4:
+		numTerminatorBits = 4
+	default:
+		numTerminatorBits = numFreeBits
+	}
+
+	return numTerminatorBits
+}
+
+// numBlocks returns the number of blocks.
+func (v qrCodeVersion) numBlocks() int {
+	numBlocks := 0
+
+	for _, b := range v.block {
+		numBlocks += b.numBlocks
+	}
+
+	return numBlocks
+}
+
+// numBitsToPadToCodeword returns the number of bits required to pad data of
+// length numDataBits upto the nearest codeword size.
+func (v qrCodeVersion) numBitsToPadToCodeword(numDataBits int) int {
+	if numDataBits == v.numDataBits() {
+		return 0
+	}
+
+	return (8 - numDataBits%8) % 8
+}
+
+// symbolSize returns the size of the QR Code symbol in number of modules (which
+// is both the width and height, since QR codes are square). The QR Code has
+// size symbolSize() x symbolSize() pixels. This does not include the quiet
+// zone.
+func (v qrCodeVersion) symbolSize() int {
+	return 21 + (v.version-1)*4
+}
+
+// quietZoneSize returns the number of pixels of border space on each side of
+// the QR Code. The quiet space assists with decoding.
+func (v qrCodeVersion) quietZoneSize() int {
+	return 4
+}
+
+// getQRCodeVersion returns the QR Code version by version number and recovery
+// level. Returns nil if the requested combination is not defined.
+func getQRCodeVersion(level RecoveryLevel, version int) *qrCodeVersion {
+	for _, v := range versions {
+		if v.level == level && v.version == version {
+			return &v
+		}
+	}
+
+	return nil
+}

+ 158 - 0
version_test.go

@@ -0,0 +1,158 @@
+// go-qrcode
+// Copyright 2014 Tom Harwood
+
+package qrcode
+
+import (
+	"testing"
+
+	bitset "code.google.com/p/go-qrcode/bitset"
+)
+
+func TestFormatInfo(t *testing.T) {
+	tests := []struct {
+		level       RecoveryLevel
+		maskPattern int
+
+		expected uint32
+	}{
+		{ // L=01 M=00 Q=11 H=10
+			Low,
+			1,
+			0x72f3,
+		},
+		{
+			Medium,
+			2,
+			0x5e7c,
+		},
+		{
+			High,
+			3,
+			0x3a06,
+		},
+		{
+			Highest,
+			4,
+			0x0762,
+		},
+		{
+			Low,
+			5,
+			0x6318,
+		},
+		{
+			Medium,
+			6,
+			0x4f97,
+		},
+		{
+			High,
+			7,
+			0x2bed,
+		},
+	}
+
+	for i, test := range tests {
+		var v *qrCodeVersion = getQRCodeVersion(test.level, 1)
+
+		result := v.formatInfo(test.maskPattern)
+
+		expected := bitset.New()
+		expected.AppendUint32(test.expected, formatInfoLengthBits)
+
+		if !expected.Equals(result) {
+			t.Errorf("formatInfo test #%d got %s, expected %s", i, result.String(),
+				expected.String())
+		}
+	}
+}
+
+func TestVersionInfo(t *testing.T) {
+	tests := []struct {
+		version  int
+		expected uint32
+	}{
+		{
+			7,
+			0x007c94,
+		},
+		{
+			10,
+			0x00a4d3,
+		},
+		{
+			20,
+			0x0149a6,
+		},
+		{
+			30,
+			0x01ed75,
+		},
+		{
+			40,
+			0x028c69,
+		},
+	}
+
+	for i, test := range tests {
+		var v *qrCodeVersion
+
+		v = getQRCodeVersion(Low, test.version)
+
+		result := v.versionInfo()
+
+		expected := bitset.New()
+		expected.AppendUint32(test.expected, versionInfoLengthBits)
+
+		if !expected.Equals(result) {
+			t.Errorf("versionInfo test #%d got %s, expected %s", i, result.String(),
+				expected.String())
+		}
+	}
+}
+
+func TestNumBitsToPadToCodeoword(t *testing.T) {
+	tests := []struct {
+		level   RecoveryLevel
+		version int
+
+		numDataBits int
+		expected    int
+	}{
+		{
+			Low,
+			1,
+			0,
+			0,
+		}, {
+			Low,
+			1,
+			1,
+			7,
+		}, {
+			Low,
+			1,
+			7,
+			1,
+		}, {
+			Low,
+			1,
+			8,
+			0,
+		},
+	}
+
+	for i, test := range tests {
+		var v *qrCodeVersion
+
+		v = getQRCodeVersion(test.level, test.version)
+
+		result := v.numBitsToPadToCodeword(test.numDataBits)
+
+		if result != test.expected {
+			t.Errorf("numBitsToPadToCodeword test %d (version=%d numDataBits=%d), got %d, expected %d",
+				i, test.version, test.numDataBits, result, test.expected)
+		}
+	}
+}