Compare commits

...

2 Commits

Author SHA1 Message Date
Icedream 800d9897ff
Implement QR code display via unicode block characters.
Use `--draw` to use ANSImage instead which is less compatible with
legacy or remote terminals.
2017-09-04 11:22:56 +02:00
Icedream cf68a4548f
Pass errors through to main function. 2017-09-04 11:21:09 +02:00
2 changed files with 111 additions and 4 deletions

View File

@ -0,0 +1,87 @@
package internal
import (
"io"
"strings"
"github.com/fatih/color"
"github.com/qpliu/qrencode-go/qrencode"
)
const (
Upper byte = 1 << iota
Lower
)
var (
// Got the information from https://de.wikipedia.org/wiki/Unicodeblock_Blockelemente
byteMapping = map[byte]rune{
0: ' ',
Upper: '\u2580', // UPPER HALF BLOCK
Lower: '\u2584', // LOWER HALF BLOCK
Upper | Lower: '\u2588', // FULL BLOCK
}
)
func ConvertGridToUnicode(target io.Writer, source *qrencode.BitGrid) (err error) {
c := color.New(color.BgWhite)
c.Add(color.FgBlack)
writeSpaceLine := func() (n int, err error) {
n, err = c.Fprint(target, strings.Repeat(" ", source.Width()+2))
if err != nil {
return
}
m, err := target.Write([]byte{'\n'})
if err != nil {
return
}
n += m
return
}
if _, err = writeSpaceLine(); err != nil {
return
}
for y := 0; y < source.Height(); y += 2 {
// Go from left to right in both rows
line := " "
for x := 0; x < source.Width(); x++ {
var runeKey byte
// First row
if source.Get(x, y) {
runeKey |= Upper
}
if y+1 < source.Height() {
if source.Get(x, y+1) {
runeKey |= Lower
}
}
line += string(byteMapping[runeKey])
}
line += " "
_, err = c.Fprint(target, line)
if err != nil {
return
}
_, err = target.Write([]byte{'\n'})
if err != nil {
return
}
}
if err == io.EOF {
err = nil
}
_, err = writeSpaceLine()
return
}

28
main.go
View File

@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/base32"
"errors"
"fmt"
@ -48,6 +49,9 @@ var (
var (
app = kingpin.New("pixelqr", "Generates QR code from any input and displays it in your ANSI true-color compatible terminal.")
flagANSImage = app.Flag("draw", "Use ANSI drawing code using ANSImage.").
Default("false").
Bool()
flagECLevel = app.Flag("ec", "Sets the error correction level for the generated code.").
Default(ECLevel_L).
Enum(ECLevel_L, ECLevel_M, ECLevel_Q, ECLevel_H)
@ -115,7 +119,7 @@ func main() {
if err != nil {
return
}
generateCliQR(string(input))
err = generateCliQR(string(input))
case cmdOtp.FullCommand(): // otp -> qr
// https://github.com/google/google-authenticator/wiki/Key-Uri-Format
@ -149,20 +153,36 @@ func main() {
RawQuery: query.Encode(),
}
log.Println("Generated URL:", url.String())
generateCliQR(url.String())
err = generateCliQR(url.String())
default: // other
err = ErrCommandNotFound
}
}
func generateCliQR(input string) {
func generateCliQR(input string) (err error) {
grid, err := qrencode.Encode(input, ecLevelMapping[*flagECLevel])
if err != nil {
return
}
s, err := internal.ConvertGridToANSImage(grid)
var s string
if *flagANSImage {
s, err = internal.ConvertGridToANSImage(grid)
if err != nil {
return
}
} else {
w := new(bytes.Buffer)
err = internal.ConvertGridToUnicode(w, grid)
if err != nil {
return
}
s = string(w.Bytes())
}
fmt.Println(s)