github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 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) YCbCrAt(x, y int) color.YCbCr { 75 if !(Point{x, y}.In(p.Rect)) { 76 return color.YCbCr{} 77 } 78 yi := p.YOffset(x, y) 79 ci := p.COffset(x, y) 80 return color.YCbCr{ 81 p.Y[yi], 82 p.Cb[ci], 83 p.Cr[ci], 84 } 85 } 86 87 // YOffset returns the index of the first element of Y that corresponds to 88 // the pixel at (x, y). 89 func (p *YCbCr) YOffset(x, y int) int { 90 return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X) 91 } 92 93 // COffset returns the index of the first element of Cb or Cr that corresponds 94 // to the pixel at (x, y). 95 func (p *YCbCr) COffset(x, y int) int { 96 switch p.SubsampleRatio { 97 case YCbCrSubsampleRatio422: 98 return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2) 99 case YCbCrSubsampleRatio420: 100 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2) 101 case YCbCrSubsampleRatio440: 102 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X) 103 case YCbCrSubsampleRatio411: 104 return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4) 105 case YCbCrSubsampleRatio410: 106 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4) 107 } 108 // Default to 4:4:4 subsampling. 109 return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X) 110 } 111 112 // SubImage returns an image representing the portion of the image p visible 113 // through r. The returned value shares pixels with the original image. 114 func (p *YCbCr) SubImage(r Rectangle) Image { 115 r = r.Intersect(p.Rect) 116 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 117 // either r1 or r2 if the intersection is empty. Without explicitly checking for 118 // this, the Pix[i:] expression below can panic. 119 if r.Empty() { 120 return &YCbCr{ 121 SubsampleRatio: p.SubsampleRatio, 122 } 123 } 124 yi := p.YOffset(r.Min.X, r.Min.Y) 125 ci := p.COffset(r.Min.X, r.Min.Y) 126 return &YCbCr{ 127 Y: p.Y[yi:], 128 Cb: p.Cb[ci:], 129 Cr: p.Cr[ci:], 130 SubsampleRatio: p.SubsampleRatio, 131 YStride: p.YStride, 132 CStride: p.CStride, 133 Rect: r, 134 } 135 } 136 137 func (p *YCbCr) Opaque() bool { 138 return true 139 } 140 141 func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) { 142 w, h = r.Dx(), r.Dy() 143 switch subsampleRatio { 144 case YCbCrSubsampleRatio422: 145 cw = (r.Max.X+1)/2 - r.Min.X/2 146 ch = h 147 case YCbCrSubsampleRatio420: 148 cw = (r.Max.X+1)/2 - r.Min.X/2 149 ch = (r.Max.Y+1)/2 - r.Min.Y/2 150 case YCbCrSubsampleRatio440: 151 cw = w 152 ch = (r.Max.Y+1)/2 - r.Min.Y/2 153 case YCbCrSubsampleRatio411: 154 cw = (r.Max.X+3)/4 - r.Min.X/4 155 ch = h 156 case YCbCrSubsampleRatio410: 157 cw = (r.Max.X+3)/4 - r.Min.X/4 158 ch = (r.Max.Y+1)/2 - r.Min.Y/2 159 default: 160 // Default to 4:4:4 subsampling. 161 cw = w 162 ch = h 163 } 164 return 165 } 166 167 // NewYCbCr returns a new YCbCr image with the given bounds and subsample 168 // ratio. 169 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr { 170 w, h, cw, ch := yCbCrSize(r, subsampleRatio) 171 i0 := w*h + 0*cw*ch 172 i1 := w*h + 1*cw*ch 173 i2 := w*h + 2*cw*ch 174 b := make([]byte, i2) 175 return &YCbCr{ 176 Y: b[:i0:i0], 177 Cb: b[i0:i1:i1], 178 Cr: b[i1:i2:i2], 179 SubsampleRatio: subsampleRatio, 180 YStride: w, 181 CStride: cw, 182 Rect: r, 183 } 184 } 185 186 // NYCbCrA is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha 187 // colors. A and AStride are analogous to the Y and YStride fields of the 188 // embedded YCbCr. 189 type NYCbCrA struct { 190 YCbCr 191 A []uint8 192 AStride int 193 } 194 195 func (p *NYCbCrA) ColorModel() color.Model { 196 return color.NYCbCrAModel 197 } 198 199 func (p *NYCbCrA) At(x, y int) color.Color { 200 return p.NYCbCrAAt(x, y) 201 } 202 203 func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA { 204 if !(Point{X: x, Y: y}.In(p.Rect)) { 205 return color.NYCbCrA{} 206 } 207 yi := p.YOffset(x, y) 208 ci := p.COffset(x, y) 209 ai := p.AOffset(x, y) 210 return color.NYCbCrA{ 211 color.YCbCr{ 212 Y: p.Y[yi], 213 Cb: p.Cb[ci], 214 Cr: p.Cr[ci], 215 }, 216 p.A[ai], 217 } 218 } 219 220 // AOffset returns the index of the first element of A that corresponds to the 221 // pixel at (x, y). 222 func (p *NYCbCrA) AOffset(x, y int) int { 223 return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X) 224 } 225 226 // SubImage returns an image representing the portion of the image p visible 227 // through r. The returned value shares pixels with the original image. 228 func (p *NYCbCrA) SubImage(r Rectangle) Image { 229 r = r.Intersect(p.Rect) 230 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 231 // either r1 or r2 if the intersection is empty. Without explicitly checking for 232 // this, the Pix[i:] expression below can panic. 233 if r.Empty() { 234 return &NYCbCrA{ 235 YCbCr: YCbCr{ 236 SubsampleRatio: p.SubsampleRatio, 237 }, 238 } 239 } 240 yi := p.YOffset(r.Min.X, r.Min.Y) 241 ci := p.COffset(r.Min.X, r.Min.Y) 242 ai := p.AOffset(r.Min.X, r.Min.Y) 243 return &NYCbCrA{ 244 YCbCr: YCbCr{ 245 Y: p.Y[yi:], 246 Cb: p.Cb[ci:], 247 Cr: p.Cr[ci:], 248 SubsampleRatio: p.SubsampleRatio, 249 YStride: p.YStride, 250 CStride: p.CStride, 251 Rect: r, 252 }, 253 A: p.A[ai:], 254 AStride: p.AStride, 255 } 256 } 257 258 // Opaque scans the entire image and reports whether it is fully opaque. 259 func (p *NYCbCrA) Opaque() bool { 260 if p.Rect.Empty() { 261 return true 262 } 263 i0, i1 := 0, p.Rect.Dx() 264 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 265 for _, a := range p.A[i0:i1] { 266 if a != 0xff { 267 return false 268 } 269 } 270 i0 += p.AStride 271 i1 += p.AStride 272 } 273 return true 274 } 275 276 // NewNYCbCrA returns a new NYCbCrA image with the given bounds and subsample 277 // ratio. 278 func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA { 279 w, h, cw, ch := yCbCrSize(r, subsampleRatio) 280 i0 := 1*w*h + 0*cw*ch 281 i1 := 1*w*h + 1*cw*ch 282 i2 := 1*w*h + 2*cw*ch 283 i3 := 2*w*h + 2*cw*ch 284 b := make([]byte, i3) 285 return &NYCbCrA{ 286 YCbCr: YCbCr{ 287 Y: b[:i0:i0], 288 Cb: b[i0:i1:i1], 289 Cr: b[i1:i2:i2], 290 SubsampleRatio: subsampleRatio, 291 YStride: w, 292 CStride: cw, 293 Rect: r, 294 }, 295 A: b[i2:], 296 AStride: w, 297 } 298 }