// 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. padding := [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) } }
// 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. encoded := bitset.New() for _, s := range d.optimised { d.encodeDataRaw(s.data, s.dataMode, encoded) } return encoded, nil }
// 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 }
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 { v := 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()) } } }
// 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 }
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 { encoder := newDataEncoder(test.dataEncoderType) encoded := 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()) } } }
// newDataEncoder constructs a dataEncoder. func newDataEncoder(t dataEncoderType) *dataEncoder { d := &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 }
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 TestBuildRegularSymbol(t *testing.T) { for k := 0; k <= 7; k++ { v := getQRCodeVersion(Low, 1) data := 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()) } } }
// 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 } block := make([]dataBlock, q.version.numBlocks()) start := 0 end := 0 blockID := 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. numErrorCodewords := b.numCodewords - b.numDataCodewords block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords) block[blockID].ecStartOffset = end - start blockID++ } } // Interleave the blocks. result := bitset.New() // Combine data blocks. working := 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 { offset := 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 }