]> Cypherpunks.ru repositories - gostls13.git/blob - src/image/ycbcr.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / image / ycbcr.go
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 //
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.
55 type YCbCr struct {
56         Y, Cb, Cr      []uint8
57         YStride        int
58         CStride        int
59         SubsampleRatio YCbCrSubsampleRatio
60         Rect           Rectangle
61 }
62
63 func (p *YCbCr) ColorModel() color.Model {
64         return color.YCbCrModel
65 }
66
67 func (p *YCbCr) Bounds() Rectangle {
68         return p.Rect
69 }
70
71 func (p *YCbCr) At(x, y int) color.Color {
72         return p.YCbCrAt(x, y)
73 }
74
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)}
78 }
79
80 func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
81         if !(Point{x, y}.In(p.Rect)) {
82                 return color.YCbCr{}
83         }
84         yi := p.YOffset(x, y)
85         ci := p.COffset(x, y)
86         return color.YCbCr{
87                 p.Y[yi],
88                 p.Cb[ci],
89                 p.Cr[ci],
90         }
91 }
92
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)
97 }
98
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)
113         }
114         // Default to 4:4:4 subsampling.
115         return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
116 }
117
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.
125         if r.Empty() {
126                 return &YCbCr{
127                         SubsampleRatio: p.SubsampleRatio,
128                 }
129         }
130         yi := p.YOffset(r.Min.X, r.Min.Y)
131         ci := p.COffset(r.Min.X, r.Min.Y)
132         return &YCbCr{
133                 Y:              p.Y[yi:],
134                 Cb:             p.Cb[ci:],
135                 Cr:             p.Cr[ci:],
136                 SubsampleRatio: p.SubsampleRatio,
137                 YStride:        p.YStride,
138                 CStride:        p.CStride,
139                 Rect:           r,
140         }
141 }
142
143 func (p *YCbCr) Opaque() bool {
144         return true
145 }
146
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
152                 ch = h
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:
157                 cw = w
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
161                 ch = h
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
165         default:
166                 // Default to 4:4:4 subsampling.
167                 cw = w
168                 ch = h
169         }
170         return
171 }
172
173 // NewYCbCr returns a new YCbCr image with the given bounds and subsample
174 // ratio.
175 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
176         w, h, cw, ch := yCbCrSize(r, subsampleRatio)
177
178         // totalLength should be the same as i2, below, for a valid Rectangle r.
179         totalLength := add2NonNeg(
180                 mul3NonNeg(1, w, h),
181                 mul3NonNeg(2, cw, ch),
182         )
183         if totalLength < 0 {
184                 panic("image: NewYCbCr Rectangle has huge or negative dimensions")
185         }
186
187         i0 := w*h + 0*cw*ch
188         i1 := w*h + 1*cw*ch
189         i2 := w*h + 2*cw*ch
190         b := make([]byte, i2)
191         return &YCbCr{
192                 Y:              b[:i0:i0],
193                 Cb:             b[i0:i1:i1],
194                 Cr:             b[i1:i2:i2],
195                 SubsampleRatio: subsampleRatio,
196                 YStride:        w,
197                 CStride:        cw,
198                 Rect:           r,
199         }
200 }
201
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
204 // embedded YCbCr.
205 type NYCbCrA struct {
206         YCbCr
207         A       []uint8
208         AStride int
209 }
210
211 func (p *NYCbCrA) ColorModel() color.Model {
212         return color.NYCbCrAModel
213 }
214
215 func (p *NYCbCrA) At(x, y int) color.Color {
216         return p.NYCbCrAAt(x, y)
217 }
218
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)}
222 }
223
224 func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
225         if !(Point{X: x, Y: y}.In(p.Rect)) {
226                 return color.NYCbCrA{}
227         }
228         yi := p.YOffset(x, y)
229         ci := p.COffset(x, y)
230         ai := p.AOffset(x, y)
231         return color.NYCbCrA{
232                 color.YCbCr{
233                         Y:  p.Y[yi],
234                         Cb: p.Cb[ci],
235                         Cr: p.Cr[ci],
236                 },
237                 p.A[ai],
238         }
239 }
240
241 // AOffset returns the index of the first element of A that corresponds to the
242 // pixel at (x, y).
243 func (p *NYCbCrA) AOffset(x, y int) int {
244         return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
245 }
246
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.
254         if r.Empty() {
255                 return &NYCbCrA{
256                         YCbCr: YCbCr{
257                                 SubsampleRatio: p.SubsampleRatio,
258                         },
259                 }
260         }
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)
264         return &NYCbCrA{
265                 YCbCr: YCbCr{
266                         Y:              p.Y[yi:],
267                         Cb:             p.Cb[ci:],
268                         Cr:             p.Cr[ci:],
269                         SubsampleRatio: p.SubsampleRatio,
270                         YStride:        p.YStride,
271                         CStride:        p.CStride,
272                         Rect:           r,
273                 },
274                 A:       p.A[ai:],
275                 AStride: p.AStride,
276         }
277 }
278
279 // Opaque scans the entire image and reports whether it is fully opaque.
280 func (p *NYCbCrA) Opaque() bool {
281         if p.Rect.Empty() {
282                 return true
283         }
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] {
287                         if a != 0xff {
288                                 return false
289                         }
290                 }
291                 i0 += p.AStride
292                 i1 += p.AStride
293         }
294         return true
295 }
296
297 // NewNYCbCrA returns a new [NYCbCrA] image with the given bounds and subsample
298 // ratio.
299 func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
300         w, h, cw, ch := yCbCrSize(r, subsampleRatio)
301
302         // totalLength should be the same as i3, below, for a valid Rectangle r.
303         totalLength := add2NonNeg(
304                 mul3NonNeg(2, w, h),
305                 mul3NonNeg(2, cw, ch),
306         )
307         if totalLength < 0 {
308                 panic("image: NewNYCbCrA Rectangle has huge or negative dimension")
309         }
310
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)
316         return &NYCbCrA{
317                 YCbCr: YCbCr{
318                         Y:              b[:i0:i0],
319                         Cb:             b[i0:i1:i1],
320                         Cr:             b[i1:i2:i2],
321                         SubsampleRatio: subsampleRatio,
322                         YStride:        w,
323                         CStride:        cw,
324                         Rect:           r,
325                 },
326                 A:       b[i2:],
327                 AStride: w,
328         }
329 }