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).
38package image
39
40import (
41	"image/color"
42)
43
44// Config holds an image's color model and dimensions.
45type 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.
52type 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.
66type 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.
80type 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.
93func pixelBufferLength(bytesPerPixel int, r Rectangle, imageTypeName string) int {
94	totalLength := mul3NonNeg(bytesPerPixel, r.Dx(), r.Dy())
95	if totalLength < 0 {
96		panic("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.
102type 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
112func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
113
114func (p *RGBA) Bounds() Rectangle { return p.Rect }
115
116func (p *RGBA) At(x, y int) color.Color {
117	return p.RGBAAt(x, y)
118}
119
120func (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
138func (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).
149func (p *RGBA) PixOffset(x, y int) int {
150	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
151}
152
153func (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
166func (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
178func (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.
192func (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.
209func (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.
227func NewRGBA(r Rectangle) *RGBA {
228	return &RGBA{
229		Pix:    make([]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.
236type 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
246func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
247
248func (p *RGBA64) Bounds() Rectangle { return p.Rect }
249
250func (p *RGBA64) At(x, y int) color.Color {
251	return p.RGBA64At(x, y)
252}
253
254func (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).
270func (p *RGBA64) PixOffset(x, y int) int {
271	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
272}
273
274func (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
291func (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.
309func (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.
326func (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.
344func NewRGBA64(r Rectangle) *RGBA64 {
345	return &RGBA64{
346		Pix:    make([]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.
353type 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
363func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
364
365func (p *NRGBA) Bounds() Rectangle { return p.Rect }
366
367func (p *NRGBA) At(x, y int) color.Color {
368	return p.NRGBAAt(x, y)
369}
370
371func (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
376func (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).
387func (p *NRGBA) PixOffset(x, y int) int {
388	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
389}
390
391func (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
404func (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
422func (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.
436func (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.
453func (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.
471func NewNRGBA(r Rectangle) *NRGBA {
472	return &NRGBA{
473		Pix:    make([]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.
480type 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
490func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
491
492func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
493
494func (p *NRGBA64) At(x, y int) color.Color {
495	return p.NRGBA64At(x, y)
496}
497
498func (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
503func (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).
519func (p *NRGBA64) PixOffset(x, y int) int {
520	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
521}
522
523func (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
540func (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
562func (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.
580func (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.
597func (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.
615func NewNRGBA64(r Rectangle) *NRGBA64 {
616	return &NRGBA64{
617		Pix:    make([]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.
624type 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
634func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
635
636func (p *Alpha) Bounds() Rectangle { return p.Rect }
637
638func (p *Alpha) At(x, y int) color.Color {
639	return p.AlphaAt(x, y)
640}
641
642func (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
648func (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).
658func (p *Alpha) PixOffset(x, y int) int {
659	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
660}
661
662func (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
670func (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
678func (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.
688func (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.
705func (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.
723func NewAlpha(r Rectangle) *Alpha {
724	return &Alpha{
725		Pix:    make([]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.
732type 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
742func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
743
744func (p *Alpha16) Bounds() Rectangle { return p.Rect }
745
746func (p *Alpha16) At(x, y int) color.Color {
747	return p.Alpha16At(x, y)
748}
749
750func (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
755func (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).
765func (p *Alpha16) PixOffset(x, y int) int {
766	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
767}
768
769func (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
779func (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
788func (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.
799func (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.
816func (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.
834func NewAlpha16(r Rectangle) *Alpha16 {
835	return &Alpha16{
836		Pix:    make([]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.
843type 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
853func (p *Gray) ColorModel() color.Model { return color.GrayModel }
854
855func (p *Gray) Bounds() Rectangle { return p.Rect }
856
857func (p *Gray) At(x, y int) color.Color {
858	return p.GrayAt(x, y)
859}
860
861func (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
867func (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).
877func (p *Gray) PixOffset(x, y int) int {
878	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
879}
880
881func (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
889func (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
899func (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.
909func (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.
926func (p *Gray) Opaque() bool {
927	return true
928}
929
930// NewGray returns a new [Gray] image with the given bounds.
931func NewGray(r Rectangle) *Gray {
932	return &Gray{
933		Pix:    make([]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.
940type 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
950func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
951
952func (p *Gray16) Bounds() Rectangle { return p.Rect }
953
954func (p *Gray16) At(x, y int) color.Color {
955	return p.Gray16At(x, y)
956}
957
958func (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
963func (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).
973func (p *Gray16) PixOffset(x, y int) int {
974	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
975}
976
977func (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
987func (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
998func (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.
1009func (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.
1026func (p *Gray16) Opaque() bool {
1027	return true
1028}
1029
1030// NewGray16 returns a new [Gray16] image with the given bounds.
1031func NewGray16(r Rectangle) *Gray16 {
1032	return &Gray16{
1033		Pix:    make([]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.
1040type 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
1050func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
1051
1052func (p *CMYK) Bounds() Rectangle { return p.Rect }
1053
1054func (p *CMYK) At(x, y int) color.Color {
1055	return p.CMYKAt(x, y)
1056}
1057
1058func (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
1063func (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).
1074func (p *CMYK) PixOffset(x, y int) int {
1075	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
1076}
1077
1078func (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
1091func (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
1104func (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.
1118func (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.
1135func (p *CMYK) Opaque() bool {
1136	return true
1137}
1138
1139// NewCMYK returns a new CMYK image with the given bounds.
1140func NewCMYK(r Rectangle) *CMYK {
1141	return &CMYK{
1142		Pix:    make([]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.
1149type 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
1161func (p *Paletted) ColorModel() color.Model { return p.Palette }
1162
1163func (p *Paletted) Bounds() Rectangle { return p.Rect }
1164
1165func (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
1176func (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).
1198func (p *Paletted) PixOffset(x, y int) int {
1199	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
1200}
1201
1202func (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
1210func (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
1218func (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
1226func (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.
1236func (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.
1256func (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.
1280func NewPaletted(r Rectangle, p color.Palette) *Paletted {
1281	return &Paletted{
1282		Pix:     make([]uint8, pixelBufferLength(1, r, "Paletted")),
1283		Stride:  1 * r.Dx(),
1284		Rect:    r,
1285		Palette: p,
1286	}
1287}
1288