]> Cypherpunks repositories - gostls13.git/commitdiff
image: add PixOffset methods; use them in image/draw and image/tiff.
authorNigel Tao <nigeltao@golang.org>
Thu, 19 Jan 2012 01:59:39 +0000 (12:59 +1100)
committerNigel Tao <nigeltao@golang.org>
Thu, 19 Jan 2012 01:59:39 +0000 (12:59 +1100)
image/draw benchmarks show <1% change for the fast paths.
The slow paths got worse by 1-4%, but they're the slow paths.
I don't care so much about them, and presumably compiler improvements
could claw it back.

IIUC 6g's inlining is enabled by default now.

benchmark                        old ns/op    new ns/op    delta
draw.BenchmarkFillOver             2988384      2999624   +0.38%
draw.BenchmarkFillSrc               153141       153262   +0.08%
draw.BenchmarkCopyOver             2155756      2170831   +0.70%
draw.BenchmarkCopySrc                72591        72646   +0.08%
draw.BenchmarkNRGBAOver            2487372      2491576   +0.17%
draw.BenchmarkNRGBASrc             1361306      1409180   +3.52%
draw.BenchmarkYCbCr                2540712      2562359   +0.85%
draw.BenchmarkGlyphOver            1004879      1023308   +1.83%
draw.BenchmarkRGBA                 8746670      8844455   +1.12%
draw.BenchmarkGenericOver         31860960     32512960   +2.05%
draw.BenchmarkGenericMaskOver     16369060     16435720   +0.41%
draw.BenchmarkGenericSrc          13128540     13127810   -0.01%
draw.BenchmarkGenericMaskSrc      30059300     28883210   -3.91%

R=r, gri
CC=golang-dev, rsc
https://golang.org/cl/5536059

src/pkg/image/draw/draw.go
src/pkg/image/image.go
src/pkg/image/tiff/reader.go
src/pkg/image/ycbcr.go

index 228ed6e719cc5e7242637de6dbebc09b79099455..2ea572d3a855e8abeb65c307be2f082981c9feeb 100644 (file)
@@ -171,7 +171,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
        sr, sg, sb, sa := src.RGBA()
        // The 0x101 is here for the same reason as in drawRGBA.
        a := (m - sa) * 0x101
-       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       i0 := dst.PixOffset(r.Min.X, r.Min.Y)
        i1 := i0 + r.Dx()*4
        for y := r.Min.Y; y != r.Max.Y; y++ {
                for i := i0; i < i1; i += 4 {
@@ -195,7 +195,7 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
        // 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)*4
+       i0 := dst.PixOffset(r.Min.X, r.Min.Y)
        i1 := i0 + r.Dx()*4
        for i := i0; i < i1; i += 4 {
                dst.Pix[i+0] = uint8(sr >> 8)
@@ -213,8 +213,8 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
 
 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)*4
-       s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
+       d0 := dst.PixOffset(r.Min.X, r.Min.Y)
+       s0 := src.PixOffset(sp.X, sp.Y)
        var (
                ddelta, sdelta int
                i0, i1, idelta int
@@ -261,8 +261,8 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
 
 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
        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
+       d0 := dst.PixOffset(r.Min.X, r.Min.Y)
+       s0 := src.PixOffset(sp.X, sp.Y)
        var ddelta, sdelta int
        if r.Min.Y <= sp.Y {
                ddelta = dst.Stride
@@ -348,9 +348,7 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
 func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
        // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
        // (i.e. fully opaque) then the op is effectively always Src.
-       var (
-               yy, cb, cr uint8
-       )
+       var yy, cb, cr uint8
        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
@@ -405,9 +403,9 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
 }
 
 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
-       i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+       i0 := dst.PixOffset(r.Min.X, r.Min.Y)
        i1 := i0 + r.Dx()*4
-       mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+       mi0 := mask.PixOffset(mp.X, mp.Y)
        sr, sg, sb, sa := src.RGBA()
        for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
                for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
@@ -451,7 +449,7 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
        sx0 := sp.X + x0 - r.Min.X
        mx0 := mp.X + x0 - r.Min.X
        sx1 := sx0 + (x1 - x0)
-       i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+       i0 := dst.PixOffset(x0, y0)
        di := dx * 4
        for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
                for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
index a0dd930c7c05c28f5badcf776d511cef216a8a0a..cc7b2a5e233e6c773d151e7c56bad698561dc7b3 100644 (file)
@@ -61,15 +61,21 @@ func (p *RGBA) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.RGBA{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGBA) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
 func (p *RGBA) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        c1 := color.RGBAModel.Convert(c).(color.RGBA)
        p.Pix[i+0] = c1.R
        p.Pix[i+1] = c1.G
@@ -81,7 +87,7 @@ func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = c.R
        p.Pix[i+1] = c.G
        p.Pix[i+2] = c.B
@@ -98,7 +104,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)*4
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &RGBA{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -150,7 +156,7 @@ func (p *RGBA64) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.RGBA64{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        return color.RGBA64{
                uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
                uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
@@ -159,11 +165,17 @@ func (p *RGBA64) At(x, y int) color.Color {
        }
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGBA64) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+}
+
 func (p *RGBA64) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
        p.Pix[i+0] = uint8(c1.R >> 8)
        p.Pix[i+1] = uint8(c1.R)
@@ -179,7 +191,7 @@ func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = uint8(c.R >> 8)
        p.Pix[i+1] = uint8(c.R)
        p.Pix[i+2] = uint8(c.G >> 8)
@@ -200,7 +212,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)*8
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &RGBA64{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -252,15 +264,21 @@ func (p *NRGBA) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.NRGBA{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *NRGBA) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
 func (p *NRGBA) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
        p.Pix[i+0] = c1.R
        p.Pix[i+1] = c1.G
@@ -272,7 +290,7 @@ func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = c.R
        p.Pix[i+1] = c.G
        p.Pix[i+2] = c.B
@@ -289,7 +307,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)*4
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &NRGBA{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -341,7 +359,7 @@ func (p *NRGBA64) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.NRGBA64{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        return color.NRGBA64{
                uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
                uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
@@ -350,11 +368,17 @@ func (p *NRGBA64) At(x, y int) color.Color {
        }
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *NRGBA64) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+}
+
 func (p *NRGBA64) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
        p.Pix[i+0] = uint8(c1.R >> 8)
        p.Pix[i+1] = uint8(c1.R)
@@ -370,7 +394,7 @@ func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = uint8(c.R >> 8)
        p.Pix[i+1] = uint8(c.R)
        p.Pix[i+2] = uint8(c.G >> 8)
@@ -391,7 +415,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)*8
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &NRGBA64{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -443,15 +467,21 @@ func (p *Alpha) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.Alpha{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        return color.Alpha{p.Pix[i]}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Alpha) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
 func (p *Alpha) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
 }
 
@@ -459,7 +489,7 @@ func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = c.A
 }
 
@@ -473,7 +503,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)*1
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &Alpha{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -525,15 +555,21 @@ func (p *Alpha16) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.Alpha16{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Alpha16) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+}
+
 func (p *Alpha16) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
        p.Pix[i+0] = uint8(c1.A >> 8)
        p.Pix[i+1] = uint8(c1.A)
@@ -543,7 +579,7 @@ func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = uint8(c.A >> 8)
        p.Pix[i+1] = uint8(c.A)
 }
@@ -558,7 +594,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)*2
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &Alpha16{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -610,15 +646,21 @@ func (p *Gray) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.Gray{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        return color.Gray{p.Pix[i]}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Gray) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
 func (p *Gray) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
 }
 
@@ -626,7 +668,7 @@ func (p *Gray) SetGray(x, y int, c color.Gray) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = c.Y
 }
 
@@ -640,7 +682,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)*1
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &Gray{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -679,15 +721,21 @@ func (p *Gray16) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.Gray16{}
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Gray16) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+}
+
 func (p *Gray16) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        c1 := color.Gray16Model.Convert(c).(color.Gray16)
        p.Pix[i+0] = uint8(c1.Y >> 8)
        p.Pix[i+1] = uint8(c1.Y)
@@ -697,7 +745,7 @@ func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+       i := p.PixOffset(x, y)
        p.Pix[i+0] = uint8(c.Y >> 8)
        p.Pix[i+1] = uint8(c.Y)
 }
@@ -712,7 +760,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)*2
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &Gray16{
                Pix:    p.Pix[i:],
                Stride: p.Stride,
@@ -756,15 +804,21 @@ func (p *Paletted) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return p.Palette[0]
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        return p.Palette[p.Pix[i]]
 }
 
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Paletted) PixOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
 func (p *Paletted) Set(x, y int, c color.Color) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = uint8(p.Palette.Index(c))
 }
 
@@ -772,7 +826,7 @@ func (p *Paletted) ColorIndexAt(x, y int) uint8 {
        if !(Point{x, y}.In(p.Rect)) {
                return 0
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        return p.Pix[i]
 }
 
@@ -780,7 +834,7 @@ func (p *Paletted) SetColorIndex(x, y int, index uint8) {
        if !(Point{x, y}.In(p.Rect)) {
                return
        }
-       i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+       i := p.PixOffset(x, y)
        p.Pix[i] = index
 }
 
@@ -796,7 +850,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)*1
+       i := p.PixOffset(r.Min.X, r.Min.Y)
        return &Paletted{
                Pix:     p.Pix[i:],
                Stride:  p.Stride,
index 00a51db9f4c6d40c4e6e006d196ca7777c05a67d..dc5a87a9fb93e1cb844dec1eeae8dfb901300000 100644 (file)
@@ -223,8 +223,8 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
                }
        case mRGB:
                img := dst.(*image.RGBA)
-               min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
-               max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
+               min := img.PixOffset(0, ymin)
+               max := img.PixOffset(0, ymax)
                var off int
                for i := min; i < max; i += 4 {
                        img.Pix[i+0] = d.buf[off+0]
@@ -235,16 +235,16 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
                }
        case mNRGBA:
                img := dst.(*image.NRGBA)
-               min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
-               max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
+               min := img.PixOffset(0, ymin)
+               max := img.PixOffset(0, ymax)
                if len(d.buf) != max-min {
                        return FormatError("short data strip")
                }
                copy(img.Pix[min:max], d.buf)
        case mRGBA:
                img := dst.(*image.RGBA)
-               min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
-               max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4
+               min := img.PixOffset(0, ymin)
+               max := img.PixOffset(0, ymax)
                if len(d.buf) != max-min {
                        return FormatError("short data strip")
                }
index 81f3c9fe03d12ce2310db18ad2516ee9cfb44ba5..4b77d242c27dd7e242a5f33d80c2129859117d1b 100644 (file)
@@ -49,28 +49,32 @@ func (p *YCbCr) At(x, y int) color.Color {
        if !(Point{x, y}.In(p.Rect)) {
                return color.YCbCr{}
        }
+       yi := p.YOffset(x, y)
+       ci := p.COffset(x, y)
+       return color.YCbCr{
+               p.Y[yi],
+               p.Cb[ci],
+               p.Cr[ci],
+       }
+}
+
+// YOffset returns the index of the first element of Y that corresponds to
+// the pixel at (x, y).
+func (p *YCbCr) YOffset(x, y int) int {
+       return y*p.YStride + x
+}
+
+// COffset returns the index of the first element of Cb or Cr that corresponds
+// to the pixel at (x, y).
+func (p *YCbCr) COffset(x, y int) int {
        switch p.SubsampleRatio {
        case YCbCrSubsampleRatio422:
-               i := x / 2
-               return color.YCbCr{
-                       p.Y[y*p.YStride+x],
-                       p.Cb[y*p.CStride+i],
-                       p.Cr[y*p.CStride+i],
-               }
+               return y*p.CStride + (x / 2)
        case YCbCrSubsampleRatio420:
-               i, j := x/2, y/2
-               return color.YCbCr{
-                       p.Y[y*p.YStride+x],
-                       p.Cb[j*p.CStride+i],
-                       p.Cr[j*p.CStride+i],
-               }
+               return (y/2)*p.CStride + (x / 2)
        }
        // Default to 4:4:4 subsampling.
-       return color.YCbCr{
-               p.Y[y*p.YStride+x],
-               p.Cb[y*p.CStride+x],
-               p.Cr[y*p.CStride+x],
-       }
+       return y*p.CStride + x
 }
 
 // SubImage returns an image representing the portion of the image p visible