summaryrefslogtreecommitdiff
path: root/src/pkg/image
diff options
context:
space:
mode:
authorChaiShushan <chaishushan@gmail.com>2013-12-12 11:24:27 -0800
committerChaiShushan <chaishushan@gmail.com>2013-12-12 11:24:27 -0800
commit2c81f1676c8d7462dbadfce7ad5d7ae2377e328e (patch)
treecae0a9f01be70a70a358abf92bd8e74bdf41474f /src/pkg/image
parent0b064177eae2422f01dc0d4568a4f06485721607 (diff)
downloadgo-2c81f1676c8d7462dbadfce7ad5d7ae2377e328e.tar.gz
image: add RGB and RGB48
R=golang-dev, r, nigeltao CC=golang-dev https://codereview.appspot.com/13239051 Committer: Rob Pike <r@golang.org>
Diffstat (limited to 'src/pkg/image')
-rw-r--r--src/pkg/image/color/color.go45
-rw-r--r--src/pkg/image/image.go170
-rw-r--r--src/pkg/image/image_test.go3
3 files changed, 218 insertions, 0 deletions
diff --git a/src/pkg/image/color/color.go b/src/pkg/image/color/color.go
index ff596a76a..61114bd91 100644
--- a/src/pkg/image/color/color.go
+++ b/src/pkg/image/color/color.go
@@ -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
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 32a89ef34..997614354 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -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
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index 799c1a7a1..1f4105bf0 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -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)),