utils.go raw

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