...
Run Format

Source file src/image/color/ycbcr.go

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

View as plain text