| |
| |
| |
|
|
| 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) RGBA64At(x, y int) color.RGBA64 { |
| r, g, b, a := p.YCbCrAt(x, y).RGBA() |
| return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} |
| } |
|
|
| 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) |
|
|
| |
| totalLength := add2NonNeg( |
| mul3NonNeg(1, w, h), |
| mul3NonNeg(2, cw, ch), |
| ) |
| if totalLength < 0 { |
| panic("image: NewYCbCr Rectangle has huge or negative dimensions") |
| } |
|
|
| 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) RGBA64At(x, y int) color.RGBA64 { |
| r, g, b, a := p.NYCbCrAAt(x, y).RGBA() |
| return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} |
| } |
|
|
| 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) |
|
|
| |
| totalLength := add2NonNeg( |
| mul3NonNeg(2, w, h), |
| mul3NonNeg(2, cw, ch), |
| ) |
| if totalLength < 0 { |
| panic("image: NewNYCbCrA Rectangle has huge or negative dimension") |
| } |
|
|
| 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, |
| } |
| } |
|
|