summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/skip2/go-qrcode/encoder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/skip2/go-qrcode/encoder.go')
-rw-r--r--vendor/github.com/skip2/go-qrcode/encoder.go486
1 files changed, 0 insertions, 486 deletions
diff --git a/vendor/github.com/skip2/go-qrcode/encoder.go b/vendor/github.com/skip2/go-qrcode/encoder.go
deleted file mode 100644
index 6a809cfe..00000000
--- a/vendor/github.com/skip2/go-qrcode/encoder.go
+++ /dev/null
@@ -1,486 +0,0 @@
-// 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
-}