...

Source file src/github.com/ericpauley/go-quantize/quantize/bucket.go

Documentation: github.com/ericpauley/go-quantize/quantize

     1  package quantize
     2  
     3  import "image/color"
     4  
     5  type colorAxis uint8
     6  
     7  // Color axis constants
     8  const (
     9  	red colorAxis = iota
    10  	green
    11  	blue
    12  )
    13  
    14  type colorPriority struct {
    15  	p uint32
    16  	color.RGBA
    17  }
    18  
    19  func (c colorPriority) axis(span colorAxis) uint8 {
    20  	switch span {
    21  	case red:
    22  		return c.R
    23  	case green:
    24  		return c.G
    25  	default:
    26  		return c.B
    27  	}
    28  }
    29  
    30  type colorBucket []colorPriority
    31  
    32  func (cb colorBucket) partition() (colorBucket, colorBucket) {
    33  	mean, span := cb.span()
    34  	left, right := 0, len(cb)-1
    35  	for left < right {
    36  		cb[left], cb[right] = cb[right], cb[left]
    37  		for cb[left].axis(span) < mean && left < right {
    38  			left++
    39  		}
    40  		for cb[right].axis(span) >= mean && left < right {
    41  			right--
    42  		}
    43  	}
    44  	if left == 0 {
    45  		return cb[:1], cb[1:]
    46  	}
    47  	if left == len(cb)-1 {
    48  		return cb[:len(cb)-1], cb[len(cb)-1:]
    49  	}
    50  	return cb[:left], cb[left:]
    51  }
    52  
    53  func (cb colorBucket) mean() color.RGBA {
    54  	var r, g, b uint64
    55  	var p uint64
    56  	for _, c := range cb {
    57  		p += uint64(c.p)
    58  		r += uint64(c.R) * uint64(c.p)
    59  		g += uint64(c.G) * uint64(c.p)
    60  		b += uint64(c.B) * uint64(c.p)
    61  	}
    62  	return color.RGBA{uint8(r / p), uint8(g / p), uint8(b / p), 255}
    63  }
    64  
    65  type constraint struct {
    66  	min  uint8
    67  	max  uint8
    68  	vals [256]uint64
    69  }
    70  
    71  func (c *constraint) update(index uint8, p uint32) {
    72  	if index < c.min {
    73  		c.min = index
    74  	}
    75  	if index > c.max {
    76  		c.max = index
    77  	}
    78  	c.vals[index] += uint64(p)
    79  }
    80  
    81  func (c *constraint) span() uint8 {
    82  	return c.max - c.min
    83  }
    84  
    85  func (cb colorBucket) span() (uint8, colorAxis) {
    86  	var R, G, B constraint
    87  	R.min = 255
    88  	G.min = 255
    89  	B.min = 255
    90  	var p uint64
    91  	for _, c := range cb {
    92  		R.update(c.R, c.p)
    93  		G.update(c.G, c.p)
    94  		B.update(c.B, c.p)
    95  		p += uint64(c.p)
    96  	}
    97  	var toCount *constraint
    98  	var span colorAxis
    99  	if R.span() > G.span() && R.span() > B.span() {
   100  		span = red
   101  		toCount = &R
   102  	} else if G.span() > B.span() {
   103  		span = green
   104  		toCount = &G
   105  	} else {
   106  		span = blue
   107  		toCount = &B
   108  	}
   109  	var counted uint64
   110  	var i int
   111  	var c uint64
   112  	for i, c = range toCount.vals {
   113  		if counted > p/2 || counted+c == p {
   114  			break
   115  		}
   116  		counted += c
   117  	}
   118  	return uint8(i), span
   119  }
   120  

View as plain text