limage - indexedalpha.go
1 package limage
2
3 import (
4 "image"
5 "image/color"
6
7 "vimagination.zapto.org/limage/lcolor"
8 )
9
10 // PalettedAlpha represents a paletted image with an alpha channel
11 type PalettedAlpha struct {
12 Pix []lcolor.IndexedAlpha
13 Stride int
14 Rect image.Rectangle
15 Palette lcolor.AlphaPalette
16 }
17
18 // NewPalettedAlpha creates a new image that uses a palette with an alpha channel
19 func NewPalettedAlpha(r image.Rectangle, p lcolor.AlphaPalette) *PalettedAlpha {
20 w, h := r.Dx(), r.Dy()
21 return &PalettedAlpha{
22 Pix: make([]lcolor.IndexedAlpha, w*h),
23 Stride: w,
24 Rect: r,
25 Palette: p,
26 }
27 }
28
29 // At returns the color of the pixel at the given coords
30 func (p *PalettedAlpha) At(x, y int) color.Color {
31 if p.Palette == nil {
32 return nil
33 }
34 ia := p.IndexAlphaAt(x, y)
35 r, g, b, _ := p.Palette[ia.I].RGBA()
36 return color.NRGBA{
37 R: uint8(r >> 8),
38 G: uint8(g >> 8),
39 B: uint8(b >> 8),
40 A: ia.A,
41 }
42 }
43
44 // Bounds returns the limits of the image
45 func (p *PalettedAlpha) Bounds() image.Rectangle {
46 return p.Rect
47 }
48
49 // ColorModel a color model to tranform arbitrary colors to one in the palette
50 func (p *PalettedAlpha) ColorModel() color.Model {
51 return p.Palette
52 }
53
54 // IndexAlphaAt returns the palette index and Alpha component of the given
55 // coords
56 func (p *PalettedAlpha) IndexAlphaAt(x, y int) lcolor.IndexedAlpha {
57 if !(image.Point{x, y}.In(p.Rect)) {
58 return lcolor.IndexedAlpha{}
59 }
60 return p.Pix[p.PixOffset(x, y)]
61 }
62
63 // Opaque returns true if the image is completely opaque
64 func (p *PalettedAlpha) Opaque() bool {
65 for _, c := range p.Pix {
66 if c.A != 255 {
67 return true
68 }
69 }
70 return false
71 }
72
73 // PixOffset returns the index of the Pix array corresponding to the given
74 // coords
75 func (p *PalettedAlpha) PixOffset(x, y int) int {
76 return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
77 }
78
79 // Set converts the given colour to the closest in the palette and sets it at
80 // the given coords
81 func (p *PalettedAlpha) Set(x, y int, c color.Color) {
82 if !(image.Point{x, y}.In(p.Rect)) {
83 return
84 }
85 _, _, _, a := c.RGBA()
86 p.Pix[p.PixOffset(x, y)] = lcolor.IndexedAlpha{
87 I: uint8(p.Palette.Index(c)),
88 A: uint8(a >> 8),
89 }
90 }
91
92 // SetIndexAlpha directly set the index and alpha channels to the given coords
93 func (p *PalettedAlpha) SetIndexAlpha(x, y int, ia lcolor.IndexedAlpha) {
94 if !(image.Point{x, y}.In(p.Rect)) {
95 return
96 }
97 p.Pix[p.PixOffset(x, y)] = ia
98 }
99
100 // SubImage retuns the Image viewable through the given bounds
101 func (p *PalettedAlpha) SubImage(r image.Rectangle) image.Image {
102 r = r.Intersect(p.Rect)
103 if r.Empty() {
104 return &PalettedAlpha{}
105 }
106 return &PalettedAlpha{
107 Pix: p.Pix[p.PixOffset(r.Min.X, r.Min.Y):],
108 Stride: p.Stride,
109 Rect: r,
110 Palette: p.Palette,
111 }
112 }
113