diff options
Diffstat (limited to 'src/image/color')
-rw-r--r-- | src/image/color/color.go | 297 | ||||
-rw-r--r-- | src/image/color/palette/gen.go | 121 | ||||
-rw-r--r-- | src/image/color/palette/generate.go | 8 | ||||
-rw-r--r-- | src/image/color/palette/palette.go | 503 | ||||
-rw-r--r-- | src/image/color/ycbcr.go | 99 | ||||
-rw-r--r-- | src/image/color/ycbcr_test.go | 33 |
6 files changed, 1061 insertions, 0 deletions
diff --git a/src/image/color/color.go b/src/image/color/color.go new file mode 100644 index 000000000..ff596a76a --- /dev/null +++ b/src/image/color/color.go @@ -0,0 +1,297 @@ +// 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 implements a basic color library. +package color + +// Color can convert itself to alpha-premultiplied 16-bits per channel RGBA. +// The conversion may be lossy. +type Color interface { + // RGBA returns the alpha-premultiplied red, green, blue and alpha values + // for the color. Each value ranges within [0, 0xFFFF], but is represented + // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not + // overflow. + RGBA() (r, g, b, a uint32) +} + +// RGBA represents a traditional 32-bit alpha-premultiplied color, +// having 8 bits for each of red, green, blue and alpha. +type RGBA struct { + R, G, B, A uint8 +} + +func (c RGBA) RGBA() (r, g, b, a uint32) { + r = uint32(c.R) + r |= r << 8 + g = uint32(c.G) + g |= g << 8 + b = uint32(c.B) + b |= b << 8 + a = uint32(c.A) + a |= a << 8 + return +} + +// RGBA64 represents a 64-bit alpha-premultiplied color, +// having 16 bits for each of red, green, blue and alpha. +type RGBA64 struct { + R, G, B, A uint16 +} + +func (c RGBA64) RGBA() (r, g, b, a uint32) { + return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A) +} + +// NRGBA represents a non-alpha-premultiplied 32-bit color. +type NRGBA struct { + R, G, B, A uint8 +} + +func (c NRGBA) RGBA() (r, g, b, a uint32) { + r = uint32(c.R) + r |= r << 8 + r *= uint32(c.A) + r /= 0xff + g = uint32(c.G) + g |= g << 8 + g *= uint32(c.A) + g /= 0xff + b = uint32(c.B) + b |= b << 8 + b *= uint32(c.A) + b /= 0xff + a = uint32(c.A) + a |= a << 8 + return +} + +// NRGBA64 represents a non-alpha-premultiplied 64-bit color, +// having 16 bits for each of red, green, blue and alpha. +type NRGBA64 struct { + R, G, B, A uint16 +} + +func (c NRGBA64) RGBA() (r, g, b, a uint32) { + r = uint32(c.R) + r *= uint32(c.A) + r /= 0xffff + g = uint32(c.G) + g *= uint32(c.A) + g /= 0xffff + b = uint32(c.B) + b *= uint32(c.A) + b /= 0xffff + a = uint32(c.A) + return +} + +// Alpha represents an 8-bit alpha color. +type Alpha struct { + A uint8 +} + +func (c Alpha) RGBA() (r, g, b, a uint32) { + a = uint32(c.A) + a |= a << 8 + return a, a, a, a +} + +// Alpha16 represents a 16-bit alpha color. +type Alpha16 struct { + A uint16 +} + +func (c Alpha16) RGBA() (r, g, b, a uint32) { + a = uint32(c.A) + return a, a, a, a +} + +// Gray represents an 8-bit grayscale color. +type Gray struct { + Y uint8 +} + +func (c Gray) RGBA() (r, g, b, a uint32) { + y := uint32(c.Y) + y |= y << 8 + return y, y, y, 0xffff +} + +// Gray16 represents a 16-bit grayscale color. +type Gray16 struct { + Y uint16 +} + +func (c Gray16) RGBA() (r, g, b, a uint32) { + y := uint32(c.Y) + return y, y, y, 0xffff +} + +// Model can convert any Color to one from its own color model. The conversion +// may be lossy. +type Model interface { + Convert(c Color) Color +} + +// ModelFunc returns a Model that invokes f to implement the conversion. +func ModelFunc(f func(Color) Color) Model { + // Note: using *modelFunc as the implementation + // means that callers can still use comparisons + // like m == RGBAModel. This is not possible if + // we use the func value directly, because funcs + // are no longer comparable. + return &modelFunc{f} +} + +type modelFunc struct { + f func(Color) Color +} + +func (m *modelFunc) Convert(c Color) Color { + return m.f(c) +} + +// Models for the standard color types. +var ( + RGBAModel Model = ModelFunc(rgbaModel) + RGBA64Model Model = ModelFunc(rgba64Model) + NRGBAModel Model = ModelFunc(nrgbaModel) + NRGBA64Model Model = ModelFunc(nrgba64Model) + AlphaModel Model = ModelFunc(alphaModel) + Alpha16Model Model = ModelFunc(alpha16Model) + GrayModel Model = ModelFunc(grayModel) + Gray16Model Model = ModelFunc(gray16Model) +) + +func rgbaModel(c Color) Color { + if _, ok := c.(RGBA); ok { + return c + } + r, g, b, a := c.RGBA() + return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} +} + +func rgba64Model(c Color) Color { + if _, ok := c.(RGBA64); ok { + return c + } + r, g, b, a := c.RGBA() + return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + +func nrgbaModel(c Color) Color { + if _, ok := c.(NRGBA); ok { + return c + } + r, g, b, a := c.RGBA() + if a == 0xffff { + return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff} + } + if a == 0 { + return NRGBA{0, 0, 0, 0} + } + // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a. + r = (r * 0xffff) / a + g = (g * 0xffff) / a + b = (b * 0xffff) / a + return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} +} + +func nrgba64Model(c Color) Color { + if _, ok := c.(NRGBA64); ok { + return c + } + r, g, b, a := c.RGBA() + if a == 0xffff { + return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff} + } + if a == 0 { + return NRGBA64{0, 0, 0, 0} + } + // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a. + r = (r * 0xffff) / a + g = (g * 0xffff) / a + b = (b * 0xffff) / a + return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} +} + +func alphaModel(c Color) Color { + if _, ok := c.(Alpha); ok { + return c + } + _, _, _, a := c.RGBA() + return Alpha{uint8(a >> 8)} +} + +func alpha16Model(c Color) Color { + if _, ok := c.(Alpha16); ok { + return c + } + _, _, _, a := c.RGBA() + return Alpha16{uint16(a)} +} + +func grayModel(c Color) Color { + if _, ok := c.(Gray); ok { + return c + } + r, g, b, _ := c.RGBA() + y := (299*r + 587*g + 114*b + 500) / 1000 + return Gray{uint8(y >> 8)} +} + +func gray16Model(c Color) Color { + if _, ok := c.(Gray16); ok { + return c + } + r, g, b, _ := c.RGBA() + y := (299*r + 587*g + 114*b + 500) / 1000 + return Gray16{uint16(y)} +} + +// Palette is a palette of colors. +type Palette []Color + +// Convert returns the palette color closest to c in Euclidean R,G,B space. +func (p Palette) Convert(c Color) Color { + if len(p) == 0 { + return nil + } + return p[p.Index(c)] +} + +// Index returns the index of the palette color closest to c in Euclidean +// R,G,B space. +func (p Palette) Index(c Color) int { + // A batch version of this computation is in image/draw/draw.go. + + cr, cg, cb, _ := c.RGBA() + ret, bestSSD := 0, uint32(1<<32-1) + for i, v := range p { + vr, vg, vb, _ := v.RGBA() + // We shift by 1 bit to avoid potential uint32 overflow in + // sum-squared-difference. + delta := (int32(cr) - int32(vr)) >> 1 + ssd := uint32(delta * delta) + delta = (int32(cg) - int32(vg)) >> 1 + ssd += uint32(delta * delta) + delta = (int32(cb) - int32(vb)) >> 1 + ssd += uint32(delta * delta) + if ssd < bestSSD { + if ssd == 0 { + return i + } + ret, bestSSD = i, ssd + } + } + return ret +} + +// Standard colors. +var ( + Black = Gray16{0} + White = Gray16{0xffff} + Transparent = Alpha16{0} + Opaque = Alpha16{0xffff} +) diff --git a/src/image/color/palette/gen.go b/src/image/color/palette/gen.go new file mode 100644 index 000000000..2b5fdaaf2 --- /dev/null +++ b/src/image/color/palette/gen.go @@ -0,0 +1,121 @@ +// Copyright 2013 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. + +// +build ignore + +package main + +// This program generates palette.go. Invoke it as +// go run gen.go -output palette.go + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "io" + "io/ioutil" + "log" +) + +var filename = flag.String("output", "palette.go", "output file name") + +func main() { + flag.Parse() + + var buf bytes.Buffer + + fmt.Fprintln(&buf, `// Copyright 2013 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.`) + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "// generated by go run gen.go -output palette.go; DO NOT EDIT") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "package palette") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, `import "image/color"`) + fmt.Fprintln(&buf) + printPlan9(&buf) + printWebSafe(&buf) + + data, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile(*filename, data, 0644) + if err != nil { + log.Fatal(err) + } +} + +func printPlan9(w io.Writer) { + c, lines := [3]int{}, [256]string{} + for r, i := 0, 0; r != 4; r++ { + for v := 0; v != 4; v, i = v+1, i+16 { + for g, j := 0, v-r; g != 4; g++ { + for b := 0; b != 4; b, j = b+1, j+1 { + den := r + if g > den { + den = g + } + if b > den { + den = b + } + if den == 0 { + c[0] = 0x11 * v + c[1] = 0x11 * v + c[2] = 0x11 * v + } else { + num := 17 * (4*den + v) + c[0] = r * num / den + c[1] = g * num / den + c[2] = b * num / den + } + lines[i+(j&0x0f)] = + fmt.Sprintf("\tcolor.RGBA{0x%02x, 0x%02x, 0x%02x, 0xff},", c[0], c[1], c[2]) + } + } + } + } + fmt.Fprintln(w, "// Plan9 is a 256-color palette that partitions the 24-bit RGB space") + fmt.Fprintln(w, "// into 4×4×4 subdivision, with 4 shades in each subcube. Compared to the") + fmt.Fprintln(w, "// WebSafe, the idea is to reduce the color resolution by dicing the") + fmt.Fprintln(w, "// color cube into fewer cells, and to use the extra space to increase the") + fmt.Fprintln(w, "// intensity resolution. This results in 16 gray shades (4 gray subcubes with") + fmt.Fprintln(w, "// 4 samples in each), 13 shades of each primary and secondary color (3") + fmt.Fprintln(w, "// subcubes with 4 samples plus black) and a reasonable selection of colors") + fmt.Fprintln(w, "// covering the rest of the color cube. The advantage is better representation") + fmt.Fprintln(w, "// of continuous tones.") + fmt.Fprintln(w, "//") + fmt.Fprintln(w, "// This palette was used in the Plan 9 Operating System, described at") + fmt.Fprintln(w, "// http://plan9.bell-labs.com/magic/man2html/6/color") + fmt.Fprintln(w, "var Plan9 = []color.Color{") + for _, line := range lines { + fmt.Fprintln(w, line) + } + fmt.Fprintln(w, "}") + fmt.Fprintln(w) +} + +func printWebSafe(w io.Writer) { + lines := [6 * 6 * 6]string{} + for r := 0; r < 6; r++ { + for g := 0; g < 6; g++ { + for b := 0; b < 6; b++ { + lines[36*r+6*g+b] = + fmt.Sprintf("\tcolor.RGBA{0x%02x, 0x%02x, 0x%02x, 0xff},", 0x33*r, 0x33*g, 0x33*b) + } + } + } + fmt.Fprintln(w, "// WebSafe is a 216-color palette that was popularized by early versions") + fmt.Fprintln(w, "// of Netscape Navigator. It is also known as the Netscape Color Cube.") + fmt.Fprintln(w, "//") + fmt.Fprintln(w, "// See http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors for details.") + fmt.Fprintln(w, "var WebSafe = []color.Color{") + for _, line := range lines { + fmt.Fprintln(w, line) + } + fmt.Fprintln(w, "}") + fmt.Fprintln(w) +} diff --git a/src/image/color/palette/generate.go b/src/image/color/palette/generate.go new file mode 100644 index 000000000..64c2ec0d9 --- /dev/null +++ b/src/image/color/palette/generate.go @@ -0,0 +1,8 @@ +// Copyright 2014 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. + +//go:generate go run gen.go -output palette.go + +// Package palette provides standard color palettes. +package palette diff --git a/src/image/color/palette/palette.go b/src/image/color/palette/palette.go new file mode 100644 index 000000000..0bf2c8e1a --- /dev/null +++ b/src/image/color/palette/palette.go @@ -0,0 +1,503 @@ +// Copyright 2013 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. + +// generated by go run gen.go -output palette.go; DO NOT EDIT + +package palette + +import "image/color" + +// Plan9 is a 256-color palette that partitions the 24-bit RGB space +// into 4×4×4 subdivision, with 4 shades in each subcube. Compared to the +// WebSafe, the idea is to reduce the color resolution by dicing the +// color cube into fewer cells, and to use the extra space to increase the +// intensity resolution. This results in 16 gray shades (4 gray subcubes with +// 4 samples in each), 13 shades of each primary and secondary color (3 +// subcubes with 4 samples plus black) and a reasonable selection of colors +// covering the rest of the color cube. The advantage is better representation +// of continuous tones. +// +// This palette was used in the Plan 9 Operating System, described at +// http://plan9.bell-labs.com/magic/man2html/6/color +var Plan9 = []color.Color{ + color.RGBA{0x00, 0x00, 0x00, 0xff}, + color.RGBA{0x00, 0x00, 0x44, 0xff}, + color.RGBA{0x00, 0x00, 0x88, 0xff}, + color.RGBA{0x00, 0x00, 0xcc, 0xff}, + color.RGBA{0x00, 0x44, 0x00, 0xff}, + color.RGBA{0x00, 0x44, 0x44, 0xff}, + color.RGBA{0x00, 0x44, 0x88, 0xff}, + color.RGBA{0x00, 0x44, 0xcc, 0xff}, + color.RGBA{0x00, 0x88, 0x00, 0xff}, + color.RGBA{0x00, 0x88, 0x44, 0xff}, + color.RGBA{0x00, 0x88, 0x88, 0xff}, + color.RGBA{0x00, 0x88, 0xcc, 0xff}, + color.RGBA{0x00, 0xcc, 0x00, 0xff}, + color.RGBA{0x00, 0xcc, 0x44, 0xff}, + color.RGBA{0x00, 0xcc, 0x88, 0xff}, + color.RGBA{0x00, 0xcc, 0xcc, 0xff}, + color.RGBA{0x00, 0xdd, 0xdd, 0xff}, + color.RGBA{0x11, 0x11, 0x11, 0xff}, + color.RGBA{0x00, 0x00, 0x55, 0xff}, + color.RGBA{0x00, 0x00, 0x99, 0xff}, + color.RGBA{0x00, 0x00, 0xdd, 0xff}, + color.RGBA{0x00, 0x55, 0x00, 0xff}, + color.RGBA{0x00, 0x55, 0x55, 0xff}, + color.RGBA{0x00, 0x4c, 0x99, 0xff}, + color.RGBA{0x00, 0x49, 0xdd, 0xff}, + color.RGBA{0x00, 0x99, 0x00, 0xff}, + color.RGBA{0x00, 0x99, 0x4c, 0xff}, + color.RGBA{0x00, 0x99, 0x99, 0xff}, + color.RGBA{0x00, 0x93, 0xdd, 0xff}, + color.RGBA{0x00, 0xdd, 0x00, 0xff}, + color.RGBA{0x00, 0xdd, 0x49, 0xff}, + color.RGBA{0x00, 0xdd, 0x93, 0xff}, + color.RGBA{0x00, 0xee, 0x9e, 0xff}, + color.RGBA{0x00, 0xee, 0xee, 0xff}, + color.RGBA{0x22, 0x22, 0x22, 0xff}, + color.RGBA{0x00, 0x00, 0x66, 0xff}, + color.RGBA{0x00, 0x00, 0xaa, 0xff}, + color.RGBA{0x00, 0x00, 0xee, 0xff}, + color.RGBA{0x00, 0x66, 0x00, 0xff}, + color.RGBA{0x00, 0x66, 0x66, 0xff}, + color.RGBA{0x00, 0x55, 0xaa, 0xff}, + color.RGBA{0x00, 0x4f, 0xee, 0xff}, + color.RGBA{0x00, 0xaa, 0x00, 0xff}, + color.RGBA{0x00, 0xaa, 0x55, 0xff}, + color.RGBA{0x00, 0xaa, 0xaa, 0xff}, + color.RGBA{0x00, 0x9e, 0xee, 0xff}, + color.RGBA{0x00, 0xee, 0x00, 0xff}, + color.RGBA{0x00, 0xee, 0x4f, 0xff}, + color.RGBA{0x00, 0xff, 0x55, 0xff}, + color.RGBA{0x00, 0xff, 0xaa, 0xff}, + color.RGBA{0x00, 0xff, 0xff, 0xff}, + color.RGBA{0x33, 0x33, 0x33, 0xff}, + color.RGBA{0x00, 0x00, 0x77, 0xff}, + color.RGBA{0x00, 0x00, 0xbb, 0xff}, + color.RGBA{0x00, 0x00, 0xff, 0xff}, + color.RGBA{0x00, 0x77, 0x00, 0xff}, + color.RGBA{0x00, 0x77, 0x77, 0xff}, + color.RGBA{0x00, 0x5d, 0xbb, 0xff}, + color.RGBA{0x00, 0x55, 0xff, 0xff}, + color.RGBA{0x00, 0xbb, 0x00, 0xff}, + color.RGBA{0x00, 0xbb, 0x5d, 0xff}, + color.RGBA{0x00, 0xbb, 0xbb, 0xff}, + color.RGBA{0x00, 0xaa, 0xff, 0xff}, + color.RGBA{0x00, 0xff, 0x00, 0xff}, + color.RGBA{0x44, 0x00, 0x44, 0xff}, + color.RGBA{0x44, 0x00, 0x88, 0xff}, + color.RGBA{0x44, 0x00, 0xcc, 0xff}, + color.RGBA{0x44, 0x44, 0x00, 0xff}, + color.RGBA{0x44, 0x44, 0x44, 0xff}, + color.RGBA{0x44, 0x44, 0x88, 0xff}, + color.RGBA{0x44, 0x44, 0xcc, 0xff}, + color.RGBA{0x44, 0x88, 0x00, 0xff}, + color.RGBA{0x44, 0x88, 0x44, 0xff}, + color.RGBA{0x44, 0x88, 0x88, 0xff}, + color.RGBA{0x44, 0x88, 0xcc, 0xff}, + color.RGBA{0x44, 0xcc, 0x00, 0xff}, + color.RGBA{0x44, 0xcc, 0x44, 0xff}, + color.RGBA{0x44, 0xcc, 0x88, 0xff}, + color.RGBA{0x44, 0xcc, 0xcc, 0xff}, + color.RGBA{0x44, 0x00, 0x00, 0xff}, + color.RGBA{0x55, 0x00, 0x00, 0xff}, + color.RGBA{0x55, 0x00, 0x55, 0xff}, + color.RGBA{0x4c, 0x00, 0x99, 0xff}, + color.RGBA{0x49, 0x00, 0xdd, 0xff}, + color.RGBA{0x55, 0x55, 0x00, 0xff}, + color.RGBA{0x55, 0x55, 0x55, 0xff}, + color.RGBA{0x4c, 0x4c, 0x99, 0xff}, + color.RGBA{0x49, 0x49, 0xdd, 0xff}, + color.RGBA{0x4c, 0x99, 0x00, 0xff}, + color.RGBA{0x4c, 0x99, 0x4c, 0xff}, + color.RGBA{0x4c, 0x99, 0x99, 0xff}, + color.RGBA{0x49, 0x93, 0xdd, 0xff}, + color.RGBA{0x49, 0xdd, 0x00, 0xff}, + color.RGBA{0x49, 0xdd, 0x49, 0xff}, + color.RGBA{0x49, 0xdd, 0x93, 0xff}, + color.RGBA{0x49, 0xdd, 0xdd, 0xff}, + color.RGBA{0x4f, 0xee, 0xee, 0xff}, + color.RGBA{0x66, 0x00, 0x00, 0xff}, + color.RGBA{0x66, 0x00, 0x66, 0xff}, + color.RGBA{0x55, 0x00, 0xaa, 0xff}, + color.RGBA{0x4f, 0x00, 0xee, 0xff}, + color.RGBA{0x66, 0x66, 0x00, 0xff}, + color.RGBA{0x66, 0x66, 0x66, 0xff}, + color.RGBA{0x55, 0x55, 0xaa, 0xff}, + color.RGBA{0x4f, 0x4f, 0xee, 0xff}, + color.RGBA{0x55, 0xaa, 0x00, 0xff}, + color.RGBA{0x55, 0xaa, 0x55, 0xff}, + color.RGBA{0x55, 0xaa, 0xaa, 0xff}, + color.RGBA{0x4f, 0x9e, 0xee, 0xff}, + color.RGBA{0x4f, 0xee, 0x00, 0xff}, + color.RGBA{0x4f, 0xee, 0x4f, 0xff}, + color.RGBA{0x4f, 0xee, 0x9e, 0xff}, + color.RGBA{0x55, 0xff, 0xaa, 0xff}, + color.RGBA{0x55, 0xff, 0xff, 0xff}, + color.RGBA{0x77, 0x00, 0x00, 0xff}, + color.RGBA{0x77, 0x00, 0x77, 0xff}, + color.RGBA{0x5d, 0x00, 0xbb, 0xff}, + color.RGBA{0x55, 0x00, 0xff, 0xff}, + color.RGBA{0x77, 0x77, 0x00, 0xff}, + color.RGBA{0x77, 0x77, 0x77, 0xff}, + color.RGBA{0x5d, 0x5d, 0xbb, 0xff}, + color.RGBA{0x55, 0x55, 0xff, 0xff}, + color.RGBA{0x5d, 0xbb, 0x00, 0xff}, + color.RGBA{0x5d, 0xbb, 0x5d, 0xff}, + color.RGBA{0x5d, 0xbb, 0xbb, 0xff}, + color.RGBA{0x55, 0xaa, 0xff, 0xff}, + color.RGBA{0x55, 0xff, 0x00, 0xff}, + color.RGBA{0x55, 0xff, 0x55, 0xff}, + color.RGBA{0x88, 0x00, 0x88, 0xff}, + color.RGBA{0x88, 0x00, 0xcc, 0xff}, + color.RGBA{0x88, 0x44, 0x00, 0xff}, + color.RGBA{0x88, 0x44, 0x44, 0xff}, + color.RGBA{0x88, 0x44, 0x88, 0xff}, + color.RGBA{0x88, 0x44, 0xcc, 0xff}, + color.RGBA{0x88, 0x88, 0x00, 0xff}, + color.RGBA{0x88, 0x88, 0x44, 0xff}, + color.RGBA{0x88, 0x88, 0x88, 0xff}, + color.RGBA{0x88, 0x88, 0xcc, 0xff}, + color.RGBA{0x88, 0xcc, 0x00, 0xff}, + color.RGBA{0x88, 0xcc, 0x44, 0xff}, + color.RGBA{0x88, 0xcc, 0x88, 0xff}, + color.RGBA{0x88, 0xcc, 0xcc, 0xff}, + color.RGBA{0x88, 0x00, 0x00, 0xff}, + color.RGBA{0x88, 0x00, 0x44, 0xff}, + color.RGBA{0x99, 0x00, 0x4c, 0xff}, + color.RGBA{0x99, 0x00, 0x99, 0xff}, + color.RGBA{0x93, 0x00, 0xdd, 0xff}, + color.RGBA{0x99, 0x4c, 0x00, 0xff}, + color.RGBA{0x99, 0x4c, 0x4c, 0xff}, + color.RGBA{0x99, 0x4c, 0x99, 0xff}, + color.RGBA{0x93, 0x49, 0xdd, 0xff}, + color.RGBA{0x99, 0x99, 0x00, 0xff}, + color.RGBA{0x99, 0x99, 0x4c, 0xff}, + color.RGBA{0x99, 0x99, 0x99, 0xff}, + color.RGBA{0x93, 0x93, 0xdd, 0xff}, + color.RGBA{0x93, 0xdd, 0x00, 0xff}, + color.RGBA{0x93, 0xdd, 0x49, 0xff}, + color.RGBA{0x93, 0xdd, 0x93, 0xff}, + color.RGBA{0x93, 0xdd, 0xdd, 0xff}, + color.RGBA{0x99, 0x00, 0x00, 0xff}, + color.RGBA{0xaa, 0x00, 0x00, 0xff}, + color.RGBA{0xaa, 0x00, 0x55, 0xff}, + color.RGBA{0xaa, 0x00, 0xaa, 0xff}, + color.RGBA{0x9e, 0x00, 0xee, 0xff}, + color.RGBA{0xaa, 0x55, 0x00, 0xff}, + color.RGBA{0xaa, 0x55, 0x55, 0xff}, + color.RGBA{0xaa, 0x55, 0xaa, 0xff}, + color.RGBA{0x9e, 0x4f, 0xee, 0xff}, + color.RGBA{0xaa, 0xaa, 0x00, 0xff}, + color.RGBA{0xaa, 0xaa, 0x55, 0xff}, + color.RGBA{0xaa, 0xaa, 0xaa, 0xff}, + color.RGBA{0x9e, 0x9e, 0xee, 0xff}, + color.RGBA{0x9e, 0xee, 0x00, 0xff}, + color.RGBA{0x9e, 0xee, 0x4f, 0xff}, + color.RGBA{0x9e, 0xee, 0x9e, 0xff}, + color.RGBA{0x9e, 0xee, 0xee, 0xff}, + color.RGBA{0xaa, 0xff, 0xff, 0xff}, + color.RGBA{0xbb, 0x00, 0x00, 0xff}, + color.RGBA{0xbb, 0x00, 0x5d, 0xff}, + color.RGBA{0xbb, 0x00, 0xbb, 0xff}, + color.RGBA{0xaa, 0x00, 0xff, 0xff}, + color.RGBA{0xbb, 0x5d, 0x00, 0xff}, + color.RGBA{0xbb, 0x5d, 0x5d, 0xff}, + color.RGBA{0xbb, 0x5d, 0xbb, 0xff}, + color.RGBA{0xaa, 0x55, 0xff, 0xff}, + color.RGBA{0xbb, 0xbb, 0x00, 0xff}, + color.RGBA{0xbb, 0xbb, 0x5d, 0xff}, + color.RGBA{0xbb, 0xbb, 0xbb, 0xff}, + color.RGBA{0xaa, 0xaa, 0xff, 0xff}, + color.RGBA{0xaa, 0xff, 0x00, 0xff}, + color.RGBA{0xaa, 0xff, 0x55, 0xff}, + color.RGBA{0xaa, 0xff, 0xaa, 0xff}, + color.RGBA{0xcc, 0x00, 0xcc, 0xff}, + color.RGBA{0xcc, 0x44, 0x00, 0xff}, + color.RGBA{0xcc, 0x44, 0x44, 0xff}, + color.RGBA{0xcc, 0x44, 0x88, 0xff}, + color.RGBA{0xcc, 0x44, 0xcc, 0xff}, + color.RGBA{0xcc, 0x88, 0x00, 0xff}, + color.RGBA{0xcc, 0x88, 0x44, 0xff}, + color.RGBA{0xcc, 0x88, 0x88, 0xff}, + color.RGBA{0xcc, 0x88, 0xcc, 0xff}, + color.RGBA{0xcc, 0xcc, 0x00, 0xff}, + color.RGBA{0xcc, 0xcc, 0x44, 0xff}, + color.RGBA{0xcc, 0xcc, 0x88, 0xff}, + color.RGBA{0xcc, 0xcc, 0xcc, 0xff}, + color.RGBA{0xcc, 0x00, 0x00, 0xff}, + color.RGBA{0xcc, 0x00, 0x44, 0xff}, + color.RGBA{0xcc, 0x00, 0x88, 0xff}, + color.RGBA{0xdd, 0x00, 0x93, 0xff}, + color.RGBA{0xdd, 0x00, 0xdd, 0xff}, + color.RGBA{0xdd, 0x49, 0x00, 0xff}, + color.RGBA{0xdd, 0x49, 0x49, 0xff}, + color.RGBA{0xdd, 0x49, 0x93, 0xff}, + color.RGBA{0xdd, 0x49, 0xdd, 0xff}, + color.RGBA{0xdd, 0x93, 0x00, 0xff}, + color.RGBA{0xdd, 0x93, 0x49, 0xff}, + color.RGBA{0xdd, 0x93, 0x93, 0xff}, + color.RGBA{0xdd, 0x93, 0xdd, 0xff}, + color.RGBA{0xdd, 0xdd, 0x00, 0xff}, + color.RGBA{0xdd, 0xdd, 0x49, 0xff}, + color.RGBA{0xdd, 0xdd, 0x93, 0xff}, + color.RGBA{0xdd, 0xdd, 0xdd, 0xff}, + color.RGBA{0xdd, 0x00, 0x00, 0xff}, + color.RGBA{0xdd, 0x00, 0x49, 0xff}, + color.RGBA{0xee, 0x00, 0x4f, 0xff}, + color.RGBA{0xee, 0x00, 0x9e, 0xff}, + color.RGBA{0xee, 0x00, 0xee, 0xff}, + color.RGBA{0xee, 0x4f, 0x00, 0xff}, + color.RGBA{0xee, 0x4f, 0x4f, 0xff}, + color.RGBA{0xee, 0x4f, 0x9e, 0xff}, + color.RGBA{0xee, 0x4f, 0xee, 0xff}, + color.RGBA{0xee, 0x9e, 0x00, 0xff}, + color.RGBA{0xee, 0x9e, 0x4f, 0xff}, + color.RGBA{0xee, 0x9e, 0x9e, 0xff}, + color.RGBA{0xee, 0x9e, 0xee, 0xff}, + color.RGBA{0xee, 0xee, 0x00, 0xff}, + color.RGBA{0xee, 0xee, 0x4f, 0xff}, + color.RGBA{0xee, 0xee, 0x9e, 0xff}, + color.RGBA{0xee, 0xee, 0xee, 0xff}, + color.RGBA{0xee, 0x00, 0x00, 0xff}, + color.RGBA{0xff, 0x00, 0x00, 0xff}, + color.RGBA{0xff, 0x00, 0x55, 0xff}, + color.RGBA{0xff, 0x00, 0xaa, 0xff}, + color.RGBA{0xff, 0x00, 0xff, 0xff}, + color.RGBA{0xff, 0x55, 0x00, 0xff}, + color.RGBA{0xff, 0x55, 0x55, 0xff}, + color.RGBA{0xff, 0x55, 0xaa, 0xff}, + color.RGBA{0xff, 0x55, 0xff, 0xff}, + color.RGBA{0xff, 0xaa, 0x00, 0xff}, + color.RGBA{0xff, 0xaa, 0x55, 0xff}, + color.RGBA{0xff, 0xaa, 0xaa, 0xff}, + color.RGBA{0xff, 0xaa, 0xff, 0xff}, + color.RGBA{0xff, 0xff, 0x00, 0xff}, + color.RGBA{0xff, 0xff, 0x55, 0xff}, + color.RGBA{0xff, 0xff, 0xaa, 0xff}, + color.RGBA{0xff, 0xff, 0xff, 0xff}, +} + +// WebSafe is a 216-color palette that was popularized by early versions +// of Netscape Navigator. It is also known as the Netscape Color Cube. +// +// See http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors for details. +var WebSafe = []color.Color{ + color.RGBA{0x00, 0x00, 0x00, 0xff}, + color.RGBA{0x00, 0x00, 0x33, 0xff}, + color.RGBA{0x00, 0x00, 0x66, 0xff}, + color.RGBA{0x00, 0x00, 0x99, 0xff}, + color.RGBA{0x00, 0x00, 0xcc, 0xff}, + color.RGBA{0x00, 0x00, 0xff, 0xff}, + color.RGBA{0x00, 0x33, 0x00, 0xff}, + color.RGBA{0x00, 0x33, 0x33, 0xff}, + color.RGBA{0x00, 0x33, 0x66, 0xff}, + color.RGBA{0x00, 0x33, 0x99, 0xff}, + color.RGBA{0x00, 0x33, 0xcc, 0xff}, + color.RGBA{0x00, 0x33, 0xff, 0xff}, + color.RGBA{0x00, 0x66, 0x00, 0xff}, + color.RGBA{0x00, 0x66, 0x33, 0xff}, + color.RGBA{0x00, 0x66, 0x66, 0xff}, + color.RGBA{0x00, 0x66, 0x99, 0xff}, + color.RGBA{0x00, 0x66, 0xcc, 0xff}, + color.RGBA{0x00, 0x66, 0xff, 0xff}, + color.RGBA{0x00, 0x99, 0x00, 0xff}, + color.RGBA{0x00, 0x99, 0x33, 0xff}, + color.RGBA{0x00, 0x99, 0x66, 0xff}, + color.RGBA{0x00, 0x99, 0x99, 0xff}, + color.RGBA{0x00, 0x99, 0xcc, 0xff}, + color.RGBA{0x00, 0x99, 0xff, 0xff}, + color.RGBA{0x00, 0xcc, 0x00, 0xff}, + color.RGBA{0x00, 0xcc, 0x33, 0xff}, + color.RGBA{0x00, 0xcc, 0x66, 0xff}, + color.RGBA{0x00, 0xcc, 0x99, 0xff}, + color.RGBA{0x00, 0xcc, 0xcc, 0xff}, + color.RGBA{0x00, 0xcc, 0xff, 0xff}, + color.RGBA{0x00, 0xff, 0x00, 0xff}, + color.RGBA{0x00, 0xff, 0x33, 0xff}, + color.RGBA{0x00, 0xff, 0x66, 0xff}, + color.RGBA{0x00, 0xff, 0x99, 0xff}, + color.RGBA{0x00, 0xff, 0xcc, 0xff}, + color.RGBA{0x00, 0xff, 0xff, 0xff}, + color.RGBA{0x33, 0x00, 0x00, 0xff}, + color.RGBA{0x33, 0x00, 0x33, 0xff}, + color.RGBA{0x33, 0x00, 0x66, 0xff}, + color.RGBA{0x33, 0x00, 0x99, 0xff}, + color.RGBA{0x33, 0x00, 0xcc, 0xff}, + color.RGBA{0x33, 0x00, 0xff, 0xff}, + color.RGBA{0x33, 0x33, 0x00, 0xff}, + color.RGBA{0x33, 0x33, 0x33, 0xff}, + color.RGBA{0x33, 0x33, 0x66, 0xff}, + color.RGBA{0x33, 0x33, 0x99, 0xff}, + color.RGBA{0x33, 0x33, 0xcc, 0xff}, + color.RGBA{0x33, 0x33, 0xff, 0xff}, + color.RGBA{0x33, 0x66, 0x00, 0xff}, + color.RGBA{0x33, 0x66, 0x33, 0xff}, + color.RGBA{0x33, 0x66, 0x66, 0xff}, + color.RGBA{0x33, 0x66, 0x99, 0xff}, + color.RGBA{0x33, 0x66, 0xcc, 0xff}, + color.RGBA{0x33, 0x66, 0xff, 0xff}, + color.RGBA{0x33, 0x99, 0x00, 0xff}, + color.RGBA{0x33, 0x99, 0x33, 0xff}, + color.RGBA{0x33, 0x99, 0x66, 0xff}, + color.RGBA{0x33, 0x99, 0x99, 0xff}, + color.RGBA{0x33, 0x99, 0xcc, 0xff}, + color.RGBA{0x33, 0x99, 0xff, 0xff}, + color.RGBA{0x33, 0xcc, 0x00, 0xff}, + color.RGBA{0x33, 0xcc, 0x33, 0xff}, + color.RGBA{0x33, 0xcc, 0x66, 0xff}, + color.RGBA{0x33, 0xcc, 0x99, 0xff}, + color.RGBA{0x33, 0xcc, 0xcc, 0xff}, + color.RGBA{0x33, 0xcc, 0xff, 0xff}, + color.RGBA{0x33, 0xff, 0x00, 0xff}, + color.RGBA{0x33, 0xff, 0x33, 0xff}, + color.RGBA{0x33, 0xff, 0x66, 0xff}, + color.RGBA{0x33, 0xff, 0x99, 0xff}, + color.RGBA{0x33, 0xff, 0xcc, 0xff}, + color.RGBA{0x33, 0xff, 0xff, 0xff}, + color.RGBA{0x66, 0x00, 0x00, 0xff}, + color.RGBA{0x66, 0x00, 0x33, 0xff}, + color.RGBA{0x66, 0x00, 0x66, 0xff}, + color.RGBA{0x66, 0x00, 0x99, 0xff}, + color.RGBA{0x66, 0x00, 0xcc, 0xff}, + color.RGBA{0x66, 0x00, 0xff, 0xff}, + color.RGBA{0x66, 0x33, 0x00, 0xff}, + color.RGBA{0x66, 0x33, 0x33, 0xff}, + color.RGBA{0x66, 0x33, 0x66, 0xff}, + color.RGBA{0x66, 0x33, 0x99, 0xff}, + color.RGBA{0x66, 0x33, 0xcc, 0xff}, + color.RGBA{0x66, 0x33, 0xff, 0xff}, + color.RGBA{0x66, 0x66, 0x00, 0xff}, + color.RGBA{0x66, 0x66, 0x33, 0xff}, + color.RGBA{0x66, 0x66, 0x66, 0xff}, + color.RGBA{0x66, 0x66, 0x99, 0xff}, + color.RGBA{0x66, 0x66, 0xcc, 0xff}, + color.RGBA{0x66, 0x66, 0xff, 0xff}, + color.RGBA{0x66, 0x99, 0x00, 0xff}, + color.RGBA{0x66, 0x99, 0x33, 0xff}, + color.RGBA{0x66, 0x99, 0x66, 0xff}, + color.RGBA{0x66, 0x99, 0x99, 0xff}, + color.RGBA{0x66, 0x99, 0xcc, 0xff}, + color.RGBA{0x66, 0x99, 0xff, 0xff}, + color.RGBA{0x66, 0xcc, 0x00, 0xff}, + color.RGBA{0x66, 0xcc, 0x33, 0xff}, + color.RGBA{0x66, 0xcc, 0x66, 0xff}, + color.RGBA{0x66, 0xcc, 0x99, 0xff}, + color.RGBA{0x66, 0xcc, 0xcc, 0xff}, + color.RGBA{0x66, 0xcc, 0xff, 0xff}, + color.RGBA{0x66, 0xff, 0x00, 0xff}, + color.RGBA{0x66, 0xff, 0x33, 0xff}, + color.RGBA{0x66, 0xff, 0x66, 0xff}, + color.RGBA{0x66, 0xff, 0x99, 0xff}, + color.RGBA{0x66, 0xff, 0xcc, 0xff}, + color.RGBA{0x66, 0xff, 0xff, 0xff}, + color.RGBA{0x99, 0x00, 0x00, 0xff}, + color.RGBA{0x99, 0x00, 0x33, 0xff}, + color.RGBA{0x99, 0x00, 0x66, 0xff}, + color.RGBA{0x99, 0x00, 0x99, 0xff}, + color.RGBA{0x99, 0x00, 0xcc, 0xff}, + color.RGBA{0x99, 0x00, 0xff, 0xff}, + color.RGBA{0x99, 0x33, 0x00, 0xff}, + color.RGBA{0x99, 0x33, 0x33, 0xff}, + color.RGBA{0x99, 0x33, 0x66, 0xff}, + color.RGBA{0x99, 0x33, 0x99, 0xff}, + color.RGBA{0x99, 0x33, 0xcc, 0xff}, + color.RGBA{0x99, 0x33, 0xff, 0xff}, + color.RGBA{0x99, 0x66, 0x00, 0xff}, + color.RGBA{0x99, 0x66, 0x33, 0xff}, + color.RGBA{0x99, 0x66, 0x66, 0xff}, + color.RGBA{0x99, 0x66, 0x99, 0xff}, + color.RGBA{0x99, 0x66, 0xcc, 0xff}, + color.RGBA{0x99, 0x66, 0xff, 0xff}, + color.RGBA{0x99, 0x99, 0x00, 0xff}, + color.RGBA{0x99, 0x99, 0x33, 0xff}, + color.RGBA{0x99, 0x99, 0x66, 0xff}, + color.RGBA{0x99, 0x99, 0x99, 0xff}, + color.RGBA{0x99, 0x99, 0xcc, 0xff}, + color.RGBA{0x99, 0x99, 0xff, 0xff}, + color.RGBA{0x99, 0xcc, 0x00, 0xff}, + color.RGBA{0x99, 0xcc, 0x33, 0xff}, + color.RGBA{0x99, 0xcc, 0x66, 0xff}, + color.RGBA{0x99, 0xcc, 0x99, 0xff}, + color.RGBA{0x99, 0xcc, 0xcc, 0xff}, + color.RGBA{0x99, 0xcc, 0xff, 0xff}, + color.RGBA{0x99, 0xff, 0x00, 0xff}, + color.RGBA{0x99, 0xff, 0x33, 0xff}, + color.RGBA{0x99, 0xff, 0x66, 0xff}, + color.RGBA{0x99, 0xff, 0x99, 0xff}, + color.RGBA{0x99, 0xff, 0xcc, 0xff}, + color.RGBA{0x99, 0xff, 0xff, 0xff}, + color.RGBA{0xcc, 0x00, 0x00, 0xff}, + color.RGBA{0xcc, 0x00, 0x33, 0xff}, + color.RGBA{0xcc, 0x00, 0x66, 0xff}, + color.RGBA{0xcc, 0x00, 0x99, 0xff}, + color.RGBA{0xcc, 0x00, 0xcc, 0xff}, + color.RGBA{0xcc, 0x00, 0xff, 0xff}, + color.RGBA{0xcc, 0x33, 0x00, 0xff}, + color.RGBA{0xcc, 0x33, 0x33, 0xff}, + color.RGBA{0xcc, 0x33, 0x66, 0xff}, + color.RGBA{0xcc, 0x33, 0x99, 0xff}, + color.RGBA{0xcc, 0x33, 0xcc, 0xff}, + color.RGBA{0xcc, 0x33, 0xff, 0xff}, + color.RGBA{0xcc, 0x66, 0x00, 0xff}, + color.RGBA{0xcc, 0x66, 0x33, 0xff}, + color.RGBA{0xcc, 0x66, 0x66, 0xff}, + color.RGBA{0xcc, 0x66, 0x99, 0xff}, + color.RGBA{0xcc, 0x66, 0xcc, 0xff}, + color.RGBA{0xcc, 0x66, 0xff, 0xff}, + color.RGBA{0xcc, 0x99, 0x00, 0xff}, + color.RGBA{0xcc, 0x99, 0x33, 0xff}, + color.RGBA{0xcc, 0x99, 0x66, 0xff}, + color.RGBA{0xcc, 0x99, 0x99, 0xff}, + color.RGBA{0xcc, 0x99, 0xcc, 0xff}, + color.RGBA{0xcc, 0x99, 0xff, 0xff}, + color.RGBA{0xcc, 0xcc, 0x00, 0xff}, + color.RGBA{0xcc, 0xcc, 0x33, 0xff}, + color.RGBA{0xcc, 0xcc, 0x66, 0xff}, + color.RGBA{0xcc, 0xcc, 0x99, 0xff}, + color.RGBA{0xcc, 0xcc, 0xcc, 0xff}, + color.RGBA{0xcc, 0xcc, 0xff, 0xff}, + color.RGBA{0xcc, 0xff, 0x00, 0xff}, + color.RGBA{0xcc, 0xff, 0x33, 0xff}, + color.RGBA{0xcc, 0xff, 0x66, 0xff}, + color.RGBA{0xcc, 0xff, 0x99, 0xff}, + color.RGBA{0xcc, 0xff, 0xcc, 0xff}, + color.RGBA{0xcc, 0xff, 0xff, 0xff}, + color.RGBA{0xff, 0x00, 0x00, 0xff}, + color.RGBA{0xff, 0x00, 0x33, 0xff}, + color.RGBA{0xff, 0x00, 0x66, 0xff}, + color.RGBA{0xff, 0x00, 0x99, 0xff}, + color.RGBA{0xff, 0x00, 0xcc, 0xff}, + color.RGBA{0xff, 0x00, 0xff, 0xff}, + color.RGBA{0xff, 0x33, 0x00, 0xff}, + color.RGBA{0xff, 0x33, 0x33, 0xff}, + color.RGBA{0xff, 0x33, 0x66, 0xff}, + color.RGBA{0xff, 0x33, 0x99, 0xff}, + color.RGBA{0xff, 0x33, 0xcc, 0xff}, + color.RGBA{0xff, 0x33, 0xff, 0xff}, + color.RGBA{0xff, 0x66, 0x00, 0xff}, + color.RGBA{0xff, 0x66, 0x33, 0xff}, + color.RGBA{0xff, 0x66, 0x66, 0xff}, + color.RGBA{0xff, 0x66, 0x99, 0xff}, + color.RGBA{0xff, 0x66, 0xcc, 0xff}, + color.RGBA{0xff, 0x66, 0xff, 0xff}, + color.RGBA{0xff, 0x99, 0x00, 0xff}, + color.RGBA{0xff, 0x99, 0x33, 0xff}, + color.RGBA{0xff, 0x99, 0x66, 0xff}, + color.RGBA{0xff, 0x99, 0x99, 0xff}, + color.RGBA{0xff, 0x99, 0xcc, 0xff}, + color.RGBA{0xff, 0x99, 0xff, 0xff}, + color.RGBA{0xff, 0xcc, 0x00, 0xff}, + color.RGBA{0xff, 0xcc, 0x33, 0xff}, + color.RGBA{0xff, 0xcc, 0x66, 0xff}, + color.RGBA{0xff, 0xcc, 0x99, 0xff}, + color.RGBA{0xff, 0xcc, 0xcc, 0xff}, + color.RGBA{0xff, 0xcc, 0xff, 0xff}, + color.RGBA{0xff, 0xff, 0x00, 0xff}, + color.RGBA{0xff, 0xff, 0x33, 0xff}, + color.RGBA{0xff, 0xff, 0x66, 0xff}, + color.RGBA{0xff, 0xff, 0x99, 0xff}, + color.RGBA{0xff, 0xff, 0xcc, 0xff}, + color.RGBA{0xff, 0xff, 0xff, 0xff}, +} diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go new file mode 100644 index 000000000..4c2f29ea0 --- /dev/null +++ b/src/image/color/ycbcr.go @@ -0,0 +1,99 @@ +// 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 RGBToYCbCr(r, g, b 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 + // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'. + r1 := int(r) + g1 := int(g) + b1 := int(b) + yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16 + cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16 + cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16 + if yy < 0 { + yy = 0 + } else if yy > 255 { + yy = 255 + } + if cb < 0 { + cb = 0 + } else if cb > 255 { + cb = 255 + } + if cr < 0 { + cr = 0 + } else if cr > 255 { + cr = 255 + } + return uint8(yy), uint8(cb), uint8(cr) +} + +// YCbCrToRGB converts a Y'CbCr triple to an RGB triple. +func YCbCrToRGB(y, cb, cr 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) + // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'. + yy1 := int(y)<<16 + 1<<15 + cb1 := int(cb) - 128 + cr1 := int(cr) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + return uint8(r), uint8(g), uint8(b) +} + +// 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 http://www.w3.org/Graphics/JPEG/jfif3.pdf. +type YCbCr struct { + Y, Cb, Cr uint8 +} + +func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) { + r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr) + return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff +} + +// YCbCrModel is the Model for Y'CbCr colors. +var YCbCrModel Model = ModelFunc(yCbCrModel) + +func yCbCrModel(c Color) Color { + if _, ok := c.(YCbCr); ok { + return c + } + r, g, b, _ := c.RGBA() + y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) + return YCbCr{y, u, v} +} diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go new file mode 100644 index 000000000..92a0e6ff1 --- /dev/null +++ b/src/image/color/ycbcr_test.go @@ -0,0 +1,33 @@ +// 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 + +import ( + "testing" +) + +func delta(x, y uint8) uint8 { + if x >= y { + return x - y + } + return y - x +} + +// Test that a subset of RGB space can be converted to YCbCr and back to within +// 1/256 tolerance. +func TestRoundtrip(t *testing.T) { + for r := 0; r < 255; r += 7 { + for g := 0; g < 255; g += 5 { + for b := 0; b < 255; b += 3 { + r0, g0, b0 := uint8(r), uint8(g), uint8(b) + y, cb, cr := RGBToYCbCr(r0, g0, b0) + r1, g1, b1 := YCbCrToRGB(y, cb, cr) + if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 { + t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1) + } + } + } + } +} |