image.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package painter
  2. import (
  3. "image"
  4. _ "image/jpeg" // avoid users having to import when using image widget
  5. _ "image/png" // avoid the same for PNG images
  6. "golang.org/x/image/draw"
  7. "fyne.io/fyne/v2"
  8. "fyne.io/fyne/v2/canvas"
  9. )
  10. // PaintImage renders a given fyne Image to a Go standard image
  11. // If a fyne.Canvas is given and the image’s fill mode is “fill original” the image’s min size has
  12. // to fit its original size. If it doesn’t, PaintImage does not paint the image but adjusts its min size.
  13. // The image will then be painted on the next frame because of the min size change.
  14. func PaintImage(img *canvas.Image, c fyne.Canvas, width, height int) image.Image {
  15. if img.Size().IsZero() && c == nil { // an image without size or canvas won't get rendered unless we setup
  16. img.Resize(fyne.NewSize(float32(width), float32(height)))
  17. }
  18. dst, err := paintImage(img, width, height)
  19. if err != nil {
  20. fyne.LogError("failed to paint image", err)
  21. }
  22. return dst
  23. }
  24. func paintImage(img *canvas.Image, width, height int) (dst image.Image, err error) {
  25. if width <= 0 || height <= 0 {
  26. return
  27. }
  28. dst = img.Image
  29. if dst == nil {
  30. dst = image.NewNRGBA(image.Rect(0, 0, width, height))
  31. }
  32. size := dst.Bounds().Size()
  33. if width != size.X || height != size.Y {
  34. dst = scaleImage(dst, width, height, img.ScaleMode)
  35. }
  36. return
  37. }
  38. func scaleImage(pixels image.Image, scaledW, scaledH int, scale canvas.ImageScale) image.Image {
  39. if scale == canvas.ImageScaleFastest || scale == canvas.ImageScalePixels {
  40. // do not perform software scaling
  41. return pixels
  42. }
  43. pixW := int(fyne.Min(float32(scaledW), float32(pixels.Bounds().Dx()))) // don't push more pixels than we have to
  44. pixH := int(fyne.Min(float32(scaledH), float32(pixels.Bounds().Dy()))) // the GL calls will scale this up on GPU.
  45. scaledBounds := image.Rect(0, 0, pixW, pixH)
  46. tex := image.NewNRGBA(scaledBounds)
  47. switch scale {
  48. case canvas.ImageScalePixels:
  49. draw.NearestNeighbor.Scale(tex, scaledBounds, pixels, pixels.Bounds(), draw.Over, nil)
  50. default:
  51. if scale != canvas.ImageScaleSmooth {
  52. fyne.LogError("Invalid canvas.ImageScale value, using canvas.ImageScaleSmooth", nil)
  53. }
  54. draw.CatmullRom.Scale(tex, scaledBounds, pixels, pixels.Bounds(), draw.Over, nil)
  55. }
  56. return tex
  57. }