diff options
Diffstat (limited to 'src/pkg/image/image.go')
-rw-r--r-- | src/pkg/image/image.go | 170 |
1 files changed, 136 insertions, 34 deletions
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go index 222d21ade..f4c38d28a 100644 --- a/src/pkg/image/image.go +++ b/src/pkg/image/image.go @@ -38,26 +38,36 @@ func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel } func (p *RGBA) Bounds() Rectangle { return p.Rect } func (p *RGBA) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return RGBAColor{} } return p.Pix[y*p.Stride+x] } func (p *RGBA) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor) } func (p *RGBA) SetRGBA(x, y int, c RGBAColor) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &RGBA{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *RGBA) Opaque() bool { if p.Rect.Empty() { @@ -97,26 +107,36 @@ func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel } func (p *RGBA64) Bounds() Rectangle { return p.Rect } func (p *RGBA64) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return RGBA64Color{} } return p.Pix[y*p.Stride+x] } func (p *RGBA64) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color) } func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &RGBA64{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *RGBA64) Opaque() bool { if p.Rect.Empty() { @@ -156,26 +176,36 @@ func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel } func (p *NRGBA) Bounds() Rectangle { return p.Rect } func (p *NRGBA) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return NRGBAColor{} } return p.Pix[y*p.Stride+x] } func (p *NRGBA) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor) } func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &NRGBA{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *NRGBA) Opaque() bool { if p.Rect.Empty() { @@ -215,26 +245,36 @@ func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel } func (p *NRGBA64) Bounds() Rectangle { return p.Rect } func (p *NRGBA64) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return NRGBA64Color{} } return p.Pix[y*p.Stride+x] } func (p *NRGBA64) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color) } func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &NRGBA64{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *NRGBA64) Opaque() bool { if p.Rect.Empty() { @@ -274,26 +314,36 @@ func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel } func (p *Alpha) Bounds() Rectangle { return p.Rect } func (p *Alpha) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return AlphaColor{} } return p.Pix[y*p.Stride+x] } -func (p *Alpha) Set(x, y int, c AlphaColor) { - if !p.Rect.Contains(Point{x, y}) { +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) } func (p *Alpha) SetAlpha(x, y int, c AlphaColor) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &Alpha{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *Alpha) Opaque() bool { if p.Rect.Empty() { @@ -333,26 +383,36 @@ func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel } func (p *Alpha16) Bounds() Rectangle { return p.Rect } func (p *Alpha16) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return Alpha16Color{} } return p.Pix[y*p.Stride+x] } func (p *Alpha16) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color) } func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &Alpha16{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *Alpha16) Opaque() bool { if p.Rect.Empty() { @@ -392,26 +452,36 @@ func (p *Gray) ColorModel() ColorModel { return GrayColorModel } func (p *Gray) Bounds() Rectangle { return p.Rect } func (p *Gray) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return GrayColor{} } return p.Pix[y*p.Stride+x] } func (p *Gray) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor) } func (p *Gray) SetGray(x, y int, c GrayColor) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &Gray{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *Gray) Opaque() bool { return true @@ -437,26 +507,36 @@ func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel } func (p *Gray16) Bounds() Rectangle { return p.Rect } func (p *Gray16) At(x, y int) Color { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return Gray16Color{} } return p.Pix[y*p.Stride+x] } func (p *Gray16) Set(x, y int, c Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color) } func (p *Gray16) SetGray16(x, y int, c Gray16Color) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &Gray16{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *Gray16) Opaque() bool { return true @@ -483,14 +563,19 @@ func (p PalettedColorModel) Convert(c Color) Color { if len(p) == 0 { return nil } + return p[p.Index(c)] +} + +// Index returns the index of the palette color closest to c in Euclidean +// R,G,B space. +func (p PalettedColorModel) Index(c Color) int { cr, cg, cb, _ := c.RGBA() // Shift by 1 bit to avoid potential uint32 overflow in sum-squared-difference. cr >>= 1 cg >>= 1 cb >>= 1 - result := Color(nil) - bestSSD := uint32(1<<32 - 1) - for _, v := range p { + ret, bestSSD := 0, uint32(1<<32-1) + for i, v := range p { vr, vg, vb, _ := v.RGBA() vr >>= 1 vg >>= 1 @@ -498,11 +583,10 @@ func (p PalettedColorModel) Convert(c Color) Color { dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb) ssd := (dr * dr) + (dg * dg) + (db * db) if ssd < bestSSD { - bestSSD = ssd - result = v + ret, bestSSD = i, ssd } } - return result + return ret } // A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel. @@ -524,26 +608,44 @@ func (p *Paletted) At(x, y int) Color { if len(p.Palette) == 0 { return nil } - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return p.Palette[0] } return p.Palette[p.Pix[y*p.Stride+x]] } +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)) +} + func (p *Paletted) ColorIndexAt(x, y int) uint8 { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return 0 } return p.Pix[y*p.Stride+x] } func (p *Paletted) SetColorIndex(x, y int, index uint8) { - if !p.Rect.Contains(Point{x, y}) { + if !(Point{x, y}.In(p.Rect)) { return } p.Pix[y*p.Stride+x] = 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 { + return &Paletted{ + Pix: p.Pix, + Stride: p.Stride, + Rect: p.Rect.Intersect(r), + Palette: p.Palette, + } +} + // Opaque scans the entire image and returns whether or not it is fully opaque. func (p *Paletted) Opaque() bool { for _, c := range p.Palette { |