123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- // go-qrcode
- // Copyright 2014 Tom Harwood
- package qrcode
- import (
- "errors"
- "log"
- bitset "github.com/skip2/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.
- //
- // Starting 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 {
- 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
- }
- // 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.
- highestRequiredMode := d.classifyDataModes()
- // Optimise segments.
- err := d.optimiseDataModes()
- if err != nil {
- return nil, err
- }
- // Check if a single byte encoded segment would be more efficient.
- optimizedLength := 0
- for _, s := range d.optimised {
- length, err := d.encodedLength(s.dataMode, len(s.data))
- if err != nil {
- return nil, err
- }
- optimizedLength += length
- }
- singleByteSegmentLength, err := d.encodedLength(highestRequiredMode, len(d.data))
- if err != nil {
- return nil, err
- }
- if singleByteSegmentLength <= optimizedLength {
- d.optimised = []segment{segment{dataMode: highestRequiredMode, data: d.data}}
- }
- // Encode data.
- encoded := 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, "#!#!"].
- //
- // Returns the highest data mode needed to encode the data. e.g. for a mixed
- // numeric/alphanumeric input, the highest is alphanumeric.
- //
- // dataModeNone < dataModeNumeric < dataModeAlphanumeric < dataModeByte
- func (d *dataEncoder) classifyDataModes() dataMode {
- var start int
- mode := dataModeNone
- highestRequiredMode := mode
- 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
- }
- if newMode > highestRequiredMode {
- highestRequiredMode = newMode
- }
- }
- d.actual = append(d.actual, segment{dataMode: mode, data: d.data[start:len(d.data)]})
- return highestRequiredMode
- }
- // 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
- }
- }
- optimised := 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) {
- modeIndicator := d.modeIndicator(dataMode)
- charCountBits := 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
- bitsUsed := 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
- for j := 0; j < charsRemaining && j < 2; j++ {
- value *= 45
- value += encodeAlphanumericCharacter(data[i+j])
- }
- bitsUsed := 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) {
- modeIndicator := d.modeIndicator(dataMode)
- charCountBits := 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")
- }
- length := 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
- }
|