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 22package image 23 24import ( 25 "image/color" 26) 27 28// Config holds an image's color model and dimensions. 29type 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. 36type 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. 53type 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. 60type 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 70func (p *RGBA) ColorModel() color.Model { return color.RGBAModel } 71 72func (p *RGBA) Bounds() Rectangle { return p.Rect } 73 74func (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). 84func (p *RGBA) PixOffset(x, y int) int { 85 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 86} 87 88func (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 100func (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. 113func (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 reports whether it is fully opaque. 130func (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. 148func 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. 155type 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 165func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model } 166 167func (p *RGBA64) Bounds() Rectangle { return p.Rect } 168 169func (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). 184func (p *RGBA64) PixOffset(x, y int) int { 185 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 186} 187 188func (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 204func (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. 221func (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 reports whether it is fully opaque. 238func (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. 256func 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. 263type 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 273func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel } 274 275func (p *NRGBA) Bounds() Rectangle { return p.Rect } 276 277func (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). 287func (p *NRGBA) PixOffset(x, y int) int { 288 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 289} 290 291func (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 303func (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. 316func (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 reports whether it is fully opaque. 333func (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. 351func 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. 358type 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 368func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model } 369 370func (p *NRGBA64) Bounds() Rectangle { return p.Rect } 371 372func (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). 387func (p *NRGBA64) PixOffset(x, y int) int { 388 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 389} 390 391func (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 407func (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. 424func (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 reports whether it is fully opaque. 441func (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. 459func 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. 466type 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 476func (p *Alpha) ColorModel() color.Model { return color.AlphaModel } 477 478func (p *Alpha) Bounds() Rectangle { return p.Rect } 479 480func (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). 490func (p *Alpha) PixOffset(x, y int) int { 491 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 492} 493 494func (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 502func (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. 512func (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 reports whether it is fully opaque. 529func (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. 547func 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. 554type 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 564func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model } 565 566func (p *Alpha16) Bounds() Rectangle { return p.Rect } 567 568func (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). 578func (p *Alpha16) PixOffset(x, y int) int { 579 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 580} 581 582func (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 592func (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. 603func (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 reports whether it is fully opaque. 620func (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. 638func 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. 645type 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 655func (p *Gray) ColorModel() color.Model { return color.GrayModel } 656 657func (p *Gray) Bounds() Rectangle { return p.Rect } 658 659func (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). 669func (p *Gray) PixOffset(x, y int) int { 670 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 671} 672 673func (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 681func (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. 691func (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 reports whether it is fully opaque. 708func (p *Gray) Opaque() bool { 709 return true 710} 711 712// NewGray returns a new Gray with the given bounds. 713func 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. 720type 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 730func (p *Gray16) ColorModel() color.Model { return color.Gray16Model } 731 732func (p *Gray16) Bounds() Rectangle { return p.Rect } 733 734func (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). 744func (p *Gray16) PixOffset(x, y int) int { 745 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 746} 747 748func (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 758func (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. 769func (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 reports whether it is fully opaque. 786func (p *Gray16) Opaque() bool { 787 return true 788} 789 790// NewGray16 returns a new Gray16 with the given bounds. 791func 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. 798type 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 810func (p *Paletted) ColorModel() color.Model { return p.Palette } 811 812func (p *Paletted) Bounds() Rectangle { return p.Rect } 813 814func (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). 827func (p *Paletted) PixOffset(x, y int) int { 828 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 829} 830 831func (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 839func (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 847func (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. 857func (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 reports whether it is fully opaque. 877func (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. 900func 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} 905