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 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) RGBA64At(x, y int) color.RGBA64 {
75 r, g, b, a := p.YCbCrAt(x, y).RGBA()
76 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
77 }
78
79 func (p *YCbCr) YCbCrAt(x, y int) color.YCbCr {
80 if !(Point{x, y}.In(p.Rect)) {
81 return color.YCbCr{}
82 }
83 yi := p.YOffset(x, y)
84 ci := p.COffset(x, y)
85 return color.YCbCr{
86 p.Y[yi],
87 p.Cb[ci],
88 p.Cr[ci],
89 }
90 }
91
92
93
94 func (p *YCbCr) YOffset(x, y int) int {
95 return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
96 }
97
98
99
100 func (p *YCbCr) COffset(x, y int) int {
101 switch p.SubsampleRatio {
102 case YCbCrSubsampleRatio422:
103 return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
104 case YCbCrSubsampleRatio420:
105 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
106 case YCbCrSubsampleRatio440:
107 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
108 case YCbCrSubsampleRatio411:
109 return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
110 case YCbCrSubsampleRatio410:
111 return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
112 }
113
114 return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
115 }
116
117
118
119 func (p *YCbCr) SubImage(r Rectangle) Image {
120 r = r.Intersect(p.Rect)
121
122
123
124 if r.Empty() {
125 return &YCbCr{
126 SubsampleRatio: p.SubsampleRatio,
127 }
128 }
129 yi := p.YOffset(r.Min.X, r.Min.Y)
130 ci := p.COffset(r.Min.X, r.Min.Y)
131 return &YCbCr{
132 Y: p.Y[yi:],
133 Cb: p.Cb[ci:],
134 Cr: p.Cr[ci:],
135 SubsampleRatio: p.SubsampleRatio,
136 YStride: p.YStride,
137 CStride: p.CStride,
138 Rect: r,
139 }
140 }
141
142 func (p *YCbCr) Opaque() bool {
143 return true
144 }
145
146 func yCbCrSize(r Rectangle, subsampleRatio YCbCrSubsampleRatio) (w, h, cw, ch int) {
147 w, h = r.Dx(), r.Dy()
148 switch subsampleRatio {
149 case YCbCrSubsampleRatio422:
150 cw = (r.Max.X+1)/2 - r.Min.X/2
151 ch = h
152 case YCbCrSubsampleRatio420:
153 cw = (r.Max.X+1)/2 - r.Min.X/2
154 ch = (r.Max.Y+1)/2 - r.Min.Y/2
155 case YCbCrSubsampleRatio440:
156 cw = w
157 ch = (r.Max.Y+1)/2 - r.Min.Y/2
158 case YCbCrSubsampleRatio411:
159 cw = (r.Max.X+3)/4 - r.Min.X/4
160 ch = h
161 case YCbCrSubsampleRatio410:
162 cw = (r.Max.X+3)/4 - r.Min.X/4
163 ch = (r.Max.Y+1)/2 - r.Min.Y/2
164 default:
165
166 cw = w
167 ch = h
168 }
169 return
170 }
171
172
173
174 func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
175 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
176
177
178 totalLength := add2NonNeg(
179 mul3NonNeg(1, w, h),
180 mul3NonNeg(2, cw, ch),
181 )
182 if totalLength < 0 {
183 panic("image: NewYCbCr Rectangle has huge or negative dimensions")
184 }
185
186 i0 := w*h + 0*cw*ch
187 i1 := w*h + 1*cw*ch
188 i2 := w*h + 2*cw*ch
189 b := make([]byte, i2)
190 return &YCbCr{
191 Y: b[:i0:i0],
192 Cb: b[i0:i1:i1],
193 Cr: b[i1:i2:i2],
194 SubsampleRatio: subsampleRatio,
195 YStride: w,
196 CStride: cw,
197 Rect: r,
198 }
199 }
200
201
202
203
204 type NYCbCrA struct {
205 YCbCr
206 A []uint8
207 AStride int
208 }
209
210 func (p *NYCbCrA) ColorModel() color.Model {
211 return color.NYCbCrAModel
212 }
213
214 func (p *NYCbCrA) At(x, y int) color.Color {
215 return p.NYCbCrAAt(x, y)
216 }
217
218 func (p *NYCbCrA) RGBA64At(x, y int) color.RGBA64 {
219 r, g, b, a := p.NYCbCrAAt(x, y).RGBA()
220 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
221 }
222
223 func (p *NYCbCrA) NYCbCrAAt(x, y int) color.NYCbCrA {
224 if !(Point{X: x, Y: y}.In(p.Rect)) {
225 return color.NYCbCrA{}
226 }
227 yi := p.YOffset(x, y)
228 ci := p.COffset(x, y)
229 ai := p.AOffset(x, y)
230 return color.NYCbCrA{
231 color.YCbCr{
232 Y: p.Y[yi],
233 Cb: p.Cb[ci],
234 Cr: p.Cr[ci],
235 },
236 p.A[ai],
237 }
238 }
239
240
241
242 func (p *NYCbCrA) AOffset(x, y int) int {
243 return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
244 }
245
246
247
248 func (p *NYCbCrA) SubImage(r Rectangle) Image {
249 r = r.Intersect(p.Rect)
250
251
252
253 if r.Empty() {
254 return &NYCbCrA{
255 YCbCr: YCbCr{
256 SubsampleRatio: p.SubsampleRatio,
257 },
258 }
259 }
260 yi := p.YOffset(r.Min.X, r.Min.Y)
261 ci := p.COffset(r.Min.X, r.Min.Y)
262 ai := p.AOffset(r.Min.X, r.Min.Y)
263 return &NYCbCrA{
264 YCbCr: YCbCr{
265 Y: p.Y[yi:],
266 Cb: p.Cb[ci:],
267 Cr: p.Cr[ci:],
268 SubsampleRatio: p.SubsampleRatio,
269 YStride: p.YStride,
270 CStride: p.CStride,
271 Rect: r,
272 },
273 A: p.A[ai:],
274 AStride: p.AStride,
275 }
276 }
277
278
279 func (p *NYCbCrA) Opaque() bool {
280 if p.Rect.Empty() {
281 return true
282 }
283 i0, i1 := 0, p.Rect.Dx()
284 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
285 for _, a := range p.A[i0:i1] {
286 if a != 0xff {
287 return false
288 }
289 }
290 i0 += p.AStride
291 i1 += p.AStride
292 }
293 return true
294 }
295
296
297
298 func NewNYCbCrA(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *NYCbCrA {
299 w, h, cw, ch := yCbCrSize(r, subsampleRatio)
300
301
302 totalLength := add2NonNeg(
303 mul3NonNeg(2, w, h),
304 mul3NonNeg(2, cw, ch),
305 )
306 if totalLength < 0 {
307 panic("image: NewNYCbCrA Rectangle has huge or negative dimension")
308 }
309
310 i0 := 1*w*h + 0*cw*ch
311 i1 := 1*w*h + 1*cw*ch
312 i2 := 1*w*h + 2*cw*ch
313 i3 := 2*w*h + 2*cw*ch
314 b := make([]byte, i3)
315 return &NYCbCrA{
316 YCbCr: YCbCr{
317 Y: b[:i0:i0],
318 Cb: b[i0:i1:i1],
319 Cr: b[i1:i2:i2],
320 SubsampleRatio: subsampleRatio,
321 YStride: w,
322 CStride: cw,
323 Rect: r,
324 },
325 A: b[i2:],
326 AStride: w,
327 }
328 }
329
View as plain text