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// https://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 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// 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 return p.RGBAAt(x, y) 76} 77 78func (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 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 84 return color.RGBA{s[0], s[1], s[2], s[3]} 85} 86 87// PixOffset returns the index of the first element of Pix that corresponds to 88// the pixel at (x, y). 89func (p *RGBA) PixOffset(x, y int) int { 90 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 91} 92 93func (p *RGBA) Set(x, y int, c color.Color) { 94 if !(Point{x, y}.In(p.Rect)) { 95 return 96 } 97 i := p.PixOffset(x, y) 98 c1 := color.RGBAModel.Convert(c).(color.RGBA) 99 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 100 s[0] = c1.R 101 s[1] = c1.G 102 s[2] = c1.B 103 s[3] = c1.A 104} 105 106func (p *RGBA) SetRGBA(x, y int, c color.RGBA) { 107 if !(Point{x, y}.In(p.Rect)) { 108 return 109 } 110 i := p.PixOffset(x, y) 111 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 112 s[0] = c.R 113 s[1] = c.G 114 s[2] = c.B 115 s[3] = c.A 116} 117 118// SubImage returns an image representing the portion of the image p visible 119// through r. The returned value shares pixels with the original image. 120func (p *RGBA) SubImage(r Rectangle) Image { 121 r = r.Intersect(p.Rect) 122 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 123 // either r1 or r2 if the intersection is empty. Without explicitly checking for 124 // this, the Pix[i:] expression below can panic. 125 if r.Empty() { 126 return &RGBA{} 127 } 128 i := p.PixOffset(r.Min.X, r.Min.Y) 129 return &RGBA{ 130 Pix: p.Pix[i:], 131 Stride: p.Stride, 132 Rect: r, 133 } 134} 135 136// Opaque scans the entire image and reports whether it is fully opaque. 137func (p *RGBA) Opaque() bool { 138 if p.Rect.Empty() { 139 return true 140 } 141 i0, i1 := 3, p.Rect.Dx()*4 142 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 143 for i := i0; i < i1; i += 4 { 144 if p.Pix[i] != 0xff { 145 return false 146 } 147 } 148 i0 += p.Stride 149 i1 += p.Stride 150 } 151 return true 152} 153 154// NewRGBA returns a new RGBA image with the given bounds. 155func NewRGBA(r Rectangle) *RGBA { 156 w, h := r.Dx(), r.Dy() 157 buf := make([]uint8, 4*w*h) 158 return &RGBA{buf, 4 * w, r} 159} 160 161// RGBA64 is an in-memory image whose At method returns color.RGBA64 values. 162type RGBA64 struct { 163 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at 164 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8]. 165 Pix []uint8 166 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 167 Stride int 168 // Rect is the image's bounds. 169 Rect Rectangle 170} 171 172func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model } 173 174func (p *RGBA64) Bounds() Rectangle { return p.Rect } 175 176func (p *RGBA64) At(x, y int) color.Color { 177 return p.RGBA64At(x, y) 178} 179 180func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 { 181 if !(Point{x, y}.In(p.Rect)) { 182 return color.RGBA64{} 183 } 184 i := p.PixOffset(x, y) 185 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 186 return color.RGBA64{ 187 uint16(s[0])<<8 | uint16(s[1]), 188 uint16(s[2])<<8 | uint16(s[3]), 189 uint16(s[4])<<8 | uint16(s[5]), 190 uint16(s[6])<<8 | uint16(s[7]), 191 } 192} 193 194// PixOffset returns the index of the first element of Pix that corresponds to 195// the pixel at (x, y). 196func (p *RGBA64) PixOffset(x, y int) int { 197 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 198} 199 200func (p *RGBA64) Set(x, y int, c color.Color) { 201 if !(Point{x, y}.In(p.Rect)) { 202 return 203 } 204 i := p.PixOffset(x, y) 205 c1 := color.RGBA64Model.Convert(c).(color.RGBA64) 206 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 207 s[0] = uint8(c1.R >> 8) 208 s[1] = uint8(c1.R) 209 s[2] = uint8(c1.G >> 8) 210 s[3] = uint8(c1.G) 211 s[4] = uint8(c1.B >> 8) 212 s[5] = uint8(c1.B) 213 s[6] = uint8(c1.A >> 8) 214 s[7] = uint8(c1.A) 215} 216 217func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) { 218 if !(Point{x, y}.In(p.Rect)) { 219 return 220 } 221 i := p.PixOffset(x, y) 222 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 223 s[0] = uint8(c.R >> 8) 224 s[1] = uint8(c.R) 225 s[2] = uint8(c.G >> 8) 226 s[3] = uint8(c.G) 227 s[4] = uint8(c.B >> 8) 228 s[5] = uint8(c.B) 229 s[6] = uint8(c.A >> 8) 230 s[7] = uint8(c.A) 231} 232 233// SubImage returns an image representing the portion of the image p visible 234// through r. The returned value shares pixels with the original image. 235func (p *RGBA64) SubImage(r Rectangle) Image { 236 r = r.Intersect(p.Rect) 237 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 238 // either r1 or r2 if the intersection is empty. Without explicitly checking for 239 // this, the Pix[i:] expression below can panic. 240 if r.Empty() { 241 return &RGBA64{} 242 } 243 i := p.PixOffset(r.Min.X, r.Min.Y) 244 return &RGBA64{ 245 Pix: p.Pix[i:], 246 Stride: p.Stride, 247 Rect: r, 248 } 249} 250 251// Opaque scans the entire image and reports whether it is fully opaque. 252func (p *RGBA64) Opaque() bool { 253 if p.Rect.Empty() { 254 return true 255 } 256 i0, i1 := 6, p.Rect.Dx()*8 257 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 258 for i := i0; i < i1; i += 8 { 259 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff { 260 return false 261 } 262 } 263 i0 += p.Stride 264 i1 += p.Stride 265 } 266 return true 267} 268 269// NewRGBA64 returns a new RGBA64 image with the given bounds. 270func NewRGBA64(r Rectangle) *RGBA64 { 271 w, h := r.Dx(), r.Dy() 272 pix := make([]uint8, 8*w*h) 273 return &RGBA64{pix, 8 * w, r} 274} 275 276// NRGBA is an in-memory image whose At method returns color.NRGBA values. 277type NRGBA struct { 278 // Pix holds the image's pixels, in R, G, B, A order. The pixel at 279 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. 280 Pix []uint8 281 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 282 Stride int 283 // Rect is the image's bounds. 284 Rect Rectangle 285} 286 287func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel } 288 289func (p *NRGBA) Bounds() Rectangle { return p.Rect } 290 291func (p *NRGBA) At(x, y int) color.Color { 292 return p.NRGBAAt(x, y) 293} 294 295func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA { 296 if !(Point{x, y}.In(p.Rect)) { 297 return color.NRGBA{} 298 } 299 i := p.PixOffset(x, y) 300 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 301 return color.NRGBA{s[0], s[1], s[2], s[3]} 302} 303 304// PixOffset returns the index of the first element of Pix that corresponds to 305// the pixel at (x, y). 306func (p *NRGBA) PixOffset(x, y int) int { 307 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 308} 309 310func (p *NRGBA) Set(x, y int, c color.Color) { 311 if !(Point{x, y}.In(p.Rect)) { 312 return 313 } 314 i := p.PixOffset(x, y) 315 c1 := color.NRGBAModel.Convert(c).(color.NRGBA) 316 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 317 s[0] = c1.R 318 s[1] = c1.G 319 s[2] = c1.B 320 s[3] = c1.A 321} 322 323func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) { 324 if !(Point{x, y}.In(p.Rect)) { 325 return 326 } 327 i := p.PixOffset(x, y) 328 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 329 s[0] = c.R 330 s[1] = c.G 331 s[2] = c.B 332 s[3] = c.A 333} 334 335// SubImage returns an image representing the portion of the image p visible 336// through r. The returned value shares pixels with the original image. 337func (p *NRGBA) SubImage(r Rectangle) Image { 338 r = r.Intersect(p.Rect) 339 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 340 // either r1 or r2 if the intersection is empty. Without explicitly checking for 341 // this, the Pix[i:] expression below can panic. 342 if r.Empty() { 343 return &NRGBA{} 344 } 345 i := p.PixOffset(r.Min.X, r.Min.Y) 346 return &NRGBA{ 347 Pix: p.Pix[i:], 348 Stride: p.Stride, 349 Rect: r, 350 } 351} 352 353// Opaque scans the entire image and reports whether it is fully opaque. 354func (p *NRGBA) Opaque() bool { 355 if p.Rect.Empty() { 356 return true 357 } 358 i0, i1 := 3, p.Rect.Dx()*4 359 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 360 for i := i0; i < i1; i += 4 { 361 if p.Pix[i] != 0xff { 362 return false 363 } 364 } 365 i0 += p.Stride 366 i1 += p.Stride 367 } 368 return true 369} 370 371// NewNRGBA returns a new NRGBA image with the given bounds. 372func NewNRGBA(r Rectangle) *NRGBA { 373 w, h := r.Dx(), r.Dy() 374 pix := make([]uint8, 4*w*h) 375 return &NRGBA{pix, 4 * w, r} 376} 377 378// NRGBA64 is an in-memory image whose At method returns color.NRGBA64 values. 379type NRGBA64 struct { 380 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at 381 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8]. 382 Pix []uint8 383 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 384 Stride int 385 // Rect is the image's bounds. 386 Rect Rectangle 387} 388 389func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model } 390 391func (p *NRGBA64) Bounds() Rectangle { return p.Rect } 392 393func (p *NRGBA64) At(x, y int) color.Color { 394 return p.NRGBA64At(x, y) 395} 396 397func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 { 398 if !(Point{x, y}.In(p.Rect)) { 399 return color.NRGBA64{} 400 } 401 i := p.PixOffset(x, y) 402 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 403 return color.NRGBA64{ 404 uint16(s[0])<<8 | uint16(s[1]), 405 uint16(s[2])<<8 | uint16(s[3]), 406 uint16(s[4])<<8 | uint16(s[5]), 407 uint16(s[6])<<8 | uint16(s[7]), 408 } 409} 410 411// PixOffset returns the index of the first element of Pix that corresponds to 412// the pixel at (x, y). 413func (p *NRGBA64) PixOffset(x, y int) int { 414 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 415} 416 417func (p *NRGBA64) Set(x, y int, c color.Color) { 418 if !(Point{x, y}.In(p.Rect)) { 419 return 420 } 421 i := p.PixOffset(x, y) 422 c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64) 423 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 424 s[0] = uint8(c1.R >> 8) 425 s[1] = uint8(c1.R) 426 s[2] = uint8(c1.G >> 8) 427 s[3] = uint8(c1.G) 428 s[4] = uint8(c1.B >> 8) 429 s[5] = uint8(c1.B) 430 s[6] = uint8(c1.A >> 8) 431 s[7] = uint8(c1.A) 432} 433 434func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) { 435 if !(Point{x, y}.In(p.Rect)) { 436 return 437 } 438 i := p.PixOffset(x, y) 439 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857 440 s[0] = uint8(c.R >> 8) 441 s[1] = uint8(c.R) 442 s[2] = uint8(c.G >> 8) 443 s[3] = uint8(c.G) 444 s[4] = uint8(c.B >> 8) 445 s[5] = uint8(c.B) 446 s[6] = uint8(c.A >> 8) 447 s[7] = uint8(c.A) 448} 449 450// SubImage returns an image representing the portion of the image p visible 451// through r. The returned value shares pixels with the original image. 452func (p *NRGBA64) SubImage(r Rectangle) Image { 453 r = r.Intersect(p.Rect) 454 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 455 // either r1 or r2 if the intersection is empty. Without explicitly checking for 456 // this, the Pix[i:] expression below can panic. 457 if r.Empty() { 458 return &NRGBA64{} 459 } 460 i := p.PixOffset(r.Min.X, r.Min.Y) 461 return &NRGBA64{ 462 Pix: p.Pix[i:], 463 Stride: p.Stride, 464 Rect: r, 465 } 466} 467 468// Opaque scans the entire image and reports whether it is fully opaque. 469func (p *NRGBA64) Opaque() bool { 470 if p.Rect.Empty() { 471 return true 472 } 473 i0, i1 := 6, p.Rect.Dx()*8 474 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 475 for i := i0; i < i1; i += 8 { 476 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff { 477 return false 478 } 479 } 480 i0 += p.Stride 481 i1 += p.Stride 482 } 483 return true 484} 485 486// NewNRGBA64 returns a new NRGBA64 image with the given bounds. 487func NewNRGBA64(r Rectangle) *NRGBA64 { 488 w, h := r.Dx(), r.Dy() 489 pix := make([]uint8, 8*w*h) 490 return &NRGBA64{pix, 8 * w, r} 491} 492 493// Alpha is an in-memory image whose At method returns color.Alpha values. 494type Alpha struct { 495 // Pix holds the image's pixels, as alpha values. The pixel at 496 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. 497 Pix []uint8 498 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 499 Stride int 500 // Rect is the image's bounds. 501 Rect Rectangle 502} 503 504func (p *Alpha) ColorModel() color.Model { return color.AlphaModel } 505 506func (p *Alpha) Bounds() Rectangle { return p.Rect } 507 508func (p *Alpha) At(x, y int) color.Color { 509 return p.AlphaAt(x, y) 510} 511 512func (p *Alpha) AlphaAt(x, y int) color.Alpha { 513 if !(Point{x, y}.In(p.Rect)) { 514 return color.Alpha{} 515 } 516 i := p.PixOffset(x, y) 517 return color.Alpha{p.Pix[i]} 518} 519 520// PixOffset returns the index of the first element of Pix that corresponds to 521// the pixel at (x, y). 522func (p *Alpha) PixOffset(x, y int) int { 523 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 524} 525 526func (p *Alpha) Set(x, y int, c color.Color) { 527 if !(Point{x, y}.In(p.Rect)) { 528 return 529 } 530 i := p.PixOffset(x, y) 531 p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A 532} 533 534func (p *Alpha) SetAlpha(x, y int, c color.Alpha) { 535 if !(Point{x, y}.In(p.Rect)) { 536 return 537 } 538 i := p.PixOffset(x, y) 539 p.Pix[i] = c.A 540} 541 542// SubImage returns an image representing the portion of the image p visible 543// through r. The returned value shares pixels with the original image. 544func (p *Alpha) SubImage(r Rectangle) Image { 545 r = r.Intersect(p.Rect) 546 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 547 // either r1 or r2 if the intersection is empty. Without explicitly checking for 548 // this, the Pix[i:] expression below can panic. 549 if r.Empty() { 550 return &Alpha{} 551 } 552 i := p.PixOffset(r.Min.X, r.Min.Y) 553 return &Alpha{ 554 Pix: p.Pix[i:], 555 Stride: p.Stride, 556 Rect: r, 557 } 558} 559 560// Opaque scans the entire image and reports whether it is fully opaque. 561func (p *Alpha) Opaque() bool { 562 if p.Rect.Empty() { 563 return true 564 } 565 i0, i1 := 0, p.Rect.Dx() 566 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 567 for i := i0; i < i1; i++ { 568 if p.Pix[i] != 0xff { 569 return false 570 } 571 } 572 i0 += p.Stride 573 i1 += p.Stride 574 } 575 return true 576} 577 578// NewAlpha returns a new Alpha image with the given bounds. 579func NewAlpha(r Rectangle) *Alpha { 580 w, h := r.Dx(), r.Dy() 581 pix := make([]uint8, 1*w*h) 582 return &Alpha{pix, 1 * w, r} 583} 584 585// Alpha16 is an in-memory image whose At method returns color.Alpha16 values. 586type Alpha16 struct { 587 // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at 588 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2]. 589 Pix []uint8 590 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 591 Stride int 592 // Rect is the image's bounds. 593 Rect Rectangle 594} 595 596func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model } 597 598func (p *Alpha16) Bounds() Rectangle { return p.Rect } 599 600func (p *Alpha16) At(x, y int) color.Color { 601 return p.Alpha16At(x, y) 602} 603 604func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 { 605 if !(Point{x, y}.In(p.Rect)) { 606 return color.Alpha16{} 607 } 608 i := p.PixOffset(x, y) 609 return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])} 610} 611 612// PixOffset returns the index of the first element of Pix that corresponds to 613// the pixel at (x, y). 614func (p *Alpha16) PixOffset(x, y int) int { 615 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 616} 617 618func (p *Alpha16) Set(x, y int, c color.Color) { 619 if !(Point{x, y}.In(p.Rect)) { 620 return 621 } 622 i := p.PixOffset(x, y) 623 c1 := color.Alpha16Model.Convert(c).(color.Alpha16) 624 p.Pix[i+0] = uint8(c1.A >> 8) 625 p.Pix[i+1] = uint8(c1.A) 626} 627 628func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) { 629 if !(Point{x, y}.In(p.Rect)) { 630 return 631 } 632 i := p.PixOffset(x, y) 633 p.Pix[i+0] = uint8(c.A >> 8) 634 p.Pix[i+1] = uint8(c.A) 635} 636 637// SubImage returns an image representing the portion of the image p visible 638// through r. The returned value shares pixels with the original image. 639func (p *Alpha16) SubImage(r Rectangle) Image { 640 r = r.Intersect(p.Rect) 641 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 642 // either r1 or r2 if the intersection is empty. Without explicitly checking for 643 // this, the Pix[i:] expression below can panic. 644 if r.Empty() { 645 return &Alpha16{} 646 } 647 i := p.PixOffset(r.Min.X, r.Min.Y) 648 return &Alpha16{ 649 Pix: p.Pix[i:], 650 Stride: p.Stride, 651 Rect: r, 652 } 653} 654 655// Opaque scans the entire image and reports whether it is fully opaque. 656func (p *Alpha16) Opaque() bool { 657 if p.Rect.Empty() { 658 return true 659 } 660 i0, i1 := 0, p.Rect.Dx()*2 661 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 662 for i := i0; i < i1; i += 2 { 663 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff { 664 return false 665 } 666 } 667 i0 += p.Stride 668 i1 += p.Stride 669 } 670 return true 671} 672 673// NewAlpha16 returns a new Alpha16 image with the given bounds. 674func NewAlpha16(r Rectangle) *Alpha16 { 675 w, h := r.Dx(), r.Dy() 676 pix := make([]uint8, 2*w*h) 677 return &Alpha16{pix, 2 * w, r} 678} 679 680// Gray is an in-memory image whose At method returns color.Gray values. 681type Gray struct { 682 // Pix holds the image's pixels, as gray values. The pixel at 683 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. 684 Pix []uint8 685 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 686 Stride int 687 // Rect is the image's bounds. 688 Rect Rectangle 689} 690 691func (p *Gray) ColorModel() color.Model { return color.GrayModel } 692 693func (p *Gray) Bounds() Rectangle { return p.Rect } 694 695func (p *Gray) At(x, y int) color.Color { 696 return p.GrayAt(x, y) 697} 698 699func (p *Gray) GrayAt(x, y int) color.Gray { 700 if !(Point{x, y}.In(p.Rect)) { 701 return color.Gray{} 702 } 703 i := p.PixOffset(x, y) 704 return color.Gray{p.Pix[i]} 705} 706 707// PixOffset returns the index of the first element of Pix that corresponds to 708// the pixel at (x, y). 709func (p *Gray) PixOffset(x, y int) int { 710 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 711} 712 713func (p *Gray) Set(x, y int, c color.Color) { 714 if !(Point{x, y}.In(p.Rect)) { 715 return 716 } 717 i := p.PixOffset(x, y) 718 p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y 719} 720 721func (p *Gray) SetGray(x, y int, c color.Gray) { 722 if !(Point{x, y}.In(p.Rect)) { 723 return 724 } 725 i := p.PixOffset(x, y) 726 p.Pix[i] = c.Y 727} 728 729// SubImage returns an image representing the portion of the image p visible 730// through r. The returned value shares pixels with the original image. 731func (p *Gray) SubImage(r Rectangle) Image { 732 r = r.Intersect(p.Rect) 733 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 734 // either r1 or r2 if the intersection is empty. Without explicitly checking for 735 // this, the Pix[i:] expression below can panic. 736 if r.Empty() { 737 return &Gray{} 738 } 739 i := p.PixOffset(r.Min.X, r.Min.Y) 740 return &Gray{ 741 Pix: p.Pix[i:], 742 Stride: p.Stride, 743 Rect: r, 744 } 745} 746 747// Opaque scans the entire image and reports whether it is fully opaque. 748func (p *Gray) Opaque() bool { 749 return true 750} 751 752// NewGray returns a new Gray image with the given bounds. 753func NewGray(r Rectangle) *Gray { 754 w, h := r.Dx(), r.Dy() 755 pix := make([]uint8, 1*w*h) 756 return &Gray{pix, 1 * w, r} 757} 758 759// Gray16 is an in-memory image whose At method returns color.Gray16 values. 760type Gray16 struct { 761 // Pix holds the image's pixels, as gray values in big-endian format. The pixel at 762 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2]. 763 Pix []uint8 764 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 765 Stride int 766 // Rect is the image's bounds. 767 Rect Rectangle 768} 769 770func (p *Gray16) ColorModel() color.Model { return color.Gray16Model } 771 772func (p *Gray16) Bounds() Rectangle { return p.Rect } 773 774func (p *Gray16) At(x, y int) color.Color { 775 return p.Gray16At(x, y) 776} 777 778func (p *Gray16) Gray16At(x, y int) color.Gray16 { 779 if !(Point{x, y}.In(p.Rect)) { 780 return color.Gray16{} 781 } 782 i := p.PixOffset(x, y) 783 return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])} 784} 785 786// PixOffset returns the index of the first element of Pix that corresponds to 787// the pixel at (x, y). 788func (p *Gray16) PixOffset(x, y int) int { 789 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 790} 791 792func (p *Gray16) Set(x, y int, c color.Color) { 793 if !(Point{x, y}.In(p.Rect)) { 794 return 795 } 796 i := p.PixOffset(x, y) 797 c1 := color.Gray16Model.Convert(c).(color.Gray16) 798 p.Pix[i+0] = uint8(c1.Y >> 8) 799 p.Pix[i+1] = uint8(c1.Y) 800} 801 802func (p *Gray16) SetGray16(x, y int, c color.Gray16) { 803 if !(Point{x, y}.In(p.Rect)) { 804 return 805 } 806 i := p.PixOffset(x, y) 807 p.Pix[i+0] = uint8(c.Y >> 8) 808 p.Pix[i+1] = uint8(c.Y) 809} 810 811// SubImage returns an image representing the portion of the image p visible 812// through r. The returned value shares pixels with the original image. 813func (p *Gray16) SubImage(r Rectangle) Image { 814 r = r.Intersect(p.Rect) 815 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 816 // either r1 or r2 if the intersection is empty. Without explicitly checking for 817 // this, the Pix[i:] expression below can panic. 818 if r.Empty() { 819 return &Gray16{} 820 } 821 i := p.PixOffset(r.Min.X, r.Min.Y) 822 return &Gray16{ 823 Pix: p.Pix[i:], 824 Stride: p.Stride, 825 Rect: r, 826 } 827} 828 829// Opaque scans the entire image and reports whether it is fully opaque. 830func (p *Gray16) Opaque() bool { 831 return true 832} 833 834// NewGray16 returns a new Gray16 image with the given bounds. 835func NewGray16(r Rectangle) *Gray16 { 836 w, h := r.Dx(), r.Dy() 837 pix := make([]uint8, 2*w*h) 838 return &Gray16{pix, 2 * w, r} 839} 840 841// CMYK is an in-memory image whose At method returns color.CMYK values. 842type CMYK struct { 843 // Pix holds the image's pixels, in C, M, Y, K order. The pixel at 844 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. 845 Pix []uint8 846 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 847 Stride int 848 // Rect is the image's bounds. 849 Rect Rectangle 850} 851 852func (p *CMYK) ColorModel() color.Model { return color.CMYKModel } 853 854func (p *CMYK) Bounds() Rectangle { return p.Rect } 855 856func (p *CMYK) At(x, y int) color.Color { 857 return p.CMYKAt(x, y) 858} 859 860func (p *CMYK) CMYKAt(x, y int) color.CMYK { 861 if !(Point{x, y}.In(p.Rect)) { 862 return color.CMYK{} 863 } 864 i := p.PixOffset(x, y) 865 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 866 return color.CMYK{s[0], s[1], s[2], s[3]} 867} 868 869// PixOffset returns the index of the first element of Pix that corresponds to 870// the pixel at (x, y). 871func (p *CMYK) PixOffset(x, y int) int { 872 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 873} 874 875func (p *CMYK) Set(x, y int, c color.Color) { 876 if !(Point{x, y}.In(p.Rect)) { 877 return 878 } 879 i := p.PixOffset(x, y) 880 c1 := color.CMYKModel.Convert(c).(color.CMYK) 881 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 882 s[0] = c1.C 883 s[1] = c1.M 884 s[2] = c1.Y 885 s[3] = c1.K 886} 887 888func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { 889 if !(Point{x, y}.In(p.Rect)) { 890 return 891 } 892 i := p.PixOffset(x, y) 893 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857 894 s[0] = c.C 895 s[1] = c.M 896 s[2] = c.Y 897 s[3] = c.K 898} 899 900// SubImage returns an image representing the portion of the image p visible 901// through r. The returned value shares pixels with the original image. 902func (p *CMYK) SubImage(r Rectangle) Image { 903 r = r.Intersect(p.Rect) 904 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 905 // either r1 or r2 if the intersection is empty. Without explicitly checking for 906 // this, the Pix[i:] expression below can panic. 907 if r.Empty() { 908 return &CMYK{} 909 } 910 i := p.PixOffset(r.Min.X, r.Min.Y) 911 return &CMYK{ 912 Pix: p.Pix[i:], 913 Stride: p.Stride, 914 Rect: r, 915 } 916} 917 918// Opaque scans the entire image and reports whether it is fully opaque. 919func (p *CMYK) Opaque() bool { 920 return true 921} 922 923// NewCMYK returns a new CMYK image with the given bounds. 924func NewCMYK(r Rectangle) *CMYK { 925 w, h := r.Dx(), r.Dy() 926 buf := make([]uint8, 4*w*h) 927 return &CMYK{buf, 4 * w, r} 928} 929 930// Paletted is an in-memory image of uint8 indices into a given palette. 931type Paletted struct { 932 // Pix holds the image's pixels, as palette indices. The pixel at 933 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. 934 Pix []uint8 935 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. 936 Stride int 937 // Rect is the image's bounds. 938 Rect Rectangle 939 // Palette is the image's palette. 940 Palette color.Palette 941} 942 943func (p *Paletted) ColorModel() color.Model { return p.Palette } 944 945func (p *Paletted) Bounds() Rectangle { return p.Rect } 946 947func (p *Paletted) At(x, y int) color.Color { 948 if len(p.Palette) == 0 { 949 return nil 950 } 951 if !(Point{x, y}.In(p.Rect)) { 952 return p.Palette[0] 953 } 954 i := p.PixOffset(x, y) 955 return p.Palette[p.Pix[i]] 956} 957 958// PixOffset returns the index of the first element of Pix that corresponds to 959// the pixel at (x, y). 960func (p *Paletted) PixOffset(x, y int) int { 961 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 962} 963 964func (p *Paletted) Set(x, y int, c color.Color) { 965 if !(Point{x, y}.In(p.Rect)) { 966 return 967 } 968 i := p.PixOffset(x, y) 969 p.Pix[i] = uint8(p.Palette.Index(c)) 970} 971 972func (p *Paletted) ColorIndexAt(x, y int) uint8 { 973 if !(Point{x, y}.In(p.Rect)) { 974 return 0 975 } 976 i := p.PixOffset(x, y) 977 return p.Pix[i] 978} 979 980func (p *Paletted) SetColorIndex(x, y int, index uint8) { 981 if !(Point{x, y}.In(p.Rect)) { 982 return 983 } 984 i := p.PixOffset(x, y) 985 p.Pix[i] = index 986} 987 988// SubImage returns an image representing the portion of the image p visible 989// through r. The returned value shares pixels with the original image. 990func (p *Paletted) SubImage(r Rectangle) Image { 991 r = r.Intersect(p.Rect) 992 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside 993 // either r1 or r2 if the intersection is empty. Without explicitly checking for 994 // this, the Pix[i:] expression below can panic. 995 if r.Empty() { 996 return &Paletted{ 997 Palette: p.Palette, 998 } 999 } 1000 i := p.PixOffset(r.Min.X, r.Min.Y) 1001 return &Paletted{ 1002 Pix: p.Pix[i:], 1003 Stride: p.Stride, 1004 Rect: p.Rect.Intersect(r), 1005 Palette: p.Palette, 1006 } 1007} 1008 1009// Opaque scans the entire image and reports whether it is fully opaque. 1010func (p *Paletted) Opaque() bool { 1011 var present [256]bool 1012 i0, i1 := 0, p.Rect.Dx() 1013 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ { 1014 for _, c := range p.Pix[i0:i1] { 1015 present[c] = true 1016 } 1017 i0 += p.Stride 1018 i1 += p.Stride 1019 } 1020 for i, c := range p.Palette { 1021 if !present[i] { 1022 continue 1023 } 1024 _, _, _, a := c.RGBA() 1025 if a != 0xffff { 1026 return false 1027 } 1028 } 1029 return true 1030} 1031 1032// NewPaletted returns a new Paletted image with the given width, height and 1033// palette. 1034func NewPaletted(r Rectangle, p color.Palette) *Paletted { 1035 w, h := r.Dx(), r.Dy() 1036 pix := make([]uint8, 1*w*h) 1037 return &Paletted{pix, 1 * w, r, p} 1038} 1039