1
2
3
4
5
6
7
8
9 package image
10
11
12 type Config struct {
13 ColorModel ColorModel
14 Width, Height int
15 }
16
17
18 type Image interface {
19
20 ColorModel() ColorModel
21
22
23 Bounds() Rectangle
24
25
26
27 At(x, y int) Color
28 }
29
30
31 type RGBA struct {
32
33
34 Pix []uint8
35
36 Stride int
37
38 Rect Rectangle
39 }
40
41 func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
42
43 func (p *RGBA) Bounds() Rectangle { return p.Rect }
44
45 func (p *RGBA) At(x, y int) Color {
46 if !(Point{x, y}.In(p.Rect)) {
47 return RGBAColor{}
48 }
49 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
50 return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
51 }
52
53 func (p *RGBA) Set(x, y int, c Color) {
54 if !(Point{x, y}.In(p.Rect)) {
55 return
56 }
57 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
58 c1 := toRGBAColor(c).(RGBAColor)
59 p.Pix[i+0] = c1.R
60 p.Pix[i+1] = c1.G
61 p.Pix[i+2] = c1.B
62 p.Pix[i+3] = c1.A
63 }
64
65 func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
66 if !(Point{x, y}.In(p.Rect)) {
67 return
68 }
69 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
70 p.Pix[i+0] = c.R
71 p.Pix[i+1] = c.G
72 p.Pix[i+2] = c.B
73 p.Pix[i+3] = c.A
74 }
75
76
77
78 func (p *RGBA) SubImage(r Rectangle) Image {
79 r = r.Intersect(p.Rect)
80
81
82
83 if r.Empty() {
84 return &RGBA{}
85 }
86 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
87 return &RGBA{
88 Pix: p.Pix[i:],
89 Stride: p.Stride,
90 Rect: r,
91 }
92 }
93
94
95 func (p *RGBA) Opaque() bool {
96 if p.Rect.Empty() {
97 return true
98 }
99 i0, i1 := 3, p.Rect.Dx()*4
100 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
101 for i := i0; i < i1; i += 4 {
102 if p.Pix[i] != 0xff {
103 return false
104 }
105 }
106 i0 += p.Stride
107 i1 += p.Stride
108 }
109 return true
110 }
111
112
113 func NewRGBA(w, h int) *RGBA {
114 buf := make([]uint8, 4*w*h)
115 return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
116 }
117
118
119 type RGBA64 struct {
120
121
122 Pix []uint8
123
124 Stride int
125
126 Rect Rectangle
127 }
128
129 func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
130
131 func (p *RGBA64) Bounds() Rectangle { return p.Rect }
132
133 func (p *RGBA64) At(x, y int) Color {
134 if !(Point{x, y}.In(p.Rect)) {
135 return RGBA64Color{}
136 }
137 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
138 return RGBA64Color{
139 uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
140 uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
141 uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
142 uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
143 }
144 }
145
146 func (p *RGBA64) Set(x, y int, c Color) {
147 if !(Point{x, y}.In(p.Rect)) {
148 return
149 }
150 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
151 c1 := toRGBA64Color(c).(RGBA64Color)
152 p.Pix[i+0] = uint8(c1.R >> 8)
153 p.Pix[i+1] = uint8(c1.R)
154 p.Pix[i+2] = uint8(c1.G >> 8)
155 p.Pix[i+3] = uint8(c1.G)
156 p.Pix[i+4] = uint8(c1.B >> 8)
157 p.Pix[i+5] = uint8(c1.B)
158 p.Pix[i+6] = uint8(c1.A >> 8)
159 p.Pix[i+7] = uint8(c1.A)
160 }
161
162 func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
163 if !(Point{x, y}.In(p.Rect)) {
164 return
165 }
166 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
167 p.Pix[i+0] = uint8(c.R >> 8)
168 p.Pix[i+1] = uint8(c.R)
169 p.Pix[i+2] = uint8(c.G >> 8)
170 p.Pix[i+3] = uint8(c.G)
171 p.Pix[i+4] = uint8(c.B >> 8)
172 p.Pix[i+5] = uint8(c.B)
173 p.Pix[i+6] = uint8(c.A >> 8)
174 p.Pix[i+7] = uint8(c.A)
175 }
176
177
178
179 func (p *RGBA64) SubImage(r Rectangle) Image {
180 r = r.Intersect(p.Rect)
181
182
183
184 if r.Empty() {
185 return &RGBA64{}
186 }
187 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
188 return &RGBA64{
189 Pix: p.Pix[i:],
190 Stride: p.Stride,
191 Rect: r,
192 }
193 }
194
195
196 func (p *RGBA64) Opaque() bool {
197 if p.Rect.Empty() {
198 return true
199 }
200 i0, i1 := 6, p.Rect.Dx()*8
201 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
202 for i := i0; i < i1; i += 8 {
203 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
204 return false
205 }
206 }
207 i0 += p.Stride
208 i1 += p.Stride
209 }
210 return true
211 }
212
213
214 func NewRGBA64(w, h int) *RGBA64 {
215 pix := make([]uint8, 8*w*h)
216 return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
217 }
218
219
220 type NRGBA struct {
221
222
223 Pix []uint8
224
225 Stride int
226
227 Rect Rectangle
228 }
229
230 func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
231
232 func (p *NRGBA) Bounds() Rectangle { return p.Rect }
233
234 func (p *NRGBA) At(x, y int) Color {
235 if !(Point{x, y}.In(p.Rect)) {
236 return NRGBAColor{}
237 }
238 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
239 return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
240 }
241
242 func (p *NRGBA) Set(x, y int, c Color) {
243 if !(Point{x, y}.In(p.Rect)) {
244 return
245 }
246 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
247 c1 := toNRGBAColor(c).(NRGBAColor)
248 p.Pix[i+0] = c1.R
249 p.Pix[i+1] = c1.G
250 p.Pix[i+2] = c1.B
251 p.Pix[i+3] = c1.A
252 }
253
254 func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
255 if !(Point{x, y}.In(p.Rect)) {
256 return
257 }
258 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
259 p.Pix[i+0] = c.R
260 p.Pix[i+1] = c.G
261 p.Pix[i+2] = c.B
262 p.Pix[i+3] = c.A
263 }
264
265
266
267 func (p *NRGBA) SubImage(r Rectangle) Image {
268 r = r.Intersect(p.Rect)
269
270
271
272 if r.Empty() {
273 return &NRGBA{}
274 }
275 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
276 return &NRGBA{
277 Pix: p.Pix[i:],
278 Stride: p.Stride,
279 Rect: r,
280 }
281 }
282
283
284 func (p *NRGBA) Opaque() bool {
285 if p.Rect.Empty() {
286 return true
287 }
288 i0, i1 := 3, p.Rect.Dx()*4
289 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
290 for i := i0; i < i1; i += 4 {
291 if p.Pix[i] != 0xff {
292 return false
293 }
294 }
295 i0 += p.Stride
296 i1 += p.Stride
297 }
298 return true
299 }
300
301
302 func NewNRGBA(w, h int) *NRGBA {
303 pix := make([]uint8, 4*w*h)
304 return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
305 }
306
307
308 type NRGBA64 struct {
309
310
311 Pix []uint8
312
313 Stride int
314
315 Rect Rectangle
316 }
317
318 func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
319
320 func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
321
322 func (p *NRGBA64) At(x, y int) Color {
323 if !(Point{x, y}.In(p.Rect)) {
324 return NRGBA64Color{}
325 }
326 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
327 return NRGBA64Color{
328 uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
329 uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
330 uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
331 uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
332 }
333 }
334
335 func (p *NRGBA64) Set(x, y int, c Color) {
336 if !(Point{x, y}.In(p.Rect)) {
337 return
338 }
339 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
340 c1 := toNRGBA64Color(c).(NRGBA64Color)
341 p.Pix[i+0] = uint8(c1.R >> 8)
342 p.Pix[i+1] = uint8(c1.R)
343 p.Pix[i+2] = uint8(c1.G >> 8)
344 p.Pix[i+3] = uint8(c1.G)
345 p.Pix[i+4] = uint8(c1.B >> 8)
346 p.Pix[i+5] = uint8(c1.B)
347 p.Pix[i+6] = uint8(c1.A >> 8)
348 p.Pix[i+7] = uint8(c1.A)
349 }
350
351 func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
352 if !(Point{x, y}.In(p.Rect)) {
353 return
354 }
355 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
356 p.Pix[i+0] = uint8(c.R >> 8)
357 p.Pix[i+1] = uint8(c.R)
358 p.Pix[i+2] = uint8(c.G >> 8)
359 p.Pix[i+3] = uint8(c.G)
360 p.Pix[i+4] = uint8(c.B >> 8)
361 p.Pix[i+5] = uint8(c.B)
362 p.Pix[i+6] = uint8(c.A >> 8)
363 p.Pix[i+7] = uint8(c.A)
364 }
365
366
367
368 func (p *NRGBA64) SubImage(r Rectangle) Image {
369 r = r.Intersect(p.Rect)
370
371
372
373 if r.Empty() {
374 return &NRGBA64{}
375 }
376 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
377 return &NRGBA64{
378 Pix: p.Pix[i:],
379 Stride: p.Stride,
380 Rect: r,
381 }
382 }
383
384
385 func (p *NRGBA64) Opaque() bool {
386 if p.Rect.Empty() {
387 return true
388 }
389 i0, i1 := 6, p.Rect.Dx()*8
390 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
391 for i := i0; i < i1; i += 8 {
392 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
393 return false
394 }
395 }
396 i0 += p.Stride
397 i1 += p.Stride
398 }
399 return true
400 }
401
402
403 func NewNRGBA64(w, h int) *NRGBA64 {
404 pix := make([]uint8, 8*w*h)
405 return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
406 }
407
408
409 type Alpha struct {
410
411
412 Pix []uint8
413
414 Stride int
415
416 Rect Rectangle
417 }
418
419 func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
420
421 func (p *Alpha) Bounds() Rectangle { return p.Rect }
422
423 func (p *Alpha) At(x, y int) Color {
424 if !(Point{x, y}.In(p.Rect)) {
425 return AlphaColor{}
426 }
427 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
428 return AlphaColor{p.Pix[i]}
429 }
430
431 func (p *Alpha) Set(x, y int, c Color) {
432 if !(Point{x, y}.In(p.Rect)) {
433 return
434 }
435 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
436 p.Pix[i] = toAlphaColor(c).(AlphaColor).A
437 }
438
439 func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
440 if !(Point{x, y}.In(p.Rect)) {
441 return
442 }
443 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
444 p.Pix[i] = c.A
445 }
446
447
448
449 func (p *Alpha) SubImage(r Rectangle) Image {
450 r = r.Intersect(p.Rect)
451
452
453
454 if r.Empty() {
455 return &Alpha{}
456 }
457 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
458 return &Alpha{
459 Pix: p.Pix[i:],
460 Stride: p.Stride,
461 Rect: r,
462 }
463 }
464
465
466 func (p *Alpha) Opaque() bool {
467 if p.Rect.Empty() {
468 return true
469 }
470 i0, i1 := 0, p.Rect.Dx()
471 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
472 for i := i0; i < i1; i++ {
473 if p.Pix[i] != 0xff {
474 return false
475 }
476 }
477 i0 += p.Stride
478 i1 += p.Stride
479 }
480 return true
481 }
482
483
484 func NewAlpha(w, h int) *Alpha {
485 pix := make([]uint8, 1*w*h)
486 return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
487 }
488
489
490 type Alpha16 struct {
491
492
493 Pix []uint8
494
495 Stride int
496
497 Rect Rectangle
498 }
499
500 func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
501
502 func (p *Alpha16) Bounds() Rectangle { return p.Rect }
503
504 func (p *Alpha16) At(x, y int) Color {
505 if !(Point{x, y}.In(p.Rect)) {
506 return Alpha16Color{}
507 }
508 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
509 return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
510 }
511
512 func (p *Alpha16) Set(x, y int, c Color) {
513 if !(Point{x, y}.In(p.Rect)) {
514 return
515 }
516 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
517 c1 := toAlpha16Color(c).(Alpha16Color)
518 p.Pix[i+0] = uint8(c1.A >> 8)
519 p.Pix[i+1] = uint8(c1.A)
520 }
521
522 func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
523 if !(Point{x, y}.In(p.Rect)) {
524 return
525 }
526 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
527 p.Pix[i+0] = uint8(c.A >> 8)
528 p.Pix[i+1] = uint8(c.A)
529 }
530
531
532
533 func (p *Alpha16) SubImage(r Rectangle) Image {
534 r = r.Intersect(p.Rect)
535
536
537
538 if r.Empty() {
539 return &Alpha16{}
540 }
541 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
542 return &Alpha16{
543 Pix: p.Pix[i:],
544 Stride: p.Stride,
545 Rect: r,
546 }
547 }
548
549
550 func (p *Alpha16) Opaque() bool {
551 if p.Rect.Empty() {
552 return true
553 }
554 i0, i1 := 0, p.Rect.Dx()*2
555 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
556 for i := i0; i < i1; i += 2 {
557 if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
558 return false
559 }
560 }
561 i0 += p.Stride
562 i1 += p.Stride
563 }
564 return true
565 }
566
567
568 func NewAlpha16(w, h int) *Alpha16 {
569 pix := make([]uint8, 2*w*h)
570 return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
571 }
572
573
574 type Gray struct {
575
576
577 Pix []uint8
578
579 Stride int
580
581 Rect Rectangle
582 }
583
584 func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
585
586 func (p *Gray) Bounds() Rectangle { return p.Rect }
587
588 func (p *Gray) At(x, y int) Color {
589 if !(Point{x, y}.In(p.Rect)) {
590 return GrayColor{}
591 }
592 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
593 return GrayColor{p.Pix[i]}
594 }
595
596 func (p *Gray) Set(x, y int, c Color) {
597 if !(Point{x, y}.In(p.Rect)) {
598 return
599 }
600 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
601 p.Pix[i] = toGrayColor(c).(GrayColor).Y
602 }
603
604 func (p *Gray) SetGray(x, y int, c GrayColor) {
605 if !(Point{x, y}.In(p.Rect)) {
606 return
607 }
608 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
609 p.Pix[i] = c.Y
610 }
611
612
613
614 func (p *Gray) SubImage(r Rectangle) Image {
615 r = r.Intersect(p.Rect)
616
617
618
619 if r.Empty() {
620 return &Gray{}
621 }
622 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
623 return &Gray{
624 Pix: p.Pix[i:],
625 Stride: p.Stride,
626 Rect: r,
627 }
628 }
629
630
631 func (p *Gray) Opaque() bool {
632 return true
633 }
634
635
636 func NewGray(w, h int) *Gray {
637 pix := make([]uint8, 1*w*h)
638 return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
639 }
640
641
642 type Gray16 struct {
643
644
645 Pix []uint8
646
647 Stride int
648
649 Rect Rectangle
650 }
651
652 func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
653
654 func (p *Gray16) Bounds() Rectangle { return p.Rect }
655
656 func (p *Gray16) At(x, y int) Color {
657 if !(Point{x, y}.In(p.Rect)) {
658 return Gray16Color{}
659 }
660 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
661 return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
662 }
663
664 func (p *Gray16) Set(x, y int, c Color) {
665 if !(Point{x, y}.In(p.Rect)) {
666 return
667 }
668 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
669 c1 := toGray16Color(c).(Gray16Color)
670 p.Pix[i+0] = uint8(c1.Y >> 8)
671 p.Pix[i+1] = uint8(c1.Y)
672 }
673
674 func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
675 if !(Point{x, y}.In(p.Rect)) {
676 return
677 }
678 i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
679 p.Pix[i+0] = uint8(c.Y >> 8)
680 p.Pix[i+1] = uint8(c.Y)
681 }
682
683
684
685 func (p *Gray16) SubImage(r Rectangle) Image {
686 r = r.Intersect(p.Rect)
687
688
689
690 if r.Empty() {
691 return &Gray16{}
692 }
693 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
694 return &Gray16{
695 Pix: p.Pix[i:],
696 Stride: p.Stride,
697 Rect: r,
698 }
699 }
700
701
702 func (p *Gray16) Opaque() bool {
703 return true
704 }
705
706
707 func NewGray16(w, h int) *Gray16 {
708 pix := make([]uint8, 2*w*h)
709 return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
710 }
711
712
713 type PalettedColorModel []Color
714
715 func diff(a, b uint32) uint32 {
716 if a > b {
717 return a - b
718 }
719 return b - a
720 }
721
722
723 func (p PalettedColorModel) Convert(c Color) Color {
724 if len(p) == 0 {
725 return nil
726 }
727 return p[p.Index(c)]
728 }
729
730
731
732 func (p PalettedColorModel) Index(c Color) int {
733 cr, cg, cb, _ := c.RGBA()
734
735 cr >>= 1
736 cg >>= 1
737 cb >>= 1
738 ret, bestSSD := 0, uint32(1<<32-1)
739 for i, v := range p {
740 vr, vg, vb, _ := v.RGBA()
741 vr >>= 1
742 vg >>= 1
743 vb >>= 1
744 dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
745 ssd := (dr * dr) + (dg * dg) + (db * db)
746 if ssd < bestSSD {
747 ret, bestSSD = i, ssd
748 }
749 }
750 return ret
751 }
752
753
754 type Paletted struct {
755
756
757 Pix []uint8
758
759 Stride int
760
761 Rect Rectangle
762
763 Palette PalettedColorModel
764 }
765
766 func (p *Paletted) ColorModel() ColorModel { return p.Palette }
767
768 func (p *Paletted) Bounds() Rectangle { return p.Rect }
769
770 func (p *Paletted) At(x, y int) Color {
771 if len(p.Palette) == 0 {
772 return nil
773 }
774 if !(Point{x, y}.In(p.Rect)) {
775 return p.Palette[0]
776 }
777 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
778 return p.Palette[p.Pix[i]]
779 }
780
781 func (p *Paletted) Set(x, y int, c Color) {
782 if !(Point{x, y}.In(p.Rect)) {
783 return
784 }
785 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
786 p.Pix[i] = uint8(p.Palette.Index(c))
787 }
788
789 func (p *Paletted) ColorIndexAt(x, y int) uint8 {
790 if !(Point{x, y}.In(p.Rect)) {
791 return 0
792 }
793 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
794 return p.Pix[i]
795 }
796
797 func (p *Paletted) SetColorIndex(x, y int, index uint8) {
798 if !(Point{x, y}.In(p.Rect)) {
799 return
800 }
801 i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
802 p.Pix[i] = index
803 }
804
805
806
807 func (p *Paletted) SubImage(r Rectangle) Image {
808 r = r.Intersect(p.Rect)
809
810
811
812 if r.Empty() {
813 return &Paletted{
814 Palette: p.Palette,
815 }
816 }
817 i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
818 return &Paletted{
819 Pix: p.Pix[i:],
820 Stride: p.Stride,
821 Rect: p.Rect.Intersect(r),
822 Palette: p.Palette,
823 }
824 }
825
826
827 func (p *Paletted) Opaque() bool {
828 var present [256]bool
829 i0, i1 := 0, p.Rect.Dx()
830 for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
831 for _, c := range p.Pix[i0:i1] {
832 present[c] = true
833 }
834 i0 += p.Stride
835 i1 += p.Stride
836 }
837 for i, c := range p.Palette {
838 if !present[i] {
839 continue
840 }
841 _, _, _, a := c.RGBA()
842 if a != 0xffff {
843 return false
844 }
845 }
846 return true
847 }
848
849
850 func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
851 pix := make([]uint8, 1*w*h)
852 return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
853 }