...

Source file src/image/ycbcr.go

Documentation: image

		 1  // Copyright 2011 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package image
		 6  
		 7  import (
		 8  	"image/color"
		 9  )
		10  
		11  // YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
		12  type YCbCrSubsampleRatio int
		13  
		14  const (
		15  	YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
		16  	YCbCrSubsampleRatio422
		17  	YCbCrSubsampleRatio420
		18  	YCbCrSubsampleRatio440
		19  	YCbCrSubsampleRatio411
		20  	YCbCrSubsampleRatio410
		21  )
		22  
		23  func (s YCbCrSubsampleRatio) String() string {
		24  	switch s {
		25  	case YCbCrSubsampleRatio444:
		26  		return "YCbCrSubsampleRatio444"
		27  	case YCbCrSubsampleRatio422:
		28  		return "YCbCrSubsampleRatio422"
		29  	case YCbCrSubsampleRatio420:
		30  		return "YCbCrSubsampleRatio420"
		31  	case YCbCrSubsampleRatio440:
		32  		return "YCbCrSubsampleRatio440"
		33  	case YCbCrSubsampleRatio411:
		34  		return "YCbCrSubsampleRatio411"
		35  	case YCbCrSubsampleRatio410:
		36  		return "YCbCrSubsampleRatio410"
		37  	}
		38  	return "YCbCrSubsampleRatioUnknown"
		39  }
		40  
		41  // YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
		42  // pixel, but each Cb and Cr sample can span one or more pixels.
		43  // YStride is the Y slice index delta between vertically adjacent pixels.
		44  // CStride is the Cb and Cr slice index delta between vertically adjacent pixels
		45  // that map to separate chroma samples.
		46  // It is not an absolute requirement, but YStride and len(Y) are typically
		47  // multiples of 8, and:
		48  //	For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
		49  //	For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
		50  //	For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
		51  //	For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
		52  //	For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
		53  //	For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
		54  type YCbCr struct {
		55  	Y, Cb, Cr			[]uint8
		56  	YStride				int
		57  	CStride				int
		58  	SubsampleRatio YCbCrSubsampleRatio
		59  	Rect					 Rectangle
		60  }
		61  
		62  func (p *YCbCr) ColorModel() color.Model {
		63  	return color.YCbCrModel
		64  }
		65  
		66  func (p *YCbCr) Bounds() Rectangle {
		67  	return p.Rect
		68  }
		69  
		70  func (p *YCbCr) At(x, y int) color.Color {
		71  	return p.YCbCrAt(x, y)
		72  }
		73  
		74  func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 {
		75  	r, g, b, a := p.YCbCrAt(x, y).RGBA()
		76  	return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
		77  }
		78  
		79  func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
		80  	if !(Point{x, y}.In(p.Rect)) {
		81  		return color.YCbCr{}
		82  	}
		83  	yi := p.YOffset(x, y)
		84  	ci := p.COffset(x, y)
		85  	return color.YCbCr{
		86  		p.Y[yi],
		87  		p.Cb[ci],
		88  		p.Cr[ci],
		89  	}
		90  }
		91  
		92  // YOffset returns the index of the first element of Y that corresponds to
		93  // the pixel at (x, y).
		94  func (p *YCbCr) YOffset(x, y int) int {
		95  	return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
		96  }
		97  
		98  // COffset returns the index of the first element of Cb or Cr that corresponds
		99  // to the pixel at (x, y).
	 100  func (p *YCbCr) COffset(x, y int) int {
	 101  	switch p.SubsampleRatio {
	 102  	case YCbCrSubsampleRatio422:
	 103  		return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
	 104  	case YCbCrSubsampleRatio420:
	 105  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
	 106  	case YCbCrSubsampleRatio440:
	 107  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
	 108  	case YCbCrSubsampleRatio411:
	 109  		return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
	 110  	case YCbCrSubsampleRatio410:
	 111  		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
	 112  	}
	 113  	// Default to 4:4:4 subsampling.
	 114  	return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
	 115  }
	 116  
	 117  // SubImage returns an image representing the portion of the image p visible
	 118  // through r. The returned value shares pixels with the original image.
	 119  func (p *YCbCr) SubImage(r Rectangle) Image {
	 120  	r = r.Intersect(p.Rect)
	 121  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	 122  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	 123  	// this, the Pix[i:] expression below can panic.
	 124  	if r.Empty() {
	 125  		return &YCbCr{
	 126  			SubsampleRatio: p.SubsampleRatio,
	 127  		}
	 128  	}
	 129  	yi := p.YOffset(r.Min.X, r.Min.Y)
	 130  	ci := p.COffset(r.Min.X, r.Min.Y)
	 131  	return &YCbCr{
	 132  		Y:							p.Y[yi:],
	 133  		Cb:						 p.Cb[ci:],
	 134  		Cr:						 p.Cr[ci:],
	 135  		SubsampleRatio: p.SubsampleRatio,
	 136  		YStride:				p.YStride,
	 137  		CStride:				p.CStride,
	 138  		Rect:					 r,
	 139  	}
	 140  }
	 141  
	 142  func (p *YCbCr) Opaque() bool {
	 143  	return true
	 144  }
	 145  
	 146  func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) {
	 147  	w, h = r.Dx(), r.Dy()
	 148  	switch subsampleRatio {
	 149  	case YCbCrSubsampleRatio422:
	 150  		cw = (r.Max.X+1)/2 - r.Min.X/2
	 151  		ch = h
	 152  	case YCbCrSubsampleRatio420:
	 153  		cw = (r.Max.X+1)/2 - r.Min.X/2
	 154  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
	 155  	case YCbCrSubsampleRatio440:
	 156  		cw = w
	 157  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
	 158  	case YCbCrSubsampleRatio411:
	 159  		cw = (r.Max.X+3)/4 - r.Min.X/4
	 160  		ch = h
	 161  	case YCbCrSubsampleRatio410:
	 162  		cw = (r.Max.X+3)/4 - r.Min.X/4
	 163  		ch = (r.Max.Y+1)/2 - r.Min.Y/2
	 164  	default:
	 165  		// Default to 4:4:4 subsampling.
	 166  		cw = w
	 167  		ch = h
	 168  	}
	 169  	return
	 170  }
	 171  
	 172  // NewYCbCr returns a new YCbCr image with the given bounds and subsample
	 173  // ratio.
	 174  func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
	 175  	w, h, cw, ch := yCbCrSize(r, subsampleRatio)
	 176  
	 177  	// totalLength should be the same as i2, below, for a valid Rectangle r.
	 178  	totalLength := add2NonNeg(
	 179  		mul3NonNeg(1, w, h),
	 180  		mul3NonNeg(2, cw, ch),
	 181  	)
	 182  	if totalLength < 0 {
	 183  		panic("image: NewYCbCr Rectangle has huge or negative dimensions")
	 184  	}
	 185  
	 186  	i0 := w*h + 0*cw*ch
	 187  	i1 := w*h + 1*cw*ch
	 188  	i2 := w*h + 2*cw*ch
	 189  	b := make([]byte, i2)
	 190  	return &YCbCr{
	 191  		Y:							b[:i0:i0],
	 192  		Cb:						 b[i0:i1:i1],
	 193  		Cr:						 b[i1:i2:i2],
	 194  		SubsampleRatio: subsampleRatio,
	 195  		YStride:				w,
	 196  		CStride:				cw,
	 197  		Rect:					 r,
	 198  	}
	 199  }
	 200  
	 201  // NYCbCrA is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha
	 202  // colors. A and AStride are analogous to the Y and YStride fields of the
	 203  // embedded YCbCr.
	 204  type NYCbCrA struct {
	 205  	YCbCr
	 206  	A			 []uint8
	 207  	AStride int
	 208  }
	 209  
	 210  func (p *NYCbCrA) ColorModel() color.Model {
	 211  	return color.NYCbCrAModel
	 212  }
	 213  
	 214  func (p *NYCbCrA) At(x, y int) color.Color {
	 215  	return p.NYCbCrAAt(x, y)
	 216  }
	 217  
	 218  func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
	 219  	r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
	 220  	return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
	 221  }
	 222  
	 223  func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
	 224  	if !(Point{X: x, Y: y}.In(p.Rect)) {
	 225  		return color.NYCbCrA{}
	 226  	}
	 227  	yi := p.YOffset(x, y)
	 228  	ci := p.COffset(x, y)
	 229  	ai := p.AOffset(x, y)
	 230  	return color.NYCbCrA{
	 231  		color.YCbCr{
	 232  			Y:	p.Y[yi],
	 233  			Cb: p.Cb[ci],
	 234  			Cr: p.Cr[ci],
	 235  		},
	 236  		p.A[ai],
	 237  	}
	 238  }
	 239  
	 240  // AOffset returns the index of the first element of A that corresponds to the
	 241  // pixel at (x, y).
	 242  func (p *NYCbCrA) AOffset(x, y int) int {
	 243  	return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
	 244  }
	 245  
	 246  // SubImage returns an image representing the portion of the image p visible
	 247  // through r. The returned value shares pixels with the original image.
	 248  func (p *NYCbCrA) SubImage(r Rectangle) Image {
	 249  	r = r.Intersect(p.Rect)
	 250  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	 251  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	 252  	// this, the Pix[i:] expression below can panic.
	 253  	if r.Empty() {
	 254  		return &NYCbCrA{
	 255  			YCbCr: YCbCr{
	 256  				SubsampleRatio: p.SubsampleRatio,
	 257  			},
	 258  		}
	 259  	}
	 260  	yi := p.YOffset(r.Min.X, r.Min.Y)
	 261  	ci := p.COffset(r.Min.X, r.Min.Y)
	 262  	ai := p.AOffset(r.Min.X, r.Min.Y)
	 263  	return &NYCbCrA{
	 264  		YCbCr: YCbCr{
	 265  			Y:							p.Y[yi:],
	 266  			Cb:						 p.Cb[ci:],
	 267  			Cr:						 p.Cr[ci:],
	 268  			SubsampleRatio: p.SubsampleRatio,
	 269  			YStride:				p.YStride,
	 270  			CStride:				p.CStride,
	 271  			Rect:					 r,
	 272  		},
	 273  		A:			 p.A[ai:],
	 274  		AStride: p.AStride,
	 275  	}
	 276  }
	 277  
	 278  // Opaque scans the entire image and reports whether it is fully opaque.
	 279  func (p *NYCbCrA) Opaque() bool {
	 280  	if p.Rect.Empty() {
	 281  		return true
	 282  	}
	 283  	i0, i1 := 0, p.Rect.Dx()
	 284  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
	 285  		for _, a := range p.A[i0:i1] {
	 286  			if a != 0xff {
	 287  				return false
	 288  			}
	 289  		}
	 290  		i0 += p.AStride
	 291  		i1 += p.AStride
	 292  	}
	 293  	return true
	 294  }
	 295  
	 296  // NewNYCbCrA returns a new NYCbCrA image with the given bounds and subsample
	 297  // ratio.
	 298  func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
	 299  	w, h, cw, ch := yCbCrSize(r, subsampleRatio)
	 300  
	 301  	// totalLength should be the same as i3, below, for a valid Rectangle r.
	 302  	totalLength := add2NonNeg(
	 303  		mul3NonNeg(2, w, h),
	 304  		mul3NonNeg(2, cw, ch),
	 305  	)
	 306  	if totalLength < 0 {
	 307  		panic("image: NewNYCbCrA Rectangle has huge or negative dimension")
	 308  	}
	 309  
	 310  	i0 := 1*w*h + 0*cw*ch
	 311  	i1 := 1*w*h + 1*cw*ch
	 312  	i2 := 1*w*h + 2*cw*ch
	 313  	i3 := 2*w*h + 2*cw*ch
	 314  	b := make([]byte, i3)
	 315  	return &NYCbCrA{
	 316  		YCbCr: YCbCr{
	 317  			Y:							b[:i0:i0],
	 318  			Cb:						 b[i0:i1:i1],
	 319  			Cr:						 b[i1:i2:i2],
	 320  			SubsampleRatio: subsampleRatio,
	 321  			YStride:				w,
	 322  			CStride:				cw,
	 323  			Rect:					 r,
	 324  		},
	 325  		A:			 b[i2:],
	 326  		AStride: w,
	 327  	}
	 328  }
	 329  

View as plain text