...
Run Format

Source file src/image/ycbcr.go

  // Copyright 2011 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package image
  
  import (
  	"image/color"
  )
  
  // YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
  type YCbCrSubsampleRatio int
  
  const (
  	YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
  	YCbCrSubsampleRatio422
  	YCbCrSubsampleRatio420
  	YCbCrSubsampleRatio440
  	YCbCrSubsampleRatio411
  	YCbCrSubsampleRatio410
  )
  
  func (s YCbCrSubsampleRatio) String() string {
  	switch s {
  	case YCbCrSubsampleRatio444:
  		return "YCbCrSubsampleRatio444"
  	case YCbCrSubsampleRatio422:
  		return "YCbCrSubsampleRatio422"
  	case YCbCrSubsampleRatio420:
  		return "YCbCrSubsampleRatio420"
  	case YCbCrSubsampleRatio440:
  		return "YCbCrSubsampleRatio440"
  	case YCbCrSubsampleRatio411:
  		return "YCbCrSubsampleRatio411"
  	case YCbCrSubsampleRatio410:
  		return "YCbCrSubsampleRatio410"
  	}
  	return "YCbCrSubsampleRatioUnknown"
  }
  
  // YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
  // pixel, but each Cb and Cr sample can span one or more pixels.
  // YStride is the Y slice index delta between vertically adjacent pixels.
  // CStride is the Cb and Cr slice index delta between vertically adjacent pixels
  // that map to separate chroma samples.
  // It is not an absolute requirement, but YStride and len(Y) are typically
  // multiples of 8, and:
  //	For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
  //	For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
  //	For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
  //	For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
  //	For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
  //	For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
  type YCbCr struct {
  	Y, Cb, Cr      []uint8
  	YStride        int
  	CStride        int
  	SubsampleRatio YCbCrSubsampleRatio
  	Rect           Rectangle
  }
  
  func (p *YCbCr) ColorModel() color.Model {
  	return color.YCbCrModel
  }
  
  func (p *YCbCr) Bounds() Rectangle {
  	return p.Rect
  }
  
  func (p *YCbCr) At(x, y int) color.Color {
  	return p.YCbCrAt(x, y)
  }
  
  func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
  	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.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.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:
  		return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
  	case YCbCrSubsampleRatio420:
  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
  	case YCbCrSubsampleRatio440:
  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
  	case YCbCrSubsampleRatio411:
  		return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
  	case YCbCrSubsampleRatio410:
  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
  	}
  	// Default to 4:4:4 subsampling.
  	return (y-p.Rect.Min.Y)*p.CStride + (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 *YCbCr) 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 &YCbCr{
  			SubsampleRatio: p.SubsampleRatio,
  		}
  	}
  	yi := p.YOffset(r.Min.X, r.Min.Y)
  	ci := p.COffset(r.Min.X, r.Min.Y)
  	return &YCbCr{
  		Y:              p.Y[yi:],
  		Cb:             p.Cb[ci:],
  		Cr:             p.Cr[ci:],
  		SubsampleRatio: p.SubsampleRatio,
  		YStride:        p.YStride,
  		CStride:        p.CStride,
  		Rect:           r,
  	}
  }
  
  func (p *YCbCr) Opaque() bool {
  	return true
  }
  
  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
  		ch = h
  	case YCbCrSubsampleRatio420:
  		cw = (r.Max.X+1)/2 - r.Min.X/2
  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
  	case YCbCrSubsampleRatio440:
  		cw = w
  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
  	case YCbCrSubsampleRatio411:
  		cw = (r.Max.X+3)/4 - r.Min.X/4
  		ch = h
  	case YCbCrSubsampleRatio410:
  		cw = (r.Max.X+3)/4 - r.Min.X/4
  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
  	default:
  		// Default to 4:4:4 subsampling.
  		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
  	b := make([]byte, i2)
  	return &YCbCr{
  		Y:              b[:i0:i0],
  		Cb:             b[i0:i1:i1],
  		Cr:             b[i1:i2:i2],
  		SubsampleRatio: subsampleRatio,
  		YStride:        w,
  		CStride:        cw,
  		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,
  	}
  }
  

View as plain text