mirror of
https://github.com/golang/go
synced 2024-10-04 08:31:22 -06:00
image: roll back 13239051 (add RGB and RGB48)
They cause too much bloat in the internals as we find ourselves adding special case code for all the cross-connections. It's better to use RGBA and just max out the alpha. We lose a little memory but reduce the number of special cases the encoders, decoders, and drawers need to provide. R=golang-dev, nigeltao CC=golang-dev https://golang.org/cl/42910045
This commit is contained in:
parent
2784a3ea85
commit
a075fdbaa6
@ -15,33 +15,6 @@ 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 {
|
||||
@ -181,8 +154,6 @@ 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)
|
||||
@ -193,22 +164,6 @@ 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,176 +56,6 @@ 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,8 +24,6 @@ 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)),
|
||||
@ -99,7 +97,6 @@ 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)),
|
||||
|
Loading…
Reference in New Issue
Block a user