Source file
src/image/ycbcr.go
Documentation: image
package image
import (
"image/color"
)
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"
}
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],
}
}
func (p *YCbCr) YOffset(x, y int) int {
return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
}
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)
}
return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
}
func (p *YCbCr) SubImage(r Rectangle) Image {
r = r.Intersect(p.Rect)
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:
cw = w
ch = h
}
return
}
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,
}
}
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],
}
}
func (p *NYCbCrA) AOffset(x, y int) int {
return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
}
func (p *NYCbCrA) SubImage(r Rectangle) Image {
r = r.Intersect(p.Rect)
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,
}
}
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
}
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