Skip to content

Commit

Permalink
Navigation and info when viewing multiple files (i toggles info, `h…
Browse files Browse the repository at this point in the history
…` for help, left arrow to go back) (#34)

* Stay in viewer and allow arrow navigations to previous image

* Show image name and format and index
  • Loading branch information
ldemailly authored Sep 24, 2024
1 parent 627b4ef commit 26ca163
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 15 deletions.
7 changes: 7 additions & 0 deletions ansipixels/ansipixels.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ func (ap *AnsiPixels) WriteCentered(y int, msg string, args ...interface{}) {
_, _ = ap.Out.WriteString(s)
}

func (ap *AnsiPixels) WriteRight(y int, msg string, args ...interface{}) {
s := fmt.Sprintf(msg, args...)
x := ap.W - len(s)
ap.MoveCursor(x, y)
_, _ = ap.Out.WriteString(s)
}

func (ap *AnsiPixels) ClearEndOfLine() {
_, _ = ap.Out.WriteString("\033[K")
}
Expand Down
50 changes: 40 additions & 10 deletions ansipixels/fps/fps.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func isStopKey(ap *ansipixels.AnsiPixels) bool {
ap.Data = ap.Data[0:0:cap(ap.Data)] // reset buffer
return false
}
if key == 'q' || key == 3 || key == 4 {
if key == 'q' || key == 'Q' || key == 3 || key == 4 {
return true
}
}
Expand Down Expand Up @@ -89,25 +89,55 @@ var fpsColorsJpg []byte
func imagesViewer(ap *ansipixels.AnsiPixels, imageFiles []string) int {
ap.ClearScreen()
ap.HideCursor()
ap.Data = make([]byte, 1)
for _, imageFile := range imageFiles {
img, err := ap.ReadImage(imageFile)
ap.Data = make([]byte, 3)
i := 0
l := len(imageFiles)
showInfo := l > 1
for {
if i >= l {
i = 0
}
imageFile := imageFiles[i]
img, format, err := ap.ReadImage(imageFile)
if err != nil {
return log.FErrf("Error reading image %s: %v", imageFile, err)
}
if err = ap.ShowImage(img, "\033[34m"); err != nil {
return log.FErrf("Error showing image: %v", err)
}
if showInfo {
ap.WriteRight(ap.H-1, "%s (%s, %d/%d)", imageFile, format, i+1, l)
ap.Out.Flush()
}
ap.Out.Flush()
_, err = ap.In.Read(ap.Data)
_, err = ap.In.Read(ap.Data[0:1])
if err != nil {
return log.FErrf("Error with cursor position request: %v", err)
}
if isStopKey(ap) {
if ap.Data[0] == '?' || ap.Data[0] == 'h' || ap.Data[0] == 'H' {
ap.WriteCentered(ap.H/2-1, "Showing %d out of %d images, hit any key to continue,", i+1, l)
ap.WriteCentered(ap.H/2, "'q' to exit, left arrow to go back, 'i' to toggle image information")
ap.Out.Flush()
_, _ = ap.In.Read(ap.Data[0:1])
}
if ap.Data[0] == 'i' || ap.Data[0] == 'I' {
showInfo = !showInfo
continue
}
if ap.Data[0] == 27 {
n, _ := ap.In.Read(ap.Data[1:3])
ap.Data = ap.Data[:1+n]
}
// check for left/right arrow to go to next/previous image
if len(ap.Data) >= 3 && ap.Data[0] == 27 && ap.Data[1] == '[' && ap.Data[2] == 'D' {
i = (i + l - 1) % l
continue
}
if isStopKey(ap) || l == 1 {
return 0
}
i++
}
return 0
}

func Main() int { //nolint:funlen,gocognit // color and mode if/else are a bit long.
Expand Down Expand Up @@ -177,12 +207,12 @@ func Main() int { //nolint:funlen,gocognit // color and mode if/else are a bit l
var err error
if *imgFlag == "" {
if *trueColorFlag || *colorFlag {
background, err = ap.DecodeImage(bytes.NewReader(fpsColorsJpg))
background, _, err = ap.DecodeImage(bytes.NewReader(fpsColorsJpg))
} else {
background, err = ap.DecodeImage(bytes.NewReader(fpsJpg))
background, _, err = ap.DecodeImage(bytes.NewReader(fpsJpg))
}
} else {
background, err = ap.ReadImage(*imgFlag)
background, _, err = ap.ReadImage(*imgFlag)
}
if err != nil {
return log.FErrf("Error reading image: %v", err)
Expand Down
10 changes: 5 additions & 5 deletions ansipixels/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,23 +215,23 @@ func convertToRGBA(src image.Image) *image.RGBA {
return dst
}

func (ap *AnsiPixels) ReadImage(path string) (*image.RGBA, error) {
func (ap *AnsiPixels) ReadImage(path string) (*image.RGBA, string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
return nil, "", err
}
defer file.Close()
return ap.DecodeImage(file)
}

func (ap *AnsiPixels) DecodeImage(data io.Reader) (*image.RGBA, error) {
func (ap *AnsiPixels) DecodeImage(data io.Reader) (*image.RGBA, string, error) {
// Automatically detect and decode the image format
img, format, err := image.Decode(data)
if err != nil {
return nil, err
return nil, "", err
}
log.Debugf("Image format: %s", format)
return convertToRGBA(img), nil
return convertToRGBA(img), format, nil
}

// Color string is the fallback mono color to use when AnsiPixels.TrueColor is false.
Expand Down

0 comments on commit 26ca163

Please sign in to comment.