mirror of https://github.com/golang/go.git
image: add NYCbCrA types.
Fixes #12722 Change-Id: I6a630d8b072ef2b1c63de941743148f8c96b8e5f Reviewed-on: https://go-review.googlesource.com/15671 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
735c65fa9c
commit
c478c48597
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue