Commit e5902fc7 authored by ChaiShushan's avatar ChaiShushan Committed by Rob Pike

image: add RGB and RGB48

R=golang-dev, r, nigeltao
CC=golang-dev
https://golang.org/cl/13239051
parent 0d624e18
......@@ -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
......
......@@ -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
......
......@@ -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)),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment