Source file src/pkg/image/image.go
1 // Copyright 2009 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 implements a basic 2-D image library.
6 //
7 // The fundamental interface is called Image. An Image contains colors, which
8 // are described in the image/color package.
9 //
10 // Values of the Image interface are created either by calling functions such
11 // as NewRGBA and NewPaletted, or by calling Decode on an io.Reader containing
12 // image data in a format such as GIF, JPEG or PNG. Decoding any particular
13 // image format requires the prior registration of a decoder function.
14 // Registration is typically automatic as a side effect of initializing that
15 // format's package so that, to decode a PNG image, it suffices to have
16 // import _ "image/png"
17 // in a program's main package. The _ means to import a package purely for its
18 // initialization side effects.
19 //
20 // See "The Go image package" for more details:
21 // http://golang.org/doc/articles/image_package.html
22 package image
23
24 import (
25 "image/color"
26 )
27
28 // Config holds an image's color model and dimensions.
29 type Config struct {
30 ColorModel color.Model
31 Width, Height int
32 }
33
34 // Image is a finite rectangular grid of color.Color values taken from a color
35 // model.
36 type Image interface {
37 // ColorModel returns the Image's color model.
38 ColorModel() color.Model
39 // Bounds returns the domain for which At can return non-zero color.
40 // The bounds do not necessarily contain the point (0, 0).
41 Bounds() Rectangle
42 // At returns the color of the pixel at (x, y).
43 // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
44 // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
45 At(x, y int) color.Color
46 }
47
48 // PalettedImage is an image whose colors may come from a limited palette.
49 // If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
50 // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
51 // color model is not a PalettedColorModel, then ColorIndexAt's behavior is
52 // undefined.
53 type PalettedImage interface {
54 // ColorIndexAt returns the palette index of the pixel at (x, y).
55 ColorIndexAt(x, y int) uint8
56 Image
57 }
58
59 // RGBA is an in-memory image whose At method returns color.RGBA values.
60 type RGBA struct {
61 // Pix holds the image's pixels, in R, G, B, A order. The pixel at
62 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
63 Pix []uint8
64 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
65 Stride int
66 // Rect is the image's bounds.
67 Rect Rectangle
68 }
69
70 func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
71
72 func (p *RGBA) Bounds() Rectangle { return p.Rect }
73
74 func (p *RGBA) At(x, y int) color.Color {
75 if !(Point{x, y}.In(p.Rect)) {
76 return color.RGBA{}
77 }
78 i := p.PixOffset(x, y)
79 return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
80 }
81
82 // PixOffset returns the index of the first element of Pix that corresponds to
83 // the pixel at (x, y).
84 func (p *RGBA) PixOffset(x, y int) int {
85 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
86 }
87
88 func (p *RGBA) Set(x, y int, c color.Color) {
89 if !(Point{x, y}.In(p.Rect)) {
90 return
91 }
92 i := p.PixOffset(x, y)
93 c1 := color.RGBAModel.Convert(c).(color.RGBA)
94 p.Pix[i+0] = c1.R
95 p.Pix[i+1] = c1.G
96 p.Pix[i+2] = c1.B
97 p.Pix[i+3] = c1.A
98 }
99
100 func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
101 if !(Point{x, y}.In(p.Rect)) {
102 return
103 }
104 i := p.PixOffset(x, y)
105 p.Pix[i+0] = c.R
106 p.Pix[i+1] = c.G
107 p.Pix[i+2] = c.B
108 p.Pix[i+3] = c.A
109 }
110
111 // SubImage returns an image representing the portion of the image p visible
112 // through r. The returned value shares pixels with the original image.
113 func (p *RGBA) SubImage(r Rectangle) Image {
114 r = r.Intersect(p.Rect)
115 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
116 // either r1 or r2 if the intersection is empty. Without explicitly checking for
117 // this, the Pix[i:] expression below can panic.
118 if r.Empty() {
119 return &RGBA{}
120 }
121 i := p.PixOffset(r.Min.X, r.Min.Y)
122 return &RGBA{
123 Pix: p.Pix[i:],
124 Stride: p.Stride,
125 Rect: r,
126 }
127 }
128
129 // Opaque scans the entire image and returns whether or not it is fully opaque.
130 func (p *RGBA) Opaque() bool {
131 if p.Rect.Empty() {
132 return true
133 }
134 i0, i1 := 3, p.Rect.Dx()*4
135 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
136 for i := i0; i < i1; i += 4 {
137 if p.Pix[i] != 0xff {
138 return false
139 }
140 }
141 i0 += p.Stride
142 i1 += p.Stride
143 }
144 return true
145 }
146
147 // NewRGBA returns a new RGBA with the given bounds.
148 func NewRGBA(r Rectangle) *RGBA {
149 w, h := r.Dx(), r.Dy()
150 buf := make([]uint8, 4*w*h)
151 return &RGBA{buf, 4 * w, r}
152 }
153
154 // RGBA64 is an in-memory image whose At method returns color.RGBA64 values.
155 type RGBA64 struct {
156 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
157 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
158 Pix []uint8
159 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
160 Stride int
161 // Rect is the image's bounds.
162 Rect Rectangle
163 }
164
165 func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
166
167 func (p *RGBA64) Bounds() Rectangle { return p.Rect }
168
169 func (p *RGBA64) At(x, y int) color.Color {
170 if !(Point{x, y}.In(p.Rect)) {
171 return color.RGBA64{}
172 }
173 i := p.PixOffset(x, y)
174 return color.RGBA64{
175 uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
176 uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
177 uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
178 uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
179 }
180 }
181
182 // PixOffset returns the index of the first element of Pix that corresponds to
183 // the pixel at (x, y).
184 func (p *RGBA64) PixOffset(x, y int) int {
185 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
186 }
187
188 func (p *RGBA64) Set(x, y int, c color.Color) {
189 if !(Point{x, y}.In(p.Rect)) {
190 return
191 }
192 i := p.PixOffset(x, y)
193 c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
194 p.Pix[i+0] = uint8(c1.R >> 8)
195 p.Pix[i+1] = uint8(c1.R)
196 p.Pix[i+2] = uint8(c1.G >> 8)
197 p.Pix[i+3] = uint8(c1.G)
198 p.Pix[i+4] = uint8(c1.B >> 8)
199 p.Pix[i+5] = uint8(c1.B)
200 p.Pix[i+6] = uint8(c1.A >> 8)
201 p.Pix[i+7] = uint8(c1.A)
202 }
203
204 func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
205 if !(Point{x, y}.In(p.Rect)) {
206 return
207 }
208 i := p.PixOffset(x, y)
209 p.Pix[i+0] = uint8(c.R >> 8)
210 p.Pix[i+1] = uint8(c.R)
211 p.Pix[i+2] = uint8(c.G >> 8)
212 p.Pix[i+3] = uint8(c.G)
213 p.Pix[i+4] = uint8(c.B >> 8)
214 p.Pix[i+5] = uint8(c.B)
215 p.Pix[i+6] = uint8(c.A >> 8)
216 p.Pix[i+7] = uint8(c.A)
217 }
218
219 // SubImage returns an image representing the portion of the image p visible
220 // through r. The returned value shares pixels with the original image.
221 func (p *RGBA64) SubImage(r Rectangle) Image {
222 r = r.Intersect(p.Rect)
223 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
224 // either r1 or r2 if the intersection is empty. Without explicitly checking for
225 // this, the Pix[i:] expression below can panic.
226 if r.Empty() {
227 return &RGBA64{}
228 }
229 i := p.PixOffset(r.Min.X, r.Min.Y)
230 return &RGBA64{
231 Pix: p.Pix[i:],
232 Stride: p.Stride,
233 Rect: r,
234 }
235 }
236
237 // Opaque scans the entire image and returns whether or not it is fully opaque.
238 func (p *RGBA64) Opaque() bool {
239 if p.Rect.Empty() {
240 return true
241 }
242 i0, i1 := 6, p.Rect.Dx()*8
243 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
244 for i := i0; i < i1; i += 8 {
245 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
246 return false
247 }
248 }
249 i0 += p.Stride
250 i1 += p.Stride
251 }
252 return true
253 }
254
255 // NewRGBA64 returns a new RGBA64 with the given bounds.
256 func NewRGBA64(r Rectangle) *RGBA64 {
257 w, h := r.Dx(), r.Dy()
258 pix := make([]uint8, 8*w*h)
259 return &RGBA64{pix, 8 * w, r}
260 }
261
262 // NRGBA is an in-memory image whose At method returns color.NRGBA values.
263 type NRGBA struct {
264 // Pix holds the image's pixels, in R, G, B, A order. The pixel at
265 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
266 Pix []uint8
267 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
268 Stride int
269 // Rect is the image's bounds.
270 Rect Rectangle
271 }
272
273 func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
274
275 func (p *NRGBA) Bounds() Rectangle { return p.Rect }
276
277 func (p *NRGBA) At(x, y int) color.Color {
278 if !(Point{x, y}.In(p.Rect)) {
279 return color.NRGBA{}
280 }
281 i := p.PixOffset(x, y)
282 return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
283 }
284
285 // PixOffset returns the index of the first element of Pix that corresponds to
286 // the pixel at (x, y).
287 func (p *NRGBA) PixOffset(x, y int) int {
288 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
289 }
290
291 func (p *NRGBA) Set(x, y int, c color.Color) {
292 if !(Point{x, y}.In(p.Rect)) {
293 return
294 }
295 i := p.PixOffset(x, y)
296 c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
297 p.Pix[i+0] = c1.R
298 p.Pix[i+1] = c1.G
299 p.Pix[i+2] = c1.B
300 p.Pix[i+3] = c1.A
301 }
302
303 func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
304 if !(Point{x, y}.In(p.Rect)) {
305 return
306 }
307 i := p.PixOffset(x, y)
308 p.Pix[i+0] = c.R
309 p.Pix[i+1] = c.G
310 p.Pix[i+2] = c.B
311 p.Pix[i+3] = c.A
312 }
313
314 // SubImage returns an image representing the portion of the image p visible
315 // through r. The returned value shares pixels with the original image.
316 func (p *NRGBA) SubImage(r Rectangle) Image {
317 r = r.Intersect(p.Rect)
318 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
319 // either r1 or r2 if the intersection is empty. Without explicitly checking for
320 // this, the Pix[i:] expression below can panic.
321 if r.Empty() {
322 return &NRGBA{}
323 }
324 i := p.PixOffset(r.Min.X, r.Min.Y)
325 return &NRGBA{
326 Pix: p.Pix[i:],
327 Stride: p.Stride,
328 Rect: r,
329 }
330 }
331
332 // Opaque scans the entire image and returns whether or not it is fully opaque.
333 func (p *NRGBA) Opaque() bool {
334 if p.Rect.Empty() {
335 return true
336 }
337 i0, i1 := 3, p.Rect.Dx()*4
338 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
339 for i := i0; i < i1; i += 4 {
340 if p.Pix[i] != 0xff {
341 return false
342 }
343 }
344 i0 += p.Stride
345 i1 += p.Stride
346 }
347 return true
348 }
349
350 // NewNRGBA returns a new NRGBA with the given bounds.
351 func NewNRGBA(r Rectangle) *NRGBA {
352 w, h := r.Dx(), r.Dy()
353 pix := make([]uint8, 4*w*h)
354 return &NRGBA{pix, 4 * w, r}
355 }
356
357 // NRGBA64 is an in-memory image whose At method returns color.NRGBA64 values.
358 type NRGBA64 struct {
359 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
360 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
361 Pix []uint8
362 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
363 Stride int
364 // Rect is the image's bounds.
365 Rect Rectangle
366 }
367
368 func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
369
370 func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
371
372 func (p *NRGBA64) At(x, y int) color.Color {
373 if !(Point{x, y}.In(p.Rect)) {
374 return color.NRGBA64{}
375 }
376 i := p.PixOffset(x, y)
377 return color.NRGBA64{
378 uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
379 uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
380 uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
381 uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
382 }
383 }
384
385 // PixOffset returns the index of the first element of Pix that corresponds to
386 // the pixel at (x, y).
387 func (p *NRGBA64) PixOffset(x, y int) int {
388 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
389 }
390
391 func (p *NRGBA64) Set(x, y int, c color.Color) {
392 if !(Point{x, y}.In(p.Rect)) {
393 return
394 }
395 i := p.PixOffset(x, y)
396 c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
397 p.Pix[i+0] = uint8(c1.R >> 8)
398 p.Pix[i+1] = uint8(c1.R)
399 p.Pix[i+2] = uint8(c1.G >> 8)
400 p.Pix[i+3] = uint8(c1.G)
401 p.Pix[i+4] = uint8(c1.B >> 8)
402 p.Pix[i+5] = uint8(c1.B)
403 p.Pix[i+6] = uint8(c1.A >> 8)
404 p.Pix[i+7] = uint8(c1.A)
405 }
406
407 func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
408 if !(Point{x, y}.In(p.Rect)) {
409 return
410 }
411 i := p.PixOffset(x, y)
412 p.Pix[i+0] = uint8(c.R >> 8)
413 p.Pix[i+1] = uint8(c.R)
414 p.Pix[i+2] = uint8(c.G >> 8)
415 p.Pix[i+3] = uint8(c.G)
416 p.Pix[i+4] = uint8(c.B >> 8)
417 p.Pix[i+5] = uint8(c.B)
418 p.Pix[i+6] = uint8(c.A >> 8)
419 p.Pix[i+7] = uint8(c.A)
420 }
421
422 // SubImage returns an image representing the portion of the image p visible
423 // through r. The returned value shares pixels with the original image.
424 func (p *NRGBA64) SubImage(r Rectangle) Image {
425 r = r.Intersect(p.Rect)
426 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
427 // either r1 or r2 if the intersection is empty. Without explicitly checking for
428 // this, the Pix[i:] expression below can panic.
429 if r.Empty() {
430 return &NRGBA64{}
431 }
432 i := p.PixOffset(r.Min.X, r.Min.Y)
433 return &NRGBA64{
434 Pix: p.Pix[i:],
435 Stride: p.Stride,
436 Rect: r,
437 }
438 }
439
440 // Opaque scans the entire image and returns whether or not it is fully opaque.
441 func (p *NRGBA64) Opaque() bool {
442 if p.Rect.Empty() {
443 return true
444 }
445 i0, i1 := 6, p.Rect.Dx()*8
446 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
447 for i := i0; i < i1; i += 8 {
448 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
449 return false
450 }
451 }
452 i0 += p.Stride
453 i1 += p.Stride
454 }
455 return true
456 }
457
458 // NewNRGBA64 returns a new NRGBA64 with the given bounds.
459 func NewNRGBA64(r Rectangle) *NRGBA64 {
460 w, h := r.Dx(), r.Dy()
461 pix := make([]uint8, 8*w*h)
462 return &NRGBA64{pix, 8 * w, r}
463 }
464
465 // Alpha is an in-memory image whose At method returns color.Alpha values.
466 type Alpha struct {
467 // Pix holds the image's pixels, as alpha values. The pixel at
468 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
469 Pix []uint8
470 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
471 Stride int
472 // Rect is the image's bounds.
473 Rect Rectangle
474 }
475
476 func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
477
478 func (p *Alpha) Bounds() Rectangle { return p.Rect }
479
480 func (p *Alpha) At(x, y int) color.Color {
481 if !(Point{x, y}.In(p.Rect)) {
482 return color.Alpha{}
483 }
484 i := p.PixOffset(x, y)
485 return color.Alpha{p.Pix[i]}
486 }
487
488 // PixOffset returns the index of the first element of Pix that corresponds to
489 // the pixel at (x, y).
490 func (p *Alpha) PixOffset(x, y int) int {
491 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
492 }
493
494 func (p *Alpha) Set(x, y int, c color.Color) {
495 if !(Point{x, y}.In(p.Rect)) {
496 return
497 }
498 i := p.PixOffset(x, y)
499 p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
500 }
501
502 func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
503 if !(Point{x, y}.In(p.Rect)) {
504 return
505 }
506 i := p.PixOffset(x, y)
507 p.Pix[i] = c.A
508 }
509
510 // SubImage returns an image representing the portion of the image p visible
511 // through r. The returned value shares pixels with the original image.
512 func (p *Alpha) SubImage(r Rectangle) Image {
513 r = r.Intersect(p.Rect)
514 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
515 // either r1 or r2 if the intersection is empty. Without explicitly checking for
516 // this, the Pix[i:] expression below can panic.
517 if r.Empty() {
518 return &Alpha{}
519 }
520 i := p.PixOffset(r.Min.X, r.Min.Y)
521 return &Alpha{
522 Pix: p.Pix[i:],
523 Stride: p.Stride,
524 Rect: r,
525 }
526 }
527
528 // Opaque scans the entire image and returns whether or not it is fully opaque.
529 func (p *Alpha) Opaque() bool {
530 if p.Rect.Empty() {
531 return true
532 }
533 i0, i1 := 0, p.Rect.Dx()
534 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
535 for i := i0; i < i1; i++ {
536 if p.Pix[i] != 0xff {
537 return false
538 }
539 }
540 i0 += p.Stride
541 i1 += p.Stride
542 }
543 return true
544 }
545
546 // NewAlpha returns a new Alpha with the given bounds.
547 func NewAlpha(r Rectangle) *Alpha {
548 w, h := r.Dx(), r.Dy()
549 pix := make([]uint8, 1*w*h)
550 return &Alpha{pix, 1 * w, r}
551 }
552
553 // Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
554 type Alpha16 struct {
555 // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
556 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
557 Pix []uint8
558 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
559 Stride int
560 // Rect is the image's bounds.
561 Rect Rectangle
562 }
563
564 func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
565
566 func (p *Alpha16) Bounds() Rectangle { return p.Rect }
567
568 func (p *Alpha16) At(x, y int) color.Color {
569 if !(Point{x, y}.In(p.Rect)) {
570 return color.Alpha16{}
571 }
572 i := p.PixOffset(x, y)
573 return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
574 }
575
576 // PixOffset returns the index of the first element of Pix that corresponds to
577 // the pixel at (x, y).
578 func (p *Alpha16) PixOffset(x, y int) int {
579 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
580 }
581
582 func (p *Alpha16) Set(x, y int, c color.Color) {
583 if !(Point{x, y}.In(p.Rect)) {
584 return
585 }
586 i := p.PixOffset(x, y)
587 c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
588 p.Pix[i+0] = uint8(c1.A >> 8)
589 p.Pix[i+1] = uint8(c1.A)
590 }
591
592 func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
593 if !(Point{x, y}.In(p.Rect)) {
594 return
595 }
596 i := p.PixOffset(x, y)
597 p.Pix[i+0] = uint8(c.A >> 8)
598 p.Pix[i+1] = uint8(c.A)
599 }
600
601 // SubImage returns an image representing the portion of the image p visible
602 // through r. The returned value shares pixels with the original image.
603 func (p *Alpha16) SubImage(r Rectangle) Image {
604 r = r.Intersect(p.Rect)
605 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
606 // either r1 or r2 if the intersection is empty. Without explicitly checking for
607 // this, the Pix[i:] expression below can panic.
608 if r.Empty() {
609 return &Alpha16{}
610 }
611 i := p.PixOffset(r.Min.X, r.Min.Y)
612 return &Alpha16{
613 Pix: p.Pix[i:],
614 Stride: p.Stride,
615 Rect: r,
616 }
617 }
618
619 // Opaque scans the entire image and returns whether or not it is fully opaque.
620 func (p *Alpha16) Opaque() bool {
621 if p.Rect.Empty() {
622 return true
623 }
624 i0, i1 := 0, p.Rect.Dx()*2
625 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
626 for i := i0; i < i1; i += 2 {
627 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
628 return false
629 }
630 }
631 i0 += p.Stride
632 i1 += p.Stride
633 }
634 return true
635 }
636
637 // NewAlpha16 returns a new Alpha16 with the given bounds.
638 func NewAlpha16(r Rectangle) *Alpha16 {
639 w, h := r.Dx(), r.Dy()
640 pix := make([]uint8, 2*w*h)
641 return &Alpha16{pix, 2 * w, r}
642 }
643
644 // Gray is an in-memory image whose At method returns color.Gray values.
645 type Gray struct {
646 // Pix holds the image's pixels, as gray values. The pixel at
647 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
648 Pix []uint8
649 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
650 Stride int
651 // Rect is the image's bounds.
652 Rect Rectangle
653 }
654
655 func (p *Gray) ColorModel() color.Model { return color.GrayModel }
656
657 func (p *Gray) Bounds() Rectangle { return p.Rect }
658
659 func (p *Gray) At(x, y int) color.Color {
660 if !(Point{x, y}.In(p.Rect)) {
661 return color.Gray{}
662 }
663 i := p.PixOffset(x, y)
664 return color.Gray{p.Pix[i]}
665 }
666
667 // PixOffset returns the index of the first element of Pix that corresponds to
668 // the pixel at (x, y).
669 func (p *Gray) PixOffset(x, y int) int {
670 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
671 }
672
673 func (p *Gray) Set(x, y int, c color.Color) {
674 if !(Point{x, y}.In(p.Rect)) {
675 return
676 }
677 i := p.PixOffset(x, y)
678 p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
679 }
680
681 func (p *Gray) SetGray(x, y int, c color.Gray) {
682 if !(Point{x, y}.In(p.Rect)) {
683 return
684 }
685 i := p.PixOffset(x, y)
686 p.Pix[i] = c.Y
687 }
688
689 // SubImage returns an image representing the portion of the image p visible
690 // through r. The returned value shares pixels with the original image.
691 func (p *Gray) SubImage(r Rectangle) Image {
692 r = r.Intersect(p.Rect)
693 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
694 // either r1 or r2 if the intersection is empty. Without explicitly checking for
695 // this, the Pix[i:] expression below can panic.
696 if r.Empty() {
697 return &Gray{}
698 }
699 i := p.PixOffset(r.Min.X, r.Min.Y)
700 return &Gray{
701 Pix: p.Pix[i:],
702 Stride: p.Stride,
703 Rect: r,
704 }
705 }
706
707 // Opaque scans the entire image and returns whether or not it is fully opaque.
708 func (p *Gray) Opaque() bool {
709 return true
710 }
711
712 // NewGray returns a new Gray with the given bounds.
713 func NewGray(r Rectangle) *Gray {
714 w, h := r.Dx(), r.Dy()
715 pix := make([]uint8, 1*w*h)
716 return &Gray{pix, 1 * w, r}
717 }
718
719 // Gray16 is an in-memory image whose At method returns color.Gray16 values.
720 type Gray16 struct {
721 // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
722 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
723 Pix []uint8
724 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
725 Stride int
726 // Rect is the image's bounds.
727 Rect Rectangle
728 }
729
730 func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
731
732 func (p *Gray16) Bounds() Rectangle { return p.Rect }
733
734 func (p *Gray16) At(x, y int) color.Color {
735 if !(Point{x, y}.In(p.Rect)) {
736 return color.Gray16{}
737 }
738 i := p.PixOffset(x, y)
739 return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
740 }
741
742 // PixOffset returns the index of the first element of Pix that corresponds to
743 // the pixel at (x, y).
744 func (p *Gray16) PixOffset(x, y int) int {
745 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
746 }
747
748 func (p *Gray16) Set(x, y int, c color.Color) {
749 if !(Point{x, y}.In(p.Rect)) {
750 return
751 }
752 i := p.PixOffset(x, y)
753 c1 := color.Gray16Model.Convert(c).(color.Gray16)
754 p.Pix[i+0] = uint8(c1.Y >> 8)
755 p.Pix[i+1] = uint8(c1.Y)
756 }
757
758 func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
759 if !(Point{x, y}.In(p.Rect)) {
760 return
761 }
762 i := p.PixOffset(x, y)
763 p.Pix[i+0] = uint8(c.Y >> 8)
764 p.Pix[i+1] = uint8(c.Y)
765 }
766
767 // SubImage returns an image representing the portion of the image p visible
768 // through r. The returned value shares pixels with the original image.
769 func (p *Gray16) SubImage(r Rectangle) Image {
770 r = r.Intersect(p.Rect)
771 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
772 // either r1 or r2 if the intersection is empty. Without explicitly checking for
773 // this, the Pix[i:] expression below can panic.
774 if r.Empty() {
775 return &Gray16{}
776 }
777 i := p.PixOffset(r.Min.X, r.Min.Y)
778 return &Gray16{
779 Pix: p.Pix[i:],
780 Stride: p.Stride,
781 Rect: r,
782 }
783 }
784
785 // Opaque scans the entire image and returns whether or not it is fully opaque.
786 func (p *Gray16) Opaque() bool {
787 return true
788 }
789
790 // NewGray16 returns a new Gray16 with the given bounds.
791 func NewGray16(r Rectangle) *Gray16 {
792 w, h := r.Dx(), r.Dy()
793 pix := make([]uint8, 2*w*h)
794 return &Gray16{pix, 2 * w, r}
795 }
796
797 // Paletted is an in-memory image of uint8 indices into a given palette.
798 type Paletted struct {
799 // Pix holds the image's pixels, as palette indices. The pixel at
800 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
801 Pix []uint8
802 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
803 Stride int
804 // Rect is the image's bounds.
805 Rect Rectangle
806 // Palette is the image's palette.
807 Palette color.Palette
808 }
809
810 func (p *Paletted) ColorModel() color.Model { return p.Palette }
811
812 func (p *Paletted) Bounds() Rectangle { return p.Rect }
813
814 func (p *Paletted) At(x, y int) color.Color {
815 if len(p.Palette) == 0 {
816 return nil
817 }
818 if !(Point{x, y}.In(p.Rect)) {
819 return p.Palette[0]
820 }
821 i := p.PixOffset(x, y)
822 return p.Palette[p.Pix[i]]
823 }
824
825 // PixOffset returns the index of the first element of Pix that corresponds to
826 // the pixel at (x, y).
827 func (p *Paletted) PixOffset(x, y int) int {
828 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
829 }
830
831 func (p *Paletted) Set(x, y int, c color.Color) {
832 if !(Point{x, y}.In(p.Rect)) {
833 return
834 }
835 i := p.PixOffset(x, y)
836 p.Pix[i] = uint8(p.Palette.Index(c))
837 }
838
839 func (p *Paletted) ColorIndexAt(x, y int) uint8 {
840 if !(Point{x, y}.In(p.Rect)) {
841 return 0
842 }
843 i := p.PixOffset(x, y)
844 return p.Pix[i]
845 }
846
847 func (p *Paletted) SetColorIndex(x, y int, index uint8) {
848 if !(Point{x, y}.In(p.Rect)) {
849 return
850 }
851 i := p.PixOffset(x, y)
852 p.Pix[i] = index
853 }
854
855 // SubImage returns an image representing the portion of the image p visible
856 // through r. The returned value shares pixels with the original image.
857 func (p *Paletted) SubImage(r Rectangle) Image {
858 r = r.Intersect(p.Rect)
859 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
860 // either r1 or r2 if the intersection is empty. Without explicitly checking for
861 // this, the Pix[i:] expression below can panic.
862 if r.Empty() {
863 return &Paletted{
864 Palette: p.Palette,
865 }
866 }
867 i := p.PixOffset(r.Min.X, r.Min.Y)
868 return &Paletted{
869 Pix: p.Pix[i:],
870 Stride: p.Stride,
871 Rect: p.Rect.Intersect(r),
872 Palette: p.Palette,
873 }
874 }
875
876 // Opaque scans the entire image and returns whether or not it is fully opaque.
877 func (p *Paletted) Opaque() bool {
878 var present [256]bool
879 i0, i1 := 0, p.Rect.Dx()
880 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
881 for _, c := range p.Pix[i0:i1] {
882 present[c] = true
883 }
884 i0 += p.Stride
885 i1 += p.Stride
886 }
887 for i, c := range p.Palette {
888 if !present[i] {
889 continue
890 }
891 _, _, _, a := c.RGBA()
892 if a != 0xffff {
893 return false
894 }
895 }
896 return true
897 }
898
899 // NewPaletted returns a new Paletted with the given width, height and palette.
900 func NewPaletted(r Rectangle, p color.Palette) *Paletted {
901 w, h := r.Dx(), r.Dy()
902 pix := make([]uint8, 1*w*h)
903 return &Paletted{pix, 1 * w, r, p}
904 }