User interface toolkit for Go with support for SDL2 and HTML Canvas render targets.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

141 lines
2.6 KiB

  1. package ui
  2. import (
  3. "fmt"
  4. "image"
  5. "image/jpeg"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "git.kirsle.net/go/render"
  10. )
  11. // ImageType for supported image formats.
  12. type ImageType string
  13. // Supported image formats.
  14. const (
  15. BMP ImageType = "bmp"
  16. PNG = "png"
  17. JPEG = "jpg"
  18. )
  19. // Image is a widget that is backed by an image file.
  20. type Image struct {
  21. BaseWidget
  22. // Configurable fields for the constructor.
  23. Type ImageType
  24. Image image.Image
  25. texture render.Texturer
  26. }
  27. // NewImage creates a new Image.
  28. func NewImage(c Image) *Image {
  29. w := &Image{
  30. Type: c.Type,
  31. }
  32. if w.Type == "" {
  33. w.Type = BMP
  34. }
  35. w.IDFunc(func() string {
  36. return fmt.Sprintf(`Image<"%s">`, w.Type)
  37. })
  38. return w
  39. }
  40. // ImageFromTexture creates an Image from a texture.
  41. func ImageFromTexture(tex render.Texturer) *Image {
  42. return &Image{
  43. texture: tex,
  44. }
  45. }
  46. // ImageFromFile creates an Image by opening a file from disk.
  47. func ImageFromFile(e render.Engine, filename string) (*Image, error) {
  48. fh, err := os.Open(filename)
  49. if err != nil {
  50. return nil, err
  51. }
  52. img, err := jpeg.Decode(fh)
  53. if err != nil {
  54. return nil, err
  55. }
  56. tex, err := e.StoreTexture(filename, img)
  57. if err != nil {
  58. return nil, err
  59. }
  60. return &Image{
  61. Image: img,
  62. texture: tex,
  63. }, nil
  64. }
  65. // OpenImage initializes an Image with a given file name.
  66. //
  67. // The file extension is important and should be a supported ImageType.
  68. func OpenImage(e render.Engine, filename string) (*Image, error) {
  69. w := &Image{}
  70. switch strings.ToLower(filepath.Ext(filename)) {
  71. case ".bmp":
  72. w.Type = BMP
  73. case ".png":
  74. w.Type = PNG
  75. case ".jpg":
  76. w.Type = JPEG
  77. case ".jpeg":
  78. w.Type = JPEG
  79. default:
  80. return nil, fmt.Errorf("OpenImage: %s: not a supported image type", filename)
  81. }
  82. tex, err := e.LoadTexture(filename)
  83. if err != nil {
  84. return nil, err
  85. }
  86. w.texture = tex
  87. return w, nil
  88. }
  89. // GetRGBA returns an image.RGBA from the image data.
  90. func (w *Image) GetRGBA() *image.RGBA {
  91. var bounds = w.Image.Bounds()
  92. var rgba = image.NewRGBA(bounds)
  93. for x := bounds.Min.X; x < bounds.Max.X; x++ {
  94. for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
  95. color := w.Image.At(x, y)
  96. rgba.Set(x, y, color)
  97. }
  98. }
  99. return rgba
  100. }
  101. // Compute the widget.
  102. func (w *Image) Compute(e render.Engine) {
  103. w.Resize(w.texture.Size())
  104. // Call the BaseWidget Compute in case we have subscribers.
  105. w.BaseWidget.Compute(e)
  106. }
  107. // Present the widget.
  108. func (w *Image) Present(e render.Engine, p render.Point) {
  109. size := w.texture.Size()
  110. dst := render.Rect{
  111. X: p.X,
  112. Y: p.Y,
  113. W: size.W,
  114. H: size.H,
  115. }
  116. e.Copy(w.texture, size, dst)
  117. // Call the BaseWidget Present in case we have subscribers.
  118. w.BaseWidget.Present(e, p)
  119. }