limage - xcf/decoder_test.go
1 package xcf
2
3 import (
4 "bytes"
5 "compress/gzip"
6 "fmt"
7 "image"
8 "image/color"
9 "io"
10 "reflect"
11 "strings"
12 "testing"
13
14 "vimagination.zapto.org/limage"
15 "vimagination.zapto.org/limage/lcolor"
16 )
17
18 var buf [2098]byte
19
20 func openFile(str string) (io.ReaderAt, error) {
21 gz, err := gzip.NewReader(strings.NewReader(str))
22 if err != nil {
23 return nil, err
24 }
25 n, err := gz.Read(buf[:])
26 if err != nil {
27 if err != io.EOF {
28 return nil, err
29 }
30 }
31 return bytes.NewReader(buf[:n]), nil
32 }
33
34 func TestConfigDecoder(t *testing.T) {
35 tests := []struct {
36 File string
37 Config image.Config
38 }{
39 {
40 File: abcFile,
41 Config: image.Config{
42 ColorModel: color.NRGBAModel,
43 Width: 36,
44 Height: 13,
45 },
46 },
47 {
48 File: blackMaskFile,
49 Config: image.Config{
50 ColorModel: color.NRGBAModel,
51 Width: 50,
52 Height: 50,
53 },
54 },
55 {
56 File: blackRedBlueFile,
57 Config: image.Config{
58 ColorModel: color.NRGBAModel,
59 Width: 50,
60 Height: 50,
61 },
62 },
63 {
64 File: blackRedFile,
65 Config: image.Config{
66 ColorModel: color.NRGBAModel,
67 Width: 50,
68 Height: 50,
69 },
70 },
71 {
72 File: blackFile,
73 Config: image.Config{
74 ColorModel: color.NRGBAModel,
75 Width: 50,
76 Height: 50,
77 },
78 },
79 {
80 File: redFile,
81 Config: image.Config{
82 ColorModel: color.NRGBAModel,
83 Width: 50,
84 Height: 50,
85 },
86 },
87 {
88 File: whiteFile,
89 Config: image.Config{
90 ColorModel: color.NRGBAModel,
91 Width: 50,
92 Height: 50,
93 },
94 },
95 }
96
97 for n, test := range tests {
98 f, err := openFile(test.File)
99 if err != nil {
100 t.Errorf("test %d: unexpected error opening file: %s", n+1, err)
101 continue
102 }
103 c, err := DecodeConfig(f)
104 if err != nil {
105 t.Errorf("test %d: unexpected error decoding config: %s", n+1, err)
106 continue
107 }
108 if !reflect.DeepEqual(test.Config, c) {
109 t.Errorf("test %d: no config match", n+1)
110 }
111 }
112 }
113
114 type singleColourImage struct {
115 Colour color.Color
116 Width, Height int
117 }
118
119 func (s singleColourImage) ColorModel() color.Model {
120 return s
121 }
122
123 func (s singleColourImage) Convert(color.Color) color.Color {
124 return s.Colour
125 }
126
127 func (s singleColourImage) Bounds() image.Rectangle {
128 return image.Rect(0, 0, s.Width, s.Height)
129 }
130
131 func (s singleColourImage) At(int, int) color.Color {
132 return s.Colour
133 }
134
135 func TestDecoder(t *testing.T) {
136 tests := []struct {
137 File string
138 Image limage.Image
139 }{
140 {
141 File: blackRedBlueFile,
142 Image: limage.Image{
143 limage.Layer{
144 Name: "Layer Group",
145 Image: limage.Image{
146 limage.Layer{
147 Name: "Blue",
148 Image: singleColourImage{
149 Colour: color.NRGBA{B: 255, A: 255},
150 Width: 30,
151 Height: 30,
152 },
153 LayerBounds: image.Rect(0, 0, 30, 30),
154 },
155 limage.Layer{
156 Name: "Red",
157 Image: singleColourImage{Colour: color.NRGBA{R: 255, A: 255},
158 Width: 30,
159 Height: 30,
160 },
161 LayerBounds: image.Rect(20, 20, 50, 50),
162 },
163 },
164 LayerBounds: image.Rect(0, 0, 50, 50),
165 },
166 limage.Layer{
167 Name: "Background",
168 Image: singleColourImage{
169 Colour: lcolor.RGB{},
170 Width: 50,
171 Height: 50,
172 },
173 LayerBounds: image.Rect(0, 0, 50, 50),
174 },
175 },
176 },
177 {
178 File: blackRedFile,
179 Image: limage.Image{
180 limage.Layer{
181 Name: "Layer",
182 Image: singleColourImage{
183 Colour: color.NRGBA{R: 255, A: 255},
184 Width: 30,
185 Height: 30,
186 },
187 LayerBounds: image.Rect(10, 10, 40, 40),
188 },
189 limage.Layer{
190 Name: "Background",
191 Image: singleColourImage{
192 Colour: lcolor.RGB{},
193 Width: 50,
194 Height: 50,
195 },
196 LayerBounds: image.Rect(0, 0, 50, 50),
197 },
198 },
199 },
200 {
201 File: blackFile,
202 Image: limage.Image{
203 limage.Layer{
204 Name: "Background",
205 Image: singleColourImage{
206 Colour: lcolor.RGB{},
207 Width: 50,
208 Height: 50,
209 },
210 LayerBounds: image.Rect(0, 0, 50, 50),
211 },
212 },
213 },
214 {
215 File: redFile,
216 Image: limage.Image{
217 limage.Layer{
218 Name: "Background",
219 Image: singleColourImage{
220 Colour: lcolor.RGB{R: 255},
221 Width: 50,
222 Height: 50,
223 },
224 LayerBounds: image.Rect(0, 0, 50, 50),
225 },
226 },
227 },
228 {
229 File: whiteFile,
230 Image: limage.Image{
231 limage.Layer{
232 Name: "Background",
233 Image: singleColourImage{
234 Colour: lcolor.RGB{R: 255, G: 255, B: 255},
235 Width: 50,
236 Height: 50,
237 },
238 LayerBounds: image.Rect(0, 0, 50, 50),
239 },
240 },
241 },
242 }
243
244 for n, test := range tests {
245 f, err := openFile(test.File)
246 if err != nil {
247 t.Errorf("test %d: unexpected error opening file: %s", n+1, err)
248 continue
249 }
250 i, err := Decode(f)
251 if err != nil {
252 t.Errorf("test %d: unexpected error decoding image: %s", n+1, err)
253 continue
254 }
255 if err := compareLayers(i, test.Image); err != nil {
256 t.Errorf("test %d: %s", n+1, err)
257 }
258 }
259 }
260
261 func compareLayers(a, b limage.Image) error {
262 if len(a) != len(b) {
263 return fmt.Errorf("incorrect number of layers, expecting %d, got %d", len(b), len(a))
264 }
265 for n, la := range a {
266 lb := b[n]
267 ia := la.Image
268 ib := lb.Image
269 la.Image = nil
270 lb.Image = nil
271 if !reflect.DeepEqual(la, lb) {
272 return fmt.Errorf("layer properties mismatched, expecting %#v, got %#v", lb, la)
273 }
274 if mib, ok := ib.(limage.MaskedImage); ok {
275 if mia, ok := ia.(limage.MaskedImage); ok {
276 if err := compareImages(mia.Mask, mib.Mask); err != nil {
277 return err
278 }
279 ia = mia.Image
280 ib = mib.Image
281 } else {
282 return fmt.Errorf("expecting MaskedImage, got %T", ia)
283 }
284 }
285 if layb, ok := ib.(limage.Image); ok {
286 if laya, ok := ia.(limage.Image); ok {
287 if err := compareLayers(laya, layb); err != nil {
288 return err
289 }
290 } else {
291 return fmt.Errorf("expecting Layer Group, got %T", ia)
292 }
293 } else if tb, ok := ib.(limage.Text); ok {
294 if ta, ok := ia.(limage.Text); ok {
295 ta.Image = nil
296 tb.Image = nil
297 if !reflect.DeepEqual(ta, tb) {
298 return fmt.Errorf("expecting text layer %#v, got %#v", tb, ta)
299 }
300 } else {
301 return fmt.Errorf("expecting Text Layer, got %T", ia)
302 }
303 } else if err := compareImages(ia, ib); err != nil {
304 return err
305 }
306 }
307 return nil
308 }
309
310 func compareImages(ia, ib image.Image) error {
311 bnds := ia.Bounds()
312 bndsb := ib.Bounds()
313 if bnds.Min.X != bndsb.Min.X || bnds.Min.Y != bndsb.Min.Y || bnds.Max.X != bndsb.Max.X || bnds.Max.Y != bndsb.Max.Y {
314 return fmt.Errorf("bounds mismatch, expecting %v, got %v", bndsb, bnds)
315 }
316 for j := 0; j < bnds.Dy(); j++ {
317 for i := 0; i < bnds.Dx(); i++ {
318 ca := ia.At(i, j)
319 cb := ib.At(i, j)
320 if !reflect.DeepEqual(ca, cb) {
321 return fmt.Errorf("pixel mismatch: expecting %#v, got %#v", cb, ca)
322 }
323 }
324 }
325 return nil
326 }
327