From 87d9e7e166ade0902ef1f1cebaedfc475c2d3278 Mon Sep 17 00:00:00 2001
From: Nigel Tao <nigeltao@golang.org>
Date: Sun, 10 Jul 2011 14:29:47 +1000
Subject: [PATCH] image: change Pix[0] to mean top-left corner of an image's
 Rect instead of the origin.

image/png and image/jpeg benchmarks show no significant changes.

The image/draw changes suggest to me that making a gofix for this is not
feasible. People are just going to have to make manual fixes.

R=r
CC=golang-dev
https://golang.org/cl/4681044
---
 src/pkg/exp/gui/x11/conn.go      |  64 ++++-----
 src/pkg/image/draw/draw.go       | 155 ++++++++++----------
 src/pkg/image/image.go           | 240 ++++++++++++++++++++++---------
 src/pkg/image/image_test.go      |   5 +
 src/pkg/image/jpeg/reader.go     |   4 +-
 src/pkg/image/jpeg/writer.go     |   4 +-
 src/pkg/image/png/writer.go      |   8 +-
 src/pkg/image/png/writer_test.go |   4 +-
 8 files changed, 299 insertions(+), 185 deletions(-)

diff --git a/src/pkg/exp/gui/x11/conn.go b/src/pkg/exp/gui/x11/conn.go
index bc7ca63dbf..420bdd82a7 100644
--- a/src/pkg/exp/gui/x11/conn.go
+++ b/src/pkg/exp/gui/x11/conn.go
@@ -85,15 +85,15 @@ func (c *conn) writeSocket() {
 
 		for y := b.Min.Y; y < b.Max.Y; y++ {
 			setU32LE(c.flushBuf0[16:20], uint32(y<<16))
-			if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil {
+			if _, err := c.w.Write(c.flushBuf0[:24]); err != nil {
 				if err != os.EOF {
 					log.Println("x11:", err.String())
 				}
 				return
 			}
-			p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride]
-			for x := b.Min.X; x < b.Max.X; {
-				nx := b.Max.X - x
+			p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
+			for x, dx := 0, b.Dx(); x < dx; {
+				nx := dx - x
 				if nx > len(c.flushBuf1)/4 {
 					nx = len(c.flushBuf1) / 4
 				}
@@ -103,7 +103,7 @@ func (c *conn) writeSocket() {
 					c.flushBuf1[4*i+2] = rgba.R
 				}
 				x += nx
-				if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+				if _, err := c.w.Write(c.flushBuf1[:4*nx]); err != nil {
 					if err != os.EOF {
 						log.Println("x11:", err.String())
 					}
@@ -154,7 +154,7 @@ func (c *conn) readSocket() {
 	defer close(c.eventc)
 	for {
 		// X events are always 32 bytes long.
-		if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
+		if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil {
 			if err != os.EOF {
 				c.eventc <- gui.ErrEvent{err}
 			}
@@ -177,7 +177,7 @@ func (c *conn) readSocket() {
 			for i := keymapLo; i <= keymapHi; i++ {
 				m := keymap[i]
 				for j := range m {
-					u, err := readU32LE(c.r, c.buf[0:4])
+					u, err := readU32LE(c.r, c.buf[:4])
 					if err != nil {
 						if err != os.EOF {
 							c.eventc <- gui.ErrEvent{err}
@@ -260,14 +260,14 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
 	// Parse the section before the colon.
 	var protocol, host, socket string
 	if display[0] == '/' {
-		socket = display[0:colonIdx]
+		socket = display[:colonIdx]
 	} else {
 		if i := strings.LastIndex(display, "/"); i < 0 {
 			// The default protocol is TCP.
 			protocol = "tcp"
-			host = display[0:colonIdx]
+			host = display[:colonIdx]
 		} else {
-			protocol = display[0:i]
+			protocol = display[:i]
 			host = display[i+1 : colonIdx]
 		}
 	}
@@ -279,7 +279,7 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
 	if i := strings.LastIndex(after, "."); i < 0 {
 		displayStr = after
 	} else {
-		displayStr = after[0:i]
+		displayStr = after[:i]
 	}
 	displayInt, err := strconv.Atoi(displayStr)
 	if err != nil || displayInt < 0 {
@@ -339,7 +339,7 @@ func authenticate(w *bufio.Writer, displayStr string) os.Error {
 
 // readU8 reads a uint8 from r, using b as a scratch buffer.
 func readU8(r io.Reader, b []byte) (uint8, os.Error) {
-	_, err := io.ReadFull(r, b[0:1])
+	_, err := io.ReadFull(r, b[:1])
 	if err != nil {
 		return 0, err
 	}
@@ -348,7 +348,7 @@ func readU8(r io.Reader, b []byte) (uint8, os.Error) {
 
 // readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
 func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
-	_, err := io.ReadFull(r, b[0:2])
+	_, err := io.ReadFull(r, b[:2])
 	if err != nil {
 		return 0, err
 	}
@@ -357,14 +357,14 @@ func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
 
 // readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
 func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
-	_, err := io.ReadFull(r, b[0:4])
+	_, err := io.ReadFull(r, b[:4])
 	if err != nil {
 		return 0, err
 	}
 	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
 }
 
-// setU32LE sets b[0:4] to be the little-endian representation of u.
+// setU32LE sets b[:4] to be the little-endian representation of u.
 func setU32LE(b []byte, u uint32) {
 	b[0] = byte((u >> 0) & 0xff)
 	b[1] = byte((u >> 8) & 0xff)
@@ -375,7 +375,7 @@ func setU32LE(b []byte, u uint32) {
 // checkPixmapFormats checks that we have an agreeable X pixmap Format.
 func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
 	for i := 0; i < n; i++ {
-		_, err = io.ReadFull(r, b[0:8])
+		_, err = io.ReadFull(r, b[:8])
 		if err != nil {
 			return
 		}
@@ -400,7 +400,7 @@ func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err o
 			return
 		}
 		// Ignore 4 bytes of padding.
-		_, err = io.ReadFull(r, b[0:4])
+		_, err = io.ReadFull(r, b[:4])
 		if err != nil {
 			return
 		}
@@ -433,7 +433,7 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
 		}
 		// Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
 		// width and height (pixels), width and height (mm), min and max installed maps.
-		_, err = io.ReadFull(r, b[0:28])
+		_, err = io.ReadFull(r, b[:28])
 		if err != nil {
 			return
 		}
@@ -462,26 +462,26 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
 // handshake performs the protocol handshake with the X server, and ensures
 // that the server provides a compatible Screen, Depth, etc.
 func (c *conn) handshake() os.Error {
-	_, err := io.ReadFull(c.r, c.buf[0:8])
+	_, err := io.ReadFull(c.r, c.buf[:8])
 	if err != nil {
 		return err
 	}
-	// Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+	// Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
 	if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
 		return os.NewError("unsupported X version")
 	}
 	// Ignore the release number.
-	_, err = io.ReadFull(c.r, c.buf[0:4])
+	_, err = io.ReadFull(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the resource ID base.
-	resourceIdBase, err := readU32LE(c.r, c.buf[0:4])
+	resourceIdBase, err := readU32LE(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the resource ID mask.
-	resourceIdMask, err := readU32LE(c.r, c.buf[0:4])
+	resourceIdMask, err := readU32LE(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
@@ -489,19 +489,19 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("X resource ID mask is too small")
 	}
 	// Ignore the motion buffer size.
-	_, err = io.ReadFull(c.r, c.buf[0:4])
+	_, err = io.ReadFull(c.r, c.buf[:4])
 	if err != nil {
 		return err
 	}
 	// Read the vendor length and round it up to a multiple of 4,
 	// for X11 protocol alignment reasons.
-	vendorLen, err := readU16LE(c.r, c.buf[0:2])
+	vendorLen, err := readU16LE(c.r, c.buf[:2])
 	if err != nil {
 		return err
 	}
 	vendorLen = (vendorLen + 3) &^ 3
 	// Read the maximum request length.
-	maxReqLen, err := readU16LE(c.r, c.buf[0:2])
+	maxReqLen, err := readU16LE(c.r, c.buf[:2])
 	if err != nil {
 		return err
 	}
@@ -509,12 +509,12 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("unsupported X maximum request length")
 	}
 	// Read the roots length.
-	rootsLen, err := readU8(c.r, c.buf[0:1])
+	rootsLen, err := readU8(c.r, c.buf[:1])
 	if err != nil {
 		return err
 	}
 	// Read the pixmap formats length.
-	pixmapFormatsLen, err := readU8(c.r, c.buf[0:1])
+	pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
 	if err != nil {
 		return err
 	}
@@ -524,12 +524,12 @@ func (c *conn) handshake() os.Error {
 	if 10+int(vendorLen) > cap(c.buf) {
 		return os.NewError("unsupported X vendor")
 	}
-	_, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
+	_, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
 	if err != nil {
 		return err
 	}
 	// Check that we have an agreeable pixmap format.
-	agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen))
+	agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
 	if err != nil {
 		return err
 	}
@@ -537,7 +537,7 @@ func (c *conn) handshake() os.Error {
 		return os.NewError("unsupported X pixmap formats")
 	}
 	// Check that we have an agreeable screen.
-	root, visual, err := checkScreens(c.r, c.buf[0:24], int(rootsLen))
+	root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
 	if err != nil {
 		return err
 	}
@@ -608,7 +608,7 @@ func NewWindowDisplay(display string) (gui.Window, os.Error) {
 	setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
 	setU32LE(c.buf[76:80], uint32(c.window))
 	// Write the bytes.
-	_, err = c.w.Write(c.buf[0:80])
+	_, err = c.w.Write(c.buf[:80])
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
index 0ab7b59ab7..5c4dedb818 100644
--- a/src/pkg/image/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -173,11 +173,10 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
 	cr, cg, cb, ca := src.RGBA()
 	// The 0x101 is here for the same reason as in drawRGBA.
 	a := (m - ca) * 0x101
-	x0, x1 := r.Min.X, r.Max.X
-	y0, y1 := r.Min.Y, r.Max.Y
-	for y := y0; y != y1; y++ {
-		dbase := y * dst.Stride
-		dpix := dst.Pix[dbase+x0 : dbase+x1]
+	i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + r.Min.X - dst.Rect.Min.X
+	i1 := i0 + r.Dx()
+	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
@@ -185,18 +184,15 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
 			da := (uint32(rgba.A)*a)/m + ca
 			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
 		}
+		i0 += dst.Stride
+		i1 += dst.Stride
 	}
 }
 
 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	nrows := dy1 - dy0
-	sx0, sx1 := sp.X, sp.X+dx1-dx0
-	d0 := dy0*dst.Stride + dx0
-	d1 := dy0*dst.Stride + dx1
-	s0 := sp.Y*src.Stride + sx0
-	s1 := sp.Y*src.Stride + sx1
+	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
 	var (
 		ddelta, sdelta int
 		i0, i1, idelta int
@@ -204,21 +200,19 @@ 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, d1-d0, +1
+		i0, i1, idelta = 0, dx, +1
 	} 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.
-		d0 += (nrows - 1) * dst.Stride
-		d1 += (nrows - 1) * dst.Stride
-		s0 += (nrows - 1) * src.Stride
-		s1 += (nrows - 1) * src.Stride
+		d0 += (dy - 1) * dst.Stride
+		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
 		sdelta = -src.Stride
-		i0, i1, idelta = d1-d0-1, -1, -1
+		i0, i1, idelta = dx-1, -1, -1
 	}
-	for ; nrows > 0; nrows-- {
-		dpix := dst.Pix[d0:d1]
-		spix := src.Pix[s0:s1]
+	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
@@ -238,17 +232,23 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
 			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
 		}
 		d0 += ddelta
-		d1 += ddelta
 		s0 += sdelta
-		s1 += sdelta
 	}
 }
 
 func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-	for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
-		for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+	xMax := r.Max.X - dst.Rect.Min.X
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		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 {
 			// 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.
@@ -275,14 +275,13 @@ func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp imag
 }
 
 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
-	x0, x1 := r.Min.X, r.Max.X
-	y0, y1 := r.Min.Y, r.Max.Y
+	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()
-	for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
-		dbase := y * dst.Stride
-		dpix := dst.Pix[dbase+x0 : dbase+x1]
-		mbase := my * mask.Stride
-		mpix := mask.Pix[mbase+mp.X:]
+	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)
 			if ma == 0 {
@@ -301,6 +300,9 @@ func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, ma
 			da = (da*a + ca*ma) / m
 			dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
 		}
+		i0 += dst.Stride
+		i1 += dst.Stride
+		j0 += mask.Stride
 	}
 }
 
@@ -313,15 +315,13 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
 	// 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.
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	dbase := dy0 * dst.Stride
-	i0, i1 := dbase+dx0, dbase+dx1
+	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
 	}
-	for y := dy0 + 1; y < dy1; y++ {
+	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
 		i0 += dst.Stride
 		i1 += dst.Stride
 		copy(dst.Pix[i0:i1], firstRow)
@@ -329,14 +329,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) {
-	dx0, dx1 := r.Min.X, r.Max.X
-	dy0, dy1 := r.Min.Y, r.Max.Y
-	nrows := dy1 - dy0
-	sx0, sx1 := sp.X, sp.X+dx1-dx0
-	d0 := dy0*dst.Stride + dx0
-	d1 := dy0*dst.Stride + dx1
-	s0 := sp.Y*src.Stride + sx0
-	s1 := sp.Y*src.Stride + sx1
+	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
 	var ddelta, sdelta int
 	if r.Min.Y <= sp.Y {
 		ddelta = dst.Stride
@@ -345,27 +340,31 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
 		// If the source start point is higher than the destination start point, then we compose the rows
 		// in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
 		// check the x co-ordinates because the built-in copy function can handle overlapping slices.
-		d0 += (nrows - 1) * dst.Stride
-		d1 += (nrows - 1) * dst.Stride
-		s0 += (nrows - 1) * src.Stride
-		s1 += (nrows - 1) * src.Stride
+		d0 += (dy - 1) * dst.Stride
+		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
 		sdelta = -src.Stride
 	}
-	for ; nrows > 0; nrows-- {
-		copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+	for ; dy > 0; dy-- {
+		copy(dst.Pix[d0:d0+dx], src.Pix[s0:s0+dx])
 		d0 += ddelta
-		d1 += ddelta
 		s0 += sdelta
-		s1 += sdelta
 	}
 }
 
 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
-	for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
-		for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+	xMax := r.Max.X - dst.Rect.Min.X
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		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 {
 			// 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.
@@ -388,11 +387,15 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
 		yy, cb, cr uint8
 		rr, gg, bb uint8
 	)
+	x0 := r.Min.X - dst.Rect.Min.X
+	x1 := r.Max.X - dst.Rect.Min.X
+	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 := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		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 {
 				i := sx / 2
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[sy*src.CStride+i]
@@ -402,9 +405,9 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
 			}
 		}
 	case ycbcr.SubsampleRatio420:
-		for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		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 {
 				i, j := sx/2, sy/2
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[j*src.CStride+i]
@@ -415,9 +418,9 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
 		}
 	default:
 		// Default to 4:4:4 subsampling.
-		for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-			for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+		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 {
 				yy = src.Y[sy*src.YStride+sx]
 				cb = src.Cb[sy*src.CStride+sx]
 				cr = src.Cr[sy*src.CStride+sx]
@@ -440,11 +443,12 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
 
 	sy := sp.Y + y0 - r.Min.Y
 	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
 	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
-		sx := sp.X + x0 - r.Min.X
-		mx := mp.X + x0 - r.Min.X
-		dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
-		for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
+		dpix := dst.Pix[i0:]
+		for x, sx, mx := x0, sx0, mx0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
 			ma := uint32(m)
 			if mask != nil {
 				_, _, _, ma = mask.At(mx, my).RGBA()
@@ -452,7 +456,7 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
 			sr, sg, sb, sa := src.At(sx, sy).RGBA()
 			var dr, dg, db, da uint32
 			if op == Over {
-				rgba := dpix[x]
+				rgba := dpix[x-dst.Rect.Min.X]
 				dr = uint32(rgba.R)
 				dg = uint32(rgba.G)
 				db = uint32(rgba.B)
@@ -474,7 +478,8 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
 				db = sb * ma / m
 				da = sa * ma / m
 			}
-			dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 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
 	}
 }
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 5ea302d0da..f2726d7d8e 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -26,7 +26,8 @@ type Image interface {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []RGBAColor
 	Stride int
 	// Rect is the image's bounds.
@@ -41,30 +42,41 @@ func (p *RGBA) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return RGBAColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *RGBA) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toRGBAColor(c).(RGBAColor)
 }
 
 func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *RGBA) 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 &RGBA{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &RGBA{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -73,8 +85,7 @@ func (p *RGBA) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 {
@@ -95,7 +106,8 @@ func NewRGBA(w, h int) *RGBA {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []RGBA64Color
 	Stride int
 	// Rect is the image's bounds.
@@ -110,30 +122,41 @@ func (p *RGBA64) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return RGBA64Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *RGBA64) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toRGBA64Color(c).(RGBA64Color)
 }
 
 func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *RGBA64) 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 &RGBA64{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &RGBA64{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -142,8 +165,7 @@ func (p *RGBA64) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 != 0xffff {
@@ -164,7 +186,8 @@ func NewRGBA64(w, h int) *RGBA64 {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []NRGBAColor
 	Stride int
 	// Rect is the image's bounds.
@@ -179,30 +202,41 @@ func (p *NRGBA) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return NRGBAColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *NRGBA) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toNRGBAColor(c).(NRGBAColor)
 }
 
 func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *NRGBA) 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 &NRGBA{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &NRGBA{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -211,8 +245,7 @@ func (p *NRGBA) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 {
@@ -233,7 +266,8 @@ func NewNRGBA(w, h int) *NRGBA {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []NRGBA64Color
 	Stride int
 	// Rect is the image's bounds.
@@ -248,30 +282,41 @@ func (p *NRGBA64) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return NRGBA64Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *NRGBA64) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toNRGBA64Color(c).(NRGBA64Color)
 }
 
 func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *NRGBA64) 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 &NRGBA64{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &NRGBA64{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -280,8 +325,7 @@ func (p *NRGBA64) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 != 0xffff {
@@ -302,7 +346,8 @@ func NewNRGBA64(w, h int) *NRGBA64 {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []AlphaColor
 	Stride int
 	// Rect is the image's bounds.
@@ -317,30 +362,41 @@ func (p *Alpha) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return AlphaColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Alpha) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toAlphaColor(c).(AlphaColor)
 }
 
 func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *Alpha) 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 &Alpha{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &Alpha{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -349,8 +405,7 @@ func (p *Alpha) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 {
@@ -371,7 +426,8 @@ func NewAlpha(w, h int) *Alpha {
 
 // An 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []Alpha16Color
 	Stride int
 	// Rect is the image's bounds.
@@ -386,30 +442,41 @@ func (p *Alpha16) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return Alpha16Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Alpha16) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toAlpha16Color(c).(Alpha16Color)
 }
 
 func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *Alpha16) 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 &Alpha16{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &Alpha16{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -418,8 +485,7 @@ func (p *Alpha16) Opaque() bool {
 	if p.Rect.Empty() {
 		return true
 	}
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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 != 0xffff {
@@ -440,7 +506,8 @@ func NewAlpha16(w, h int) *Alpha16 {
 
 // A 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []GrayColor
 	Stride int
 	// Rect is the image's bounds.
@@ -455,30 +522,41 @@ func (p *Gray) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return GrayColor{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Gray) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toGrayColor(c).(GrayColor)
 }
 
 func (p *Gray) SetGray(x, y int, c GrayColor) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *Gray) 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 &Gray{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &Gray{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -495,7 +573,8 @@ func NewGray(w, h int) *Gray {
 
 // A 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*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []Gray16Color
 	Stride int
 	// Rect is the image's bounds.
@@ -510,30 +589,41 @@ func (p *Gray16) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return Gray16Color{}
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Gray16) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = toGray16Color(c).(Gray16Color)
 }
 
 func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = c
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = c
 }
 
 // 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 *Gray16) 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 &Gray16{}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &Gray16{
-		Pix:    p.Pix,
+		Pix:    p.Pix[i:],
 		Stride: p.Stride,
-		Rect:   p.Rect.Intersect(r),
+		Rect:   r,
 	}
 }
 
@@ -591,7 +681,8 @@ func (p PalettedColorModel) Index(c Color) int {
 
 // A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
 type Paletted struct {
-	// Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+	// Pix holds the image's pixels. The pixel at (x, y) is
+	// Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
 	Pix    []uint8
 	Stride int
 	// Rect is the image's bounds.
@@ -611,35 +702,49 @@ func (p *Paletted) At(x, y int) Color {
 	if !(Point{x, y}.In(p.Rect)) {
 		return p.Palette[0]
 	}
-	return p.Palette[p.Pix[y*p.Stride+x]]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Palette[p.Pix[i]]
 }
 
 func (p *Paletted) Set(x, y int, c Color) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = uint8(p.Palette.Index(c))
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = uint8(p.Palette.Index(c))
 }
 
 func (p *Paletted) ColorIndexAt(x, y int) uint8 {
 	if !(Point{x, y}.In(p.Rect)) {
 		return 0
 	}
-	return p.Pix[y*p.Stride+x]
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	return p.Pix[i]
 }
 
 func (p *Paletted) SetColorIndex(x, y int, index uint8) {
 	if !(Point{x, y}.In(p.Rect)) {
 		return
 	}
-	p.Pix[y*p.Stride+x] = index
+	i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+	p.Pix[i] = index
 }
 
 // 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 *Paletted) 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 &Paletted{
+			Palette: p.Palette,
+		}
+	}
+	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
 	return &Paletted{
-		Pix:     p.Pix,
+		Pix:     p.Pix[i:],
 		Stride:  p.Stride,
 		Rect:    p.Rect.Intersect(r),
 		Palette: p.Palette,
@@ -649,8 +754,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
 // Opaque scans the entire image and returns whether or not it is fully opaque.
 func (p *Paletted) Opaque() bool {
 	var present [256]bool
-	base := p.Rect.Min.Y * p.Stride
-	i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+	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] {
 			present[c] = true
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index 5469d64230..a368e71e63 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -72,6 +72,11 @@ func TestImage(t *testing.T) {
 			t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
 			continue
 		}
+		// Test that taking an empty sub-image starting at a corner does not panic.
+		m.SubImage(Rect(0, 0, 0, 0))
+		m.SubImage(Rect(10, 0, 10, 0))
+		m.SubImage(Rect(0, 10, 0, 10))
+		m.SubImage(Rect(10, 10, 10, 10))
 	}
 }
 
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
index ef8383a35e..8798919637 100644
--- a/src/pkg/image/jpeg/reader.go
+++ b/src/pkg/image/jpeg/reader.go
@@ -199,8 +199,8 @@ func (d *decoder) processDQT(n int) os.Error {
 // makeImg allocates and initializes the destination image.
 func (d *decoder) makeImg(h0, v0, mxx, myy int) {
 	if d.nComp == nGrayComponent {
-		d.img1 = image.NewGray(8*mxx, 8*myy)
-		d.img1.Rect = image.Rect(0, 0, d.width, d.height)
+		m := image.NewGray(8*mxx, 8*myy)
+		d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
 		return
 	}
 	var subsampleRatio ycbcr.SubsampleRatio
diff --git a/src/pkg/image/jpeg/writer.go b/src/pkg/image/jpeg/writer.go
index eddaaefb6b..76a85adb05 100644
--- a/src/pkg/image/jpeg/writer.go
+++ b/src/pkg/image/jpeg/writer.go
@@ -397,13 +397,13 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
 		if sj > ymax {
 			sj = ymax
 		}
-		yoff := sj * m.Stride
+		offset := (sj-b.Min.Y)*m.Stride - b.Min.X
 		for i := 0; i < 8; i++ {
 			sx := p.X + i
 			if sx > xmax {
 				sx = xmax
 			}
-			col := &m.Pix[yoff+sx]
+			col := &m.Pix[offset+sx]
 			yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
 			yBlock[8*j+i] = int(yy)
 			cbBlock[8*j+i] = int(cb)
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index d770cfad5f..81d402fc9f 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -324,8 +324,8 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 			// We have previously verified that the alpha value is fully opaque.
 			cr0 := cr[0]
 			if rgba != nil {
-				yoff := y * rgba.Stride
-				for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] {
+				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
@@ -341,8 +341,8 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
 				}
 			}
 		case cbP8:
-			rowOffset := y * paletted.Stride
-			copy(cr[0][1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+			offset := (y - b.Min.Y) * paletted.Stride
+			copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
 		case cbTCA8:
 			// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
 			for x := b.Min.X; x < b.Max.X; x++ {
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
index 271519a11f..1599791b3a 100644
--- a/src/pkg/image/png/writer_test.go
+++ b/src/pkg/image/png/writer_test.go
@@ -81,14 +81,14 @@ func TestWriter(t *testing.T) {
 	}
 }
 
-func TestSubimage(t *testing.T) {
+func TestSubImage(t *testing.T) {
 	m0 := image.NewRGBA(256, 256)
 	for y := 0; y < 256; y++ {
 		for x := 0; x < 256; x++ {
 			m0.Set(x, y, image.RGBAColor{uint8(x), uint8(y), 0, 255})
 		}
 	}
-	m0.Rect = image.Rect(50, 30, 250, 130)
+	m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA)
 	m1, err := encodeDecode(m0)
 	if err != nil {
 		t.Error(err)
-- 
2.30.9