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.
11 // YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
12 type YCbCrSubsampleRatio int
15 YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
16 YCbCrSubsampleRatio422
17 YCbCrSubsampleRatio420
18 YCbCrSubsampleRatio440
19 YCbCrSubsampleRatio411
20 YCbCrSubsampleRatio410
23 func (s YCbCrSubsampleRatio) String() string {
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"
38 return "YCbCrSubsampleRatioUnknown"
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:
49 // For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
50 // For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
51 // For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
52 // For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
53 // For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
54 // For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
59 SubsampleRatio YCbCrSubsampleRatio
63 func (p *YCbCr) ColorModel() color.Model {
64 return color.YCbCrModel
67 func (p *YCbCr) Bounds() Rectangle {
71 func (p *YCbCr) At(x, y int) color.Color {
72 return p.YCbCrAt(x, y)
75 func (p *YCbCr) RGBA64At(x, y int) color.RGBA64 {
76 r, g, b, a := p.YCbCrAt(x, y).RGBA()
77 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
80 func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
81 if !(Point{x, y}.In(p.Rect)) {
93 // YOffset returns the index of the first element of Y that corresponds to
94 // the pixel at (x, y).
95 func (p *YCbCr) YOffset(x, y int) int {
96 return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
99 // COffset returns the index of the first element of Cb or Cr that corresponds
100 // to the pixel at (x, y).
101 func (p *YCbCr) COffset(x, y int) int {
102 switch p.SubsampleRatio {
103 case YCbCrSubsampleRatio422:
104 return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
105 case YCbCrSubsampleRatio420:
106 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
107 case YCbCrSubsampleRatio440:
108 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
109 case YCbCrSubsampleRatio411:
110 return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
111 case YCbCrSubsampleRatio410:
112 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
114 // Default to 4:4:4 subsampling.
115 return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
118 // SubImage returns an image representing the portion of the image p visible
119 // through r. The returned value shares pixels with the original image.
120 func (p *YCbCr) SubImage(r Rectangle) Image {
121 r = r.Intersect(p.Rect)
122 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
123 // either r1 or r2 if the intersection is empty. Without explicitly checking for
124 // this, the Pix[i:] expression below can panic.
127 SubsampleRatio: p.SubsampleRatio,
130 yi := p.YOffset(r.Min.X, r.Min.Y)
131 ci := p.COffset(r.Min.X, r.Min.Y)
136 SubsampleRatio: p.SubsampleRatio,
143 func (p *YCbCr) Opaque() bool {
147 func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) {
148 w, h = r.Dx(), r.Dy()
149 switch subsampleRatio {
150 case YCbCrSubsampleRatio422:
151 cw = (r.Max.X+1)/2 - r.Min.X/2
153 case YCbCrSubsampleRatio420:
154 cw = (r.Max.X+1)/2 - r.Min.X/2
155 ch = (r.Max.Y+1)/2 - r.Min.Y/2
156 case YCbCrSubsampleRatio440:
158 ch = (r.Max.Y+1)/2 - r.Min.Y/2
159 case YCbCrSubsampleRatio411:
160 cw = (r.Max.X+3)/4 - r.Min.X/4
162 case YCbCrSubsampleRatio410:
163 cw = (r.Max.X+3)/4 - r.Min.X/4
164 ch = (r.Max.Y+1)/2 - r.Min.Y/2
166 // Default to 4:4:4 subsampling.
173 // NewYCbCr returns a new YCbCr image with the given bounds and subsample
175 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
176 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
178 // totalLength should be the same as i2, below, for a valid Rectangle r.
179 totalLength := add2NonNeg(
181 mul3NonNeg(2, cw, ch),
184 panic("image: NewYCbCr Rectangle has huge or negative dimensions")
190 b := make([]byte, i2)
195 SubsampleRatio: subsampleRatio,
202 // NYCbCrA is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha
203 // colors. A and AStride are analogous to the Y and YStride fields of the
205 type NYCbCrA struct {
211 func (p *NYCbCrA) ColorModel() color.Model {
212 return color.NYCbCrAModel
215 func (p *NYCbCrA) At(x, y int) color.Color {
216 return p.NYCbCrAAt(x, y)
219 func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
220 r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
221 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
224 func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
225 if !(Point{X: x, Y: y}.In(p.Rect)) {
226 return color.NYCbCrA{}
228 yi := p.YOffset(x, y)
229 ci := p.COffset(x, y)
230 ai := p.AOffset(x, y)
231 return color.NYCbCrA{
241 // AOffset returns the index of the first element of A that corresponds to the
243 func (p *NYCbCrA) AOffset(x, y int) int {
244 return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
247 // SubImage returns an image representing the portion of the image p visible
248 // through r. The returned value shares pixels with the original image.
249 func (p *NYCbCrA) SubImage(r Rectangle) Image {
250 r = r.Intersect(p.Rect)
251 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
252 // either r1 or r2 if the intersection is empty. Without explicitly checking for
253 // this, the Pix[i:] expression below can panic.
257 SubsampleRatio: p.SubsampleRatio,
261 yi := p.YOffset(r.Min.X, r.Min.Y)
262 ci := p.COffset(r.Min.X, r.Min.Y)
263 ai := p.AOffset(r.Min.X, r.Min.Y)
269 SubsampleRatio: p.SubsampleRatio,
279 // Opaque scans the entire image and reports whether it is fully opaque.
280 func (p *NYCbCrA) Opaque() bool {
284 i0, i1 := 0, p.Rect.Dx()
285 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
286 for _, a := range p.A[i0:i1] {
297 // NewNYCbCrA returns a new [NYCbCrA] image with the given bounds and subsample
299 func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
300 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
302 // totalLength should be the same as i3, below, for a valid Rectangle r.
303 totalLength := add2NonNeg(
305 mul3NonNeg(2, cw, ch),
308 panic("image: NewNYCbCrA Rectangle has huge or negative dimension")
311 i0 := 1*w*h + 0*cw*ch
312 i1 := 1*w*h + 1*cw*ch
313 i2 := 1*w*h + 2*cw*ch
314 i3 := 2*w*h + 2*cw*ch
315 b := make([]byte, i3)
321 SubsampleRatio: subsampleRatio,