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 //
17 // import _ "image/png"
18 //
19 // in a program's main package. The _ means to import a package purely for its
20 // initialization side effects.
21 //
22 // See "The Go image package" for more details:
23 // https://golang.org/doc/articles/image_package.html
24 //
25 // # Security Considerations
26 //
27 // The image package can be used to parse arbitrarily large images, which can
28 // cause resource exhaustion on machines which do not have enough memory to
29 // store them. When operating on arbitrary images, [DecodeConfig] should be called
30 // before [Decode], so that the program can decide whether the image, as defined
31 // in the returned header, can be safely decoded with the available resources. A
32 // call to [Decode] which produces an extremely large image, as defined in the
33 // header returned by [DecodeConfig], is not considered a security issue,
34 // regardless of whether the image is itself malformed or not. A call to
35 // [DecodeConfig] which returns a header which does not match the image returned
36 // by [Decode] may be considered a security issue, and should be reported per the
37 // [Go Security Policy](https://go.dev/security/policy).
38 package image
39 40 import (
41 "image/color"
42 )
43 44 // Config holds an image's color model and dimensions.
45 type Config struct {
46 ColorModel color.Model
47 Width, Height int
48 }
49 50 // Image is a finite rectangular grid of [color.Color] values taken from a color
51 // model.
52 type Image interface {
53 // ColorModel returns the Image's color model.
54 ColorModel() color.Model
55 // Bounds returns the domain for which At can return non-zero color.
56 // The bounds do not necessarily contain the point (0, 0).
57 Bounds() Rectangle
58 // At returns the color of the pixel at (x, y).
59 // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
60 // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
61 At(x, y int) color.Color
62 }
63 64 // RGBA64Image is an [Image] whose pixels can be converted directly to a
65 // color.RGBA64.
66 type RGBA64Image interface {
67 // RGBA64At returns the RGBA64 color of the pixel at (x, y). It is
68 // equivalent to calling At(x, y).RGBA() and converting the resulting
69 // 32-bit return values to a color.RGBA64, but it can avoid allocations
70 // from converting concrete color types to the color.Color interface type.
71 RGBA64At(x, y int) color.RGBA64
72 Image
73 }
74 75 // PalettedImage is an image whose colors may come from a limited palette.
76 // If m is a PalettedImage and m.ColorModel() returns a [color.Palette] p,
77 // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
78 // color model is not a color.Palette, then ColorIndexAt's behavior is
79 // undefined.
80 type PalettedImage interface {
81 // ColorIndexAt returns the palette index of the pixel at (x, y).
82 ColorIndexAt(x, y int) uint8
83 Image
84 }
85 86 // pixelBufferLength returns the length of the []uint8 typed Pix slice field
87 // for the NewXxx functions. Conceptually, this is just (bpp * width * height),
88 // but this function panics if at least one of those is negative or if the
89 // computation would overflow the int type.
90 //
91 // This panics instead of returning an error because of backwards
92 // compatibility. The NewXxx functions do not return an error.
93 func pixelBufferLength(bytesPerPixel int, r Rectangle, imageTypeName []byte) int {
94 totalLength := mul3NonNeg(bytesPerPixel, r.Dx(), r.Dy())
95 if totalLength < 0 {
96 panic(string(append(append([]byte("image: New"), imageTypeName...), " Rectangle has huge or negative dimensions"...)))
97 }
98 return totalLength
99 }
100 101 // RGBA is an in-memory image whose At method returns [color.RGBA] values.
102 type RGBA struct {
103 // Pix holds the image's pixels, in R, G, B, A order. The pixel at
104 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
105 Pix []uint8
106 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
107 Stride int
108 // Rect is the image's bounds.
109 Rect Rectangle
110 }
111 112 func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
113 114 func (p *RGBA) Bounds() Rectangle { return p.Rect }
115 116 func (p *RGBA) At(x, y int) color.Color {
117 return p.RGBAAt(x, y)
118 }
119 120 func (p *RGBA) RGBA64At(x, y int) color.RGBA64 {
121 if !(Point{x, y}.In(p.Rect)) {
122 return color.RGBA64{}
123 }
124 i := p.PixOffset(x, y)
125 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
126 r := uint16(s[0])
127 g := uint16(s[1])
128 b := uint16(s[2])
129 a := uint16(s[3])
130 return color.RGBA64{
131 (r << 8) | r,
132 (g << 8) | g,
133 (b << 8) | b,
134 (a << 8) | a,
135 }
136 }
137 138 func (p *RGBA) RGBAAt(x, y int) color.RGBA {
139 if !(Point{x, y}.In(p.Rect)) {
140 return color.RGBA{}
141 }
142 i := p.PixOffset(x, y)
143 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
144 return color.RGBA{s[0], s[1], s[2], s[3]}
145 }
146 147 // PixOffset returns the index of the first element of Pix that corresponds to
148 // the pixel at (x, y).
149 func (p *RGBA) PixOffset(x, y int) int {
150 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
151 }
152 153 func (p *RGBA) Set(x, y int, c color.Color) {
154 if !(Point{x, y}.In(p.Rect)) {
155 return
156 }
157 i := p.PixOffset(x, y)
158 c1 := color.RGBAModel.Convert(c).(color.RGBA)
159 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
160 s[0] = c1.R
161 s[1] = c1.G
162 s[2] = c1.B
163 s[3] = c1.A
164 }
165 166 func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) {
167 if !(Point{x, y}.In(p.Rect)) {
168 return
169 }
170 i := p.PixOffset(x, y)
171 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
172 s[0] = uint8(c.R >> 8)
173 s[1] = uint8(c.G >> 8)
174 s[2] = uint8(c.B >> 8)
175 s[3] = uint8(c.A >> 8)
176 }
177 178 func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
179 if !(Point{x, y}.In(p.Rect)) {
180 return
181 }
182 i := p.PixOffset(x, y)
183 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
184 s[0] = c.R
185 s[1] = c.G
186 s[2] = c.B
187 s[3] = c.A
188 }
189 190 // SubImage returns an image representing the portion of the image p visible
191 // through r. The returned value shares pixels with the original image.
192 func (p *RGBA) SubImage(r Rectangle) Image {
193 r = r.Intersect(p.Rect)
194 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
195 // either r1 or r2 if the intersection is empty. Without explicitly checking for
196 // this, the Pix[i:] expression below can panic.
197 if r.Empty() {
198 return &RGBA{}
199 }
200 i := p.PixOffset(r.Min.X, r.Min.Y)
201 return &RGBA{
202 Pix: p.Pix[i:],
203 Stride: p.Stride,
204 Rect: r,
205 }
206 }
207 208 // Opaque scans the entire image and reports whether it is fully opaque.
209 func (p *RGBA) Opaque() bool {
210 if p.Rect.Empty() {
211 return true
212 }
213 i0, i1 := 3, p.Rect.Dx()*4
214 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
215 for i := i0; i < i1; i += 4 {
216 if p.Pix[i] != 0xff {
217 return false
218 }
219 }
220 i0 += p.Stride
221 i1 += p.Stride
222 }
223 return true
224 }
225 226 // NewRGBA returns a new [RGBA] image with the given bounds.
227 func NewRGBA(r Rectangle) *RGBA {
228 return &RGBA{
229 Pix: []uint8{:pixelBufferLength(4, r, "RGBA")},
230 Stride: 4 * r.Dx(),
231 Rect: r,
232 }
233 }
234 235 // RGBA64 is an in-memory image whose At method returns [color.RGBA64] values.
236 type RGBA64 struct {
237 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
238 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
239 Pix []uint8
240 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
241 Stride int
242 // Rect is the image's bounds.
243 Rect Rectangle
244 }
245 246 func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
247 248 func (p *RGBA64) Bounds() Rectangle { return p.Rect }
249 250 func (p *RGBA64) At(x, y int) color.Color {
251 return p.RGBA64At(x, y)
252 }
253 254 func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 {
255 if !(Point{x, y}.In(p.Rect)) {
256 return color.RGBA64{}
257 }
258 i := p.PixOffset(x, y)
259 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
260 return color.RGBA64{
261 uint16(s[0])<<8 | uint16(s[1]),
262 uint16(s[2])<<8 | uint16(s[3]),
263 uint16(s[4])<<8 | uint16(s[5]),
264 uint16(s[6])<<8 | uint16(s[7]),
265 }
266 }
267 268 // PixOffset returns the index of the first element of Pix that corresponds to
269 // the pixel at (x, y).
270 func (p *RGBA64) PixOffset(x, y int) int {
271 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
272 }
273 274 func (p *RGBA64) Set(x, y int, c color.Color) {
275 if !(Point{x, y}.In(p.Rect)) {
276 return
277 }
278 i := p.PixOffset(x, y)
279 c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
280 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
281 s[0] = uint8(c1.R >> 8)
282 s[1] = uint8(c1.R)
283 s[2] = uint8(c1.G >> 8)
284 s[3] = uint8(c1.G)
285 s[4] = uint8(c1.B >> 8)
286 s[5] = uint8(c1.B)
287 s[6] = uint8(c1.A >> 8)
288 s[7] = uint8(c1.A)
289 }
290 291 func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
292 if !(Point{x, y}.In(p.Rect)) {
293 return
294 }
295 i := p.PixOffset(x, y)
296 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
297 s[0] = uint8(c.R >> 8)
298 s[1] = uint8(c.R)
299 s[2] = uint8(c.G >> 8)
300 s[3] = uint8(c.G)
301 s[4] = uint8(c.B >> 8)
302 s[5] = uint8(c.B)
303 s[6] = uint8(c.A >> 8)
304 s[7] = uint8(c.A)
305 }
306 307 // SubImage returns an image representing the portion of the image p visible
308 // through r. The returned value shares pixels with the original image.
309 func (p *RGBA64) SubImage(r Rectangle) Image {
310 r = r.Intersect(p.Rect)
311 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
312 // either r1 or r2 if the intersection is empty. Without explicitly checking for
313 // this, the Pix[i:] expression below can panic.
314 if r.Empty() {
315 return &RGBA64{}
316 }
317 i := p.PixOffset(r.Min.X, r.Min.Y)
318 return &RGBA64{
319 Pix: p.Pix[i:],
320 Stride: p.Stride,
321 Rect: r,
322 }
323 }
324 325 // Opaque scans the entire image and reports whether it is fully opaque.
326 func (p *RGBA64) Opaque() bool {
327 if p.Rect.Empty() {
328 return true
329 }
330 i0, i1 := 6, p.Rect.Dx()*8
331 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
332 for i := i0; i < i1; i += 8 {
333 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
334 return false
335 }
336 }
337 i0 += p.Stride
338 i1 += p.Stride
339 }
340 return true
341 }
342 343 // NewRGBA64 returns a new [RGBA64] image with the given bounds.
344 func NewRGBA64(r Rectangle) *RGBA64 {
345 return &RGBA64{
346 Pix: []uint8{:pixelBufferLength(8, r, "RGBA64")},
347 Stride: 8 * r.Dx(),
348 Rect: r,
349 }
350 }
351 352 // NRGBA is an in-memory image whose At method returns [color.NRGBA] values.
353 type NRGBA struct {
354 // Pix holds the image's pixels, in R, G, B, A order. The pixel at
355 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
356 Pix []uint8
357 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
358 Stride int
359 // Rect is the image's bounds.
360 Rect Rectangle
361 }
362 363 func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
364 365 func (p *NRGBA) Bounds() Rectangle { return p.Rect }
366 367 func (p *NRGBA) At(x, y int) color.Color {
368 return p.NRGBAAt(x, y)
369 }
370 371 func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 {
372 r, g, b, a := p.NRGBAAt(x, y).RGBA()
373 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
374 }
375 376 func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
377 if !(Point{x, y}.In(p.Rect)) {
378 return color.NRGBA{}
379 }
380 i := p.PixOffset(x, y)
381 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
382 return color.NRGBA{s[0], s[1], s[2], s[3]}
383 }
384 385 // PixOffset returns the index of the first element of Pix that corresponds to
386 // the pixel at (x, y).
387 func (p *NRGBA) PixOffset(x, y int) int {
388 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
389 }
390 391 func (p *NRGBA) 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.NRGBAModel.Convert(c).(color.NRGBA)
397 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
398 s[0] = c1.R
399 s[1] = c1.G
400 s[2] = c1.B
401 s[3] = c1.A
402 }
403 404 func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) {
405 if !(Point{x, y}.In(p.Rect)) {
406 return
407 }
408 r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
409 if (a != 0) && (a != 0xffff) {
410 r = (r * 0xffff) / a
411 g = (g * 0xffff) / a
412 b = (b * 0xffff) / a
413 }
414 i := p.PixOffset(x, y)
415 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
416 s[0] = uint8(r >> 8)
417 s[1] = uint8(g >> 8)
418 s[2] = uint8(b >> 8)
419 s[3] = uint8(a >> 8)
420 }
421 422 func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
423 if !(Point{x, y}.In(p.Rect)) {
424 return
425 }
426 i := p.PixOffset(x, y)
427 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
428 s[0] = c.R
429 s[1] = c.G
430 s[2] = c.B
431 s[3] = c.A
432 }
433 434 // SubImage returns an image representing the portion of the image p visible
435 // through r. The returned value shares pixels with the original image.
436 func (p *NRGBA) SubImage(r Rectangle) Image {
437 r = r.Intersect(p.Rect)
438 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
439 // either r1 or r2 if the intersection is empty. Without explicitly checking for
440 // this, the Pix[i:] expression below can panic.
441 if r.Empty() {
442 return &NRGBA{}
443 }
444 i := p.PixOffset(r.Min.X, r.Min.Y)
445 return &NRGBA{
446 Pix: p.Pix[i:],
447 Stride: p.Stride,
448 Rect: r,
449 }
450 }
451 452 // Opaque scans the entire image and reports whether it is fully opaque.
453 func (p *NRGBA) Opaque() bool {
454 if p.Rect.Empty() {
455 return true
456 }
457 i0, i1 := 3, p.Rect.Dx()*4
458 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
459 for i := i0; i < i1; i += 4 {
460 if p.Pix[i] != 0xff {
461 return false
462 }
463 }
464 i0 += p.Stride
465 i1 += p.Stride
466 }
467 return true
468 }
469 470 // NewNRGBA returns a new [NRGBA] image with the given bounds.
471 func NewNRGBA(r Rectangle) *NRGBA {
472 return &NRGBA{
473 Pix: []uint8{:pixelBufferLength(4, r, "NRGBA")},
474 Stride: 4 * r.Dx(),
475 Rect: r,
476 }
477 }
478 479 // NRGBA64 is an in-memory image whose At method returns [color.NRGBA64] values.
480 type NRGBA64 struct {
481 // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
482 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
483 Pix []uint8
484 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
485 Stride int
486 // Rect is the image's bounds.
487 Rect Rectangle
488 }
489 490 func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
491 492 func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
493 494 func (p *NRGBA64) At(x, y int) color.Color {
495 return p.NRGBA64At(x, y)
496 }
497 498 func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 {
499 r, g, b, a := p.NRGBA64At(x, y).RGBA()
500 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
501 }
502 503 func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
504 if !(Point{x, y}.In(p.Rect)) {
505 return color.NRGBA64{}
506 }
507 i := p.PixOffset(x, y)
508 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
509 return color.NRGBA64{
510 uint16(s[0])<<8 | uint16(s[1]),
511 uint16(s[2])<<8 | uint16(s[3]),
512 uint16(s[4])<<8 | uint16(s[5]),
513 uint16(s[6])<<8 | uint16(s[7]),
514 }
515 }
516 517 // PixOffset returns the index of the first element of Pix that corresponds to
518 // the pixel at (x, y).
519 func (p *NRGBA64) PixOffset(x, y int) int {
520 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
521 }
522 523 func (p *NRGBA64) Set(x, y int, c color.Color) {
524 if !(Point{x, y}.In(p.Rect)) {
525 return
526 }
527 i := p.PixOffset(x, y)
528 c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
529 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
530 s[0] = uint8(c1.R >> 8)
531 s[1] = uint8(c1.R)
532 s[2] = uint8(c1.G >> 8)
533 s[3] = uint8(c1.G)
534 s[4] = uint8(c1.B >> 8)
535 s[5] = uint8(c1.B)
536 s[6] = uint8(c1.A >> 8)
537 s[7] = uint8(c1.A)
538 }
539 540 func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) {
541 if !(Point{x, y}.In(p.Rect)) {
542 return
543 }
544 r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
545 if (a != 0) && (a != 0xffff) {
546 r = (r * 0xffff) / a
547 g = (g * 0xffff) / a
548 b = (b * 0xffff) / a
549 }
550 i := p.PixOffset(x, y)
551 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
552 s[0] = uint8(r >> 8)
553 s[1] = uint8(r)
554 s[2] = uint8(g >> 8)
555 s[3] = uint8(g)
556 s[4] = uint8(b >> 8)
557 s[5] = uint8(b)
558 s[6] = uint8(a >> 8)
559 s[7] = uint8(a)
560 }
561 562 func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
563 if !(Point{x, y}.In(p.Rect)) {
564 return
565 }
566 i := p.PixOffset(x, y)
567 s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
568 s[0] = uint8(c.R >> 8)
569 s[1] = uint8(c.R)
570 s[2] = uint8(c.G >> 8)
571 s[3] = uint8(c.G)
572 s[4] = uint8(c.B >> 8)
573 s[5] = uint8(c.B)
574 s[6] = uint8(c.A >> 8)
575 s[7] = uint8(c.A)
576 }
577 578 // SubImage returns an image representing the portion of the image p visible
579 // through r. The returned value shares pixels with the original image.
580 func (p *NRGBA64) SubImage(r Rectangle) Image {
581 r = r.Intersect(p.Rect)
582 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
583 // either r1 or r2 if the intersection is empty. Without explicitly checking for
584 // this, the Pix[i:] expression below can panic.
585 if r.Empty() {
586 return &NRGBA64{}
587 }
588 i := p.PixOffset(r.Min.X, r.Min.Y)
589 return &NRGBA64{
590 Pix: p.Pix[i:],
591 Stride: p.Stride,
592 Rect: r,
593 }
594 }
595 596 // Opaque scans the entire image and reports whether it is fully opaque.
597 func (p *NRGBA64) Opaque() bool {
598 if p.Rect.Empty() {
599 return true
600 }
601 i0, i1 := 6, p.Rect.Dx()*8
602 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
603 for i := i0; i < i1; i += 8 {
604 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
605 return false
606 }
607 }
608 i0 += p.Stride
609 i1 += p.Stride
610 }
611 return true
612 }
613 614 // NewNRGBA64 returns a new [NRGBA64] image with the given bounds.
615 func NewNRGBA64(r Rectangle) *NRGBA64 {
616 return &NRGBA64{
617 Pix: []uint8{:pixelBufferLength(8, r, "NRGBA64")},
618 Stride: 8 * r.Dx(),
619 Rect: r,
620 }
621 }
622 623 // Alpha is an in-memory image whose At method returns [color.Alpha] values.
624 type Alpha struct {
625 // Pix holds the image's pixels, as alpha values. The pixel at
626 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
627 Pix []uint8
628 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
629 Stride int
630 // Rect is the image's bounds.
631 Rect Rectangle
632 }
633 634 func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
635 636 func (p *Alpha) Bounds() Rectangle { return p.Rect }
637 638 func (p *Alpha) At(x, y int) color.Color {
639 return p.AlphaAt(x, y)
640 }
641 642 func (p *Alpha) RGBA64At(x, y int) color.RGBA64 {
643 a := uint16(p.AlphaAt(x, y).A)
644 a |= a << 8
645 return color.RGBA64{a, a, a, a}
646 }
647 648 func (p *Alpha) AlphaAt(x, y int) color.Alpha {
649 if !(Point{x, y}.In(p.Rect)) {
650 return color.Alpha{}
651 }
652 i := p.PixOffset(x, y)
653 return color.Alpha{p.Pix[i]}
654 }
655 656 // PixOffset returns the index of the first element of Pix that corresponds to
657 // the pixel at (x, y).
658 func (p *Alpha) PixOffset(x, y int) int {
659 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
660 }
661 662 func (p *Alpha) Set(x, y int, c color.Color) {
663 if !(Point{x, y}.In(p.Rect)) {
664 return
665 }
666 i := p.PixOffset(x, y)
667 p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
668 }
669 670 func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) {
671 if !(Point{x, y}.In(p.Rect)) {
672 return
673 }
674 i := p.PixOffset(x, y)
675 p.Pix[i] = uint8(c.A >> 8)
676 }
677 678 func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
679 if !(Point{x, y}.In(p.Rect)) {
680 return
681 }
682 i := p.PixOffset(x, y)
683 p.Pix[i] = c.A
684 }
685 686 // SubImage returns an image representing the portion of the image p visible
687 // through r. The returned value shares pixels with the original image.
688 func (p *Alpha) SubImage(r Rectangle) Image {
689 r = r.Intersect(p.Rect)
690 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
691 // either r1 or r2 if the intersection is empty. Without explicitly checking for
692 // this, the Pix[i:] expression below can panic.
693 if r.Empty() {
694 return &Alpha{}
695 }
696 i := p.PixOffset(r.Min.X, r.Min.Y)
697 return &Alpha{
698 Pix: p.Pix[i:],
699 Stride: p.Stride,
700 Rect: r,
701 }
702 }
703 704 // Opaque scans the entire image and reports whether it is fully opaque.
705 func (p *Alpha) Opaque() bool {
706 if p.Rect.Empty() {
707 return true
708 }
709 i0, i1 := 0, p.Rect.Dx()
710 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
711 for i := i0; i < i1; i++ {
712 if p.Pix[i] != 0xff {
713 return false
714 }
715 }
716 i0 += p.Stride
717 i1 += p.Stride
718 }
719 return true
720 }
721 722 // NewAlpha returns a new [Alpha] image with the given bounds.
723 func NewAlpha(r Rectangle) *Alpha {
724 return &Alpha{
725 Pix: []uint8{:pixelBufferLength(1, r, "Alpha")},
726 Stride: 1 * r.Dx(),
727 Rect: r,
728 }
729 }
730 731 // Alpha16 is an in-memory image whose At method returns [color.Alpha16] values.
732 type Alpha16 struct {
733 // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
734 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
735 Pix []uint8
736 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
737 Stride int
738 // Rect is the image's bounds.
739 Rect Rectangle
740 }
741 742 func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
743 744 func (p *Alpha16) Bounds() Rectangle { return p.Rect }
745 746 func (p *Alpha16) At(x, y int) color.Color {
747 return p.Alpha16At(x, y)
748 }
749 750 func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 {
751 a := p.Alpha16At(x, y).A
752 return color.RGBA64{a, a, a, a}
753 }
754 755 func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
756 if !(Point{x, y}.In(p.Rect)) {
757 return color.Alpha16{}
758 }
759 i := p.PixOffset(x, y)
760 return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
761 }
762 763 // PixOffset returns the index of the first element of Pix that corresponds to
764 // the pixel at (x, y).
765 func (p *Alpha16) PixOffset(x, y int) int {
766 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
767 }
768 769 func (p *Alpha16) Set(x, y int, c color.Color) {
770 if !(Point{x, y}.In(p.Rect)) {
771 return
772 }
773 i := p.PixOffset(x, y)
774 c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
775 p.Pix[i+0] = uint8(c1.A >> 8)
776 p.Pix[i+1] = uint8(c1.A)
777 }
778 779 func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) {
780 if !(Point{x, y}.In(p.Rect)) {
781 return
782 }
783 i := p.PixOffset(x, y)
784 p.Pix[i+0] = uint8(c.A >> 8)
785 p.Pix[i+1] = uint8(c.A)
786 }
787 788 func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
789 if !(Point{x, y}.In(p.Rect)) {
790 return
791 }
792 i := p.PixOffset(x, y)
793 p.Pix[i+0] = uint8(c.A >> 8)
794 p.Pix[i+1] = uint8(c.A)
795 }
796 797 // SubImage returns an image representing the portion of the image p visible
798 // through r. The returned value shares pixels with the original image.
799 func (p *Alpha16) SubImage(r Rectangle) Image {
800 r = r.Intersect(p.Rect)
801 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
802 // either r1 or r2 if the intersection is empty. Without explicitly checking for
803 // this, the Pix[i:] expression below can panic.
804 if r.Empty() {
805 return &Alpha16{}
806 }
807 i := p.PixOffset(r.Min.X, r.Min.Y)
808 return &Alpha16{
809 Pix: p.Pix[i:],
810 Stride: p.Stride,
811 Rect: r,
812 }
813 }
814 815 // Opaque scans the entire image and reports whether it is fully opaque.
816 func (p *Alpha16) Opaque() bool {
817 if p.Rect.Empty() {
818 return true
819 }
820 i0, i1 := 0, p.Rect.Dx()*2
821 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
822 for i := i0; i < i1; i += 2 {
823 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
824 return false
825 }
826 }
827 i0 += p.Stride
828 i1 += p.Stride
829 }
830 return true
831 }
832 833 // NewAlpha16 returns a new [Alpha16] image with the given bounds.
834 func NewAlpha16(r Rectangle) *Alpha16 {
835 return &Alpha16{
836 Pix: []uint8{:pixelBufferLength(2, r, "Alpha16")},
837 Stride: 2 * r.Dx(),
838 Rect: r,
839 }
840 }
841 842 // Gray is an in-memory image whose At method returns [color.Gray] values.
843 type Gray struct {
844 // Pix holds the image's pixels, as gray values. The pixel at
845 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
846 Pix []uint8
847 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
848 Stride int
849 // Rect is the image's bounds.
850 Rect Rectangle
851 }
852 853 func (p *Gray) ColorModel() color.Model { return color.GrayModel }
854 855 func (p *Gray) Bounds() Rectangle { return p.Rect }
856 857 func (p *Gray) At(x, y int) color.Color {
858 return p.GrayAt(x, y)
859 }
860 861 func (p *Gray) RGBA64At(x, y int) color.RGBA64 {
862 gray := uint16(p.GrayAt(x, y).Y)
863 gray |= gray << 8
864 return color.RGBA64{gray, gray, gray, 0xffff}
865 }
866 867 func (p *Gray) GrayAt(x, y int) color.Gray {
868 if !(Point{x, y}.In(p.Rect)) {
869 return color.Gray{}
870 }
871 i := p.PixOffset(x, y)
872 return color.Gray{p.Pix[i]}
873 }
874 875 // PixOffset returns the index of the first element of Pix that corresponds to
876 // the pixel at (x, y).
877 func (p *Gray) PixOffset(x, y int) int {
878 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
879 }
880 881 func (p *Gray) Set(x, y int, c color.Color) {
882 if !(Point{x, y}.In(p.Rect)) {
883 return
884 }
885 i := p.PixOffset(x, y)
886 p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
887 }
888 889 func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) {
890 if !(Point{x, y}.In(p.Rect)) {
891 return
892 }
893 // This formula is the same as in color.grayModel.
894 gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24
895 i := p.PixOffset(x, y)
896 p.Pix[i] = uint8(gray)
897 }
898 899 func (p *Gray) SetGray(x, y int, c color.Gray) {
900 if !(Point{x, y}.In(p.Rect)) {
901 return
902 }
903 i := p.PixOffset(x, y)
904 p.Pix[i] = c.Y
905 }
906 907 // SubImage returns an image representing the portion of the image p visible
908 // through r. The returned value shares pixels with the original image.
909 func (p *Gray) SubImage(r Rectangle) Image {
910 r = r.Intersect(p.Rect)
911 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
912 // either r1 or r2 if the intersection is empty. Without explicitly checking for
913 // this, the Pix[i:] expression below can panic.
914 if r.Empty() {
915 return &Gray{}
916 }
917 i := p.PixOffset(r.Min.X, r.Min.Y)
918 return &Gray{
919 Pix: p.Pix[i:],
920 Stride: p.Stride,
921 Rect: r,
922 }
923 }
924 925 // Opaque scans the entire image and reports whether it is fully opaque.
926 func (p *Gray) Opaque() bool {
927 return true
928 }
929 930 // NewGray returns a new [Gray] image with the given bounds.
931 func NewGray(r Rectangle) *Gray {
932 return &Gray{
933 Pix: []uint8{:pixelBufferLength(1, r, "Gray")},
934 Stride: 1 * r.Dx(),
935 Rect: r,
936 }
937 }
938 939 // Gray16 is an in-memory image whose At method returns [color.Gray16] values.
940 type Gray16 struct {
941 // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
942 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
943 Pix []uint8
944 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
945 Stride int
946 // Rect is the image's bounds.
947 Rect Rectangle
948 }
949 950 func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
951 952 func (p *Gray16) Bounds() Rectangle { return p.Rect }
953 954 func (p *Gray16) At(x, y int) color.Color {
955 return p.Gray16At(x, y)
956 }
957 958 func (p *Gray16) RGBA64At(x, y int) color.RGBA64 {
959 gray := p.Gray16At(x, y).Y
960 return color.RGBA64{gray, gray, gray, 0xffff}
961 }
962 963 func (p *Gray16) Gray16At(x, y int) color.Gray16 {
964 if !(Point{x, y}.In(p.Rect)) {
965 return color.Gray16{}
966 }
967 i := p.PixOffset(x, y)
968 return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
969 }
970 971 // PixOffset returns the index of the first element of Pix that corresponds to
972 // the pixel at (x, y).
973 func (p *Gray16) PixOffset(x, y int) int {
974 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
975 }
976 977 func (p *Gray16) Set(x, y int, c color.Color) {
978 if !(Point{x, y}.In(p.Rect)) {
979 return
980 }
981 i := p.PixOffset(x, y)
982 c1 := color.Gray16Model.Convert(c).(color.Gray16)
983 p.Pix[i+0] = uint8(c1.Y >> 8)
984 p.Pix[i+1] = uint8(c1.Y)
985 }
986 987 func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) {
988 if !(Point{x, y}.In(p.Rect)) {
989 return
990 }
991 // This formula is the same as in color.gray16Model.
992 gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16
993 i := p.PixOffset(x, y)
994 p.Pix[i+0] = uint8(gray >> 8)
995 p.Pix[i+1] = uint8(gray)
996 }
997 998 func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
999 if !(Point{x, y}.In(p.Rect)) {
1000 return
1001 }
1002 i := p.PixOffset(x, y)
1003 p.Pix[i+0] = uint8(c.Y >> 8)
1004 p.Pix[i+1] = uint8(c.Y)
1005 }
1006 1007 // SubImage returns an image representing the portion of the image p visible
1008 // through r. The returned value shares pixels with the original image.
1009 func (p *Gray16) SubImage(r Rectangle) Image {
1010 r = r.Intersect(p.Rect)
1011 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
1012 // either r1 or r2 if the intersection is empty. Without explicitly checking for
1013 // this, the Pix[i:] expression below can panic.
1014 if r.Empty() {
1015 return &Gray16{}
1016 }
1017 i := p.PixOffset(r.Min.X, r.Min.Y)
1018 return &Gray16{
1019 Pix: p.Pix[i:],
1020 Stride: p.Stride,
1021 Rect: r,
1022 }
1023 }
1024 1025 // Opaque scans the entire image and reports whether it is fully opaque.
1026 func (p *Gray16) Opaque() bool {
1027 return true
1028 }
1029 1030 // NewGray16 returns a new [Gray16] image with the given bounds.
1031 func NewGray16(r Rectangle) *Gray16 {
1032 return &Gray16{
1033 Pix: []uint8{:pixelBufferLength(2, r, "Gray16")},
1034 Stride: 2 * r.Dx(),
1035 Rect: r,
1036 }
1037 }
1038 1039 // CMYK is an in-memory image whose At method returns [color.CMYK] values.
1040 type CMYK struct {
1041 // Pix holds the image's pixels, in C, M, Y, K order. The pixel at
1042 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
1043 Pix []uint8
1044 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
1045 Stride int
1046 // Rect is the image's bounds.
1047 Rect Rectangle
1048 }
1049 1050 func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
1051 1052 func (p *CMYK) Bounds() Rectangle { return p.Rect }
1053 1054 func (p *CMYK) At(x, y int) color.Color {
1055 return p.CMYKAt(x, y)
1056 }
1057 1058 func (p *CMYK) RGBA64At(x, y int) color.RGBA64 {
1059 r, g, b, a := p.CMYKAt(x, y).RGBA()
1060 return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
1061 }
1062 1063 func (p *CMYK) CMYKAt(x, y int) color.CMYK {
1064 if !(Point{x, y}.In(p.Rect)) {
1065 return color.CMYK{}
1066 }
1067 i := p.PixOffset(x, y)
1068 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
1069 return color.CMYK{s[0], s[1], s[2], s[3]}
1070 }
1071 1072 // PixOffset returns the index of the first element of Pix that corresponds to
1073 // the pixel at (x, y).
1074 func (p *CMYK) PixOffset(x, y int) int {
1075 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
1076 }
1077 1078 func (p *CMYK) Set(x, y int, c color.Color) {
1079 if !(Point{x, y}.In(p.Rect)) {
1080 return
1081 }
1082 i := p.PixOffset(x, y)
1083 c1 := color.CMYKModel.Convert(c).(color.CMYK)
1084 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
1085 s[0] = c1.C
1086 s[1] = c1.M
1087 s[2] = c1.Y
1088 s[3] = c1.K
1089 }
1090 1091 func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) {
1092 if !(Point{x, y}.In(p.Rect)) {
1093 return
1094 }
1095 cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8))
1096 i := p.PixOffset(x, y)
1097 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
1098 s[0] = cc
1099 s[1] = mm
1100 s[2] = yy
1101 s[3] = kk
1102 }
1103 1104 func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
1105 if !(Point{x, y}.In(p.Rect)) {
1106 return
1107 }
1108 i := p.PixOffset(x, y)
1109 s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
1110 s[0] = c.C
1111 s[1] = c.M
1112 s[2] = c.Y
1113 s[3] = c.K
1114 }
1115 1116 // SubImage returns an image representing the portion of the image p visible
1117 // through r. The returned value shares pixels with the original image.
1118 func (p *CMYK) SubImage(r Rectangle) Image {
1119 r = r.Intersect(p.Rect)
1120 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
1121 // either r1 or r2 if the intersection is empty. Without explicitly checking for
1122 // this, the Pix[i:] expression below can panic.
1123 if r.Empty() {
1124 return &CMYK{}
1125 }
1126 i := p.PixOffset(r.Min.X, r.Min.Y)
1127 return &CMYK{
1128 Pix: p.Pix[i:],
1129 Stride: p.Stride,
1130 Rect: r,
1131 }
1132 }
1133 1134 // Opaque scans the entire image and reports whether it is fully opaque.
1135 func (p *CMYK) Opaque() bool {
1136 return true
1137 }
1138 1139 // NewCMYK returns a new CMYK image with the given bounds.
1140 func NewCMYK(r Rectangle) *CMYK {
1141 return &CMYK{
1142 Pix: []uint8{:pixelBufferLength(4, r, "CMYK")},
1143 Stride: 4 * r.Dx(),
1144 Rect: r,
1145 }
1146 }
1147 1148 // Paletted is an in-memory image of uint8 indices into a given palette.
1149 type Paletted struct {
1150 // Pix holds the image's pixels, as palette indices. The pixel at
1151 // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
1152 Pix []uint8
1153 // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
1154 Stride int
1155 // Rect is the image's bounds.
1156 Rect Rectangle
1157 // Palette is the image's palette.
1158 Palette color.Palette
1159 }
1160 1161 func (p *Paletted) ColorModel() color.Model { return p.Palette }
1162 1163 func (p *Paletted) Bounds() Rectangle { return p.Rect }
1164 1165 func (p *Paletted) At(x, y int) color.Color {
1166 if len(p.Palette) == 0 {
1167 return nil
1168 }
1169 if !(Point{x, y}.In(p.Rect)) {
1170 return p.Palette[0]
1171 }
1172 i := p.PixOffset(x, y)
1173 return p.Palette[p.Pix[i]]
1174 }
1175 1176 func (p *Paletted) RGBA64At(x, y int) color.RGBA64 {
1177 if len(p.Palette) == 0 {
1178 return color.RGBA64{}
1179 }
1180 c := color.Color(nil)
1181 if !(Point{x, y}.In(p.Rect)) {
1182 c = p.Palette[0]
1183 } else {
1184 i := p.PixOffset(x, y)
1185 c = p.Palette[p.Pix[i]]
1186 }
1187 r, g, b, a := c.RGBA()
1188 return color.RGBA64{
1189 uint16(r),
1190 uint16(g),
1191 uint16(b),
1192 uint16(a),
1193 }
1194 }
1195 1196 // PixOffset returns the index of the first element of Pix that corresponds to
1197 // the pixel at (x, y).
1198 func (p *Paletted) PixOffset(x, y int) int {
1199 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
1200 }
1201 1202 func (p *Paletted) Set(x, y int, c color.Color) {
1203 if !(Point{x, y}.In(p.Rect)) {
1204 return
1205 }
1206 i := p.PixOffset(x, y)
1207 p.Pix[i] = uint8(p.Palette.Index(c))
1208 }
1209 1210 func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) {
1211 if !(Point{x, y}.In(p.Rect)) {
1212 return
1213 }
1214 i := p.PixOffset(x, y)
1215 p.Pix[i] = uint8(p.Palette.Index(c))
1216 }
1217 1218 func (p *Paletted) ColorIndexAt(x, y int) uint8 {
1219 if !(Point{x, y}.In(p.Rect)) {
1220 return 0
1221 }
1222 i := p.PixOffset(x, y)
1223 return p.Pix[i]
1224 }
1225 1226 func (p *Paletted) SetColorIndex(x, y int, index uint8) {
1227 if !(Point{x, y}.In(p.Rect)) {
1228 return
1229 }
1230 i := p.PixOffset(x, y)
1231 p.Pix[i] = index
1232 }
1233 1234 // SubImage returns an image representing the portion of the image p visible
1235 // through r. The returned value shares pixels with the original image.
1236 func (p *Paletted) SubImage(r Rectangle) Image {
1237 r = r.Intersect(p.Rect)
1238 // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
1239 // either r1 or r2 if the intersection is empty. Without explicitly checking for
1240 // this, the Pix[i:] expression below can panic.
1241 if r.Empty() {
1242 return &Paletted{
1243 Palette: p.Palette,
1244 }
1245 }
1246 i := p.PixOffset(r.Min.X, r.Min.Y)
1247 return &Paletted{
1248 Pix: p.Pix[i:],
1249 Stride: p.Stride,
1250 Rect: p.Rect.Intersect(r),
1251 Palette: p.Palette,
1252 }
1253 }
1254 1255 // Opaque scans the entire image and reports whether it is fully opaque.
1256 func (p *Paletted) Opaque() bool {
1257 var present [256]bool
1258 i0, i1 := 0, p.Rect.Dx()
1259 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
1260 for _, c := range p.Pix[i0:i1] {
1261 present[c] = true
1262 }
1263 i0 += p.Stride
1264 i1 += p.Stride
1265 }
1266 for i, c := range p.Palette {
1267 if !present[i] {
1268 continue
1269 }
1270 _, _, _, a := c.RGBA()
1271 if a != 0xffff {
1272 return false
1273 }
1274 }
1275 return true
1276 }
1277 1278 // NewPaletted returns a new [Paletted] image with the given width, height and
1279 // palette.
1280 func NewPaletted(r Rectangle, p color.Palette) *Paletted {
1281 return &Paletted{
1282 Pix: []uint8{:pixelBufferLength(1, r, "Paletted")},
1283 Stride: 1 * r.Dx(),
1284 Rect: r,
1285 Palette: p,
1286 }
1287 }
1288