]> Cypherpunks repositories - gostls13.git/commitdiff
image: change Pix from []FooColor to []uint8.
authorNigel Tao <nigeltao@golang.org>
Tue, 12 Jul 2011 06:39:38 +0000 (16:39 +1000)
committerNigel Tao <nigeltao@golang.org>
Tue, 12 Jul 2011 06:39:38 +0000 (16:39 +1000)
Some benchmark numbers below. The image/draw fast-paths show dramatic
improvement, the generic slow-paths show a smaller slow-down.

BEFORE
png.BenchmarkEncodePaletted      200       8203800 ns/op      37.45 MB/s
png.BenchmarkEncodeRGBOpaque         100      26940440 ns/op      45.61 MB/s
png.BenchmarkEncodeRGBA       20      73821000 ns/op      16.65 MB/s
jpeg.BenchmarkEncodeRGBOpaque         50      35598640 ns/op      34.52 MB/s
draw.BenchmarkFillOver      500    4024226 ns/op
draw.BenchmarkFillSrc    10000     152736 ns/op
draw.BenchmarkCopyOver      500    3452824 ns/op
draw.BenchmarkCopySrc    50000      73218 ns/op
draw.BenchmarkNRGBAOver      500    3941234 ns/op
draw.BenchmarkNRGBASrc     1000    2484400 ns/op
draw.BenchmarkYCbCr     1000    2609005 ns/op
draw.BenchmarkGlyphOver     2000    1169575 ns/op
draw.BenchmarkRGBA      200    9031390 ns/op
draw.BenchmarkGenericOver       50   34636620 ns/op
draw.BenchmarkGenericMaskOver      100   16561150 ns/op
draw.BenchmarkGenericSrc      100   13873760 ns/op
draw.BenchmarkGenericMaskSrc      100   25198860 ns/op

AFTER
png.BenchmarkEncodePaletted      200       8206600 ns/op      37.43 MB/s
png.BenchmarkEncodeRGBOpaque         100      26129530 ns/op      47.03 MB/s
png.BenchmarkEncodeRGBA       20      75776750 ns/op      16.22 MB/s
jpeg.BenchmarkEncodeRGBOpaque         50      37192940 ns/op      33.04 MB/s
draw.BenchmarkFillOver      500    3008134 ns/op
draw.BenchmarkFillSrc    10000     154214 ns/op
draw.BenchmarkCopyOver     1000    2169988 ns/op
draw.BenchmarkCopySrc    50000      73095 ns/op
draw.BenchmarkNRGBAOver     1000    2491079 ns/op
draw.BenchmarkNRGBASrc     2000    1361244 ns/op
draw.BenchmarkYCbCr     1000    2554269 ns/op
draw.BenchmarkGlyphOver     2000    1042225 ns/op
draw.BenchmarkRGBA      100   10233340 ns/op
draw.BenchmarkGenericOver       50   38421560 ns/op
draw.BenchmarkGenericMaskOver      100   17521190 ns/op
draw.BenchmarkGenericSrc      100   16351200 ns/op
draw.BenchmarkGenericMaskSrc      100   26538190 ns/op

R=r
CC=golang-dev
https://golang.org/cl/4675076

src/pkg/exp/gui/x11/conn.go
src/pkg/image/bmp/reader.go
src/pkg/image/color.go
src/pkg/image/draw/draw.go
src/pkg/image/image.go
src/pkg/image/jpeg/reader.go
src/pkg/image/jpeg/writer.go
src/pkg/image/png/writer.go

index 420bdd82a7e705ed62fc8dfcbab5e066a8991aa7..1d237816abf923b53e7a4df71fc085e9381ed810 100644 (file)
@@ -92,18 +92,19 @@ func (c *conn) writeSocket() {
                                return
                        }
                        p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
-                       for x, dx := 0, b.Dx(); x < dx; {
+                       for x, dx := 0, 4*b.Dx(); x < dx; {
                                nx := dx - x
-                               if nx > len(c.flushBuf1)/4 {
-                                       nx = len(c.flushBuf1) / 4
+                               if nx > len(c.flushBuf1) {
+                                       nx = len(c.flushBuf1) &^ 3
                                }
-                               for i, rgba := range p[x : x+nx] {
-                                       c.flushBuf1[4*i+0] = rgba.B
-                                       c.flushBuf1[4*i+1] = rgba.G
-                                       c.flushBuf1[4*i+2] = rgba.R
+                               for i := 0; i < nx; i += 4 {
+                                       // X11's order is BGRX, not RGBA.
+                                       c.flushBuf1[i+0] = p[x+i+2]
+                                       c.flushBuf1[i+1] = p[x+i+1]
+                                       c.flushBuf1[i+2] = p[x+i+0]
                                }
                                x += nx
-                               if _, err := c.w.Write(c.flushBuf1[:4*nx]); err != nil {
+                               if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
                                        if err != os.EOF {
                                                log.Println("x11:", err.String())
                                        }
index f2842caedda8d7132abe0e6807d46c20ff71e6be..357da1dacdc07d1571a1376ed6dad241119c81a9 100644 (file)
@@ -58,10 +58,13 @@ func decodeRGBA(r io.Reader, c image.Config) (image.Image, os.Error) {
                if err != nil {
                        return nil, err
                }
-               p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width]
-               for x := range p {
+               p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
+               for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
                        // BMP images are stored in BGR order rather than RGB order.
-                       p[x] = image.RGBAColor{b[3*x+2], b[3*x+1], b[3*x+0], 0xFF}
+                       p[i+0] = b[j+2]
+                       p[i+1] = b[j+1]
+                       p[i+2] = b[j+0]
+                       p[i+3] = 0xFF
                }
        }
        return rgba, nil
index c1345c0252c7495ce199b1feaafedfeeca81a154..501a882f02ee39915d9fb1a37c4ac7b66da62eb1 100644 (file)
@@ -4,14 +4,14 @@
 
 package image
 
-// All Colors can convert themselves, with a possible loss of precision,
-// to 64-bit alpha-premultiplied RGBA. Each channel value ranges within
-// [0, 0xFFFF].
+// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
+// of precision. 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.
 type Color interface {
        RGBA() (r, g, b, a uint32)
 }
 
-// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
 // having 8 bits for each of red, green, blue and alpha.
 type RGBAColor struct {
        R, G, B, A uint8
@@ -29,7 +29,7 @@ func (c RGBAColor) RGBA() (r, g, b, a uint32) {
        return
 }
 
-// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// RGBA64Color represents a 64-bit alpha-premultiplied color,
 // having 16 bits for each of red, green, blue and alpha.
 type RGBA64Color struct {
        R, G, B, A uint16
@@ -39,7 +39,7 @@ func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
        return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
 }
 
-// An NRGBAColor represents a non-alpha-premultiplied 32-bit color.
+// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
 type NRGBAColor struct {
        R, G, B, A uint8
 }
@@ -62,7 +62,7 @@ func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
        return
 }
 
-// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
 // having 16 bits for each of red, green, blue and alpha.
 type NRGBA64Color struct {
        R, G, B, A uint16
@@ -82,7 +82,7 @@ func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
        return
 }
 
-// An AlphaColor represents an 8-bit alpha.
+// AlphaColor represents an 8-bit alpha.
 type AlphaColor struct {
        A uint8
 }
@@ -93,7 +93,7 @@ func (c AlphaColor) RGBA() (r, g, b, a uint32) {
        return a, a, a, a
 }
 
-// An Alpha16Color represents a 16-bit alpha.
+// Alpha16Color represents a 16-bit alpha.
 type Alpha16Color struct {
        A uint16
 }
@@ -103,7 +103,7 @@ func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
        return a, a, a, a
 }
 
-// GrayColor represents an 8-bit grayscale color.
+// GrayColor represents an 8-bit grayscale color.
 type GrayColor struct {
        Y uint8
 }
@@ -114,7 +114,7 @@ func (c GrayColor) RGBA() (r, g, b, a uint32) {
        return y, y, y, 0xffff
 }
 
-// Gray16Color represents a 16-bit grayscale color.
+// Gray16Color represents a 16-bit grayscale color.
 type Gray16Color struct {
        Y uint16
 }
@@ -124,7 +124,7 @@ func (c Gray16Color) RGBA() (r, g, b, a uint32) {
        return y, y, y, 0xffff
 }
 
-// ColorModel can convert foreign Colors, with a possible loss of precision,
+// ColorModel can convert foreign Colors, with a possible loss of precision,
 // to a Color from its own color model.
 type ColorModel interface {
        Convert(c Color) Color
index 5c4dedb81888b5eff9cb93a45b63fd5edbcb36c9..6468952b145b87f618df484cb3dd6a6003ce46ad 100644 (file)
@@ -170,19 +170,22 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 }
 
 func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
-       cr, cg, cb, ca := src.RGBA()
+       sr, sg, sb, sa := src.RGBA()
        // The 0x101 is here for the same reason as in drawRGBA.
-       a := (m - ca) * 0x101
-       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
-       i1 := i0 + r.Dx()
+       a := (m - sa) * 0x101
+       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       i1 := i0 + r.Dx()*4
        for y := r.Min.Y; y != r.Max.Y; y++ {
-               dpix := dst.Pix[i0:i1]
-               for i, rgba := range dpix {
-                       dr := (uint32(rgba.R)*a)/m + cr
-                       dg := (uint32(rgba.G)*a)/m + cg
-                       db := (uint32(rgba.B)*a)/m + cb
-                       da := (uint32(rgba.A)*a)/m + ca
-                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+               for i := i0; i < i1; i += 4 {
+                       dr := uint32(dst.Pix[i+0])
+                       dg := uint32(dst.Pix[i+1])
+                       db := uint32(dst.Pix[i+2])
+                       da := uint32(dst.Pix[i+3])
+
+                       dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
+                       dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
+                       dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
+                       dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
                }
                i0 += dst.Stride
                i1 += dst.Stride
@@ -191,8 +194,8 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
 
 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
        dx, dy := r.Dx(), r.Dy()
-       d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
-       s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + sp.X - src.Rect.Min.X
+       d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
        var (
                ddelta, sdelta int
                i0, i1, idelta int
@@ -200,7 +203,7 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
        if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
                ddelta = dst.Stride
                sdelta = src.Stride
-               i0, i1, idelta = 0, dx, +1
+               i0, i1, idelta = 0, dx*4, +4
        } else {
                // If the source start point is higher than the destination start point, or equal height but to the left,
                // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
@@ -208,28 +211,29 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
                s0 += (dy - 1) * src.Stride
                ddelta = -dst.Stride
                sdelta = -src.Stride
-               i0, i1, idelta = dx-1, -1, -1
+               i0, i1, idelta = (dx-1)*4, -4, -4
        }
        for ; dy > 0; dy-- {
                dpix := dst.Pix[d0:]
                spix := src.Pix[s0:]
                for i := i0; i != i1; i += idelta {
-                       // For unknown reasons, even though both dpix[i] and spix[i] are
-                       // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
-                       // for the source but to do it manually for the destination.
-                       sr, sg, sb, sa := spix[i].RGBA()
-                       rgba := dpix[i]
-                       dr := uint32(rgba.R)
-                       dg := uint32(rgba.G)
-                       db := uint32(rgba.B)
-                       da := uint32(rgba.A)
+                       sr := uint32(spix[i+0]) * 0x101
+                       sg := uint32(spix[i+1]) * 0x101
+                       sb := uint32(spix[i+2]) * 0x101
+                       sa := uint32(spix[i+3]) * 0x101
+
+                       dr := uint32(dpix[i+0])
+                       dg := uint32(dpix[i+1])
+                       db := uint32(dpix[i+2])
+                       da := uint32(dpix[i+3])
+
                        // The 0x101 is here for the same reason as in drawRGBA.
                        a := (m - sa) * 0x101
-                       dr = (dr*a)/m + sr
-                       dg = (dg*a)/m + sg
-                       db = (db*a)/m + sb
-                       da = (da*a)/m + sa
-                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+
+                       dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+                       dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+                       dpix[i+2] = uint8((db*a/m + sb) >> 8)
+                       dpix[i+3] = uint8((da*a/m + sa) >> 8)
                }
                d0 += ddelta
                s0 += sdelta
@@ -237,7 +241,9 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
 }
 
 func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-       xMax := r.Max.X - dst.Rect.Min.X
+       i0 := (r.Min.X - dst.Rect.Min.X) * 4
+       i1 := (r.Max.X - dst.Rect.Min.X) * 4
+       si0 := (sp.X - src.Rect.Min.X) * 4
        yMax := r.Max.Y - dst.Rect.Min.Y
 
        y := r.Min.Y - dst.Rect.Min.Y
@@ -246,63 +252,58 @@ func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp imag
                dpix := dst.Pix[y*dst.Stride:]
                spix := src.Pix[sy*src.Stride:]
 
-               x := r.Min.X - dst.Rect.Min.X
-               sx := sp.X - src.Rect.Min.X
-               for ; x != xMax; x, sx = x+1, sx+1 {
+               for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
                        // Convert from non-premultiplied color to pre-multiplied color.
-                       // The order of operations here is to match the NRGBAColor.RGBA
-                       // method in image/color.go.
-                       snrgba := spix[sx]
-                       sa := uint32(snrgba.A)
-                       sr := uint32(snrgba.R) * 0x101 * sa / 0xff
-                       sg := uint32(snrgba.G) * 0x101 * sa / 0xff
-                       sb := uint32(snrgba.B) * 0x101 * sa / 0xff
-                       sa *= 0x101
-
-                       rgba := dpix[x]
-                       dr := uint32(rgba.R)
-                       dg := uint32(rgba.G)
-                       db := uint32(rgba.B)
-                       da := uint32(rgba.A)
+                       sa := uint32(spix[si+3]) * 0x101
+                       sr := uint32(spix[si+0]) * sa / 0xff
+                       sg := uint32(spix[si+1]) * sa / 0xff
+                       sb := uint32(spix[si+2]) * sa / 0xff
+
+                       dr := uint32(dpix[i+0])
+                       dg := uint32(dpix[i+1])
+                       db := uint32(dpix[i+2])
+                       da := uint32(dpix[i+3])
+
+                       // The 0x101 is here for the same reason as in drawRGBA.
                        a := (m - sa) * 0x101
-                       dr = (dr*a + sr*m) / m
-                       dg = (dg*a + sg*m) / m
-                       db = (db*a + sb*m) / m
-                       da = (da*a + sa*m) / m
-                       dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+
+                       dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+                       dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+                       dpix[i+2] = uint8((db*a/m + sb) >> 8)
+                       dpix[i+3] = uint8((da*a/m + sa) >> 8)
                }
        }
 }
 
 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
-       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
-       i1 := i0 + r.Dx()
-       j0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
-       cr, cg, cb, ca := src.RGBA()
+       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       i1 := i0 + r.Dx()*4
+       mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+       sr, sg, sb, sa := src.RGBA()
        for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
-               dpix := dst.Pix[i0:i1]
-               mpix := mask.Pix[j0:]
-               for i, rgba := range dpix {
-                       ma := uint32(mpix[i].A)
+               for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
+                       ma := uint32(mask.Pix[mi])
                        if ma == 0 {
                                continue
                        }
                        ma |= ma << 8
-                       dr := uint32(rgba.R)
-                       dg := uint32(rgba.G)
-                       db := uint32(rgba.B)
-                       da := uint32(rgba.A)
+
+                       dr := uint32(dst.Pix[i+0])
+                       dg := uint32(dst.Pix[i+1])
+                       db := uint32(dst.Pix[i+2])
+                       da := uint32(dst.Pix[i+3])
+
                        // The 0x101 is here for the same reason as in drawRGBA.
-                       a := (m - (ca * ma / m)) * 0x101
-                       dr = (dr*a + cr*ma) / m
-                       dg = (dg*a + cg*ma) / m
-                       db = (db*a + cb*ma) / m
-                       da = (da*a + ca*ma) / m
-                       dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+                       a := (m - (sa * ma / m)) * 0x101
+
+                       dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+                       dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+                       dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+                       dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
                }
                i0 += dst.Stride
                i1 += dst.Stride
-               j0 += mask.Stride
+               mi0 += mask.Stride
        }
 }
 
@@ -310,17 +311,19 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
        if r.Dy() < 1 {
                return
        }
-       cr, cg, cb, ca := src.RGBA()
-       color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)}
+       sr, sg, sb, sa := src.RGBA()
        // The built-in copy function is faster than a straightforward for loop to fill the destination with
        // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
        // then use the first row as the slice source for the remaining rows.
-       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
-       i1 := i0 + r.Dx()
-       firstRow := dst.Pix[i0:i1]
-       for i := range firstRow {
-               firstRow[i] = color
+       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       i1 := i0 + r.Dx()*4
+       for i := i0; i < i1; i += 4 {
+               dst.Pix[i+0] = uint8(sr >> 8)
+               dst.Pix[i+1] = uint8(sg >> 8)
+               dst.Pix[i+2] = uint8(sb >> 8)
+               dst.Pix[i+3] = uint8(sa >> 8)
        }
+       firstRow := dst.Pix[i0:i1]
        for y := r.Min.Y + 1; y < r.Max.Y; y++ {
                i0 += dst.Stride
                i1 += dst.Stride
@@ -329,9 +332,9 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
 }
 
 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
-       dx, dy := r.Dx(), r.Dy()
-       d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
-       s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + sp.X - src.Rect.Min.X
+       n, dy := 4*r.Dx(), r.Dy()
+       d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
        var ddelta, sdelta int
        if r.Min.Y <= sp.Y {
                ddelta = dst.Stride
@@ -346,14 +349,16 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
                sdelta = -src.Stride
        }
        for ; dy > 0; dy-- {
-               copy(dst.Pix[d0:d0+dx], src.Pix[s0:s0+dx])
+               copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
                d0 += ddelta
                s0 += sdelta
        }
 }
 
 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-       xMax := r.Max.X - dst.Rect.Min.X
+       i0 := (r.Min.X - dst.Rect.Min.X) * 4
+       i1 := (r.Max.X - dst.Rect.Min.X) * 4
+       si0 := (sp.X - src.Rect.Min.X) * 4
        yMax := r.Max.Y - dst.Rect.Min.Y
 
        y := r.Min.Y - dst.Rect.Min.Y
@@ -362,20 +367,17 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
                dpix := dst.Pix[y*dst.Stride:]
                spix := src.Pix[sy*src.Stride:]
 
-               x := r.Min.X - dst.Rect.Min.X
-               sx := sp.X - src.Rect.Min.X
-               for ; x != xMax; x, sx = x+1, sx+1 {
+               for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
                        // Convert from non-premultiplied color to pre-multiplied color.
-                       // The order of operations here is to match the NRGBAColor.RGBA
-                       // method in image/color.go.
-                       snrgba := spix[sx]
-                       sa := uint32(snrgba.A)
-                       sr := uint32(snrgba.R) * 0x101 * sa / 0xff
-                       sg := uint32(snrgba.G) * 0x101 * sa / 0xff
-                       sb := uint32(snrgba.B) * 0x101 * sa / 0xff
-                       sa *= 0x101
-
-                       dpix[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)}
+                       sa := uint32(spix[si+3]) * 0x101
+                       sr := uint32(spix[si+0]) * sa / 0xff
+                       sg := uint32(spix[si+1]) * sa / 0xff
+                       sb := uint32(spix[si+2]) * sa / 0xff
+
+                       dpix[i+0] = uint8(sr >> 8)
+                       dpix[i+1] = uint8(sg >> 8)
+                       dpix[i+2] = uint8(sb >> 8)
+                       dpix[i+3] = uint8(sa >> 8)
                }
        }
 }
@@ -385,47 +387,55 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
        // (i.e. fully opaque) then the op is effectively always Src.
        var (
                yy, cb, cr uint8
-               rr, gg, bb uint8
        )
-       x0 := r.Min.X - dst.Rect.Min.X
-       x1 := r.Max.X - dst.Rect.Min.X
+       x0 := (r.Min.X - dst.Rect.Min.X) * 4
+       x1 := (r.Max.X - dst.Rect.Min.X) * 4
        y0 := r.Min.Y - dst.Rect.Min.Y
        y1 := r.Max.Y - dst.Rect.Min.Y
        switch src.SubsampleRatio {
        case ycbcr.SubsampleRatio422:
                for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
                        dpix := dst.Pix[y*dst.Stride:]
-                       for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+                       for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
                                i := sx / 2
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[sy*src.CStride+i]
                                cr = src.Cr[sy*src.CStride+i]
-                               rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-                               dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               dpix[x+0] = rr
+                               dpix[x+1] = gg
+                               dpix[x+2] = bb
+                               dpix[x+3] = 255
                        }
                }
        case ycbcr.SubsampleRatio420:
                for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
                        dpix := dst.Pix[y*dst.Stride:]
-                       for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+                       for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
                                i, j := sx/2, sy/2
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[j*src.CStride+i]
                                cr = src.Cr[j*src.CStride+i]
-                               rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-                               dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               dpix[x+0] = rr
+                               dpix[x+1] = gg
+                               dpix[x+2] = bb
+                               dpix[x+3] = 255
                        }
                }
        default:
                // Default to 4:4:4 subsampling.
                for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
                        dpix := dst.Pix[y*dst.Stride:]
-                       for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
+                       for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[sy*src.CStride+sx]
                                cr = src.Cr[sy*src.CStride+sx]
-                               rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
-                               dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               dpix[x+0] = rr
+                               dpix[x+1] = gg
+                               dpix[x+2] = bb
+                               dpix[x+3] = 255
                        }
                }
        }
@@ -445,22 +455,22 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
        my := mp.Y + y0 - r.Min.Y
        sx0 := sp.X + x0 - r.Min.X
        mx0 := mp.X + x0 - r.Min.X
-       i0 := (y0 - dst.Rect.Min.Y) * dst.Stride
+       sx1 := sx0 + (x1 - x0)
+       i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+       di := dx * 4
        for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
-               dpix := dst.Pix[i0:]
-               for x, sx, mx := x0, sx0, mx0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+               for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
                        ma := uint32(m)
                        if mask != nil {
                                _, _, _, ma = mask.At(mx, my).RGBA()
                        }
                        sr, sg, sb, sa := src.At(sx, sy).RGBA()
-                       var dr, dg, db, da uint32
                        if op == Over {
-                               rgba := dpix[x-dst.Rect.Min.X]
-                               dr = uint32(rgba.R)
-                               dg = uint32(rgba.G)
-                               db = uint32(rgba.B)
-                               da = uint32(rgba.A)
+                               dr := uint32(dst.Pix[i+0])
+                               dg := uint32(dst.Pix[i+1])
+                               db := uint32(dst.Pix[i+2])
+                               da := uint32(dst.Pix[i+3])
+
                                // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
                                // We work in 16-bit color, and so would normally do:
                                // dr |= dr << 8
@@ -468,17 +478,18 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
                                // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
                                // This yields the same result, but is fewer arithmetic operations.
                                a := (m - (sa * ma / m)) * 0x101
-                               dr = (dr*a + sr*ma) / m
-                               dg = (dg*a + sg*ma) / m
-                               db = (db*a + sb*ma) / m
-                               da = (da*a + sa*ma) / m
+
+                               dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+                               dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+                               dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+                               dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+
                        } else {
-                               dr = sr * ma / m
-                               dg = sg * ma / m
-                               db = sb * ma / m
-                               da = sa * ma / m
+                               dst.Pix[i+0] = uint8(sr * ma / m >> 8)
+                               dst.Pix[i+1] = uint8(sg * ma / m >> 8)
+                               dst.Pix[i+2] = uint8(sb * ma / m >> 8)
+                               dst.Pix[i+3] = uint8(sa * ma / m >> 8)
                        }
-                       dpix[x-dst.Rect.Min.X] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
                }
                i0 += dy * dst.Stride
        }
index f2726d7d8ed1fe36f097cc7b4a1d0f93914ccb03..11def94354ad9570d435f7793388b8454332d9a9 100644 (file)
@@ -5,13 +5,13 @@
 // Package image implements a basic 2-D image library.
 package image
 
-// A Config consists of an image's color model and dimensions.
+// Config holds an image's color model and dimensions.
 type Config struct {
        ColorModel    ColorModel
        Width, Height int
 }
 
-// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
+// Image is a finite rectangular grid of Colors drawn from a ColorModel.
 type Image interface {
        // ColorModel returns the Image's ColorModel.
        ColorModel() ColorModel
@@ -24,11 +24,12 @@ type Image interface {
        At(x, y int) Color
 }
 
-// An RGBA is an in-memory image of RGBAColor values.
+// RGBA is an in-memory image of RGBAColor values.
 type RGBA struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []RGBAColor
+       // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -42,24 +43,31 @@ func (p *RGBA) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return RGBAColor{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
 func (p *RGBA) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toRGBAColor(c).(RGBAColor)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       c1 := toRGBAColor(c).(RGBAColor)
+       p.Pix[i+0] = c1.R
+       p.Pix[i+1] = c1.G
+       p.Pix[i+2] = c1.B
+       p.Pix[i+3] = c1.A
 }
 
 func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       p.Pix[i+0] = c.R
+       p.Pix[i+1] = c.G
+       p.Pix[i+2] = c.B
+       p.Pix[i+3] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -72,7 +80,7 @@ func (p *RGBA) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &RGBA{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
        return &RGBA{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -85,10 +93,10 @@ func (p *RGBA) Opaque() bool {
        if p.Rect.Empty() {
                return true
        }
-       i0, i1 := 0, p.Rect.Dx()
+       i0, i1 := 3, p.Rect.Dx()*4
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xff {
+               for i := i0; i < i1; i += 4 {
+                       if p.Pix[i] != 0xff {
                                return false
                        }
                }
@@ -100,15 +108,16 @@ func (p *RGBA) Opaque() bool {
 
 // NewRGBA returns a new RGBA with the given width and height.
 func NewRGBA(w, h int) *RGBA {
-       buf := make([]RGBAColor, w*h)
-       return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
+       buf := make([]uint8, 4*w*h)
+       return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An RGBA64 is an in-memory image of RGBA64Color values.
+// RGBA64 is an in-memory image of RGBA64Color values.
 type RGBA64 struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []RGBA64Color
+       // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -122,24 +131,44 @@ func (p *RGBA64) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return RGBA64Color{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       return RGBA64Color{
+               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]),
+               uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+       }
 }
 
 func (p *RGBA64) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toRGBA64Color(c).(RGBA64Color)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       c1 := toRGBA64Color(c).(RGBA64Color)
+       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)
+       p.Pix[i+6] = uint8(c1.A >> 8)
+       p.Pix[i+7] = uint8(c1.A)
 }
 
 func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       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)
+       p.Pix[i+6] = uint8(c.A >> 8)
+       p.Pix[i+7] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -152,7 +181,7 @@ func (p *RGBA64) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &RGBA64{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
        return &RGBA64{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -165,10 +194,10 @@ func (p *RGBA64) Opaque() bool {
        if p.Rect.Empty() {
                return true
        }
-       i0, i1 := 0, p.Rect.Dx()
+       i0, i1 := 6, p.Rect.Dx()*8
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xffff {
+               for i := i0; i < i1; i += 8 {
+                       if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
                                return false
                        }
                }
@@ -180,15 +209,16 @@ func (p *RGBA64) Opaque() bool {
 
 // NewRGBA64 returns a new RGBA64 with the given width and height.
 func NewRGBA64(w, h int) *RGBA64 {
-       pix := make([]RGBA64Color, w*h)
-       return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 8*w*h)
+       return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An NRGBA is an in-memory image of NRGBAColor values.
+// NRGBA is an in-memory image of NRGBAColor values.
 type NRGBA struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []NRGBAColor
+       // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -202,24 +232,31 @@ func (p *NRGBA) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return NRGBAColor{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
 func (p *NRGBA) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toNRGBAColor(c).(NRGBAColor)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       c1 := toNRGBAColor(c).(NRGBAColor)
+       p.Pix[i+0] = c1.R
+       p.Pix[i+1] = c1.G
+       p.Pix[i+2] = c1.B
+       p.Pix[i+3] = c1.A
 }
 
 func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       p.Pix[i+0] = c.R
+       p.Pix[i+1] = c.G
+       p.Pix[i+2] = c.B
+       p.Pix[i+3] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -232,7 +269,7 @@ func (p *NRGBA) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &NRGBA{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
        return &NRGBA{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -245,10 +282,10 @@ func (p *NRGBA) Opaque() bool {
        if p.Rect.Empty() {
                return true
        }
-       i0, i1 := 0, p.Rect.Dx()
+       i0, i1 := 3, p.Rect.Dx()*4
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xff {
+               for i := i0; i < i1; i += 4 {
+                       if p.Pix[i] != 0xff {
                                return false
                        }
                }
@@ -260,15 +297,16 @@ func (p *NRGBA) Opaque() bool {
 
 // NewNRGBA returns a new NRGBA with the given width and height.
 func NewNRGBA(w, h int) *NRGBA {
-       pix := make([]NRGBAColor, w*h)
-       return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 4*w*h)
+       return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An NRGBA64 is an in-memory image of NRGBA64Color values.
+// NRGBA64 is an in-memory image of NRGBA64Color values.
 type NRGBA64 struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []NRGBA64Color
+       // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -282,24 +320,44 @@ func (p *NRGBA64) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return NRGBA64Color{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       return NRGBA64Color{
+               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]),
+               uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+       }
 }
 
 func (p *NRGBA64) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toNRGBA64Color(c).(NRGBA64Color)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       c1 := toNRGBA64Color(c).(NRGBA64Color)
+       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)
+       p.Pix[i+6] = uint8(c1.A >> 8)
+       p.Pix[i+7] = uint8(c1.A)
 }
 
 func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       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)
+       p.Pix[i+6] = uint8(c.A >> 8)
+       p.Pix[i+7] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -312,7 +370,7 @@ func (p *NRGBA64) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &NRGBA64{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
        return &NRGBA64{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -325,10 +383,10 @@ func (p *NRGBA64) Opaque() bool {
        if p.Rect.Empty() {
                return true
        }
-       i0, i1 := 0, p.Rect.Dx()
+       i0, i1 := 6, p.Rect.Dx()*8
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xffff {
+               for i := i0; i < i1; i += 8 {
+                       if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
                                return false
                        }
                }
@@ -340,15 +398,16 @@ func (p *NRGBA64) Opaque() bool {
 
 // NewNRGBA64 returns a new NRGBA64 with the given width and height.
 func NewNRGBA64(w, h int) *NRGBA64 {
-       pix := make([]NRGBA64Color, w*h)
-       return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 8*w*h)
+       return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An Alpha is an in-memory image of AlphaColor values.
+// Alpha is an in-memory image of AlphaColor values.
 type Alpha struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []AlphaColor
+       // Pix holds the image's pixels, as alpha values. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -363,7 +422,7 @@ func (p *Alpha) At(x, y int) Color {
                return AlphaColor{}
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       return AlphaColor{p.Pix[i]}
 }
 
 func (p *Alpha) Set(x, y int, c Color) {
@@ -371,7 +430,7 @@ func (p *Alpha) Set(x, y int, c Color) {
                return
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toAlphaColor(c).(AlphaColor)
+       p.Pix[i] = toAlphaColor(c).(AlphaColor).A
 }
 
 func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
@@ -379,7 +438,7 @@ func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
                return
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       p.Pix[i] = c.A
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -392,7 +451,7 @@ func (p *Alpha) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &Alpha{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
        return &Alpha{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -407,8 +466,8 @@ func (p *Alpha) Opaque() bool {
        }
        i0, i1 := 0, p.Rect.Dx()
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xff {
+               for i := i0; i < i1; i++ {
+                       if p.Pix[i] != 0xff {
                                return false
                        }
                }
@@ -420,15 +479,16 @@ func (p *Alpha) Opaque() bool {
 
 // NewAlpha returns a new Alpha with the given width and height.
 func NewAlpha(w, h int) *Alpha {
-       pix := make([]AlphaColor, w*h)
-       return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 1*w*h)
+       return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// An Alpha16 is an in-memory image of Alpha16Color values.
+// Alpha16 is an in-memory image of Alpha16Color values.
 type Alpha16 struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []Alpha16Color
+       // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -442,24 +502,27 @@ func (p *Alpha16) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return Alpha16Color{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
 func (p *Alpha16) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toAlpha16Color(c).(Alpha16Color)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       c1 := toAlpha16Color(c).(Alpha16Color)
+       p.Pix[i+0] = uint8(c1.A >> 8)
+       p.Pix[i+1] = uint8(c1.A)
 }
 
 func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       p.Pix[i+0] = uint8(c.A >> 8)
+       p.Pix[i+1] = uint8(c.A)
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -472,7 +535,7 @@ func (p *Alpha16) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &Alpha16{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
        return &Alpha16{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -485,10 +548,10 @@ func (p *Alpha16) Opaque() bool {
        if p.Rect.Empty() {
                return true
        }
-       i0, i1 := 0, p.Rect.Dx()
+       i0, i1 := 0, p.Rect.Dx()*2
        for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
-               for _, c := range p.Pix[i0:i1] {
-                       if c.A != 0xffff {
+               for i := i0; i < i1; i += 2 {
+                       if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
                                return false
                        }
                }
@@ -500,15 +563,16 @@ func (p *Alpha16) Opaque() bool {
 
 // NewAlpha16 returns a new Alpha16 with the given width and height.
 func NewAlpha16(w, h int) *Alpha16 {
-       pix := make([]Alpha16Color, w*h)
-       return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 2*w*h)
+       return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// Gray is an in-memory image of GrayColor values.
+// Gray is an in-memory image of GrayColor values.
 type Gray struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []GrayColor
+       // Pix holds the image's pixels, as gray values. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -523,7 +587,7 @@ func (p *Gray) At(x, y int) Color {
                return GrayColor{}
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       return GrayColor{p.Pix[i]}
 }
 
 func (p *Gray) Set(x, y int, c Color) {
@@ -531,7 +595,7 @@ func (p *Gray) Set(x, y int, c Color) {
                return
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toGrayColor(c).(GrayColor)
+       p.Pix[i] = toGrayColor(c).(GrayColor).Y
 }
 
 func (p *Gray) SetGray(x, y int, c GrayColor) {
@@ -539,7 +603,7 @@ func (p *Gray) SetGray(x, y int, c GrayColor) {
                return
        }
        i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       p.Pix[i] = c.Y
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -552,7 +616,7 @@ func (p *Gray) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &Gray{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
        return &Gray{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -567,15 +631,16 @@ func (p *Gray) Opaque() bool {
 
 // NewGray returns a new Gray with the given width and height.
 func NewGray(w, h int) *Gray {
-       pix := make([]GrayColor, w*h)
-       return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 1*w*h)
+       return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
 }
 
-// Gray16 is an in-memory image of Gray16Color values.
+// Gray16 is an in-memory image of Gray16Color values.
 type Gray16 struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []Gray16Color
+       // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -589,24 +654,27 @@ func (p *Gray16) At(x, y int) Color {
        if !(Point{x, y}.In(p.Rect)) {
                return Gray16Color{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       return p.Pix[i]
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
 func (p *Gray16) Set(x, y int, c Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = toGray16Color(c).(Gray16Color)
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       c1 := toGray16Color(c).(Gray16Color)
+       p.Pix[i+0] = uint8(c1.Y >> 8)
+       p.Pix[i+1] = uint8(c1.Y)
 }
 
 func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
-       p.Pix[i] = c
+       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       p.Pix[i+0] = uint8(c.Y >> 8)
+       p.Pix[i+1] = uint8(c.Y)
 }
 
 // SubImage returns an image representing the portion of the image p visible
@@ -619,7 +687,7 @@ func (p *Gray16) SubImage(r Rectangle) Image {
        if r.Empty() {
                return &Gray16{}
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
        return &Gray16{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -634,8 +702,8 @@ func (p *Gray16) Opaque() bool {
 
 // NewGray16 returns a new Gray16 with the given width and height.
 func NewGray16(w, h int) *Gray16 {
-       pix := make([]Gray16Color, w*h)
-       return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
+       pix := make([]uint8, 2*w*h)
+       return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
 }
 
 // A PalettedColorModel represents a fixed palette of at most 256 colors.
@@ -679,11 +747,12 @@ func (p PalettedColorModel) Index(c Color) int {
        return ret
 }
 
-// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+// Paletted is an in-memory image of uint8 indices into a given palette.
 type Paletted struct {
-       // Pix holds the image's pixels. The pixel at (x, y) is
-       // Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
-       Pix    []uint8
+       // Pix holds the image's pixels, as palette indices. The pixel at
+       // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+       Pix []uint8
+       // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
        Stride int
        // Rect is the image's bounds.
        Rect Rectangle
@@ -742,7 +811,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
                        Palette: p.Palette,
                }
        }
-       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
+       i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
        return &Paletted{
                Pix:     p.Pix[i:],
                Stride:  p.Stride,
@@ -776,6 +845,6 @@ func (p *Paletted) Opaque() bool {
 
 // NewPaletted returns a new Paletted with the given width, height and palette.
 func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
-       pix := make([]uint8, w*h)
-       return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
+       pix := make([]uint8, 1*w*h)
+       return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
 }
index 8798919637bc5a2e2059cdacf77191ed6577b0ea..3f22c5271f317699d062167a0e1f59b5b3c6dbf4 100644 (file)
@@ -319,16 +319,7 @@ func (d *decoder) processSOS(n int) os.Error {
 
                                        // Perform the inverse DCT and store the MCU component to the image.
                                        if d.nComp == nGrayComponent {
-                                               idct(d.tmp[:64], 8, &b)
-                                               // Convert from []uint8 to []image.GrayColor.
-                                               p := d.img1.Pix[8*(my*d.img1.Stride+mx):]
-                                               for y := 0; y < 8; y++ {
-                                                       dst := p[y*d.img1.Stride:]
-                                                       src := d.tmp[8*y:]
-                                                       for x := 0; x < 8; x++ {
-                                                               dst[x] = image.GrayColor{src[x]}
-                                                       }
-                                               }
+                                               idct(d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride, &b)
                                        } else {
                                                switch i {
                                                case 0:
index 76a85adb058c34cdac48d9c84bfb27237a26a224..2bb6df5dd1b3eea565cd86402d40c766d56d3472 100644 (file)
@@ -397,14 +397,14 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
                if sj > ymax {
                        sj = ymax
                }
-               offset := (sj-b.Min.Y)*m.Stride - b.Min.X
+               offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
                for i := 0; i < 8; i++ {
                        sx := p.X + i
                        if sx > xmax {
                                sx = xmax
                        }
-                       col := &m.Pix[offset+sx]
-                       yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+                       pix := m.Pix[offset+sx*4:]
+                       yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
                        yBlock[8*j+i] = int(yy)
                        cbBlock[8*j+i] = int(cb)
                        crBlock[8*j+i] = int(cr)
index 81d402fc9fb4e091c613c45d0fae18ac69929b9f..55ca97e0628ed98dd2da24be53cd4c5665b6f800 100644 (file)
@@ -275,11 +275,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 
        bpp := 0 // Bytes per pixel.
 
-       // Used by fast paths for common image types
-       var paletted *image.Paletted
-       var rgba *image.RGBA
-       rgba, _ = m.(*image.RGBA)
-
        switch cb {
        case cbG8:
                bpp = 1
@@ -287,7 +282,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
                bpp = 3
        case cbP8:
                bpp = 1
-               paletted = m.(*image.Paletted)
        case cbTCA8:
                bpp = 4
        case cbTC16:
@@ -323,12 +317,13 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
                case cbTC8:
                        // We have previously verified that the alpha value is fully opaque.
                        cr0 := cr[0]
-                       if rgba != nil {
-                               offset := (y - b.Min.Y) * rgba.Stride
-                               for _, color := range rgba.Pix[offset : offset+b.Dx()] {
-                                       cr0[i+0] = color.R
-                                       cr0[i+1] = color.G
-                                       cr0[i+2] = color.B
+                       if rgba, _ := m.(*image.RGBA); rgba != nil {
+                               j0 := (y - b.Min.Y) * rgba.Stride
+                               j1 := j0 + b.Dx()*4
+                               for j := j0; j < j1; j += 4 {
+                                       cr0[i+0] = rgba.Pix[j+0]
+                                       cr0[i+1] = rgba.Pix[j+1]
+                                       cr0[i+2] = rgba.Pix[j+2]
                                        i += 3
                                }
                        } else {
@@ -341,6 +336,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
                                }
                        }
                case cbP8:
+                       paletted := m.(*image.Paletted)
                        offset := (y - b.Min.Y) * paletted.Stride
                        copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
                case cbTCA8: