image.go 27.1 KB
Newer Older
Nigel Tao's avatar
Nigel Tao committed
1 2 3 4
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

5
// Package image implements a basic 2-D image library.
6
//
7 8 9 10 11 12 13 14 15 16 17 18 19 20
// The fundamental interface is called Image. An Image contains colors, which
// are described in the image/color package.
//
// Values of the Image interface are created either by calling functions such
// as NewRGBA and NewPaletted, or by calling Decode on an io.Reader containing
// image data in a format such as GIF, JPEG or PNG. Decoding any particular
// image format requires the prior registration of a decoder function.
// Registration is typically automatic as a side effect of initializing that
// format's package so that, to decode a PNG image, it suffices to have
//	import _ "image/png"
// in a program's main package. The _ means to import a package purely for its
// initialization side effects.
//
// See "The Go image package" for more details:
21
// http://golang.org/doc/articles/image_package.html
Nigel Tao's avatar
Nigel Tao committed
22 23
package image

24 25 26 27
import (
	"image/color"
)

28
// Config holds an image's color model and dimensions.
29
type Config struct {
30
	ColorModel    color.Model
31 32 33
	Width, Height int
}

34 35
// Image is a finite rectangular grid of color.Color values taken from a color
// model.
Nigel Tao's avatar
Nigel Tao committed
36
type Image interface {
37 38
	// ColorModel returns the Image's color model.
	ColorModel() color.Model
39 40 41 42 43 44
	// Bounds returns the domain for which At can return non-zero color.
	// The bounds do not necessarily contain the point (0, 0).
	Bounds() Rectangle
	// At returns the color of the pixel at (x, y).
	// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
	// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
45
	At(x, y int) color.Color
Nigel Tao's avatar
Nigel Tao committed
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 color.Palette 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 color.Palette, then ColorIndexAt's behavior is
52 53 54 55 56 57 58
// undefined.
type PalettedImage interface {
	// ColorIndexAt returns the palette index of the pixel at (x, y).
	ColorIndexAt(x, y int) uint8
	Image
}

59
// RGBA is an in-memory image whose At method returns color.RGBA values.
Nigel Tao's avatar
Nigel Tao committed
60
type RGBA struct {
61 62 63 64
	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
65 66 67
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
Nigel Tao's avatar
Nigel Tao committed
68 69
}

70
func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
Nigel Tao's avatar
Nigel Tao committed
71

72
func (p *RGBA) Bounds() Rectangle { return p.Rect }
Nigel Tao's avatar
Nigel Tao committed
73

74
func (p *RGBA) At(x, y int) color.Color {
75 76 77 78
	return p.RGBAAt(x, y)
}

func (p *RGBA) RGBAAt(x, y int) color.RGBA {
79
	if !(Point{x, y}.In(p.Rect)) {
80
		return color.RGBA{}
81
	}
82
	i := p.PixOffset(x, y)
83
	return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
84
}
Nigel Tao's avatar
Nigel Tao committed
85

86 87 88 89 90 91
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *RGBA) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
}

92
func (p *RGBA) Set(x, y int, c color.Color) {
93
	if !(Point{x, y}.In(p.Rect)) {
94 95
		return
	}
96
	i := p.PixOffset(x, y)
97
	c1 := color.RGBAModel.Convert(c).(color.RGBA)
98 99 100 101
	p.Pix[i+0] = c1.R
	p.Pix[i+1] = c1.G
	p.Pix[i+2] = c1.B
	p.Pix[i+3] = c1.A
102
}
Nigel Tao's avatar
Nigel Tao committed
103

104
func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
105
	if !(Point{x, y}.In(p.Rect)) {
106 107
		return
	}
108
	i := p.PixOffset(x, y)
109 110 111 112
	p.Pix[i+0] = c.R
	p.Pix[i+1] = c.G
	p.Pix[i+2] = c.B
	p.Pix[i+3] = c.A
113 114
}

Nigel Tao's avatar
Nigel Tao committed
115 116 117
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *RGBA) SubImage(r Rectangle) Image {
118 119 120 121 122 123 124
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &RGBA{}
	}
125
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
126
	return &RGBA{
127
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
128
		Stride: p.Stride,
129
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
130 131 132
	}
}

133
// Opaque scans the entire image and reports whether it is fully opaque.
134
func (p *RGBA) Opaque() bool {
135 136 137
	if p.Rect.Empty() {
		return true
	}
138
	i0, i1 := 3, p.Rect.Dx()*4
139
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
140 141
		for i := i0; i < i1; i += 4 {
			if p.Pix[i] != 0xff {
142
				return false
143 144
			}
		}
145 146
		i0 += p.Stride
		i1 += p.Stride
147 148 149 150
	}
	return true
}

151
// NewRGBA returns a new RGBA with the given bounds.
152 153
func NewRGBA(r Rectangle) *RGBA {
	w, h := r.Dx(), r.Dy()
154
	buf := make([]uint8, 4*w*h)
155
	return &RGBA{buf, 4 * w, r}
Nigel Tao's avatar
Nigel Tao committed
156 157
}

158
// RGBA64 is an in-memory image whose At method returns color.RGBA64 values.
Nigel Tao's avatar
Nigel Tao committed
159
type RGBA64 struct {
160 161 162 163
	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
164 165 166
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
Nigel Tao's avatar
Nigel Tao committed
167 168
}

169
func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
Nigel Tao's avatar
Nigel Tao committed
170

171 172
func (p *RGBA64) Bounds() Rectangle { return p.Rect }

173
func (p *RGBA64) At(x, y int) color.Color {
174 175 176 177
	return p.RGBA64At(x, y)
}

func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 {
178
	if !(Point{x, y}.In(p.Rect)) {
179
		return color.RGBA64{}
Nigel Tao's avatar
Nigel Tao committed
180
	}
181
	i := p.PixOffset(x, y)
182
	return color.RGBA64{
183 184 185 186 187
		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
		uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
	}
Nigel Tao's avatar
Nigel Tao committed
188 189
}

190 191 192 193 194 195
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *RGBA64) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
}

196
func (p *RGBA64) Set(x, y int, c color.Color) {
197
	if !(Point{x, y}.In(p.Rect)) {
198 199
		return
	}
200
	i := p.PixOffset(x, y)
201
	c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
202 203 204 205 206 207 208 209
	p.Pix[i+0] = uint8(c1.R >> 8)
	p.Pix[i+1] = uint8(c1.R)
	p.Pix[i+2] = uint8(c1.G >> 8)
	p.Pix[i+3] = uint8(c1.G)
	p.Pix[i+4] = uint8(c1.B >> 8)
	p.Pix[i+5] = uint8(c1.B)
	p.Pix[i+6] = uint8(c1.A >> 8)
	p.Pix[i+7] = uint8(c1.A)
210
}
Nigel Tao's avatar
Nigel Tao committed
211

212
func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
213
	if !(Point{x, y}.In(p.Rect)) {
214 215
		return
	}
216
	i := p.PixOffset(x, y)
217 218 219 220 221 222 223 224
	p.Pix[i+0] = uint8(c.R >> 8)
	p.Pix[i+1] = uint8(c.R)
	p.Pix[i+2] = uint8(c.G >> 8)
	p.Pix[i+3] = uint8(c.G)
	p.Pix[i+4] = uint8(c.B >> 8)
	p.Pix[i+5] = uint8(c.B)
	p.Pix[i+6] = uint8(c.A >> 8)
	p.Pix[i+7] = uint8(c.A)
225 226
}

Nigel Tao's avatar
Nigel Tao committed
227 228 229
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *RGBA64) SubImage(r Rectangle) Image {
230 231 232 233 234 235 236
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &RGBA64{}
	}
237
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
238
	return &RGBA64{
239
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
240
		Stride: p.Stride,
241
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
242 243 244
	}
}

245
// Opaque scans the entire image and reports whether it is fully opaque.
246
func (p *RGBA64) Opaque() bool {
247 248 249
	if p.Rect.Empty() {
		return true
	}
250
	i0, i1 := 6, p.Rect.Dx()*8
251
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
252 253
		for i := i0; i < i1; i += 8 {
			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
254
				return false
255 256
			}
		}
257 258
		i0 += p.Stride
		i1 += p.Stride
259 260 261 262
	}
	return true
}

263
// NewRGBA64 returns a new RGBA64 with the given bounds.
264 265
func NewRGBA64(r Rectangle) *RGBA64 {
	w, h := r.Dx(), r.Dy()
266
	pix := make([]uint8, 8*w*h)
267
	return &RGBA64{pix, 8 * w, r}
Nigel Tao's avatar
Nigel Tao committed
268 269
}

270
// NRGBA is an in-memory image whose At method returns color.NRGBA values.
Nigel Tao's avatar
Nigel Tao committed
271
type NRGBA struct {
272 273 274 275
	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
276 277 278
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
Nigel Tao's avatar
Nigel Tao committed
279 280
}

281
func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
Nigel Tao's avatar
Nigel Tao committed
282

283 284
func (p *NRGBA) Bounds() Rectangle { return p.Rect }

285
func (p *NRGBA) At(x, y int) color.Color {
286 287 288 289
	return p.NRGBAAt(x, y)
}

func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
290
	if !(Point{x, y}.In(p.Rect)) {
291
		return color.NRGBA{}
Nigel Tao's avatar
Nigel Tao committed
292
	}
293
	i := p.PixOffset(x, y)
294
	return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
Nigel Tao's avatar
Nigel Tao committed
295 296
}

297 298 299 300 301 302
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *NRGBA) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
}

303
func (p *NRGBA) Set(x, y int, c color.Color) {
304
	if !(Point{x, y}.In(p.Rect)) {
305 306
		return
	}
307
	i := p.PixOffset(x, y)
308
	c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
309 310 311 312
	p.Pix[i+0] = c1.R
	p.Pix[i+1] = c1.G
	p.Pix[i+2] = c1.B
	p.Pix[i+3] = c1.A
313
}
Nigel Tao's avatar
Nigel Tao committed
314

315
func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
316
	if !(Point{x, y}.In(p.Rect)) {
317 318
		return
	}
319
	i := p.PixOffset(x, y)
320 321 322 323
	p.Pix[i+0] = c.R
	p.Pix[i+1] = c.G
	p.Pix[i+2] = c.B
	p.Pix[i+3] = c.A
324 325
}

Nigel Tao's avatar
Nigel Tao committed
326 327 328
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *NRGBA) SubImage(r Rectangle) Image {
329 330 331 332 333 334 335
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &NRGBA{}
	}
336
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
337
	return &NRGBA{
338
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
339
		Stride: p.Stride,
340
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
341 342 343
	}
}

344
// Opaque scans the entire image and reports whether it is fully opaque.
345
func (p *NRGBA) Opaque() bool {
346 347 348
	if p.Rect.Empty() {
		return true
	}
349
	i0, i1 := 3, p.Rect.Dx()*4
350
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
351 352
		for i := i0; i < i1; i += 4 {
			if p.Pix[i] != 0xff {
353
				return false
354 355
			}
		}
356 357
		i0 += p.Stride
		i1 += p.Stride
358 359 360 361
	}
	return true
}

362
// NewNRGBA returns a new NRGBA with the given bounds.
363 364
func NewNRGBA(r Rectangle) *NRGBA {
	w, h := r.Dx(), r.Dy()
365
	pix := make([]uint8, 4*w*h)
366
	return &NRGBA{pix, 4 * w, r}
Nigel Tao's avatar
Nigel Tao committed
367 368
}

369
// NRGBA64 is an in-memory image whose At method returns color.NRGBA64 values.
Nigel Tao's avatar
Nigel Tao committed
370
type NRGBA64 struct {
371 372 373 374
	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
375 376 377
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
Nigel Tao's avatar
Nigel Tao committed
378 379
}

380
func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
Nigel Tao's avatar
Nigel Tao committed
381

382 383
func (p *NRGBA64) Bounds() Rectangle { return p.Rect }

384
func (p *NRGBA64) At(x, y int) color.Color {
385 386 387 388
	return p.NRGBA64At(x, y)
}

func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
389
	if !(Point{x, y}.In(p.Rect)) {
390
		return color.NRGBA64{}
Nigel Tao's avatar
Nigel Tao committed
391
	}
392
	i := p.PixOffset(x, y)
393
	return color.NRGBA64{
394 395 396 397 398
		uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
		uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
		uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
		uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
	}
Nigel Tao's avatar
Nigel Tao committed
399 400
}

401 402 403 404 405 406
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *NRGBA64) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
}

407
func (p *NRGBA64) Set(x, y int, c color.Color) {
408
	if !(Point{x, y}.In(p.Rect)) {
409 410
		return
	}
411
	i := p.PixOffset(x, y)
412
	c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
413 414 415 416 417 418 419 420
	p.Pix[i+0] = uint8(c1.R >> 8)
	p.Pix[i+1] = uint8(c1.R)
	p.Pix[i+2] = uint8(c1.G >> 8)
	p.Pix[i+3] = uint8(c1.G)
	p.Pix[i+4] = uint8(c1.B >> 8)
	p.Pix[i+5] = uint8(c1.B)
	p.Pix[i+6] = uint8(c1.A >> 8)
	p.Pix[i+7] = uint8(c1.A)
421
}
Nigel Tao's avatar
Nigel Tao committed
422

423
func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
424
	if !(Point{x, y}.In(p.Rect)) {
425 426
		return
	}
427
	i := p.PixOffset(x, y)
428 429 430 431 432 433 434 435
	p.Pix[i+0] = uint8(c.R >> 8)
	p.Pix[i+1] = uint8(c.R)
	p.Pix[i+2] = uint8(c.G >> 8)
	p.Pix[i+3] = uint8(c.G)
	p.Pix[i+4] = uint8(c.B >> 8)
	p.Pix[i+5] = uint8(c.B)
	p.Pix[i+6] = uint8(c.A >> 8)
	p.Pix[i+7] = uint8(c.A)
436 437
}

Nigel Tao's avatar
Nigel Tao committed
438 439 440
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *NRGBA64) SubImage(r Rectangle) Image {
441 442 443 444 445 446 447
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &NRGBA64{}
	}
448
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
449
	return &NRGBA64{
450
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
451
		Stride: p.Stride,
452
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
453 454 455
	}
}

456
// Opaque scans the entire image and reports whether it is fully opaque.
457
func (p *NRGBA64) Opaque() bool {
458 459 460
	if p.Rect.Empty() {
		return true
	}
461
	i0, i1 := 6, p.Rect.Dx()*8
462
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
463 464
		for i := i0; i < i1; i += 8 {
			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
465
				return false
466 467
			}
		}
468 469
		i0 += p.Stride
		i1 += p.Stride
470 471 472 473
	}
	return true
}

474
// NewNRGBA64 returns a new NRGBA64 with the given bounds.
475 476
func NewNRGBA64(r Rectangle) *NRGBA64 {
	w, h := r.Dx(), r.Dy()
477
	pix := make([]uint8, 8*w*h)
478
	return &NRGBA64{pix, 8 * w, r}
Nigel Tao's avatar
Nigel Tao committed
479 480
}

481
// Alpha is an in-memory image whose At method returns color.Alpha values.
482
type Alpha struct {
483 484 485 486
	// Pix holds the image's pixels, as alpha values. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
487 488 489
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
490 491
}

492
func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
493

494 495
func (p *Alpha) Bounds() Rectangle { return p.Rect }

496
func (p *Alpha) At(x, y int) color.Color {
497 498 499 500
	return p.AlphaAt(x, y)
}

func (p *Alpha) AlphaAt(x, y int) color.Alpha {
501
	if !(Point{x, y}.In(p.Rect)) {
502
		return color.Alpha{}
503
	}
504
	i := p.PixOffset(x, y)
505
	return color.Alpha{p.Pix[i]}
506 507
}

508 509 510 511 512 513
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Alpha) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
}

514
func (p *Alpha) Set(x, y int, c color.Color) {
515
	if !(Point{x, y}.In(p.Rect)) {
Rob Pike's avatar
Rob Pike committed
516 517
		return
	}
518
	i := p.PixOffset(x, y)
519
	p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
Rob Pike's avatar
Rob Pike committed
520 521
}

522
func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
523
	if !(Point{x, y}.In(p.Rect)) {
524 525
		return
	}
526
	i := p.PixOffset(x, y)
527
	p.Pix[i] = c.A
528
}
529

Nigel Tao's avatar
Nigel Tao committed
530 531 532
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Alpha) SubImage(r Rectangle) Image {
533 534 535 536 537 538 539
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Alpha{}
	}
540
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
541
	return &Alpha{
542
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
543
		Stride: p.Stride,
544
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
545 546 547
	}
}

548
// Opaque scans the entire image and reports whether it is fully opaque.
549
func (p *Alpha) Opaque() bool {
550 551 552
	if p.Rect.Empty() {
		return true
	}
553
	i0, i1 := 0, p.Rect.Dx()
554
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
555 556
		for i := i0; i < i1; i++ {
			if p.Pix[i] != 0xff {
557
				return false
558 559
			}
		}
560 561
		i0 += p.Stride
		i1 += p.Stride
562 563 564 565
	}
	return true
}

566
// NewAlpha returns a new Alpha with the given bounds.
567 568
func NewAlpha(r Rectangle) *Alpha {
	w, h := r.Dx(), r.Dy()
569
	pix := make([]uint8, 1*w*h)
570
	return &Alpha{pix, 1 * w, r}
571 572
}

573
// Alpha16 is an in-memory image whose At method returns color.Alpha16 values.
574
type Alpha16 struct {
575 576 577 578
	// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
579 580 581
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
582 583
}

584
func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
585

586 587
func (p *Alpha16) Bounds() Rectangle { return p.Rect }

588
func (p *Alpha16) At(x, y int) color.Color {
589 590 591 592
	return p.Alpha16At(x, y)
}

func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
593
	if !(Point{x, y}.In(p.Rect)) {
594
		return color.Alpha16{}
595
	}
596
	i := p.PixOffset(x, y)
597
	return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
598 599
}

600 601 602 603 604 605
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Alpha16) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}

606
func (p *Alpha16) Set(x, y int, c color.Color) {
607
	if !(Point{x, y}.In(p.Rect)) {
608 609
		return
	}
610
	i := p.PixOffset(x, y)
611
	c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
612 613
	p.Pix[i+0] = uint8(c1.A >> 8)
	p.Pix[i+1] = uint8(c1.A)
614
}
615

616
func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
617
	if !(Point{x, y}.In(p.Rect)) {
618 619
		return
	}
620
	i := p.PixOffset(x, y)
621 622
	p.Pix[i+0] = uint8(c.A >> 8)
	p.Pix[i+1] = uint8(c.A)
623 624
}

Nigel Tao's avatar
Nigel Tao committed
625 626 627
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Alpha16) SubImage(r Rectangle) Image {
628 629 630 631 632 633 634
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Alpha16{}
	}
635
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
636
	return &Alpha16{
637
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
638
		Stride: p.Stride,
639
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
640 641 642
	}
}

643
// Opaque scans the entire image and reports whether it is fully opaque.
644
func (p *Alpha16) Opaque() bool {
645 646 647
	if p.Rect.Empty() {
		return true
	}
648
	i0, i1 := 0, p.Rect.Dx()*2
649
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
650 651
		for i := i0; i < i1; i += 2 {
			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
652
				return false
653 654
			}
		}
655 656
		i0 += p.Stride
		i1 += p.Stride
657 658 659 660
	}
	return true
}

661
// NewAlpha16 returns a new Alpha16 with the given bounds.
662 663
func NewAlpha16(r Rectangle) *Alpha16 {
	w, h := r.Dx(), r.Dy()
664
	pix := make([]uint8, 2*w*h)
665
	return &Alpha16{pix, 2 * w, r}
666 667
}

668
// Gray is an in-memory image whose At method returns color.Gray values.
669
type Gray struct {
670 671 672 673
	// Pix holds the image's pixels, as gray values. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
674 675 676
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
677 678
}

679
func (p *Gray) ColorModel() color.Model { return color.GrayModel }
680

681 682
func (p *Gray) Bounds() Rectangle { return p.Rect }

683
func (p *Gray) At(x, y int) color.Color {
684 685 686 687
	return p.GrayAt(x, y)
}

func (p *Gray) GrayAt(x, y int) color.Gray {
688
	if !(Point{x, y}.In(p.Rect)) {
689
		return color.Gray{}
690
	}
691
	i := p.PixOffset(x, y)
692
	return color.Gray{p.Pix[i]}
693 694
}

695 696 697 698 699 700
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Gray) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
}

701
func (p *Gray) Set(x, y int, c color.Color) {
702
	if !(Point{x, y}.In(p.Rect)) {
703 704
		return
	}
705
	i := p.PixOffset(x, y)
706
	p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
707
}
708

709
func (p *Gray) SetGray(x, y int, c color.Gray) {
710
	if !(Point{x, y}.In(p.Rect)) {
711 712
		return
	}
713
	i := p.PixOffset(x, y)
714
	p.Pix[i] = c.Y
715 716
}

Nigel Tao's avatar
Nigel Tao committed
717 718 719
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Gray) SubImage(r Rectangle) Image {
720 721 722 723 724 725 726
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Gray{}
	}
727
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
728
	return &Gray{
729
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
730
		Stride: p.Stride,
731
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
732 733 734
	}
}

735
// Opaque scans the entire image and reports whether it is fully opaque.
736 737 738 739
func (p *Gray) Opaque() bool {
	return true
}

740
// NewGray returns a new Gray with the given bounds.
741 742
func NewGray(r Rectangle) *Gray {
	w, h := r.Dx(), r.Dy()
743
	pix := make([]uint8, 1*w*h)
744
	return &Gray{pix, 1 * w, r}
745 746
}

747
// Gray16 is an in-memory image whose At method returns color.Gray16 values.
748
type Gray16 struct {
749 750 751 752
	// Pix holds the image's pixels, as gray values in big-endian format. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
753 754 755
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
756 757
}

758
func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
759

760 761
func (p *Gray16) Bounds() Rectangle { return p.Rect }

762
func (p *Gray16) At(x, y int) color.Color {
763 764 765 766
	return p.Gray16At(x, y)
}

func (p *Gray16) Gray16At(x, y int) color.Gray16 {
767
	if !(Point{x, y}.In(p.Rect)) {
768
		return color.Gray16{}
769
	}
770
	i := p.PixOffset(x, y)
771
	return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
772 773
}

774 775 776 777 778 779
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Gray16) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}

780
func (p *Gray16) Set(x, y int, c color.Color) {
781
	if !(Point{x, y}.In(p.Rect)) {
782 783
		return
	}
784
	i := p.PixOffset(x, y)
785
	c1 := color.Gray16Model.Convert(c).(color.Gray16)
786 787
	p.Pix[i+0] = uint8(c1.Y >> 8)
	p.Pix[i+1] = uint8(c1.Y)
788
}
789

790
func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
791
	if !(Point{x, y}.In(p.Rect)) {
792 793
		return
	}
794
	i := p.PixOffset(x, y)
795 796
	p.Pix[i+0] = uint8(c.Y >> 8)
	p.Pix[i+1] = uint8(c.Y)
797 798
}

Nigel Tao's avatar
Nigel Tao committed
799 800 801
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Gray16) SubImage(r Rectangle) Image {
802 803 804 805 806 807 808
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Gray16{}
	}
809
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
810
	return &Gray16{
811
		Pix:    p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
812
		Stride: p.Stride,
813
		Rect:   r,
Nigel Tao's avatar
Nigel Tao committed
814 815 816
	}
}

817
// Opaque scans the entire image and reports whether it is fully opaque.
818 819 820 821
func (p *Gray16) Opaque() bool {
	return true
}

822
// NewGray16 returns a new Gray16 with the given bounds.
823 824
func NewGray16(r Rectangle) *Gray16 {
	w, h := r.Dx(), r.Dy()
825
	pix := make([]uint8, 2*w*h)
826
	return &Gray16{pix, 2 * w, r}
827 828
}

829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
// CMYK is an in-memory image whose At method returns color.CMYK values.
type CMYK struct {
	// Pix holds the image's pixels, in C, M, Y, K order. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
}

func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }

func (p *CMYK) Bounds() Rectangle { return p.Rect }

func (p *CMYK) At(x, y int) color.Color {
	return p.CMYKAt(x, y)
}

func (p *CMYK) CMYKAt(x, y int) color.CMYK {
	if !(Point{x, y}.In(p.Rect)) {
		return color.CMYK{}
	}
	i := p.PixOffset(x, y)
	return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}

// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *CMYK) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
}

func (p *CMYK) Set(x, y int, c color.Color) {
	if !(Point{x, y}.In(p.Rect)) {
		return
	}
	i := p.PixOffset(x, y)
	c1 := color.CMYKModel.Convert(c).(color.CMYK)
	p.Pix[i+0] = c1.C
	p.Pix[i+1] = c1.M
	p.Pix[i+2] = c1.Y
	p.Pix[i+3] = c1.K
}

func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
	if !(Point{x, y}.In(p.Rect)) {
		return
	}
	i := p.PixOffset(x, y)
	p.Pix[i+0] = c.C
	p.Pix[i+1] = c.M
	p.Pix[i+2] = c.Y
	p.Pix[i+3] = c.K
}

// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *CMYK) SubImage(r Rectangle) Image {
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &CMYK{}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &CMYK{
		Pix:    p.Pix[i:],
		Stride: p.Stride,
		Rect:   r,
	}
}

// Opaque scans the entire image and reports whether it is fully opaque.
func (p *CMYK) Opaque() bool {
	return true
}

// NewCMYK returns a new CMYK with the given bounds.
func NewCMYK(r Rectangle) *CMYK {
	w, h := r.Dx(), r.Dy()
	buf := make([]uint8, 4*w*h)
	return &CMYK{buf, 4 * w, r}
}

915
// Paletted is an in-memory image of uint8 indices into a given palette.
Nigel Tao's avatar
Nigel Tao committed
916
type Paletted struct {
917 918 919 920
	// Pix holds the image's pixels, as palette indices. The pixel at
	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
	Pix []uint8
	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
921 922 923 924
	Stride int
	// Rect is the image's bounds.
	Rect Rectangle
	// Palette is the image's palette.
925
	Palette color.Palette
Nigel Tao's avatar
Nigel Tao committed
926 927
}

928
func (p *Paletted) ColorModel() color.Model { return p.Palette }
Nigel Tao's avatar
Nigel Tao committed
929

930 931
func (p *Paletted) Bounds() Rectangle { return p.Rect }

932
func (p *Paletted) At(x, y int) color.Color {
933 934 935
	if len(p.Palette) == 0 {
		return nil
	}
936
	if !(Point{x, y}.In(p.Rect)) {
937
		return p.Palette[0]
Nigel Tao's avatar
Nigel Tao committed
938
	}
939
	i := p.PixOffset(x, y)
940
	return p.Palette[p.Pix[i]]
Nigel Tao's avatar
Nigel Tao committed
941 942
}

943 944 945 946 947 948
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *Paletted) PixOffset(x, y int) int {
	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
}

949
func (p *Paletted) Set(x, y int, c color.Color) {
950 951 952
	if !(Point{x, y}.In(p.Rect)) {
		return
	}
953
	i := p.PixOffset(x, y)
954
	p.Pix[i] = uint8(p.Palette.Index(c))
955 956
}

957
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
958
	if !(Point{x, y}.In(p.Rect)) {
959 960
		return 0
	}
961
	i := p.PixOffset(x, y)
962
	return p.Pix[i]
963 964
}

Nigel Tao's avatar
Nigel Tao committed
965
func (p *Paletted) SetColorIndex(x, y int, index uint8) {
966
	if !(Point{x, y}.In(p.Rect)) {
967 968
		return
	}
969
	i := p.PixOffset(x, y)
970
	p.Pix[i] = index
Nigel Tao's avatar
Nigel Tao committed
971 972
}

Nigel Tao's avatar
Nigel Tao committed
973 974 975
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Paletted) SubImage(r Rectangle) Image {
976 977 978 979 980 981 982 983 984
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Paletted{
			Palette: p.Palette,
		}
	}
985
	i := p.PixOffset(r.Min.X, r.Min.Y)
Nigel Tao's avatar
Nigel Tao committed
986
	return &Paletted{
987
		Pix:     p.Pix[i:],
Nigel Tao's avatar
Nigel Tao committed
988 989 990 991 992 993
		Stride:  p.Stride,
		Rect:    p.Rect.Intersect(r),
		Palette: p.Palette,
	}
}

994
// Opaque scans the entire image and reports whether it is fully opaque.
995
func (p *Paletted) Opaque() bool {
996
	var present [256]bool
997
	i0, i1 := 0, p.Rect.Dx()
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
		for _, c := range p.Pix[i0:i1] {
			present[c] = true
		}
		i0 += p.Stride
		i1 += p.Stride
	}
	for i, c := range p.Palette {
		if !present[i] {
			continue
		}
1009 1010 1011 1012 1013 1014 1015 1016
		_, _, _, a := c.RGBA()
		if a != 0xffff {
			return false
		}
	}
	return true
}

Nigel Tao's avatar
Nigel Tao committed
1017
// NewPaletted returns a new Paletted with the given width, height and palette.
1018
func NewPaletted(r Rectangle, p color.Palette) *Paletted {
1019
	w, h := r.Dx(), r.Dy()
1020
	pix := make([]uint8, 1*w*h)
1021
	return &Paletted{pix, 1 * w, r, p}
Nigel Tao's avatar
Nigel Tao committed
1022
}