2019-04-10 00:35:44 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-03-09 05:07:46 +00:00
|
|
|
"image"
|
|
|
|
"image/jpeg"
|
|
|
|
"os"
|
2019-04-10 00:35:44 +00:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
2019-12-23 02:21:58 +00:00
|
|
|
"git.kirsle.net/go/render"
|
2019-04-10 00:35:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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"
|
2019-04-10 00:35:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
2019-04-10 00:35:44 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-07-04 03:24:04 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
// 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
|
2019-04-10 00:35:44 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("OpenImage: %s: not a supported image type", filename)
|
|
|
|
}
|
|
|
|
|
2019-06-27 20:01:01 +00:00
|
|
|
tex, err := e.LoadTexture(filename)
|
2019-04-10 00:35:44 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
// Compute the widget.
|
|
|
|
func (w *Image) Compute(e render.Engine) {
|
|
|
|
w.Resize(w.texture.Size())
|
2020-03-10 00:13:33 +00:00
|
|
|
|
|
|
|
// Call the BaseWidget Compute in case we have subscribers.
|
|
|
|
w.BaseWidget.Compute(e)
|
2019-04-10 00:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
2020-03-10 00:13:33 +00:00
|
|
|
|
|
|
|
// Call the BaseWidget Present in case we have subscribers.
|
|
|
|
w.BaseWidget.Present(e, p)
|
2019-04-10 00:35:44 +00:00
|
|
|
}
|