• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

msoap / tcg / 6449834132

08 Oct 2023 08:31PM UTC coverage: 71.257% (+0.1%) from 71.154%
6449834132

push

github

msoap
clean up

595 of 835 relevant lines covered (71.26%)

179.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/buffer.go
1
package tcg
2

3
import (
4
        "fmt"
5
        "image"
6
        "image/color"
7
        _ "image/png"
8
        "strings"
9
)
10

11
// Buffer - implement base screen pixel buffer
12
type Buffer struct {
13
        Width  int
14
        Height int
15
        buffer [][]byte
16
}
17

18
// NewBuffer - get new buffer object
19
func NewBuffer(width, height int) Buffer {
26✔
20
        return Buffer{
26✔
21
                Width:  width,
26✔
22
                Height: height,
26✔
23
                buffer: allocateBuffer(width, height),
26✔
24
        }
26✔
25
}
26✔
26

27
// NewBufferFromStrings - get new buffer object from list of strings (00110001, 0001001, ...)
28
// such symbols are also valid: "  **  ", "..##.."
29
func NewBufferFromStrings(in []string) (*Buffer, error) {
87✔
30
        if len(in) == 0 {
87✔
31
                return nil, fmt.Errorf("got empty string list")
×
32
        }
×
33

34
        width, height := len(in[0]), len(in)
87✔
35

87✔
36
        buf := Buffer{
87✔
37
                Width:  width,
87✔
38
                Height: height,
87✔
39
                buffer: allocateBuffer(width, height),
87✔
40
        }
87✔
41

87✔
42
        for y, line := range in {
727✔
43
                if len(line) != width {
640✔
44
                        return nil, fmt.Errorf("got line with different width (%d != %d) on line %d", width, len(line), y)
×
45
                }
×
46
                for x, char := range line {
6,488✔
47
                        switch char {
5,848✔
48
                        case '0', '.', ' ':
4,409✔
49
                                // pass
50
                        case '1', '*', '#':
1,439✔
51
                                buf.Set(x, y, Black)
1,439✔
52
                        default:
×
53
                                return nil, fmt.Errorf("got not valid char %v on %d:%d", char, x, y)
×
54
                        }
55
                }
56
        }
57

58
        return &buf, nil
87✔
59
}
60

61
// MustNewBufferFromStrings - get new buffer object from list of strings or die on error
62
func MustNewBufferFromStrings(in []string) Buffer {
87✔
63
        buf, err := NewBufferFromStrings(in)
87✔
64
        if err != nil {
87✔
65
                panic(err)
×
66
        }
67
        return *buf
87✔
68
}
69

70
// Strings - render as slice of string, ["...**...", ...]
71
func (b Buffer) Strings() []string {
7✔
72
        return b.RenderAsStrings(Mode1x1Simple)
7✔
73
}
7✔
74

75
// String - render as string with new-line separator: "..*..\n*....*\n..*.."
76
func (b Buffer) String() string {
7✔
77
        return strings.Join(b.Strings(), "\n")
7✔
78
}
7✔
79

80
func allocateBuffer(w, h int) [][]byte {
121✔
81
        buffer := make([][]byte, h)
121✔
82
        bytesLen := widthInBytes(w)
121✔
83
        for i := range buffer {
1,062✔
84
                buffer[i] = make([]byte, bytesLen)
941✔
85
        }
941✔
86

87
        return buffer
121✔
88
}
89

90
func widthInBytes(w int) int {
137✔
91
        result := w / 8
137✔
92
        if w%8 > 0 {
267✔
93
                result++
130✔
94
        }
130✔
95
        return result
137✔
96
}
97

98
// NewBufferFromImage - get new buffer from image.Image object
99
func NewBufferFromImage(img image.Image) Buffer {
1✔
100
        buf := NewBuffer(img.Bounds().Size().X, img.Bounds().Size().Y)
1✔
101

1✔
102
        for y := 0; y < buf.Height; y++ {
11✔
103
                for x := 0; x < buf.Width; x++ {
110✔
104
                        tc := Black
100✔
105
                        if color.GrayModel.Convert(img.At(x, y)).(color.Gray).Y >= 128 {
180✔
106
                                tc = White
80✔
107
                        }
80✔
108
                        buf.Set(x, y, tc)
100✔
109
                }
110
        }
111

112
        return buf
1✔
113
}
114

115
// ToImage - convert buffer to stdlib Image with Gray colorspace, for example for save buffer to the image file like png
116
func (b Buffer) ToImage() image.Image {
×
117
        img := image.NewGray(image.Rect(0, 0, b.Width, b.Height))
×
118
        var c uint8
×
119
        for y := 0; y < b.Height; y++ {
×
120
                for x := 0; x < b.Width; x++ {
×
121
                        c = 255
×
122
                        if b.IsSet(x, y) {
×
123
                                c = 0
×
124
                        }
×
125
                        img.SetGray(x, y, color.Gray{Y: c})
×
126
                }
127
        }
128

129
        return img
×
130
}
131

132
// Clone to new buffer
133
func (b Buffer) Clone() *Buffer {
4✔
134
        newBuf := NewBuffer(b.Width, b.Height)
4✔
135
        for y := 0; y < b.Height; y++ {
44✔
136
                copy(newBuf.buffer[y], b.buffer[y])
40✔
137
        }
40✔
138
        return &newBuf
4✔
139
}
140

141
// Cut area to the new buffer, without change current buffer
142
func (b Buffer) Cut(x, y, width, height int) Buffer {
1✔
143
        newBuf := NewBuffer(width, height)
1✔
144
        newBuf.BitBlt(0, 0, width, height, b, x, y)
1✔
145
        return newBuf
1✔
146
}
1✔
147

148
// Set - put pixel into buffer
149
func (b *Buffer) Set(x, y int, color int) {
3,113✔
150
        if x < 0 || x > b.Width-1 || y < 0 || y > b.Height-1 {
3,113✔
151
                return
×
152
        }
×
153

154
        // [0][1][2][3] [4][5][6][7]
155
        i, mask := x/8, byte(0b1000_0000>>byte(x%8))
3,113✔
156
        switch color {
3,113✔
157
        case Black:
2,450✔
158
                b.buffer[y][i] |= mask
2,450✔
159
        case White:
663✔
160
                b.buffer[y][i] &^= mask
663✔
161
        }
162
}
163

164
// IsSet - is pixel set to black?
165
func (b Buffer) IsSet(x, y int) bool {
17✔
166
        return b.At(x, y) == Black
17✔
167
}
17✔
168

169
// At - get pixel color from buffer
170
func (b Buffer) At(x, y int) int {
9,495✔
171
        if x < 0 || x > b.Width-1 || y < 0 || y > b.Height-1 {
9,525✔
172
                return White
30✔
173
        }
30✔
174

175
        // [0][1][2][3] [4][5][6][7]
176
        i, mask := x/8, byte(0b1000_0000>>byte(x%8))
9,465✔
177

9,465✔
178
        if b.buffer[y][i]&mask > 0 {
12,100✔
179
                return Black
2,635✔
180
        }
2,635✔
181

182
        return White
6,830✔
183
}
184

185
// getPixelsBlock - get rectangular block of pixels as linear bits
186
func (b Buffer) getPixelsBlock(x, y, width, height int) int {
781✔
187
        if x < 0 || x > b.Width || y < 0 || y > b.Height {
781✔
188
                return 0
×
189
        }
×
190

191
        result, num := 0, width*height-1
781✔
192

781✔
193
        for h := 0; h < height; h++ {
1,619✔
194
                for w := 0; w < width; w++ {
1,730✔
195
                        result |= b.At(x+w, y+h) << num
892✔
196
                        num--
892✔
197
                }
892✔
198
        }
199

200
        return result
781✔
201
}
202

203
// IsEqual - are two buffers equal?
204
func (b Buffer) IsEqual(a Buffer) bool {
41✔
205
        if b.Width != a.Width || b.Height != a.Height {
41✔
206
                return false
×
207
        }
×
208

209
        for y := 0; y < b.Height; y++ {
408✔
210
                for x := 0; x < b.Width; x++ {
3,912✔
211
                        if b.At(x, y) != a.At(x, y) {
3,545✔
212
                                return false
×
213
                        }
×
214
                }
215
        }
216

217
        return true
41✔
218
}
219

220
// RenderAsStrings - render buffer as slice of strings with pixel characters
221
func (b Buffer) RenderAsStrings(mode PixelMode) []string {
16✔
222
        blockW, blockH := mode.Width(), mode.Height()
16✔
223

16✔
224
        var result []string
16✔
225

16✔
226
        width := b.Width / blockW
16✔
227
        if b.Width%blockW != 0 {
16✔
228
                width++
×
229
        }
×
230

231
        height := b.Height / blockH
16✔
232
        if b.Height%blockH != 0 {
21✔
233
                height++
5✔
234
        }
5✔
235

236
        for y := 0; y < height; y++ {
103✔
237
                line := ""
87✔
238
                for x := 0; x < width; x++ {
868✔
239
                        charIndex := b.getPixelsBlock(x*blockW, y*blockH, blockW, blockH)
781✔
240
                        line += string(mode.charMapping[charIndex])
781✔
241
                }
781✔
242
                result = append(result, line)
87✔
243
        }
244

245
        return result
16✔
246
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc