taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

regular_symbol.go (6323B)


      1 // go-qrcode
      2 // Copyright 2014 Tom Harwood
      3 
      4 package qrcode
      5 
      6 import (
      7 	bitset "github.com/skip2/go-qrcode/bitset"
      8 )
      9 
     10 type regularSymbol struct {
     11 	version qrCodeVersion
     12 	mask    int
     13 
     14 	data *bitset.Bitset
     15 
     16 	symbol *symbol
     17 	size   int
     18 }
     19 
     20 // Abbreviated true/false.
     21 const (
     22 	b0 = false
     23 	b1 = true
     24 )
     25 
     26 var (
     27 	alignmentPatternCenter = [][]int{
     28 		{}, // Version 0 doesn't exist.
     29 		{}, // Version 1 doesn't use alignment patterns.
     30 		{6, 18},
     31 		{6, 22},
     32 		{6, 26},
     33 		{6, 30},
     34 		{6, 34},
     35 		{6, 22, 38},
     36 		{6, 24, 42},
     37 		{6, 26, 46},
     38 		{6, 28, 50},
     39 		{6, 30, 54},
     40 		{6, 32, 58},
     41 		{6, 34, 62},
     42 		{6, 26, 46, 66},
     43 		{6, 26, 48, 70},
     44 		{6, 26, 50, 74},
     45 		{6, 30, 54, 78},
     46 		{6, 30, 56, 82},
     47 		{6, 30, 58, 86},
     48 		{6, 34, 62, 90},
     49 		{6, 28, 50, 72, 94},
     50 		{6, 26, 50, 74, 98},
     51 		{6, 30, 54, 78, 102},
     52 		{6, 28, 54, 80, 106},
     53 		{6, 32, 58, 84, 110},
     54 		{6, 30, 58, 86, 114},
     55 		{6, 34, 62, 90, 118},
     56 		{6, 26, 50, 74, 98, 122},
     57 		{6, 30, 54, 78, 102, 126},
     58 		{6, 26, 52, 78, 104, 130},
     59 		{6, 30, 56, 82, 108, 134},
     60 		{6, 34, 60, 86, 112, 138},
     61 		{6, 30, 58, 86, 114, 142},
     62 		{6, 34, 62, 90, 118, 146},
     63 		{6, 30, 54, 78, 102, 126, 150},
     64 		{6, 24, 50, 76, 102, 128, 154},
     65 		{6, 28, 54, 80, 106, 132, 158},
     66 		{6, 32, 58, 84, 110, 136, 162},
     67 		{6, 26, 54, 82, 110, 138, 166},
     68 		{6, 30, 58, 86, 114, 142, 170},
     69 	}
     70 
     71 	finderPattern = [][]bool{
     72 		{b1, b1, b1, b1, b1, b1, b1},
     73 		{b1, b0, b0, b0, b0, b0, b1},
     74 		{b1, b0, b1, b1, b1, b0, b1},
     75 		{b1, b0, b1, b1, b1, b0, b1},
     76 		{b1, b0, b1, b1, b1, b0, b1},
     77 		{b1, b0, b0, b0, b0, b0, b1},
     78 		{b1, b1, b1, b1, b1, b1, b1},
     79 	}
     80 
     81 	finderPatternSize = 7
     82 
     83 	finderPatternHorizontalBorder = [][]bool{
     84 		{b0, b0, b0, b0, b0, b0, b0, b0},
     85 	}
     86 
     87 	finderPatternVerticalBorder = [][]bool{
     88 		{b0},
     89 		{b0},
     90 		{b0},
     91 		{b0},
     92 		{b0},
     93 		{b0},
     94 		{b0},
     95 		{b0},
     96 	}
     97 
     98 	alignmentPattern = [][]bool{
     99 		{b1, b1, b1, b1, b1},
    100 		{b1, b0, b0, b0, b1},
    101 		{b1, b0, b1, b0, b1},
    102 		{b1, b0, b0, b0, b1},
    103 		{b1, b1, b1, b1, b1},
    104 	}
    105 )
    106 
    107 func buildRegularSymbol(version qrCodeVersion, mask int,
    108 	data *bitset.Bitset, includeQuietZone bool) (*symbol, error) {
    109 
    110 	quietZoneSize := 0
    111 	if includeQuietZone {
    112 		quietZoneSize = version.quietZoneSize()
    113 	}
    114 
    115 	m := &regularSymbol{
    116 		version: version,
    117 		mask:    mask,
    118 		data:    data,
    119 
    120 		symbol: newSymbol(version.symbolSize(), quietZoneSize),
    121 		size:   version.symbolSize(),
    122 	}
    123 
    124 	m.addFinderPatterns()
    125 	m.addAlignmentPatterns()
    126 	m.addTimingPatterns()
    127 	m.addFormatInfo()
    128 	m.addVersionInfo()
    129 
    130 	ok, err := m.addData()
    131 	if !ok {
    132 		return nil, err
    133 	}
    134 
    135 	return m.symbol, nil
    136 }
    137 
    138 func (m *regularSymbol) addFinderPatterns() {
    139 	fpSize := finderPatternSize
    140 	fp := finderPattern
    141 	fpHBorder := finderPatternHorizontalBorder
    142 	fpVBorder := finderPatternVerticalBorder
    143 
    144 	// Top left Finder Pattern.
    145 	m.symbol.set2dPattern(0, 0, fp)
    146 	m.symbol.set2dPattern(0, fpSize, fpHBorder)
    147 	m.symbol.set2dPattern(fpSize, 0, fpVBorder)
    148 
    149 	// Top right Finder Pattern.
    150 	m.symbol.set2dPattern(m.size-fpSize, 0, fp)
    151 	m.symbol.set2dPattern(m.size-fpSize-1, fpSize, fpHBorder)
    152 	m.symbol.set2dPattern(m.size-fpSize-1, 0, fpVBorder)
    153 
    154 	// Bottom left Finder Pattern.
    155 	m.symbol.set2dPattern(0, m.size-fpSize, fp)
    156 	m.symbol.set2dPattern(0, m.size-fpSize-1, fpHBorder)
    157 	m.symbol.set2dPattern(fpSize, m.size-fpSize-1, fpVBorder)
    158 }
    159 
    160 func (m *regularSymbol) addAlignmentPatterns() {
    161 	for _, x := range alignmentPatternCenter[m.version.version] {
    162 		for _, y := range alignmentPatternCenter[m.version.version] {
    163 			if !m.symbol.empty(x, y) {
    164 				continue
    165 			}
    166 
    167 			m.symbol.set2dPattern(x-2, y-2, alignmentPattern)
    168 		}
    169 	}
    170 }
    171 
    172 func (m *regularSymbol) addTimingPatterns() {
    173 	value := true
    174 
    175 	for i := finderPatternSize + 1; i < m.size-finderPatternSize; i++ {
    176 		m.symbol.set(i, finderPatternSize-1, value)
    177 		m.symbol.set(finderPatternSize-1, i, value)
    178 
    179 		value = !value
    180 	}
    181 }
    182 
    183 func (m *regularSymbol) addFormatInfo() {
    184 	fpSize := finderPatternSize
    185 	l := formatInfoLengthBits - 1
    186 
    187 	f := m.version.formatInfo(m.mask)
    188 
    189 	// Bits 0-7, under the top right finder pattern.
    190 	for i := 0; i <= 7; i++ {
    191 		m.symbol.set(m.size-i-1, fpSize+1, f.At(l-i))
    192 	}
    193 
    194 	// Bits 0-5, right of the top left finder pattern.
    195 	for i := 0; i <= 5; i++ {
    196 		m.symbol.set(fpSize+1, i, f.At(l-i))
    197 	}
    198 
    199 	// Bits 6-8 on the corner of the top left finder pattern.
    200 	m.symbol.set(fpSize+1, fpSize, f.At(l-6))
    201 	m.symbol.set(fpSize+1, fpSize+1, f.At(l-7))
    202 	m.symbol.set(fpSize, fpSize+1, f.At(l-8))
    203 
    204 	// Bits 9-14 on the underside of the top left finder pattern.
    205 	for i := 9; i <= 14; i++ {
    206 		m.symbol.set(14-i, fpSize+1, f.At(l-i))
    207 	}
    208 
    209 	// Bits 8-14 on the right side of the bottom left finder pattern.
    210 	for i := 8; i <= 14; i++ {
    211 		m.symbol.set(fpSize+1, m.size-fpSize+i-8, f.At(l-i))
    212 	}
    213 
    214 	// Always dark symbol.
    215 	m.symbol.set(fpSize+1, m.size-fpSize-1, true)
    216 }
    217 
    218 func (m *regularSymbol) addVersionInfo() {
    219 	fpSize := finderPatternSize
    220 
    221 	v := m.version.versionInfo()
    222 	l := versionInfoLengthBits - 1
    223 
    224 	if v == nil {
    225 		return
    226 	}
    227 
    228 	for i := 0; i < v.Len(); i++ {
    229 		// Above the bottom left finder pattern.
    230 		m.symbol.set(i/3, m.size-fpSize-4+i%3, v.At(l-i))
    231 
    232 		// Left of the top right finder pattern.
    233 		m.symbol.set(m.size-fpSize-4+i%3, i/3, v.At(l-i))
    234 	}
    235 }
    236 
    237 type direction uint8
    238 
    239 const (
    240 	up direction = iota
    241 	down
    242 )
    243 
    244 func (m *regularSymbol) addData() (bool, error) {
    245 	xOffset := 1
    246 	dir := up
    247 
    248 	x := m.size - 2
    249 	y := m.size - 1
    250 
    251 	for i := 0; i < m.data.Len(); i++ {
    252 		var mask bool
    253 		switch m.mask {
    254 		case 0:
    255 			mask = (y+x+xOffset)%2 == 0
    256 		case 1:
    257 			mask = y%2 == 0
    258 		case 2:
    259 			mask = (x+xOffset)%3 == 0
    260 		case 3:
    261 			mask = (y+x+xOffset)%3 == 0
    262 		case 4:
    263 			mask = (y/2+(x+xOffset)/3)%2 == 0
    264 		case 5:
    265 			mask = (y*(x+xOffset))%2+(y*(x+xOffset))%3 == 0
    266 		case 6:
    267 			mask = ((y*(x+xOffset))%2+((y*(x+xOffset))%3))%2 == 0
    268 		case 7:
    269 			mask = ((y+x+xOffset)%2+((y*(x+xOffset))%3))%2 == 0
    270 		}
    271 
    272 		// != is equivalent to XOR.
    273 		m.symbol.set(x+xOffset, y, mask != m.data.At(i))
    274 
    275 		if i == m.data.Len()-1 {
    276 			break
    277 		}
    278 
    279 		// Find next free bit in the symbol.
    280 		for {
    281 			if xOffset == 1 {
    282 				xOffset = 0
    283 			} else {
    284 				xOffset = 1
    285 
    286 				if dir == up {
    287 					if y > 0 {
    288 						y--
    289 					} else {
    290 						dir = down
    291 						x -= 2
    292 					}
    293 				} else {
    294 					if y < m.size-1 {
    295 						y++
    296 					} else {
    297 						dir = up
    298 						x -= 2
    299 					}
    300 				}
    301 			}
    302 
    303 			// Skip over the vertical timing pattern entirely.
    304 			if x == 5 {
    305 				x--
    306 			}
    307 
    308 			if m.symbol.empty(x+xOffset, y) {
    309 				break
    310 			}
    311 		}
    312 	}
    313 
    314 	return true, nil
    315 }