1// Command pixels compares the fixed 1280x720 fixture's terminal content.
2package main
3
4import (
5 "encoding/json"
6 "errors"
7 "fmt"
8 "image"
9 _ "image/png"
10 "os"
11)
12
13const fixtureMargin = 100
14const minimumChangedPixels = 20
15
16func load(path string) (image.Image, error) {
17 f, err := os.Open(path)
18 if err != nil {
19 return nil, err
20 }
21 defer f.Close()
22 im, _, err := image.Decode(f)
23 return im, err
24}
25
26func compare(a, b image.Image) (int, error) {
27 if a.Bounds() != b.Bounds() {
28 return 0, errors.New("capture dimensions changed")
29 }
30 bounds := a.Bounds()
31 if bounds.Dx() <= 2*fixtureMargin || bounds.Dy() <= 2*fixtureMargin {
32 return 0, errors.New("capture has no comparison region")
33 }
34 changed := 0
35 for y := bounds.Min.Y + fixtureMargin; y < bounds.Max.Y-fixtureMargin; y++ {
36 for x := bounds.Min.X + fixtureMargin; x < bounds.Max.X-fixtureMargin; x++ {
37 ar, ag, ab, _ := a.At(x, y).RGBA()
38 br, bg, bb, _ := b.At(x, y).RGBA()
39 if ar != br || ag != bg || ab != bb {
40 changed++
41 }
42 }
43 }
44 return changed, nil
45}
46
47func execute(args []string) (int, error) {
48 if len(args) != 2 {
49 return 2, errors.New("usage: pixels before.png after.png")
50 }
51 a, err := load(args[0])
52 if err != nil {
53 return 2, err
54 }
55 b, err := load(args[1])
56 if err != nil {
57 return 2, err
58 }
59 changed, err := compare(a, b)
60 if err != nil {
61 return 2, err
62 }
63 if err := json.NewEncoder(os.Stdout).Encode(map[string]int{"changed_pixels": changed}); err != nil {
64 return 2, err
65 }
66 if changed < minimumChangedPixels {
67 return 1, nil
68 }
69 return 0, nil
70}
71func main() {
72 code, err := execute(os.Args[1:])
73 if err != nil {
74 fmt.Fprintln(os.Stderr, err)
75 }
76 os.Exit(code)
77}