ui/image.go

141 lines
2.6 KiB
Go
Raw Normal View History

package ui
import (
"fmt"
2020-03-09 05:07:46 +00:00
"image"
"image/jpeg"
"os"
"path/filepath"
"strings"
"git.kirsle.net/go/render"
)
// ImageType for supported image formats.
type ImageType string
// Supported image formats.
const (
2020-03-09 05:07:46 +00:00
BMP ImageType = "bmp"
PNG = "png"
JPEG = "jpg"
)
// Image is a widget that is backed by an image file.
type Image struct {
BaseWidget
// Configurable fields for the constructor.
Type ImageType
2020-03-09 05:07:46 +00:00
Image image.Image
texture render.Texturer
}
// NewImage creates a new Image.
func NewImage(c Image) *Image {
w := &Image{
Type: c.Type,
}
if w.Type == "" {
w.Type = BMP
}
w.IDFunc(func() string {
return fmt.Sprintf(`Image<"%s">`, w.Type)
})
return w
}
// ImageFromTexture creates an Image from a texture.
func ImageFromTexture(tex render.Texturer) *Image {
return &Image{
texture: tex,
}
}
2020-03-09 05:07:46 +00:00
// ImageFromFile creates an Image by opening a file from disk.
func ImageFromFile(e render.Engine, filename string) (*Image, error) {
fh, err := os.Open(filename)
if err != nil {
return nil, err
}
img, err := jpeg.Decode(fh)
if err != nil {
return nil, err
}
tex, err := e.StoreTexture(filename, img)
if err != nil {
return nil, err
}
return &Image{
Image: img,
texture: tex,
}, nil
}
// OpenImage initializes an Image with a given file name.
//
// The file extension is important and should be a supported ImageType.
func OpenImage(e render.Engine, filename string) (*Image, error) {
w := &Image{}
switch strings.ToLower(filepath.Ext(filename)) {
case ".bmp":
w.Type = BMP
case ".png":
w.Type = PNG
2020-03-09 05:07:46 +00:00
case ".jpg":
w.Type = JPEG
case ".jpeg":
w.Type = JPEG
default:
return nil, fmt.Errorf("OpenImage: %s: not a supported image type", filename)
}
tex, err := e.LoadTexture(filename)
if err != nil {
return nil, err
}
w.texture = tex
return w, nil
}
2020-03-09 05:07:46 +00:00
// GetRGBA returns an image.RGBA from the image data.
func (w *Image) GetRGBA() *image.RGBA {
var bounds = w.Image.Bounds()
var rgba = image.NewRGBA(bounds)
for x := bounds.Min.X; x < bounds.Max.X; x++ {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
color := w.Image.At(x, y)
rgba.Set(x, y, color)
}
}
return rgba
}
// Compute the widget.
func (w *Image) Compute(e render.Engine) {
w.Resize(w.texture.Size())
// Call the BaseWidget Compute in case we have subscribers.
w.BaseWidget.Compute(e)
}
// Present the widget.
func (w *Image) Present(e render.Engine, p render.Point) {
size := w.texture.Size()
dst := render.Rect{
X: p.X,
Y: p.Y,
W: size.W,
H: size.H,
}
e.Copy(w.texture, size, dst)
// Call the BaseWidget Present in case we have subscribers.
w.BaseWidget.Present(e, p)
}