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