utils.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package imaging
  2. import (
  3. "image"
  4. "math"
  5. "runtime"
  6. "sync"
  7. )
  8. // parallel processes the data in separate goroutines.
  9. func parallel(start, stop int, fn func(<-chan int)) {
  10. count := stop - start
  11. if count < 1 {
  12. return
  13. }
  14. procs := runtime.GOMAXPROCS(0)
  15. if procs > count {
  16. procs = count
  17. }
  18. c := make(chan int, count)
  19. for i := start; i < stop; i++ {
  20. c <- i
  21. }
  22. close(c)
  23. var wg sync.WaitGroup
  24. for i := 0; i < procs; i++ {
  25. wg.Add(1)
  26. go func() {
  27. defer wg.Done()
  28. fn(c)
  29. }()
  30. }
  31. wg.Wait()
  32. }
  33. // absint returns the absolute value of i.
  34. func absint(i int) int {
  35. if i < 0 {
  36. return -i
  37. }
  38. return i
  39. }
  40. // clamp rounds and clamps float64 value to fit into uint8.
  41. func clamp(x float64) uint8 {
  42. v := int64(x + 0.5)
  43. if v > 255 {
  44. return 255
  45. }
  46. if v > 0 {
  47. return uint8(v)
  48. }
  49. return 0
  50. }
  51. func reverse(pix []uint8) {
  52. if len(pix) <= 4 {
  53. return
  54. }
  55. i := 0
  56. j := len(pix) - 4
  57. for i < j {
  58. pi := pix[i : i+4 : i+4]
  59. pj := pix[j : j+4 : j+4]
  60. pi[0], pj[0] = pj[0], pi[0]
  61. pi[1], pj[1] = pj[1], pi[1]
  62. pi[2], pj[2] = pj[2], pi[2]
  63. pi[3], pj[3] = pj[3], pi[3]
  64. i += 4
  65. j -= 4
  66. }
  67. }
  68. func toNRGBA(img image.Image) *image.NRGBA {
  69. if img, ok := img.(*image.NRGBA); ok {
  70. return &image.NRGBA{
  71. Pix: img.Pix,
  72. Stride: img.Stride,
  73. Rect: img.Rect.Sub(img.Rect.Min),
  74. }
  75. }
  76. return Clone(img)
  77. }
  78. // rgbToHSL converts a color from RGB to HSL.
  79. func rgbToHSL(r, g, b uint8) (float64, float64, float64) {
  80. rr := float64(r) / 255
  81. gg := float64(g) / 255
  82. bb := float64(b) / 255
  83. max := math.Max(rr, math.Max(gg, bb))
  84. min := math.Min(rr, math.Min(gg, bb))
  85. l := (max + min) / 2
  86. if max == min {
  87. return 0, 0, l
  88. }
  89. var h, s float64
  90. d := max - min
  91. if l > 0.5 {
  92. s = d / (2 - max - min)
  93. } else {
  94. s = d / (max + min)
  95. }
  96. switch max {
  97. case rr:
  98. h = (gg - bb) / d
  99. if g < b {
  100. h += 6
  101. }
  102. case gg:
  103. h = (bb-rr)/d + 2
  104. case bb:
  105. h = (rr-gg)/d + 4
  106. }
  107. h /= 6
  108. return h, s, l
  109. }
  110. // hslToRGB converts a color from HSL to RGB.
  111. func hslToRGB(h, s, l float64) (uint8, uint8, uint8) {
  112. var r, g, b float64
  113. if s == 0 {
  114. v := clamp(l * 255)
  115. return v, v, v
  116. }
  117. var q float64
  118. if l < 0.5 {
  119. q = l * (1 + s)
  120. } else {
  121. q = l + s - l*s
  122. }
  123. p := 2*l - q
  124. r = hueToRGB(p, q, h+1/3.0)
  125. g = hueToRGB(p, q, h)
  126. b = hueToRGB(p, q, h-1/3.0)
  127. return clamp(r * 255), clamp(g * 255), clamp(b * 255)
  128. }
  129. func hueToRGB(p, q, t float64) float64 {
  130. if t < 0 {
  131. t++
  132. }
  133. if t > 1 {
  134. t--
  135. }
  136. if t < 1/6.0 {
  137. return p + (q-p)*6*t
  138. }
  139. if t < 1/2.0 {
  140. return q
  141. }
  142. if t < 2/3.0 {
  143. return p + (q-p)*(2/3.0-t)*6
  144. }
  145. return p
  146. }