-
Notifications
You must be signed in to change notification settings - Fork 0
/
im8.go
111 lines (89 loc) · 2.63 KB
/
im8.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Package im8 provides a 6- or 8-bit image format.
package im8
import (
"image"
"image/color"
"github.com/superloach/im8/col8"
)
// Im8 is an in-memory image whose At method returns col8.Col8 values.
type Im8 struct {
// Pix holds the image's pixels. The pixel at (x, y) is at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)].
Pix []uint8
// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect image.Rectangle
}
// NewIm8 returns a new Im8 image with the given bounds.
func NewIm8(r image.Rectangle) *Im8 {
return &Im8{
Pix: make([]uint8, r.Dx()*r.Dy()),
Stride: r.Dx(),
Rect: r,
}
}
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
func (i *Im8) At(x, y int) color.Color {
return i.Col8At(x, y)
}
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
func (i *Im8) Bounds() image.Rectangle {
return i.Rect
}
// ColorModel returns the Image's color model.
func (i *Im8) ColorModel() color.Model {
return col8.Col8Model
}
// Col8At returns the col8.Col8 pixel at (x, y).
func (i *Im8) Col8At(x, y int) col8.Col8 {
if !(image.Point{x, y}.In(i.Rect)) {
return 0
}
idx := i.PixOffset(x, y)
return col8.Col8(i.Pix[idx])
}
// Opaque scans the entire image and reports whether it is fully opaque.
func (i *Im8) Opaque() bool {
for x := i.Rect.Min.X; x < i.Rect.Max.X; x++ {
for y := i.Rect.Min.Y; y < i.Rect.Max.Y; y++ {
_, _, _, a := i.At(x, y).RGBA()
if a < (1<<16)-1 {
return false
}
}
}
return true
}
// PixOffset returns the index of the element of Pix that corresponds to the pixel at (x, y).
func (i *Im8) PixOffset(x, y int) int {
return (y-i.Rect.Min.Y)*i.Stride + (x - i.Rect.Min.X)
}
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (i *Im8) SubImage(r image.Rectangle) image.Image {
r = r.Intersect(i.Rect)
if r.Empty() {
return &Im8{}
}
idx := i.PixOffset(r.Min.X, r.Min.Y)
return &Im8{
Pix: i.Pix[idx:],
Stride: i.Stride,
Rect: r,
}
}
// Set sets the pixel at (x, y) to c, after converting to a col8.Col8.
func (i *Im8) Set(x, y int, c color.Color) {
i.SetCol8(x, y, col8.Col8Model.Convert(c).(col8.Col8))
}
// SetCol8 sets the pixel at (x, y) to c.
func (i *Im8) SetCol8(x, y int, c col8.Col8) {
if !(image.Point{x, y}.In(i.Rect)) {
return
}
idx := i.PixOffset(x, y)
i.Pix[idx] = uint8(c)
}