helpers.go 2.8 KB

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