raster.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package canvas
  2. import (
  3. "image"
  4. "image/color"
  5. "image/draw"
  6. "fyne.io/fyne/v2"
  7. )
  8. // Declare conformity with CanvasObject interface
  9. var _ fyne.CanvasObject = (*Raster)(nil)
  10. // Raster describes a raster image area that can render in a Fyne canvas
  11. type Raster struct {
  12. baseObject
  13. // Render the raster image from code
  14. Generator func(w, h int) image.Image
  15. // Set a translucency value > 0.0 to fade the raster
  16. Translucency float64
  17. // Specify the type of scaling interpolation applied to the raster if it is not full-size
  18. // Since: 1.4.1
  19. ScaleMode ImageScale
  20. }
  21. // Alpha is a convenience function that returns the alpha value for a raster
  22. // based on its Translucency value. The result is 1.0 - Translucency.
  23. func (r *Raster) Alpha() float64 {
  24. return 1.0 - r.Translucency
  25. }
  26. // Hide will set this raster to not be visible
  27. func (r *Raster) Hide() {
  28. r.baseObject.Hide()
  29. repaint(r)
  30. }
  31. // Move the raster to a new position, relative to its parent / canvas
  32. func (r *Raster) Move(pos fyne.Position) {
  33. r.baseObject.Move(pos)
  34. repaint(r)
  35. }
  36. // Resize on a raster image causes the new size to be set and then calls Refresh.
  37. // This causes the underlying data to be recalculated and a new output to be drawn.
  38. func (r *Raster) Resize(s fyne.Size) {
  39. if s == r.Size() {
  40. return
  41. }
  42. r.baseObject.Resize(s)
  43. Refresh(r)
  44. }
  45. // Refresh causes this raster to be redrawn with its configured state.
  46. func (r *Raster) Refresh() {
  47. Refresh(r)
  48. }
  49. // NewRaster returns a new Image instance that is rendered dynamically using
  50. // the specified generate function.
  51. // Images returned from this method should draw dynamically to fill the width
  52. // and height parameters passed to pixelColor.
  53. func NewRaster(generate func(w, h int) image.Image) *Raster {
  54. return &Raster{Generator: generate}
  55. }
  56. type pixelRaster struct {
  57. r *Raster
  58. img draw.Image
  59. }
  60. // NewRasterWithPixels returns a new Image instance that is rendered dynamically
  61. // by iterating over the specified pixelColor function for each x, y pixel.
  62. // Images returned from this method should draw dynamically to fill the width
  63. // and height parameters passed to pixelColor.
  64. func NewRasterWithPixels(pixelColor func(x, y, w, h int) color.Color) *Raster {
  65. pix := &pixelRaster{}
  66. pix.r = &Raster{
  67. Generator: func(w, h int) image.Image {
  68. if pix.img == nil || pix.img.Bounds().Size().X != w || pix.img.Bounds().Size().Y != h {
  69. // raster first pixel, figure out color type
  70. var dst draw.Image
  71. rect := image.Rect(0, 0, w, h)
  72. switch pixelColor(0, 0, w, h).(type) {
  73. case color.Alpha:
  74. dst = image.NewAlpha(rect)
  75. case color.Alpha16:
  76. dst = image.NewAlpha16(rect)
  77. case color.CMYK:
  78. dst = image.NewCMYK(rect)
  79. case color.Gray:
  80. dst = image.NewGray(rect)
  81. case color.Gray16:
  82. dst = image.NewGray16(rect)
  83. case color.NRGBA:
  84. dst = image.NewNRGBA(rect)
  85. case color.NRGBA64:
  86. dst = image.NewNRGBA64(rect)
  87. case color.RGBA:
  88. dst = image.NewRGBA(rect)
  89. case color.RGBA64:
  90. dst = image.NewRGBA64(rect)
  91. default:
  92. dst = image.NewRGBA(rect)
  93. }
  94. pix.img = dst
  95. }
  96. for y := 0; y < h; y++ {
  97. for x := 0; x < w; x++ {
  98. pix.img.Set(x, y, pixelColor(x, y, w, h))
  99. }
  100. }
  101. return pix.img
  102. },
  103. }
  104. return pix.r
  105. }
  106. type subImg interface {
  107. SubImage(r image.Rectangle) image.Image
  108. }
  109. // NewRasterFromImage returns a new Raster instance that is rendered from the Go
  110. // image.Image passed in.
  111. // Rasters returned from this method will map pixel for pixel to the screen
  112. // starting img.Bounds().Min pixels from the top left of the canvas object.
  113. // Truncates rather than scales the image.
  114. // If smaller than the target space, the image will be padded with zero-pixels to the target size.
  115. func NewRasterFromImage(img image.Image) *Raster {
  116. return &Raster{
  117. Generator: func(w int, h int) image.Image {
  118. bounds := img.Bounds()
  119. rect := image.Rect(0, 0, w, h)
  120. switch {
  121. case w == bounds.Max.X && h == bounds.Max.Y:
  122. return img
  123. case w >= bounds.Max.X && h >= bounds.Max.Y:
  124. // try quickly truncating
  125. if sub, ok := img.(subImg); ok {
  126. return sub.SubImage(image.Rectangle{
  127. Min: bounds.Min,
  128. Max: image.Point{
  129. X: bounds.Min.X + w,
  130. Y: bounds.Min.Y + h,
  131. },
  132. })
  133. }
  134. default:
  135. if !rect.Overlaps(bounds) {
  136. return image.NewUniform(color.RGBA{})
  137. }
  138. bounds = bounds.Intersect(rect)
  139. }
  140. // respect the user's pixel format (if possible)
  141. var dst draw.Image
  142. switch i := img.(type) {
  143. case *image.Alpha:
  144. dst = image.NewAlpha(rect)
  145. case *image.Alpha16:
  146. dst = image.NewAlpha16(rect)
  147. case *image.CMYK:
  148. dst = image.NewCMYK(rect)
  149. case *image.Gray:
  150. dst = image.NewGray(rect)
  151. case *image.Gray16:
  152. dst = image.NewGray16(rect)
  153. case *image.NRGBA:
  154. dst = image.NewNRGBA(rect)
  155. case *image.NRGBA64:
  156. dst = image.NewNRGBA64(rect)
  157. case *image.Paletted:
  158. dst = image.NewPaletted(rect, i.Palette)
  159. case *image.RGBA:
  160. dst = image.NewRGBA(rect)
  161. case *image.RGBA64:
  162. dst = image.NewRGBA64(rect)
  163. default:
  164. dst = image.NewRGBA(rect)
  165. }
  166. draw.Draw(dst, bounds, img, bounds.Min, draw.Over)
  167. return dst
  168. },
  169. }
  170. }