limage - xcf/encoder.go
1 package xcf
2
3 import (
4 "image"
5 "image/color"
6 "io"
7
8 "vimagination.zapto.org/limage"
9 "vimagination.zapto.org/limage/lcolor"
10 )
11
12 const chanLen = 64 * 64 * 1 // tile width (64) * tile height (64) * max channels (4) * bytewidth (1)
13
14 type colourBufFunc func(*encoder, color.Color)
15
16 type encoder struct {
17 writer
18
19 colourPalette lcolor.AlphaPalette
20 colourFunc colourBufFunc
21 colourType uint8
22 colourChannels uint8
23
24 channelBuf [4][chanLen]byte
25 colourBuf [4]byte
26 }
27
28 // Encode encodes the given image as an XCF file to the given WriterAt
29 func Encode(w io.WriterAt, im image.Image) error {
30 switch imt := im.(type) {
31 case *limage.Image:
32 im = *imt
33 case limage.Layer:
34 im = limage.Image{imt}
35 case *limage.Layer:
36 im = limage.Image{*imt}
37 }
38
39 e := encoder{
40 writer: newWriter(w),
41 }
42
43 e.Write(header)
44 b := im.Bounds()
45 e.WriteUint32(uint32(b.Dx()))
46 e.WriteUint32(uint32(b.Dy()))
47 switch cm := im.ColorModel(); cm {
48 case color.GrayModel, color.Gray16Model, lcolor.GrayAlphaModel:
49 e.colourType = 1
50 e.colourFunc = (*encoder).grayAlphaToBuf
51 e.colourChannels = 2
52 default:
53 switch m := cm.(type) {
54 case color.Palette:
55 e.colourPalette = lcolor.AlphaPalette(m)
56 e.colourType = 2
57 e.colourFunc = (*encoder).paletteAlphaToBuf
58 e.colourChannels = 2
59 case lcolor.AlphaPalette:
60 e.colourPalette = m
61 e.colourType = 2
62 e.colourFunc = (*encoder).paletteAlphaToBuf
63 e.colourChannels = 2
64 default:
65 e.colourType = 0
66 e.colourFunc = (*encoder).rgbAlphaToBuf
67 e.colourChannels = 4
68 }
69 }
70 e.WriteUint32(uint32(e.colourType))
71
72 // write property list
73
74 if e.colourPalette != nil {
75 e.WriteUint32(propColorMap)
76 e.WriteUint32(3*uint32(len(e.colourPalette)) + 4)
77 e.WriteUint32(uint32(len(e.colourPalette)))
78 for _, colour := range e.colourPalette {
79 rgb := lcolor.RGBModel.Convert(colour).(lcolor.RGB)
80 e.WriteUint8(rgb.R)
81 e.WriteUint8(rgb.G)
82 e.WriteUint8(rgb.B)
83 }
84 }
85
86 e.WriteUint32(propCompression)
87 e.WriteUint32(1)
88 e.WriteUint8(1) // rle
89
90 e.WriteUint32(0)
91 e.WriteUint32(0)
92
93 switch im := im.(type) {
94 case limage.Image:
95 pw := e.ReservePointerList(layerCount(im))
96 e.WriteUint32(0) // no channels
97 e.WriteLayers(im, 0, 0, make([]uint32, 0, 32), pw)
98 default:
99 pw := e.ReservePointerList(1)
100 e.WriteUint32(0) // no channels
101 e.WriteLayer(limage.Layer{Image: im}, 0, 0, []uint32{}, pw)
102 }
103
104 return e.Err
105 }
106 func layerCount(g limage.Image) uint32 {
107 count := uint32(len(g))
108 for _, l := range g {
109 switch g := l.Image.(type) {
110 case limage.Image:
111 count += layerCount(g)
112 case *limage.Image:
113 count += layerCount(*g)
114 }
115
116 }
117 return count
118 }
119
120 var header = []byte{'g', 'i', 'm', 'p', ' ', 'x', 'c', 'f', ' ', 'v', '0', '0', '3', 0}
121