helpers.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package imaging
  2. import (
  3. "fmt"
  4. "image"
  5. "image/color"
  6. _ "image/gif"
  7. "image/jpeg"
  8. "image/png"
  9. "math"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "code.google.com/p/go.image/bmp"
  14. "code.google.com/p/go.image/tiff"
  15. )
  16. // Open loads an image from file
  17. func Open(filename string) (img image.Image, err error) {
  18. file, err := os.Open(filename)
  19. if err != nil {
  20. return
  21. }
  22. defer file.Close()
  23. img, _, err = image.Decode(file)
  24. if err != nil {
  25. return
  26. }
  27. img = toNRGBA(img)
  28. return
  29. }
  30. // Save saves the image to file with the specified filename.
  31. // The format is determined from the filename extension: "jpg" (or "jpeg"), "png", "tif" (or "tiff") and "bmp" are supported.
  32. func Save(img image.Image, filename string) (err error) {
  33. format := strings.ToLower(filepath.Ext(filename))
  34. okay := false
  35. for _, ext := range []string{".jpg", ".jpeg", ".png", ".tif", ".tiff", ".bmp"} {
  36. if format == ext {
  37. okay = true
  38. break
  39. }
  40. }
  41. if !okay {
  42. return fmt.Errorf(`imaging: unsupported image format: "%s"`, format)
  43. }
  44. file, err := os.Create(filename)
  45. if err != nil {
  46. return
  47. }
  48. defer file.Close()
  49. switch format {
  50. case ".jpg", ".jpeg":
  51. var rgba *image.RGBA
  52. if nrgba, ok := img.(*image.NRGBA); ok {
  53. if nrgba.Opaque() {
  54. rgba = &image.RGBA{
  55. Pix: nrgba.Pix,
  56. Stride: nrgba.Stride,
  57. Rect: nrgba.Rect,
  58. }
  59. }
  60. }
  61. if rgba != nil {
  62. err = jpeg.Encode(file, rgba, &jpeg.Options{Quality: 95})
  63. } else {
  64. err = jpeg.Encode(file, img, &jpeg.Options{Quality: 95})
  65. }
  66. case ".png":
  67. err = png.Encode(file, img)
  68. case ".tif", ".tiff":
  69. err = tiff.Encode(file, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
  70. case ".bmp":
  71. err = bmp.Encode(file, img)
  72. }
  73. return
  74. }
  75. // New creates a new image with the specified width and height, and fills it with the specified color.
  76. func New(width, height int, fillColor color.Color) *image.NRGBA {
  77. if width <= 0 || height <= 0 {
  78. return &image.NRGBA{}
  79. }
  80. dst := image.NewNRGBA(image.Rect(0, 0, width, height))
  81. c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
  82. if c.R == 0 && c.G == 0 && c.B == 0 && c.A == 0 {
  83. return dst
  84. }
  85. cs := []uint8{c.R, c.G, c.B, c.A}
  86. // fill the first row
  87. for x := 0; x < width; x++ {
  88. copy(dst.Pix[x*4:(x+1)*4], cs)
  89. }
  90. // copy the first row to other rows
  91. for y := 1; y < height; y++ {
  92. copy(dst.Pix[y*dst.Stride:y*dst.Stride+width*4], dst.Pix[0:width*4])
  93. }
  94. return dst
  95. }
  96. // This function used internally to convert any image type to NRGBA if needed.
  97. func toNRGBA(img image.Image) *image.NRGBA {
  98. srcBounds := img.Bounds()
  99. if srcBounds.Min.X == 0 && srcBounds.Min.Y == 0 {
  100. if src0, ok := img.(*image.NRGBA); ok {
  101. return src0
  102. }
  103. }
  104. return Clone(img)
  105. }
  106. // clamp & round float64 to uint8 (0..255)
  107. func clamp(v float64) uint8 {
  108. return uint8(math.Min(math.Max(v, 0.0), 255.0) + 0.5)
  109. }