forked from BurntSushi/imgv
/
image.go
107 lines (90 loc) · 2.82 KB
/
image.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
package main
import (
"image"
"os"
"time"
"github.com/BurntSushi/xgbutil/xgraphics"
)
type Img struct {
name string
load chan *vimage
loading bool // Maybe we should use a nil load chan instead?
vimage *vimage
}
// vimage acts as an xgraphics.Image type with a name.
// (The name is the basename of the image's corresponding file name.)
type vimage struct {
*xgraphics.Image
err error // Nil unless there is an error loading or decoding the image.
}
// newImage loads a decodes an image into an xgraphics.Image value and draws it
// to an X pixmap.
func newImage(img *Img) *vimage {
start := time.Now()
file, err := os.Open(img.name)
if err != nil {
errLg.Printf("Error opening '%s': %s", img.name, err)
return &vimage{nil, err}
}
im, kind, err := image.Decode(file)
if err != nil {
errLg.Printf("Error decoding '%s': %s", img.name, err)
return &vimage{nil, err}
}
lg("Decoded '%s' into image type '%s' (%s).", img.name, kind, time.Since(start))
// im = scale(im, window.Geom.Width(), window.Geom.Height())
start = time.Now()
reg := xgraphics.NewConvert(window.X, im)
lg("Converted '%s' to an xgraphics.Image type (%s).", img.name, time.Since(start))
// Only blend a checkered background if the image *may* have an alpha
// channel. If we want to be a bit more efficient, we could type switch
// on all image types use Opaque, but this may add undesirable overhead.
// (Where the overhead is scanning the image for opaqueness.)
switch im.(type) {
case *image.Gray:
case *image.Gray16:
case *image.YCbCr:
default:
start = time.Now()
blendCheckered(reg)
lg("Blended '%s' into checkered background (%s).", img.name, time.Since(start))
}
if err = reg.CreatePixmap(); err != nil {
// TODO: We should display a "Could not load image" image instead
// of dying. However, creating a pixmap rarely fails, unless we have
// a *ton* of images. (In all likelihood, we'll run out of memory
// before a new pixmap cannot be created.)
errLg.Fatal(err)
}
reg.XDraw()
return &vimage{reg, err}
}
// blendCheckered is basically a copy of xgraphics.Blend with no interfaces.
// (It's faster.) Also, it is hardcoded to blend into a checkered background.
func blendCheckered(dest *xgraphics.Image) {
dsrc := dest.Bounds()
dmnx, dmxx, dmny, dmxy := dsrc.Min.X, dsrc.Max.X, dsrc.Min.Y, dsrc.Max.Y
clr1 := xgraphics.BGRA{B: 0xff, G: 0xff, R: 0xff, A: 0xff}
clr2 := xgraphics.BGRA{B: 0xde, G: 0xdc, R: 0xdf, A: 0xff}
var dx, dy int
var bgra, clr xgraphics.BGRA
for dx = dmnx; dx < dmxx; dx++ {
for dy = dmny; dy < dmxy; dy++ {
if dx%30 >= 15 {
if dy%30 >= 15 {
clr = clr1
} else {
clr = clr2
}
} else {
if dy%30 >= 15 {
clr = clr2
} else {
clr = clr1
}
}
bgra = dest.At(dx, dy).(xgraphics.BGRA)
dest.SetBGRA(dx, dy, xgraphics.BlendBGRA(clr, bgra))
}
}
}