Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Terminal v2 suggestion #109

Closed
alexballas opened this issue May 20, 2024 · 4 comments
Closed

[FEATURE] Terminal v2 suggestion #109

alexballas opened this issue May 20, 2024 · 4 comments
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@alexballas
Copy link
Contributor

alexballas commented May 20, 2024

Hello! Thanks for working on this very helpful package and for keeping the QR code stuff active in the Go ecosystem.
I have a proposal and I'd like to hear your thoughts.

The current terminal writer uses Termbox, which is nice but difficult to integrate with for better control over CLI tools. It's especially challenging to display a QR code in the terminal without creating a whole new screen. Additionally, Termbox is no longer maintained.

I'm proposing a terminal v2 writer that uses *os.File for output. I chose *os.File instead of io.Writer because it has a better chance of displaying correctly. I also added a Bitmap() method, which I found useful when working with the skip2 package.

using this writer should be as simple as doing that

func main() {
	QRCodeItem, _ := qrcode.New("Hello!")
	termV2 := New(os.Stdout)
	_ = QRCodeItem.Save(termV2)
}

full example

package main

import (
	"errors"
	"os"

	"github.com/yeqown/go-qrcode/v2"
)

const (
	upRune     = '▀'
	downRune   = '▄'
	upDownRune = '█'
)

var _ qrcode.Writer = (*terminalv2)(nil)

func main() {
	QRCodeItem, _ := qrcode.New("Hello!")
	termV2 := New(os.Stdout)
	_ = QRCodeItem.Save(termV2)
}

type terminalv2 struct {
	out    *os.File
	bitmap [][]bool
}

func (a *terminalv2) Close() error { return nil }
func (a *terminalv2) Write(mat qrcode.Matrix) error {
	if a.out == nil {
		return errors.New("nil file")
	}

	a.bitmap = make([][]bool, mat.Height())
	for i := range a.bitmap {
		a.bitmap[i] = make([]bool, mat.Width())
	}
	mat.Iterate(qrcode.IterDirection_ROW, func(row, col int, s qrcode.QRValue) {
		a.bitmap[col][row] = s.IsSet()
	})

	bm := a.bitmap

	output := make([][]string, len(bm)/2+len(bm)%2)
	for i := range output {
		output[i] = make([]string, len(bm[0]))
	}

	for col := range output {
		for row := range output[col] {
			var selectedRune rune = ' '

			if bm[col*2][row] {
				selectedRune = upRune
			}

			if col*2+1 < len(bm) {
				if bm[col*2+1][row] && !bm[col*2][row] {
					selectedRune = downRune
				}

				if bm[col*2+1][row] && bm[col*2][row] {
					selectedRune = upDownRune
				}

				if !bm[col*2+1][row] && !bm[col*2][row] {
					selectedRune = ' '
				}
			}

			output[col][row] = string(selectedRune)
		}
	}

	for _, col := range output {
		for _, row := range col {
			_, err := a.out.WriteString(row)
			if err != nil {
				return err
			}
		}
		_, err := a.out.WriteString("\n")
		if err != nil {
			return err
		}
	}

	return nil
}

func (a *terminalv2) Bitmap() [][]bool {
	return a.bitmap
}

func New(f *os.File) *terminalv2 {
	return &terminalv2{out: f}
}

Screenshot from 2024-05-20 16-53-24

If you're happy with it, I can raise a PR.

@alexballas alexballas added enhancement New feature or request help wanted Extra attention is needed labels May 20, 2024
@yeqown
Copy link
Owner

yeqown commented May 22, 2024

It looks pretty good, feel free to raise a PR

@yeqown
Copy link
Owner

yeqown commented May 22, 2024

Maybe Bitmap can be added to the Matrix struct so that you don't have to iterate to get it?

@alexballas
Copy link
Contributor Author

Sounds good, I'll proceed with the changes

@alexballas
Copy link
Contributor Author

raised #110

@yeqown yeqown closed this as completed Jun 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants