Source file
src/image/ycbcr.go
1
2
3
4
5 package image
6
7 import (
8 "image/color"
9 )
10
11
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
42
43
44
45
46
47
48
49
50
51
52
53
54
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
94
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
100
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
115 return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
116 }
117
118
119
120 func (p *YCbCr) SubImage(r Rectangle) Image {
121 r = r.Intersect(p.Rect)
122
123
124
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
167 cw = w
168 ch = h
169 }
170 return
171 }
172
173
174
175 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
176 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
177
178
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
203
204
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
242
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
248
249 func (p *NYCbCrA) SubImage(r Rectangle) Image {
250 r = r.Intersect(p.Rect)
251
252
253
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
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
298
299 func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
300 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
301
302
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 }
330
View as plain text