utils.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package imaging
  2. import (
  3. "image"
  4. "runtime"
  5. "sync"
  6. "math"
  7. "image/color"
  8. )
  9. // parallel processes the data in separate goroutines.
  10. func parallel(start, stop int, fn func(<-chan int)) {
  11. count := stop - start
  12. if count < 1 {
  13. return
  14. }
  15. procs := runtime.GOMAXPROCS(0)
  16. if procs > count {
  17. procs = count
  18. }
  19. c := make(chan int, count)
  20. for i := start; i < stop; i++ {
  21. c <- i
  22. }
  23. close(c)
  24. var wg sync.WaitGroup
  25. for i := 0; i < procs; i++ {
  26. wg.Add(1)
  27. go func() {
  28. defer wg.Done()
  29. fn(c)
  30. }()
  31. }
  32. wg.Wait()
  33. }
  34. // absint returns the absolute value of i.
  35. func absint(i int) int {
  36. if i < 0 {
  37. return -i
  38. }
  39. return i
  40. }
  41. // clamp rounds and clamps float64 value to fit into uint8.
  42. func clamp(x float64) uint8 {
  43. v := int64(x + 0.5)
  44. if v > 255 {
  45. return 255
  46. }
  47. if v > 0 {
  48. return uint8(v)
  49. }
  50. return 0
  51. }
  52. func reverse(pix []uint8) {
  53. if len(pix) <= 4 {
  54. return
  55. }
  56. i := 0
  57. j := len(pix) - 4
  58. for i < j {
  59. pix[i+0], pix[j+0] = pix[j+0], pix[i+0]
  60. pix[i+1], pix[j+1] = pix[j+1], pix[i+1]
  61. pix[i+2], pix[j+2] = pix[j+2], pix[i+2]
  62. pix[i+3], pix[j+3] = pix[j+3], pix[i+3]
  63. i += 4
  64. j -= 4
  65. }
  66. }
  67. func toNRGBA(img image.Image) *image.NRGBA {
  68. if img, ok := img.(*image.NRGBA); ok {
  69. return &image.NRGBA{
  70. Pix: img.Pix,
  71. Stride: img.Stride,
  72. Rect: img.Rect.Sub(img.Rect.Min),
  73. }
  74. }
  75. return Clone(img)
  76. }
  77. // nrgbaToHSL converts NRGBA to HSL.
  78. func nrgbaToHSL(c color.NRGBA) (float64, float64, float64) {
  79. var h, s, l float64
  80. r := float64(c.R) / float64(255)
  81. g := float64(c.G) / float64(255)
  82. b := float64(c.B) / float64(255)
  83. min := math.Min(math.Min(r, g), b)
  84. max := math.Max(math.Max(r, g), b)
  85. l = (max + min) / 2
  86. if min == max {
  87. s = 0
  88. h = 0
  89. } else {
  90. if l < 0.5 {
  91. s = (max - min) / (max + min)
  92. } else {
  93. s = (max - min) / (2.0 - max - min)
  94. }
  95. if max == r {
  96. h = (g - b) / (max - min)
  97. } else if max == g {
  98. h = 2.0 + (b-r)/(max-min)
  99. } else {
  100. h = 4.0 + (r-g)/(max-min)
  101. }
  102. h *= 60
  103. if h < 0 {
  104. h += 360
  105. }
  106. }
  107. return h, s, l
  108. }
  109. // hslToNRGBA converts HSL to NRGBA with A=1.
  110. func hslToNRGBA(h, s, l float64) color.NRGBA {
  111. if s == 0 {
  112. c := uint8(l * 255)
  113. return color.NRGBA{R: c, G: c, B: c, A: 1}
  114. }
  115. var r, g, b float64
  116. var t1, t2, tr, tg, tb float64
  117. if l < 0.5 {
  118. t1 = l * (1.0 + s)
  119. } else {
  120. t1 = l + s - l*s
  121. }
  122. t2 = 2*l - t1
  123. h = h / 360
  124. tr = h + 1.0/3.0
  125. tg = h
  126. tb = h - 1.0/3.0
  127. if tr < 0 {
  128. tr++
  129. } else if tr > 1 {
  130. tr--
  131. }
  132. if tg < 0 {
  133. tg++
  134. } else if tg > 1 {
  135. tg--
  136. }
  137. if tb < 0 {
  138. tb++
  139. } else if tb > 1 {
  140. tb--
  141. }
  142. // Red
  143. if 6*tr < 1 {
  144. r = t2 + (t1-t2)*6*tr
  145. } else if 2*tr < 1 {
  146. r = t1
  147. } else if 3*tr < 2 {
  148. r = t2 + (t1-t2)*(2.0/3.0-tr)*6
  149. } else {
  150. r = t2
  151. }
  152. // Green
  153. if 6*tg < 1 {
  154. g = t2 + (t1-t2)*6*tg
  155. } else if 2*tg < 1 {
  156. g = t1
  157. } else if 3*tg < 2 {
  158. g = t2 + (t1-t2)*(2.0/3.0-tg)*6
  159. } else {
  160. g = t2
  161. }
  162. // Blue
  163. if 6*tb < 1 {
  164. b = t2 + (t1-t2)*6*tb
  165. } else if 2*tb < 1 {
  166. b = t1
  167. } else if 3*tb < 2 {
  168. b = t2 + (t1-t2)*(2.0/3.0-tb)*6
  169. } else {
  170. b = t2
  171. }
  172. return color.NRGBA{R: uint8(r * 255), G: uint8(g * 255), B: uint8(b * 255)}
  173. }