Home | History | Annotate | Download | only in color
      1 // Copyright 2011 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package color
      6 
      7 // RGBToYCbCr converts an RGB triple to a Y'CbCr triple.
      8 func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
      9 	// The JFIF specification says:
     10 	//	Y' =  0.2990*R + 0.5870*G + 0.1140*B
     11 	//	Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
     12 	//	Cr =  0.5000*R - 0.4187*G - 0.0813*B + 128
     13 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
     14 
     15 	r1 := int32(r)
     16 	g1 := int32(g)
     17 	b1 := int32(b)
     18 
     19 	// yy is in range [0,0xff].
     20 	//
     21 	// Note that 19595 + 38470 + 7471 equals 65536.
     22 	yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
     23 
     24 	// The bit twiddling below is equivalent to
     25 	//
     26 	// cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
     27 	// if cb < 0 {
     28 	//     cb = 0
     29 	// } else if cb > 0xff {
     30 	//     cb = ^int32(0)
     31 	// }
     32 	//
     33 	// but uses fewer branches and is faster.
     34 	// Note that the uint8 type conversion in the return
     35 	// statement will convert ^int32(0) to 0xff.
     36 	// The code below to compute cr uses a similar pattern.
     37 	//
     38 	// Note that -11056 - 21712 + 32768 equals 0.
     39 	cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
     40 	if uint32(cb)&0xff000000 == 0 {
     41 		cb >>= 16
     42 	} else {
     43 		cb = ^(cb >> 31)
     44 	}
     45 
     46 	// Note that 32768 - 27440 - 5328 equals 0.
     47 	cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
     48 	if uint32(cr)&0xff000000 == 0 {
     49 		cr >>= 16
     50 	} else {
     51 		cr = ^(cr >> 31)
     52 	}
     53 
     54 	return uint8(yy), uint8(cb), uint8(cr)
     55 }
     56 
     57 // YCbCrToRGB converts a Y'CbCr triple to an RGB triple.
     58 func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
     59 	// The JFIF specification says:
     60 	//	R = Y' + 1.40200*(Cr-128)
     61 	//	G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
     62 	//	B = Y' + 1.77200*(Cb-128)
     63 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
     64 
     65 	yy1 := int32(y) * 0x010100 // Convert 0x12 to 0x121200.
     66 	cb1 := int32(cb) - 128
     67 	cr1 := int32(cr) - 128
     68 
     69 	// The bit twiddling below is equivalent to
     70 	//
     71 	// r := (yy1 + 91881*cr1) >> 16
     72 	// if r < 0 {
     73 	//     r = 0
     74 	// } else if r > 0xff {
     75 	//     r = ^int32(0)
     76 	// }
     77 	//
     78 	// but uses fewer branches and is faster.
     79 	// Note that the uint8 type conversion in the return
     80 	// statement will convert ^int32(0) to 0xff.
     81 	// The code below to compute g and b uses a similar pattern.
     82 	r := yy1 + 91881*cr1
     83 	if uint32(r)&0xff000000 == 0 {
     84 		r >>= 16
     85 	} else {
     86 		r = ^(r >> 31)
     87 	}
     88 
     89 	g := yy1 - 22554*cb1 - 46802*cr1
     90 	if uint32(g)&0xff000000 == 0 {
     91 		g >>= 16
     92 	} else {
     93 		g = ^(g >> 31)
     94 	}
     95 
     96 	b := yy1 + 116130*cb1
     97 	if uint32(b)&0xff000000 == 0 {
     98 		b >>= 16
     99 	} else {
    100 		b = ^(b >> 31)
    101 	}
    102 
    103 	return uint8(r), uint8(g), uint8(b)
    104 }
    105 
    106 // YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for
    107 // one luma and two chroma components.
    108 //
    109 // JPEG, VP8, the MPEG family and other codecs use this color model. Such
    110 // codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
    111 // speaking, the term YUV applies only to analog video signals, and Y' (luma)
    112 // is Y (luminance) after applying gamma correction.
    113 //
    114 // Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
    115 // different formulae for converting between the two. This package follows
    116 // the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
    117 type YCbCr struct {
    118 	Y, Cb, Cr uint8
    119 }
    120 
    121 func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
    122 	// This code is a copy of the YCbCrToRGB function above, except that it
    123 	// returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a
    124 	// subtle difference between doing this and having YCbCr satisfy the Color
    125 	// interface by first converting to an RGBA. The latter loses some
    126 	// information by going to and from 8 bits per channel.
    127 	//
    128 	// For example, this code:
    129 	//	const y, cb, cr = 0x7f, 0x7f, 0x7f
    130 	//	r, g, b := color.YCbCrToRGB(y, cb, cr)
    131 	//	r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA()
    132 	//	r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA()
    133 	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)
    134 	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)
    135 	// prints:
    136 	//	0x7e18 0x808d 0x7db9
    137 	//	0x7e7e 0x8080 0x7d7d
    138 
    139 	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
    140 	cb1 := int32(c.Cb) - 128
    141 	cr1 := int32(c.Cr) - 128
    142 
    143 	// The bit twiddling below is equivalent to
    144 	//
    145 	// r := (yy1 + 91881*cr1) >> 8
    146 	// if r < 0 {
    147 	//     r = 0
    148 	// } else if r > 0xff {
    149 	//     r = 0xffff
    150 	// }
    151 	//
    152 	// but uses fewer branches and is faster.
    153 	// The code below to compute g and b uses a similar pattern.
    154 	r := yy1 + 91881*cr1
    155 	if uint32(r)&0xff000000 == 0 {
    156 		r >>= 8
    157 	} else {
    158 		r = ^(r >> 31) & 0xffff
    159 	}
    160 
    161 	g := yy1 - 22554*cb1 - 46802*cr1
    162 	if uint32(g)&0xff000000 == 0 {
    163 		g >>= 8
    164 	} else {
    165 		g = ^(g >> 31) & 0xffff
    166 	}
    167 
    168 	b := yy1 + 116130*cb1
    169 	if uint32(b)&0xff000000 == 0 {
    170 		b >>= 8
    171 	} else {
    172 		b = ^(b >> 31) & 0xffff
    173 	}
    174 
    175 	return uint32(r), uint32(g), uint32(b), 0xffff
    176 }
    177 
    178 // YCbCrModel is the Model for Y'CbCr colors.
    179 var YCbCrModel Model = ModelFunc(yCbCrModel)
    180 
    181 func yCbCrModel(c Color) Color {
    182 	if _, ok := c.(YCbCr); ok {
    183 		return c
    184 	}
    185 	r, g, b, _ := c.RGBA()
    186 	y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
    187 	return YCbCr{y, u, v}
    188 }
    189 
    190 // NYCbCrA represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having
    191 // 8 bits each for one luma, two chroma and one alpha component.
    192 type NYCbCrA struct {
    193 	YCbCr
    194 	A uint8
    195 }
    196 
    197 func (c NYCbCrA) RGBA() (uint32, uint32, uint32, uint32) {
    198 	// The first part of this method is the same as YCbCr.RGBA.
    199 	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
    200 	cb1 := int32(c.Cb) - 128
    201 	cr1 := int32(c.Cr) - 128
    202 
    203 	// The bit twiddling below is equivalent to
    204 	//
    205 	// r := (yy1 + 91881*cr1) >> 8
    206 	// if r < 0 {
    207 	//     r = 0
    208 	// } else if r > 0xff {
    209 	//     r = 0xffff
    210 	// }
    211 	//
    212 	// but uses fewer branches and is faster.
    213 	// The code below to compute g and b uses a similar pattern.
    214 	r := yy1 + 91881*cr1
    215 	if uint32(r)&0xff000000 == 0 {
    216 		r >>= 8
    217 	} else {
    218 		r = ^(r >> 31) & 0xffff
    219 	}
    220 
    221 	g := yy1 - 22554*cb1 - 46802*cr1
    222 	if uint32(g)&0xff000000 == 0 {
    223 		g >>= 8
    224 	} else {
    225 		g = ^(g >> 31) & 0xffff
    226 	}
    227 
    228 	b := yy1 + 116130*cb1
    229 	if uint32(b)&0xff000000 == 0 {
    230 		b >>= 8
    231 	} else {
    232 		b = ^(b >> 31) & 0xffff
    233 	}
    234 
    235 	// The second part of this method applies the alpha.
    236 	a := uint32(c.A) * 0x101
    237 	return uint32(r) * a / 0xffff, uint32(g) * a / 0xffff, uint32(b) * a / 0xffff, a
    238 }
    239 
    240 // NYCbCrAModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha
    241 // colors.
    242 var NYCbCrAModel Model = ModelFunc(nYCbCrAModel)
    243 
    244 func nYCbCrAModel(c Color) Color {
    245 	switch c := c.(type) {
    246 	case NYCbCrA:
    247 		return c
    248 	case YCbCr:
    249 		return NYCbCrA{c, 0xff}
    250 	}
    251 	r, g, b, a := c.RGBA()
    252 
    253 	// Convert from alpha-premultiplied to non-alpha-premultiplied.
    254 	if a != 0 {
    255 		r = (r * 0xffff) / a
    256 		g = (g * 0xffff) / a
    257 		b = (b * 0xffff) / a
    258 	}
    259 
    260 	y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
    261 	return NYCbCrA{YCbCr{Y: y, Cb: u, Cr: v}, uint8(a >> 8)}
    262 }
    263 
    264 // RGBToCMYK converts an RGB triple to a CMYK quadruple.
    265 func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
    266 	rr := uint32(r)
    267 	gg := uint32(g)
    268 	bb := uint32(b)
    269 	w := rr
    270 	if w < gg {
    271 		w = gg
    272 	}
    273 	if w < bb {
    274 		w = bb
    275 	}
    276 	if w == 0 {
    277 		return 0, 0, 0, 0xff
    278 	}
    279 	c := (w - rr) * 0xff / w
    280 	m := (w - gg) * 0xff / w
    281 	y := (w - bb) * 0xff / w
    282 	return uint8(c), uint8(m), uint8(y), uint8(0xff - w)
    283 }
    284 
    285 // CMYKToRGB converts a CMYK quadruple to an RGB triple.
    286 func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
    287 	w := 0xffff - uint32(k)*0x101
    288 	r := (0xffff - uint32(c)*0x101) * w / 0xffff
    289 	g := (0xffff - uint32(m)*0x101) * w / 0xffff
    290 	b := (0xffff - uint32(y)*0x101) * w / 0xffff
    291 	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
    292 }
    293 
    294 // CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
    295 // magenta, yellow and black.
    296 //
    297 // It is not associated with any particular color profile.
    298 type CMYK struct {
    299 	C, M, Y, K uint8
    300 }
    301 
    302 func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
    303 	// This code is a copy of the CMYKToRGB function above, except that it
    304 	// returns values in the range [0, 0xffff] instead of [0, 0xff].
    305 
    306 	w := 0xffff - uint32(c.K)*0x101
    307 	r := (0xffff - uint32(c.C)*0x101) * w / 0xffff
    308 	g := (0xffff - uint32(c.M)*0x101) * w / 0xffff
    309 	b := (0xffff - uint32(c.Y)*0x101) * w / 0xffff
    310 	return r, g, b, 0xffff
    311 }
    312 
    313 // CMYKModel is the Model for CMYK colors.
    314 var CMYKModel Model = ModelFunc(cmykModel)
    315 
    316 func cmykModel(c Color) Color {
    317 	if _, ok := c.(CMYK); ok {
    318 		return c
    319 	}
    320 	r, g, b, _ := c.RGBA()
    321 	cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8))
    322 	return CMYK{cc, mm, yy, kk}
    323 }
    324