1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gif
6
7import (
8	"bufio"
9	"compress/lzw"
10	"errors"
11	"image"
12	"image/color"
13	"image/color/palette"
14	"image/draw"
15	"io"
16)
17
18// Graphic control extension fields.
19const (
20	gcLabel     = 0xF9
21	gcBlockSize = 0x04
22)
23
24var log2Lookup = [8]int{2, 4, 8, 16, 32, 64, 128, 256}
25
26func log2(x int) int {
27	for i, v := range log2Lookup {
28		if x <= v {
29			return i
30		}
31	}
32	return -1
33}
34
35// Little-endian.
36func writeUint16(b []uint8, u uint16) {
37	b[0] = uint8(u)
38	b[1] = uint8(u >> 8)
39}
40
41// writer is a buffered writer.
42type writer interface {
43	Flush() error
44	io.Writer
45	io.ByteWriter
46}
47
48// encoder encodes an image to the GIF format.
49type encoder struct {
50	// w is the writer to write to. err is the first error encountered during
51	// writing. All attempted writes after the first error become no-ops.
52	w   writer
53	err error
54	// g is a reference to the data that is being encoded.
55	g *GIF
56	// buf is a scratch buffer. It must be at least 768 so we can write the color map.
57	buf [1024]byte
58}
59
60// blockWriter writes the block structure of GIF image data, which
61// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
62// writer given to the LZW encoder, which is thus immune to the
63// blocking.
64type blockWriter struct {
65	e *encoder
66}
67
68func (b blockWriter) Write(data []byte) (int, error) {
69	if b.e.err != nil {
70		return 0, b.e.err
71	}
72	if len(data) == 0 {
73		return 0, nil
74	}
75	total := 0
76	for total < len(data) {
77		n := copy(b.e.buf[1:256], data[total:])
78		total += n
79		b.e.buf[0] = uint8(n)
80
81		n, b.e.err = b.e.w.Write(b.e.buf[:n+1])
82		if b.e.err != nil {
83			return 0, b.e.err
84		}
85	}
86	return total, b.e.err
87}
88
89func (e *encoder) flush() {
90	if e.err != nil {
91		return
92	}
93	e.err = e.w.Flush()
94}
95
96func (e *encoder) write(p []byte) {
97	if e.err != nil {
98		return
99	}
100	_, e.err = e.w.Write(p)
101}
102
103func (e *encoder) writeByte(b byte) {
104	if e.err != nil {
105		return
106	}
107	e.err = e.w.WriteByte(b)
108}
109
110func (e *encoder) writeHeader() {
111	if e.err != nil {
112		return
113	}
114	_, e.err = io.WriteString(e.w, "GIF89a")
115	if e.err != nil {
116		return
117	}
118
119	pm := e.g.Image[0]
120	// Logical screen width and height.
121	writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx()))
122	writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy()))
123	e.write(e.buf[:4])
124
125	// All frames have a local color table, so a global color table
126	// is not needed.
127	e.buf[0] = 0x00
128	e.buf[1] = 0x00 // Background Color Index.
129	e.buf[2] = 0x00 // Pixel Aspect Ratio.
130	e.write(e.buf[:3])
131
132	// Add animation info if necessary.
133	if len(e.g.Image) > 1 {
134		e.buf[0] = 0x21 // Extension Introducer.
135		e.buf[1] = 0xff // Application Label.
136		e.buf[2] = 0x0b // Block Size.
137		e.write(e.buf[:3])
138		_, e.err = io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
139		if e.err != nil {
140			return
141		}
142		e.buf[0] = 0x03 // Block Size.
143		e.buf[1] = 0x01 // Sub-block Index.
144		writeUint16(e.buf[2:4], uint16(e.g.LoopCount))
145		e.buf[4] = 0x00 // Block Terminator.
146		e.write(e.buf[:5])
147	}
148}
149
150func (e *encoder) writeColorTable(p color.Palette, size int) {
151	if e.err != nil {
152		return
153	}
154
155	for i := 0; i < log2Lookup[size]; i++ {
156		if i < len(p) {
157			r, g, b, _ := p[i].RGBA()
158			e.buf[3*i+0] = uint8(r >> 8)
159			e.buf[3*i+1] = uint8(g >> 8)
160			e.buf[3*i+2] = uint8(b >> 8)
161		} else {
162			// Pad with black.
163			e.buf[3*i+0] = 0x00
164			e.buf[3*i+1] = 0x00
165			e.buf[3*i+2] = 0x00
166		}
167	}
168	e.write(e.buf[:3*log2Lookup[size]])
169}
170
171func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
172	if e.err != nil {
173		return
174	}
175
176	if len(pm.Palette) == 0 {
177		e.err = errors.New("gif: cannot encode image block with empty palette")
178		return
179	}
180
181	b := pm.Bounds()
182	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 {
183		e.err = errors.New("gif: image block is too large to encode")
184		return
185	}
186
187	transparentIndex := -1
188	for i, c := range pm.Palette {
189		if _, _, _, a := c.RGBA(); a == 0 {
190			transparentIndex = i
191			break
192		}
193	}
194
195	if delay > 0 || transparentIndex != -1 {
196		e.buf[0] = sExtension  // Extension Introducer.
197		e.buf[1] = gcLabel     // Graphic Control Label.
198		e.buf[2] = gcBlockSize // Block Size.
199		if transparentIndex != -1 {
200			e.buf[3] = 0x01
201		} else {
202			e.buf[3] = 0x00
203		}
204		writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
205
206		// Transparent color index.
207		if transparentIndex != -1 {
208			e.buf[6] = uint8(transparentIndex)
209		} else {
210			e.buf[6] = 0x00
211		}
212		e.buf[7] = 0x00 // Block Terminator.
213		e.write(e.buf[:8])
214	}
215	e.buf[0] = sImageDescriptor
216	writeUint16(e.buf[1:3], uint16(b.Min.X))
217	writeUint16(e.buf[3:5], uint16(b.Min.Y))
218	writeUint16(e.buf[5:7], uint16(b.Dx()))
219	writeUint16(e.buf[7:9], uint16(b.Dy()))
220	e.write(e.buf[:9])
221
222	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
223	// Interlacing is not supported.
224	e.writeByte(0x80 | uint8(paddedSize))
225
226	// Local Color Table.
227	e.writeColorTable(pm.Palette, paddedSize)
228
229	litWidth := paddedSize + 1
230	if litWidth < 2 {
231		litWidth = 2
232	}
233	e.writeByte(uint8(litWidth)) // LZW Minimum Code Size.
234
235	lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth)
236	_, e.err = lzww.Write(pm.Pix)
237	if e.err != nil {
238		lzww.Close()
239		return
240	}
241	lzww.Close()
242	e.writeByte(0x00) // Block Terminator.
243}
244
245// Options are the encoding parameters.
246type Options struct {
247	// NumColors is the maximum number of colors used in the image.
248	// It ranges from 1 to 256.
249	NumColors int
250
251	// Quantizer is used to produce a palette with size NumColors.
252	// palette.Plan9 is used in place of a nil Quantizer.
253	Quantizer draw.Quantizer
254
255	// Drawer is used to convert the source image to the desired palette.
256	// draw.FloydSteinberg is used in place of a nil Drawer.
257	Drawer draw.Drawer
258}
259
260// EncodeAll writes the images in g to w in GIF format with the
261// given loop count and delay between frames.
262func EncodeAll(w io.Writer, g *GIF) error {
263	if len(g.Image) == 0 {
264		return errors.New("gif: must provide at least one image")
265	}
266
267	if len(g.Image) != len(g.Delay) {
268		return errors.New("gif: mismatched image and delay lengths")
269	}
270	if g.LoopCount < 0 {
271		g.LoopCount = 0
272	}
273
274	e := encoder{g: g}
275	if ww, ok := w.(writer); ok {
276		e.w = ww
277	} else {
278		e.w = bufio.NewWriter(w)
279	}
280
281	e.writeHeader()
282	for i, pm := range g.Image {
283		e.writeImageBlock(pm, g.Delay[i])
284	}
285	e.writeByte(sTrailer)
286	e.flush()
287	return e.err
288}
289
290// Encode writes the Image m to w in GIF format.
291func Encode(w io.Writer, m image.Image, o *Options) error {
292	// Check for bounds and size restrictions.
293	b := m.Bounds()
294	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 {
295		return errors.New("gif: image is too large to encode")
296	}
297
298	opts := Options{}
299	if o != nil {
300		opts = *o
301	}
302	if opts.NumColors < 1 || 256 < opts.NumColors {
303		opts.NumColors = 256
304	}
305	if opts.Drawer == nil {
306		opts.Drawer = draw.FloydSteinberg
307	}
308
309	pm, ok := m.(*image.Paletted)
310	if !ok || len(pm.Palette) > opts.NumColors {
311		// TODO: Pick a better sub-sample of the Plan 9 palette.
312		pm = image.NewPaletted(b, palette.Plan9[:opts.NumColors])
313		if opts.Quantizer != nil {
314			pm.Palette = opts.Quantizer.Quantize(make(color.Palette, 0, opts.NumColors), m)
315		}
316		opts.Drawer.Draw(pm, b, m, image.ZP)
317	}
318
319	return EncodeAll(w, &GIF{
320		Image: []*image.Paletted{pm},
321		Delay: []int{0},
322	})
323}
324