Source File
ycbcr.go
Belonging Package
image/color
// Copyright 2011 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package color// RGBToYCbCr converts an RGB triple to a Y'CbCr triple.func (, , uint8) (uint8, uint8, uint8) {// The JFIF specification says:// Y' = 0.2990*R + 0.5870*G + 0.1140*B// Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128// Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128// https://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.:= int32():= int32():= int32()// yy is in range [0,0xff].//// Note that 19595 + 38470 + 7471 equals 65536.:= (19595* + 38470* + 7471* + 1<<15) >> 16// The bit twiddling below is equivalent to//// cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16// if cb < 0 {// cb = 0// } else if cb > 0xff {// cb = ^int32(0)// }//// but uses fewer branches and is faster.// Note that the uint8 type conversion in the return// statement will convert ^int32(0) to 0xff.// The code below to compute cr uses a similar pattern.//// Note that -11056 - 21712 + 32768 equals 0.:= -11056* - 21712* + 32768* + 257<<15if uint32()&0xff000000 == 0 {>>= 16} else {= ^( >> 31)}// Note that 32768 - 27440 - 5328 equals 0.:= 32768* - 27440* - 5328* + 257<<15if uint32()&0xff000000 == 0 {>>= 16} else {= ^( >> 31)}return uint8(), uint8(), uint8()}// YCbCrToRGB converts a Y'CbCr triple to an RGB triple.func (, , uint8) (uint8, uint8, uint8) {// The JFIF specification says:// R = Y' + 1.40200*(Cr-128)// G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)// B = Y' + 1.77200*(Cb-128)// https://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.//// Those formulae use non-integer multiplication factors. When computing,// integer math is generally faster than floating point math. We multiply// all of those factors by 1<<16 and round to the nearest integer:// 91881 = roundToNearestInteger(1.40200 * 65536).// 22554 = roundToNearestInteger(0.34414 * 65536).// 46802 = roundToNearestInteger(0.71414 * 65536).// 116130 = roundToNearestInteger(1.77200 * 65536).//// Adding a rounding adjustment in the range [0, 1<<16-1] and then shifting// right by 16 gives us an integer math version of the original formulae.// R = (65536*Y' + 91881 *(Cr-128) + adjustment) >> 16// G = (65536*Y' - 22554 *(Cb-128) - 46802*(Cr-128) + adjustment) >> 16// B = (65536*Y' + 116130 *(Cb-128) + adjustment) >> 16// A constant rounding adjustment of 1<<15, one half of 1<<16, would mean// round-to-nearest when dividing by 65536 (shifting right by 16).// Similarly, a constant rounding adjustment of 0 would mean round-down.//// Defining YY1 = 65536*Y' + adjustment simplifies the formulae and// requires fewer CPU operations:// R = (YY1 + 91881 *(Cr-128) ) >> 16// G = (YY1 - 22554 *(Cb-128) - 46802*(Cr-128)) >> 16// B = (YY1 + 116130 *(Cb-128) ) >> 16//// The inputs (y, cb, cr) are 8 bit color, ranging in [0x00, 0xff]. In this// function, the output is also 8 bit color, but in the related YCbCr.RGBA// method, below, the output is 16 bit color, ranging in [0x0000, 0xffff].// Outputting 16 bit color simply requires changing the 16 to 8 in the "R =// etc >> 16" equation, and likewise for G and B.//// As mentioned above, a constant rounding adjustment of 1<<15 is a natural// choice, but there is an additional constraint: if c0 := YCbCr{Y: y, Cb:// 0x80, Cr: 0x80} and c1 := Gray{Y: y} then c0.RGBA() should equal// c1.RGBA(). Specifically, if y == 0 then "R = etc >> 8" should yield// 0x0000 and if y == 0xff then "R = etc >> 8" should yield 0xffff. If we// used a constant rounding adjustment of 1<<15, then it would yield 0x0080// and 0xff80 respectively.//// Note that when cb == 0x80 and cr == 0x80 then the formulae collapse to:// R = YY1 >> n// G = YY1 >> n// B = YY1 >> n// where n is 16 for this function (8 bit color output) and 8 for the// YCbCr.RGBA method (16 bit color output).//// The solution is to make the rounding adjustment non-constant, and equal// to 257*Y', which ranges over [0, 1<<16-1] as Y' ranges over [0, 255].// YY1 is then defined as:// YY1 = 65536*Y' + 257*Y'// or equivalently:// YY1 = Y' * 0x10101:= int32() * 0x10101:= int32() - 128:= int32() - 128// The bit twiddling below is equivalent to//// r := (yy1 + 91881*cr1) >> 16// if r < 0 {// r = 0// } else if r > 0xff {// r = ^int32(0)// }//// but uses fewer branches and is faster.// Note that the uint8 type conversion in the return// statement will convert ^int32(0) to 0xff.// The code below to compute g and b uses a similar pattern.:= + 91881*if uint32()&0xff000000 == 0 {>>= 16} else {= ^( >> 31)}:= - 22554* - 46802*if uint32()&0xff000000 == 0 {>>= 16} else {= ^( >> 31)}:= + 116130*if uint32()&0xff000000 == 0 {>>= 16} else {= ^( >> 31)}return uint8(), uint8(), uint8()}// YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for// one luma and two chroma components.//// JPEG, VP8, the MPEG family and other codecs use this color model. Such// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly// speaking, the term YUV applies only to analog video signals, and Y' (luma)// is Y (luminance) after applying gamma correction.//// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly// different formulae for converting between the two. This package follows// the JFIF specification at https://www.w3.org/Graphics/JPEG/jfif3.pdf.type YCbCr struct {Y, Cb, Cr uint8}func ( YCbCr) () (uint32, uint32, uint32, uint32) {// This code is a copy of the YCbCrToRGB function above, except that it// returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a// subtle difference between doing this and having YCbCr satisfy the Color// interface by first converting to an RGBA. The latter loses some// information by going to and from 8 bits per channel.//// For example, this code:// const y, cb, cr = 0x7f, 0x7f, 0x7f// r, g, b := color.YCbCrToRGB(y, cb, cr)// r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA()// r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA()// fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)// fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)// prints:// 0x7e18 0x808d 0x7db9// 0x7e7e 0x8080 0x7d7d:= int32(.Y) * 0x10101:= int32(.Cb) - 128:= int32(.Cr) - 128// The bit twiddling below is equivalent to//// r := (yy1 + 91881*cr1) >> 8// if r < 0 {// r = 0// } else if r > 0xff {// r = 0xffff// }//// but uses fewer branches and is faster.// The code below to compute g and b uses a similar pattern.:= + 91881*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}:= - 22554* - 46802*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}:= + 116130*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}return uint32(), uint32(), uint32(), 0xffff}// YCbCrModel is the Model for Y'CbCr colors.var YCbCrModel Model = ModelFunc(yCbCrModel)func ( Color) Color {if , := .(YCbCr); {return}, , , := .RGBA(), , := RGBToYCbCr(uint8(>>8), uint8(>>8), uint8(>>8))return YCbCr{, , }}// NYCbCrA represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having// 8 bits each for one luma, two chroma and one alpha component.type NYCbCrA struct {YCbCrA uint8}func ( NYCbCrA) () (uint32, uint32, uint32, uint32) {// The first part of this method is the same as YCbCr.RGBA.:= int32(.Y) * 0x10101:= int32(.Cb) - 128:= int32(.Cr) - 128// The bit twiddling below is equivalent to//// r := (yy1 + 91881*cr1) >> 8// if r < 0 {// r = 0// } else if r > 0xff {// r = 0xffff// }//// but uses fewer branches and is faster.// The code below to compute g and b uses a similar pattern.:= + 91881*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}:= - 22554* - 46802*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}:= + 116130*if uint32()&0xff000000 == 0 {>>= 8} else {= ^( >> 31) & 0xffff}// The second part of this method applies the alpha.:= uint32(.A) * 0x101return uint32() * / 0xffff, uint32() * / 0xffff, uint32() * / 0xffff,}// NYCbCrAModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha// colors.var NYCbCrAModel Model = ModelFunc(nYCbCrAModel)func ( Color) Color {switch c := .(type) {case NYCbCrA:returncase YCbCr:return NYCbCrA{, 0xff}}, , , := .RGBA()// Convert from alpha-premultiplied to non-alpha-premultiplied.if != 0 {= ( * 0xffff) /= ( * 0xffff) /= ( * 0xffff) /}, , := RGBToYCbCr(uint8(>>8), uint8(>>8), uint8(>>8))return NYCbCrA{YCbCr{Y: , Cb: , Cr: }, uint8( >> 8)}}// RGBToCMYK converts an RGB triple to a CMYK quadruple.func (, , uint8) (uint8, uint8, uint8, uint8) {:= uint32():= uint32():= uint32():=if < {=}if < {=}if == 0 {return 0, 0, 0, 0xff}:= ( - ) * 0xff /:= ( - ) * 0xff /:= ( - ) * 0xff /return uint8(), uint8(), uint8(), uint8(0xff - )}// CMYKToRGB converts a CMYK quadruple to an RGB triple.func (, , , uint8) (uint8, uint8, uint8) {:= 0xffff - uint32()*0x101:= (0xffff - uint32()*0x101) * / 0xffff:= (0xffff - uint32()*0x101) * / 0xffff:= (0xffff - uint32()*0x101) * / 0xffffreturn uint8( >> 8), uint8( >> 8), uint8( >> 8)}// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,// magenta, yellow and black.//// It is not associated with any particular color profile.type CMYK struct {C, M, Y, K uint8}func ( CMYK) () (uint32, uint32, uint32, uint32) {// This code is a copy of the CMYKToRGB function above, except that it// returns values in the range [0, 0xffff] instead of [0, 0xff].:= 0xffff - uint32(.K)*0x101:= (0xffff - uint32(.C)*0x101) * / 0xffff:= (0xffff - uint32(.M)*0x101) * / 0xffff:= (0xffff - uint32(.Y)*0x101) * / 0xffffreturn , , , 0xffff}// CMYKModel is the Model for CMYK colors.var CMYKModel Model = ModelFunc(cmykModel)func ( Color) Color {if , := .(CMYK); {return}, , , := .RGBA(), , , := RGBToCMYK(uint8(>>8), uint8(>>8), uint8(>>8))return CMYK{, , , }}
![]() |
The pages are generated with Golds v0.6.7. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |