]> Cypherpunks repositories - gostls13.git/commitdiff
image: add RGB and RGB48
authorChaiShushan <chaishushan@gmail.com>
Thu, 12 Dec 2013 19:24:27 +0000 (11:24 -0800)
committerRob Pike <r@golang.org>
Thu, 12 Dec 2013 19:24:27 +0000 (11:24 -0800)
R=golang-dev, r, nigeltao
CC=golang-dev
https://golang.org/cl/13239051

src/pkg/image/color/color.go
src/pkg/image/image.go
src/pkg/image/image_test.go

index ff596a76a367632484689e60220811b2a7b2c8ed..61114bd918fbb841d48366bd331ef7e3937aa64b 100644 (file)
@@ -15,6 +15,33 @@ type Color interface {
        RGBA() (r, g, b, a uint32)
 }
 
+// RGB represents a traditional 24-bit fully opaque color,
+// having 8 bits for each of red, green and blue.
+type RGB struct {
+       R, G, B uint8
+}
+
+func (c RGB) 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 = 0xFFFF
+       return
+}
+
+// RGB48 represents a 48-bit fully opaque color,
+// having 16 bits for each of red, green and blue.
+type RGB48 struct {
+       R, G, B uint16
+}
+
+func (c RGB48) RGBA() (r, g, b, a uint32) {
+       return uint32(c.R), uint32(c.G), uint32(c.B), 0xFFFF
+}
+
 // RGBA represents a traditional 32-bit alpha-premultiplied color,
 // having 8 bits for each of red, green, blue and alpha.
 type RGBA struct {
@@ -154,6 +181,8 @@ func (m *modelFunc) Convert(c Color) Color {
 
 // Models for the standard color types.
 var (
+       RGBModel     Model = ModelFunc(rgbModel)
+       RGB48Model   Model = ModelFunc(rgb48Model)
        RGBAModel    Model = ModelFunc(rgbaModel)
        RGBA64Model  Model = ModelFunc(rgba64Model)
        NRGBAModel   Model = ModelFunc(nrgbaModel)
@@ -164,6 +193,22 @@ var (
        Gray16Model  Model = ModelFunc(gray16Model)
 )
 
+func rgbModel(c Color) Color {
+       if _, ok := c.(RGB); ok {
+               return c
+       }
+       r, g, b, _ := c.RGBA()
+       return RGB{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)}
+}
+
+func rgb48Model(c Color) Color {
+       if _, ok := c.(RGB48); ok {
+               return c
+       }
+       r, g, b, _ := c.RGBA()
+       return RGB48{uint16(r), uint16(g), uint16(b)}
+}
+
 func rgbaModel(c Color) Color {
        if _, ok := c.(RGBA); ok {
                return c
index 32a89ef34ca8c1e9326bf136ffc9445a25bdbc40..9976143540fd3f0db05305454ab19221a91b2371 100644 (file)
@@ -56,6 +56,176 @@ type PalettedImage interface {
        Image
 }
 
+// RGB is an in-memory image whose At method returns color.RGB values.
+type RGB struct {
+       // Pix holds the image's pixels, in R, G, B order. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*3].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *RGB) ColorModel() color.Model { return color.RGBModel }
+
+func (p *RGB) Bounds() Rectangle { return p.Rect }
+
+func (p *RGB) At(x, y int) color.Color {
+       if !(Point{x, y}.In(p.Rect)) {
+               return color.RGB{}
+       }
+       i := p.PixOffset(x, y)
+       return color.RGB{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2]}
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGB) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*3
+}
+
+func (p *RGB) Set(x, y int, c color.Color) {
+       if !(Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       c1 := color.RGBModel.Convert(c).(color.RGB)
+       p.Pix[i+0] = c1.R
+       p.Pix[i+1] = c1.G
+       p.Pix[i+2] = c1.B
+}
+
+func (p *RGB) SetRGB(x, y int, c color.RGB) {
+       if !(Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       p.Pix[i+0] = c.R
+       p.Pix[i+1] = c.G
+       p.Pix[i+2] = c.B
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGB) SubImage(r Rectangle) Image {
+       r = r.Intersect(p.Rect)
+       // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+       // either r1 or r2 if the intersection is empty. Without explicitly checking for
+       // this, the Pix[i:] expression below can panic.
+       if r.Empty() {
+               return &RGB{}
+       }
+       i := p.PixOffset(r.Min.X, r.Min.Y)
+       return &RGB{
+               Pix:    p.Pix[i:],
+               Stride: p.Stride,
+               Rect:   r,
+       }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *RGB) Opaque() bool {
+       return true
+}
+
+// NewRGB returns a new RGB with the given bounds.
+func NewRGB(r Rectangle) *RGB {
+       w, h := r.Dx(), r.Dy()
+       buf := make([]uint8, 3*w*h)
+       return &RGB{buf, 3 * w, r}
+}
+
+// RGB48 is an in-memory image whose At method returns color.RGB48 values.
+type RGB48 struct {
+       // Pix holds the image's pixels, in R, G, B order and big-endian format. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*6].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+       Stride int
+       // Rect is the image's bounds.
+       Rect Rectangle
+}
+
+func (p *RGB48) ColorModel() color.Model { return color.RGB48Model }
+
+func (p *RGB48) Bounds() Rectangle { return p.Rect }
+
+func (p *RGB48) At(x, y int) color.Color {
+       if !(Point{x, y}.In(p.Rect)) {
+               return color.RGB48{}
+       }
+       i := p.PixOffset(x, y)
+       return color.RGB48{
+               uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+               uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+               uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+       }
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGB48) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*6
+}
+
+func (p *RGB48) Set(x, y int, c color.Color) {
+       if !(Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       c1 := color.RGB48Model.Convert(c).(color.RGB48)
+       p.Pix[i+0] = uint8(c1.R >> 8)
+       p.Pix[i+1] = uint8(c1.R)
+       p.Pix[i+2] = uint8(c1.G >> 8)
+       p.Pix[i+3] = uint8(c1.G)
+       p.Pix[i+4] = uint8(c1.B >> 8)
+       p.Pix[i+5] = uint8(c1.B)
+}
+
+func (p *RGB48) SetRGB48(x, y int, c color.RGB48) {
+       if !(Point{x, y}.In(p.Rect)) {
+               return
+       }
+       i := p.PixOffset(x, y)
+       p.Pix[i+0] = uint8(c.R >> 8)
+       p.Pix[i+1] = uint8(c.R)
+       p.Pix[i+2] = uint8(c.G >> 8)
+       p.Pix[i+3] = uint8(c.G)
+       p.Pix[i+4] = uint8(c.B >> 8)
+       p.Pix[i+5] = uint8(c.B)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGB48) SubImage(r Rectangle) Image {
+       r = r.Intersect(p.Rect)
+       // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+       // either r1 or r2 if the intersection is empty. Without explicitly checking for
+       // this, the Pix[i:] expression below can panic.
+       if r.Empty() {
+               return &RGB48{}
+       }
+       i := p.PixOffset(r.Min.X, r.Min.Y)
+       return &RGB48{
+               Pix:    p.Pix[i:],
+               Stride: p.Stride,
+               Rect:   r,
+       }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *RGB48) Opaque() bool {
+       return true
+}
+
+// NewRGB48 returns a new RGB48 with the given bounds.
+func NewRGB48(r Rectangle) *RGB48 {
+       w, h := r.Dx(), r.Dy()
+       pix := make([]uint8, 6*w*h)
+       return &RGB48{pix, 6 * w, r}
+}
+
 // RGBA is an in-memory image whose At method returns color.RGBA values.
 type RGBA struct {
        // Pix holds the image's pixels, in R, G, B, A order. The pixel at
index 799c1a7a11d5f1b98a71fd009ebe33551656c624..1f4105bf030f28c8017f53feefdc444c1e199fd7 100644 (file)
@@ -24,6 +24,8 @@ func cmp(t *testing.T, cm color.Model, c0, c1 color.Color) bool {
 
 func TestImage(t *testing.T) {
        testImage := []image{
+               NewRGB(Rect(0, 0, 10, 10)),
+               NewRGB48(Rect(0, 0, 10, 10)),
                NewRGBA(Rect(0, 0, 10, 10)),
                NewRGBA64(Rect(0, 0, 10, 10)),
                NewNRGBA(Rect(0, 0, 10, 10)),
@@ -97,6 +99,7 @@ func Test16BitsPerColorChannel(t *testing.T) {
                }
        }
        testImage := []image{
+               NewRGB48(Rect(0, 0, 10, 10)),
                NewRGBA64(Rect(0, 0, 10, 10)),
                NewNRGBA64(Rect(0, 0, 10, 10)),
                NewAlpha16(Rect(0, 0, 10, 10)),