-
Notifications
You must be signed in to change notification settings - Fork 0
/
xbm.go
89 lines (77 loc) · 2.11 KB
/
xbm.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
package xbm
import (
"fmt"
"image"
"image/color"
"io"
"strings"
)
// Encoder contains encoding configuration that is used by the Encode method
type Encoder struct {
// The internal image name, when encoding the data. The default is "img".
Name string
// The threshold, from 0 to 1, for when grayscale colors should appear as
// white or black. The default is 0.5.
Threshold float64
}
// hexify converts a slice of bytes to a slice of hex strings on the form 0x00
func hexify(data []byte) (r []string) {
for _, b := range data {
r = append(r, fmt.Sprintf("0x%02x", b))
}
return r
}
// Encode will encode the given image as XBM, using a custom image name from
// the Encoder struct. The colors are first converted to grayscale, and then
// with a 50% cutoff they are converted to 1-bit colors.
func (enc *Encoder) Encode(w io.Writer, m image.Image) error {
imageName := enc.Name
width := m.Bounds().Dx()
height := m.Bounds().Dy()
fmt.Fprintf(w, "/* XBM X11 format */\n")
maskIndex := 0
masks := []uint8{
0x1,
0x2,
0x4,
0x8,
0x10,
0x20,
0x40,
0x80,
}
var pixels []byte
var pixel uint8
for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
c := m.At(x, y)
grayColor := color.GrayModel.Convert(c).(color.Gray)
value := grayColor.Y
if value <= byte(float64(256)*enc.Threshold) {
// white
pixel |= masks[maskIndex]
} else {
// black, skip
}
// Prepare to write the next bit
maskIndex++
if maskIndex == len(masks) {
// Filled up an entire byte with pixel bits, flush and reset
maskIndex = 0
pixels = append(pixels, pixel)
pixel = 0
}
}
}
fmt.Fprintf(w, "#define %s_width %d\n", imageName, width)
fmt.Fprintf(w, "#define %s_height %d\n", imageName, height)
fmt.Fprintf(w, "static unsigned char %s_bits[] = {\n", imageName)
fmt.Fprintf(w, " %s\n", strings.Join(hexify(pixels), ", "))
fmt.Fprintf(w, "};\n")
return nil
}
// Encode will encode the image as XBM, using "img" as the image name
func Encode(w io.Writer, m image.Image) error {
e := &Encoder{"img", 0.5}
return e.Encode(w, m)
}