1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
package qrterminal
import (
"io"
"strings"
"rsc.io/qr"
)
const WHITE = "\033[47m \033[0m"
const BLACK = "\033[40m \033[0m"
// Use ascii blocks to form the QR Code
const BLACK_WHITE = "▄"
const BLACK_BLACK = " "
const WHITE_BLACK = "▀"
const WHITE_WHITE = "█"
// Level - the QR Code's redundancy level
const H = qr.H
const M = qr.M
const L = qr.L
// default is 4-pixel-wide white quiet zone
const QUIET_ZONE = 4
//Config for generating a barcode
type Config struct {
Level qr.Level
Writer io.Writer
HalfBlocks bool
BlackChar string
BlackWhiteChar string
WhiteChar string
WhiteBlackChar string
QuietZone int
}
func (c *Config) writeFullBlocks(w io.Writer, code *qr.Code) {
white := c.WhiteChar
black := c.BlackChar
// Frame the barcode in a 1 pixel border
w.Write([]byte(stringRepeat(stringRepeat(white,
code.Size+c.QuietZone*2)+"\n", c.QuietZone))) // top border
for i := 0; i <= code.Size; i++ {
w.Write([]byte(stringRepeat(white, c.QuietZone))) // left border
for j := 0; j <= code.Size; j++ {
if code.Black(j, i) {
w.Write([]byte(black))
} else {
w.Write([]byte(white))
}
}
w.Write([]byte(stringRepeat(white, c.QuietZone-1) + "\n")) // right border
}
w.Write([]byte(stringRepeat(stringRepeat(white,
code.Size+c.QuietZone*2)+"\n", c.QuietZone-1))) // bottom border
}
func (c *Config) writeHalfBlocks(w io.Writer, code *qr.Code) {
ww := c.WhiteChar
bb := c.BlackChar
wb := c.WhiteBlackChar
bw := c.BlackWhiteChar
// Frame the barcode in a 4 pixel border
// top border
if c.QuietZone%2 != 0 {
w.Write([]byte(stringRepeat(bw, code.Size+c.QuietZone*2) + "\n"))
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
} else {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
}
for i := 0; i <= code.Size; i += 2 {
w.Write([]byte(stringRepeat(ww, c.QuietZone))) // left border
for j := 0; j <= code.Size; j++ {
next_black := false
if i+1 < code.Size {
next_black = code.Black(j, i+1)
}
curr_black := code.Black(j, i)
if curr_black && next_black {
w.Write([]byte(bb))
} else if curr_black && !next_black {
w.Write([]byte(bw))
} else if !curr_black && !next_black {
w.Write([]byte(ww))
} else {
w.Write([]byte(wb))
}
}
w.Write([]byte(stringRepeat(ww, c.QuietZone-1) + "\n")) // right border
}
// bottom border
if c.QuietZone%2 == 0 {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2-1)))
w.Write([]byte(stringRepeat(wb, code.Size+c.QuietZone*2) + "\n"))
} else {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
}
}
func stringRepeat(s string, count int) string {
if count <= 0 {
return ""
}
return strings.Repeat(s, count)
}
// GenerateWithConfig expects a string to encode and a config
func GenerateWithConfig(text string, config Config) {
if config.QuietZone < 1 {
config.QuietZone = 1 // at least 1-pixel-wide white quiet zone
}
w := config.Writer
code, _ := qr.Encode(text, config.Level)
if config.HalfBlocks {
config.writeHalfBlocks(w, code)
} else {
config.writeFullBlocks(w, code)
}
}
// Generate a QR Code and write it out to io.Writer
func Generate(text string, l qr.Level, w io.Writer) {
config := Config{
Level: l,
Writer: w,
BlackChar: BLACK,
WhiteChar: WHITE,
QuietZone: QUIET_ZONE,
}
GenerateWithConfig(text, config)
}
// Generate a QR Code with half blocks and write it out to io.Writer
func GenerateHalfBlock(text string, l qr.Level, w io.Writer) {
config := Config{
Level: l,
Writer: w,
HalfBlocks: true,
BlackChar: BLACK_BLACK,
WhiteBlackChar: WHITE_BLACK,
WhiteChar: WHITE_WHITE,
BlackWhiteChar: BLACK_WHITE,
QuietZone: QUIET_ZONE,
}
GenerateWithConfig(text, config)
}
|