Files
why/main.go
2025-02-22 00:34:15 -05:00

139 lines
2.8 KiB
Go

package main
import (
"bytes"
_ "embed"
"fmt"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io"
"log"
"os"
"slices"
"strings"
"time"
tk "modernc.org/tk9.0"
)
//go:embed gopher.png
var gopher []byte
var validFileTypes = []tk.FileType{
{
TypeName: "JPEG",
Extensions: []string{".jpg", ".jpeg"},
},
{
TypeName: "GIF",
Extensions: []string{".gif"},
},
{
TypeName: "PNG",
Extensions: []string{".png"},
},
{
TypeName: "SVG",
Extensions: []string{".svg"},
},
}
var metaPressed bool
func isType(filename string, desired string) bool {
splode := strings.Split(filename, ".")
if len(splode) < 2 {
return false
}
ext := fmt.Sprintf(".%s", splode[len(splode)-1])
for _, ft := range validFileTypes {
if slices.Contains(ft.Extensions, ext) && ft.TypeName == desired {
return true
}
}
return false
}
func jpegToPng(in io.Reader) (*bytes.Buffer, error) {
start := time.Now()
buf := new(bytes.Buffer)
img, err := jpeg.Decode(in)
if err != nil {
return nil, fmt.Errorf("unable to decode jpeg: %w", err)
}
b := img.Bounds()
dst := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
draw.Draw(dst, dst.Bounds(), img, b.Min, draw.Src)
if err := (&png.Encoder{
CompressionLevel: -2,
}).Encode(buf, dst); err != nil {
return nil, fmt.Errorf("unable to encode png: %w", err)
}
end := time.Now()
log.Printf("jpeg to png took %v", end.Sub(start))
return buf, nil
}
func loadImage(img *tk.LabelWidget) func() {
return func() {
files := tk.GetOpenFile(tk.Filetypes(validFileTypes))
if len(files) > 0 {
f, err := os.Open(files[0])
if err != nil {
log.Println(err.Error())
return
}
var r io.Reader
if isType(files[0], "JPEG") {
r, err = jpegToPng(f)
if err != nil {
log.Println(err.Error())
return
}
} else {
r = f
}
i, err := io.ReadAll(r)
if err != nil {
log.Println(err.Error())
return
}
img.Configure(tk.Image(tk.NewPhoto(tk.Data(i))))
}
}
}
func main() {
img := tk.Label(tk.Image(tk.NewPhoto(tk.Data(gopher))))
menubar := tk.Menu()
fileMenu := menubar.Menu()
fileMenu.AddCommand(tk.Lbl("Open"), tk.Underline(0), tk.Accelerator("Meta+O"), tk.Command(loadImage(img)))
menubar.AddCascade(tk.Lbl("File"), tk.Underline(0), tk.Mnu(fileMenu))
tk.Bind(tk.App, "<KeyPress>", tk.Command(func(e *tk.Event) {
if e.Keysym == "Meta_L" || e.Keysym == "Meta_R" {
metaPressed = true
}
if e.Keysym == "o" && metaPressed {
loadImage(img)()
}
}))
tk.Bind(tk.App, "<KeyRelease>", tk.Command(func(e *tk.Event) {
if e.Keysym == "Meta_L" || e.Keysym == "Meta_R" {
metaPressed = false
}
}))
tk.Bind(tk.App, "<TouchpadScroll>", tk.Command(func(e *tk.Event) {
// TODO: this event doesn't contain deltas, which means I can't tell if I'm scrolling "in" or "out"
}))
tk.Pack(img)
tk.App.Configure(tk.Mnu(menubar)).Center().Wait()
}