From 800d9897ff4e2f1df60e7d73e98c46ac12ac6bea Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Mon, 4 Sep 2017 11:22:56 +0200 Subject: [PATCH] Implement QR code display via unicode block characters. Use `--draw` to use ANSImage instead which is less compatible with legacy or remote terminals. --- internal/bytes_to_unicode.go | 87 ++++++++++++++++++++++++++++++++++++ main.go | 22 ++++++++- 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 internal/bytes_to_unicode.go diff --git a/internal/bytes_to_unicode.go b/internal/bytes_to_unicode.go new file mode 100644 index 0000000..9b7d8bf --- /dev/null +++ b/internal/bytes_to_unicode.go @@ -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 +} diff --git a/main.go b/main.go index 908a726..70aa55b 100644 --- a/main.go +++ b/main.go @@ -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) @@ -162,7 +166,23 @@ func generateCliQR(input string) (err error) { 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)