github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/image/ycbcr.go (about) 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 ) 20 21 func (s YCbCrSubsampleRatio) String() string { 22 switch s { 23 case YCbCrSubsampleRatio444: 24 return "YCbCrSubsampleRatio444" 25 case YCbCrSubsampleRatio422: 26 return "YCbCrSubsampleRatio422" 27 case YCbCrSubsampleRatio420: 28 return "YCbCrSubsampleRatio420" 29 case YCbCrSubsampleRatio440: 30 return "YCbCrSubsampleRatio440" 31 } 32 return "YCbCrSubsampleRatioUnknown" 33 } 34 35 // YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per 36 // pixel, but each Cb and Cr sample can span one or more pixels. 37 // YStride is the Y slice index delta between vertically adjacent pixels. 38 // CStride is the Cb and Cr slice index delta between vertically adjacent pixels 39 // that map to separate chroma samples. 40 // It is not an absolute requirement, but YStride and len(Y) are typically 41 // multiples of 8, and: 42 // For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1. 43 // For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2. 44 // For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4. 45 // For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2. 46 type YCbCr struct { 47 Y, Cb, Cr []uint8 48 YStride int 49 CStride int 50 SubsampleRatio YCbCrSubsampleRatio 51 Rect Rectangle 52 } 53 54 func (p *YCbCr) ColorModel() color.Model { 55 return color.YCbCrModel 56 } 57 58 func (p *YCbCr) Bounds() Rectangle { 59 return p.Rect 60 } 61 62 func (p *YCbCr) At(x, y int) color.Color { 63 return p.YCbCrAt(x, y) 64 } 65 66 func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr { 67 if !(Point{x, y}.In(p.Rect)) { 68 return color.YCbCr{} 69 } 70 yi := p.YOffset(x, y) 71 ci := p.COffset(x, y) 72 return color.YCbCr{ 73 p.Y[yi], 74 p.Cb[ci], 75 p.Cr[ci], 76 } 77 } 78 79 // YOffset returns the index of the first element of Y that corresponds to 80 // the pixel at (x, y). 81 func (p *YCbCr) YOffset(x, y int) int { 82 return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X) 83 } 84 85 // COffset returns the index of the first element of Cb or Cr that corresponds 86 // to the pixel at (x, y). 87 func (p *YCbCr) COffset(x, y int) int { 88 switch p.SubsampleRatio { 89 case YCbCrSubsampleRatio422: 90 return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2) 91 case YCbCrSubsampleRatio420: 92 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2) 93 case YCbCrSubsampleRatio440: 94 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X) 95 } 96 // Default to 4:4:4 subsampling. 97 return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X) 98 } 99 100 // SubImage returns an image representing the portion of the image p visible 101 // through r. The returned value shares pixels with the original image. 102 func (p *YCbCr) SubImage(r Rectangle) Image { 103 r = r.Intersect(p.Rect) 104 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 105 // either r1 or r2 if the intersection is empty. Without explicitly checking for 106 // this, the Pix[i:] expression below can panic. 107 if r.Empty() { 108 return &YCbCr{ 109 SubsampleRatio: p.SubsampleRatio, 110 } 111 } 112 yi := p.YOffset(r.Min.X, r.Min.Y) 113 ci := p.COffset(r.Min.X, r.Min.Y) 114 return &YCbCr{ 115 Y: p.Y[yi:], 116 Cb: p.Cb[ci:], 117 Cr: p.Cr[ci:], 118 SubsampleRatio: p.SubsampleRatio, 119 YStride: p.YStride, 120 CStride: p.CStride, 121 Rect: r, 122 } 123 } 124 125 func (p *YCbCr) Opaque() bool { 126 return true 127 } 128 129 // NewYCbCr returns a new YCbCr with the given bounds and subsample ratio. 130 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr { 131 w, h, cw, ch := r.Dx(), r.Dy(), 0, 0 132 switch subsampleRatio { 133 case YCbCrSubsampleRatio422: 134 cw = (r.Max.X+1)/2 - r.Min.X/2 135 ch = h 136 case YCbCrSubsampleRatio420: 137 cw = (r.Max.X+1)/2 - r.Min.X/2 138 ch = (r.Max.Y+1)/2 - r.Min.Y/2 139 case YCbCrSubsampleRatio440: 140 cw = w 141 ch = (r.Max.Y+1)/2 - r.Min.Y/2 142 default: 143 // Default to 4:4:4 subsampling. 144 cw = w 145 ch = h 146 } 147 i0 := w*h + 0*cw*ch 148 i1 := w*h + 1*cw*ch 149 i2 := w*h + 2*cw*ch 150 b := make([]byte, i2) 151 return &YCbCr{ 152 Y: b[:i0:i0], 153 Cb: b[i0:i1:i1], 154 Cr: b[i1:i2:i2], 155 SubsampleRatio: subsampleRatio, 156 YStride: w, 157 CStride: cw, 158 Rect: r, 159 } 160 }