]> Cypherpunks repositories - gostls13.git/commitdiff
image: add NYCbCrA types.
authorNigel Tao <nigeltao@golang.org>
Sat, 10 Oct 2015 00:25:47 +0000 (11:25 +1100)
committerNigel Tao <nigeltao@golang.org>
Sun, 11 Oct 2015 11:07:25 +0000 (11:07 +0000)
Fixes #12722

Change-Id: I6a630d8b072ef2b1c63de941743148f8c96b8e5f
Reviewed-on: https://go-review.googlesource.com/15671
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/image/color/ycbcr.go
src/image/image.go
src/image/ycbcr.go

index 4bcb07dce221e3055553d0057cace63f3da022b2..0c2ba84c57293fe70cbda1ffd3dbe20bb7e0e376 100644 (file)
@@ -137,6 +137,46 @@ func yCbCrModel(c Color) Color {
        return YCbCr{y, u, v}
 }
 
+// NYCbCrA represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having
+// 8 bits each for one luma, two chroma and one alpha component.
+type NYCbCrA struct {
+       YCbCr
+       A uint8
+}
+
+func (c NYCbCrA) RGBA() (r, g, b, a uint32) {
+       r8, g8, b8 := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+       a = uint32(c.A) * 0x101
+       r = uint32(r8) * 0x101 * a / 0xffff
+       g = uint32(g8) * 0x101 * a / 0xffff
+       b = uint32(b8) * 0x101 * a / 0xffff
+       return
+}
+
+// NYCbCrAModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha
+// colors.
+var NYCbCrAModel Model = ModelFunc(nYCbCrAModel)
+
+func nYCbCrAModel(c Color) Color {
+       switch c := c.(type) {
+       case NYCbCrA:
+               return c
+       case YCbCr:
+               return NYCbCrA{c, 0xff}
+       }
+       r, g, b, a := c.RGBA()
+
+       // Convert from alpha-premultiplied to non-alpha-premultiplied.
+       if a != 0 {
+               r = (r * 0xffff) / a
+               g = (g * 0xffff) / a
+               b = (b * 0xffff) / a
+       }
+
+       y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+       return NYCbCrA{YCbCr{Y: y, Cb: u, Cr: v}, uint8(a >> 8)}
+}
+
 // RGBToCMYK converts an RGB triple to a CMYK quadruple.
 func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
        rr := uint32(r)
index 20b64d78e1aab97b858e522afacb0f34b2f7c3e5..bebb9f70fa65e03dc41057bf5a66b7ff8d3bba5e 100644 (file)
@@ -148,7 +148,7 @@ func (p *RGBA) Opaque() bool {
        return true
 }
 
-// NewRGBA returns a new RGBA with the given bounds.
+// NewRGBA returns a new RGBA image with the given bounds.
 func NewRGBA(r Rectangle) *RGBA {
        w, h := r.Dx(), r.Dy()
        buf := make([]uint8, 4*w*h)
@@ -260,7 +260,7 @@ func (p *RGBA64) Opaque() bool {
        return true
 }
 
-// NewRGBA64 returns a new RGBA64 with the given bounds.
+// NewRGBA64 returns a new RGBA64 image with the given bounds.
 func NewRGBA64(r Rectangle) *RGBA64 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 8*w*h)
@@ -359,7 +359,7 @@ func (p *NRGBA) Opaque() bool {
        return true
 }
 
-// NewNRGBA returns a new NRGBA with the given bounds.
+// NewNRGBA returns a new NRGBA image with the given bounds.
 func NewNRGBA(r Rectangle) *NRGBA {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 4*w*h)
@@ -471,7 +471,7 @@ func (p *NRGBA64) Opaque() bool {
        return true
 }
 
-// NewNRGBA64 returns a new NRGBA64 with the given bounds.
+// NewNRGBA64 returns a new NRGBA64 image with the given bounds.
 func NewNRGBA64(r Rectangle) *NRGBA64 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 8*w*h)
@@ -563,7 +563,7 @@ func (p *Alpha) Opaque() bool {
        return true
 }
 
-// NewAlpha returns a new Alpha with the given bounds.
+// NewAlpha returns a new Alpha image with the given bounds.
 func NewAlpha(r Rectangle) *Alpha {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
@@ -658,7 +658,7 @@ func (p *Alpha16) Opaque() bool {
        return true
 }
 
-// NewAlpha16 returns a new Alpha16 with the given bounds.
+// NewAlpha16 returns a new Alpha16 image with the given bounds.
 func NewAlpha16(r Rectangle) *Alpha16 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 2*w*h)
@@ -737,7 +737,7 @@ func (p *Gray) Opaque() bool {
        return true
 }
 
-// NewGray returns a new Gray with the given bounds.
+// NewGray returns a new Gray image with the given bounds.
 func NewGray(r Rectangle) *Gray {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
@@ -819,7 +819,7 @@ func (p *Gray16) Opaque() bool {
        return true
 }
 
-// NewGray16 returns a new Gray16 with the given bounds.
+// NewGray16 returns a new Gray16 image with the given bounds.
 func NewGray16(r Rectangle) *Gray16 {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 2*w*h)
@@ -905,7 +905,7 @@ func (p *CMYK) Opaque() bool {
        return true
 }
 
-// NewCMYK returns a new CMYK with the given bounds.
+// NewCMYK returns a new CMYK image with the given bounds.
 func NewCMYK(r Rectangle) *CMYK {
        w, h := r.Dx(), r.Dy()
        buf := make([]uint8, 4*w*h)
@@ -1014,7 +1014,8 @@ func (p *Paletted) Opaque() bool {
        return true
 }
 
-// NewPaletted returns a new Paletted with the given width, height and palette.
+// NewPaletted returns a new Paletted image with the given width, height and
+// palette.
 func NewPaletted(r Rectangle, p color.Palette) *Paletted {
        w, h := r.Dx(), r.Dy()
        pix := make([]uint8, 1*w*h)
index 93c354b33b41c04eaf2b2dd45c9cbc14b4704c6e..71c0518a8180e649f7cffd23e89de65e43118b3d 100644 (file)
@@ -138,9 +138,8 @@ func (p *YCbCr) Opaque() bool {
        return true
 }
 
-// NewYCbCr returns a new YCbCr with the given bounds and subsample ratio.
-func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
-       w, h, cw, ch := r.Dx(), r.Dy(), 0, 0
+func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) {
+       w, h = r.Dx(), r.Dy()
        switch subsampleRatio {
        case YCbCrSubsampleRatio422:
                cw = (r.Max.X+1)/2 - r.Min.X/2
@@ -162,6 +161,13 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
                cw = w
                ch = h
        }
+       return
+}
+
+// NewYCbCr returns a new YCbCr image with the given bounds and subsample
+// ratio.
+func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
+       w, h, cw, ch := yCbCrSize(r, subsampleRatio)
        i0 := w*h + 0*cw*ch
        i1 := w*h + 1*cw*ch
        i2 := w*h + 2*cw*ch
@@ -176,3 +182,117 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
                Rect:           r,
        }
 }
+
+// NYCbCrA is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha
+// colors. A and AStride are analogous to the Y and YStride fields of the
+// embedded YCbCr.
+type NYCbCrA struct {
+       YCbCr
+       A       []uint8
+       AStride int
+}
+
+func (p *NYCbCrA) ColorModel() color.Model {
+       return color.NYCbCrAModel
+}
+
+func (p *NYCbCrA) At(x, y int) color.Color {
+       return p.NYCbCrAAt(x, y)
+}
+
+func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
+       if !(Point{X: x, Y: y}.In(p.Rect)) {
+               return color.NYCbCrA{}
+       }
+       yi := p.YOffset(x, y)
+       ci := p.COffset(x, y)
+       ai := p.AOffset(x, y)
+       return color.NYCbCrA{
+               color.YCbCr{
+                       Y:  p.Y[yi],
+                       Cb: p.Cb[ci],
+                       Cr: p.Cr[ci],
+               },
+               p.A[ai],
+       }
+}
+
+// AOffset returns the index of the first element of A that corresponds to the
+// pixel at (x, y).
+func (p *NYCbCrA) AOffset(x, y int) int {
+       return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
+}
+
+// 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 *NYCbCrA) 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 &NYCbCrA{
+                       YCbCr: YCbCr{
+                               SubsampleRatio: p.SubsampleRatio,
+                       },
+               }
+       }
+       yi := p.YOffset(r.Min.X, r.Min.Y)
+       ci := p.COffset(r.Min.X, r.Min.Y)
+       ai := p.AOffset(r.Min.X, r.Min.Y)
+       return &NYCbCrA{
+               YCbCr: YCbCr{
+                       Y:              p.Y[yi:],
+                       Cb:             p.Cb[ci:],
+                       Cr:             p.Cr[ci:],
+                       SubsampleRatio: p.SubsampleRatio,
+                       YStride:        p.YStride,
+                       CStride:        p.CStride,
+                       Rect:           r,
+               },
+               A:       p.A[ai:],
+               AStride: p.AStride,
+       }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *NYCbCrA) Opaque() bool {
+       if p.Rect.Empty() {
+               return true
+       }
+       i0, i1 := 0, p.Rect.Dx()
+       for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+               for _, a := range p.A[i0:i1] {
+                       if a != 0xff {
+                               return false
+                       }
+               }
+               i0 += p.AStride
+               i1 += p.AStride
+       }
+       return true
+}
+
+// NewNYCbCrA returns a new NYCbCrA image with the given bounds and subsample
+// ratio.
+func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
+       w, h, cw, ch := yCbCrSize(r, subsampleRatio)
+       i0 := 1*w*h + 0*cw*ch
+       i1 := 1*w*h + 1*cw*ch
+       i2 := 1*w*h + 2*cw*ch
+       i3 := 2*w*h + 2*cw*ch
+       b := make([]byte, i3)
+       return &NYCbCrA{
+               YCbCr: YCbCr{
+                       Y:              b[:i0:i0],
+                       Cb:             b[i0:i1:i1],
+                       Cr:             b[i1:i2:i2],
+                       SubsampleRatio: subsampleRatio,
+                       YStride:        w,
+                       CStride:        cw,
+                       Rect:           r,
+               },
+               A:       b[i2:],
+               AStride: w,
+       }
+}