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	"bytes"
10	"compress/lzw"
11	"errors"
12	"image"
13	"image/color"
14	"image/color/palette"
15	"image/draw"
16	"io"
17)
18
19// Graphic control extension fields.
20const (
21	gcLabel     = 0xF9
22	gcBlockSize = 0x04
23)
24
25var log2Lookup = [8]int{2, 4, 8, 16, 32, 64, 128, 256}
26
27func log2(x int) int {
28	for i, v := range log2Lookup {
29		if x <= v {
30			return i
31		}
32	}
33	return -1
34}
35
36// Little-endian.
37func writeUint16(b []uint8, u uint16) {
38	b[0] = uint8(u)
39	b[1] = uint8(u >> 8)
40}
41
42// writer is a buffered writer.
43type writer interface {
44	Flush() error
45	io.Writer
46	io.ByteWriter
47}
48
49// encoder encodes an image to the GIF format.
50type encoder struct {
51	// w is the writer to write to. err is the first error encountered during
52	// writing. All attempted writes after the first error become no-ops.
53	w   writer
54	err error
55	// g is a reference to the data that is being encoded.
56	g GIF
57	// globalCT is the size in bytes of the global color table.
58	globalCT int
59	// buf is a scratch buffer. It must be at least 256 for the blockWriter.
60	buf              [256]byte
61	globalColorTable [3 * 256]byte
62	localColorTable  [3 * 256]byte
63}
64
65// blockWriter writes the block structure of GIF image data, which
66// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
67// writer given to the LZW encoder, which is thus immune to the
68// blocking.
69type blockWriter struct {
70	e *encoder
71}
72
73func (b blockWriter) setup() {
74	b.e.buf[0] = 0
75}
76
77func (b blockWriter) Flush() error {
78	return b.e.err
79}
80
81func (b blockWriter) WriteByte(c byte) error {
82	if b.e.err != nil {
83		return b.e.err
84	}
85
86	// Append c to buffered sub-block.
87	b.e.buf[0]++
88	b.e.buf[b.e.buf[0]] = c
89	if b.e.buf[0] < 255 {
90		return nil
91	}
92
93	// Flush block
94	b.e.write(b.e.buf[:256])
95	b.e.buf[0] = 0
96	return b.e.err
97}
98
99// blockWriter must be an io.Writer for lzw.NewWriter, but this is never
100// actually called.
101func (b blockWriter) Write(data []byte) (int, error) {
102	for i, c := range data {
103		if err := b.WriteByte(c); err != nil {
104			return i, err
105		}
106	}
107	return len(data), nil
108}
109
110func (b blockWriter) close() {
111	// Write the block terminator (0x00), either by itself, or along with a
112	// pending sub-block.
113	if b.e.buf[0] == 0 {
114		b.e.writeByte(0)
115	} else {
116		n := uint(b.e.buf[0])
117		b.e.buf[n+1] = 0
118		b.e.write(b.e.buf[:n+2])
119	}
120	b.e.flush()
121}
122
123func (e *encoder) flush() {
124	if e.err != nil {
125		return
126	}
127	e.err = e.w.Flush()
128}
129
130func (e *encoder) write(p []byte) {
131	if e.err != nil {
132		return
133	}
134	_, e.err = e.w.Write(p)
135}
136
137func (e *encoder) writeByte(b byte) {
138	if e.err != nil {
139		return
140	}
141	e.err = e.w.WriteByte(b)
142}
143
144func (e *encoder) writeHeader() {
145	if e.err != nil {
146		return
147	}
148	_, e.err = io.WriteString(e.w, "GIF89a")
149	if e.err != nil {
150		return
151	}
152
153	// Logical screen width and height.
154	writeUint16(e.buf[0:2], uint16(e.g.Config.Width))
155	writeUint16(e.buf[2:4], uint16(e.g.Config.Height))
156	e.write(e.buf[:4])
157
158	if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 {
159		paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n).
160		e.buf[0] = fColorTable | uint8(paddedSize)
161		e.buf[1] = e.g.BackgroundIndex
162		e.buf[2] = 0x00 // Pixel Aspect Ratio.
163		e.write(e.buf[:3])
164		var err error
165		e.globalCT, err = encodeColorTable(e.globalColorTable[:], p, paddedSize)
166		if err != nil && e.err == nil {
167			e.err = err
168			return
169		}
170		e.write(e.globalColorTable[:e.globalCT])
171	} else {
172		// All frames have a local color table, so a global color table
173		// is not needed.
174		e.buf[0] = 0x00
175		e.buf[1] = 0x00 // Background Color Index.
176		e.buf[2] = 0x00 // Pixel Aspect Ratio.
177		e.write(e.buf[:3])
178	}
179
180	// Add animation info if necessary.
181	if len(e.g.Image) > 1 && e.g.LoopCount >= 0 {
182		e.buf[0] = 0x21 // Extension Introducer.
183		e.buf[1] = 0xff // Application Label.
184		e.buf[2] = 0x0b // Block Size.
185		e.write(e.buf[:3])
186		_, err := io.WriteString(e.w, "NETSCAPE2.0") // Application Identifier.
187		if err != nil && e.err == nil {
188			e.err = err
189			return
190		}
191		e.buf[0] = 0x03 // Block Size.
192		e.buf[1] = 0x01 // Sub-block Index.
193		writeUint16(e.buf[2:4], uint16(e.g.LoopCount))
194		e.buf[4] = 0x00 // Block Terminator.
195		e.write(e.buf[:5])
196	}
197}
198
199func encodeColorTable(dst []byte, p color.Palette, size int) (int, error) {
200	if uint(size) >= uint(len(log2Lookup)) {
201		return 0, errors.New("gif: cannot encode color table with more than 256 entries")
202	}
203	for i, c := range p {
204		if c == nil {
205			return 0, errors.New("gif: cannot encode color table with nil entries")
206		}
207		var r, g, b uint8
208		// It is most likely that the palette is full of color.RGBAs, so they
209		// get a fast path.
210		if rgba, ok := c.(color.RGBA); ok {
211			r, g, b = rgba.R, rgba.G, rgba.B
212		} else {
213			rr, gg, bb, _ := c.RGBA()
214			r, g, b = uint8(rr>>8), uint8(gg>>8), uint8(bb>>8)
215		}
216		dst[3*i+0] = r
217		dst[3*i+1] = g
218		dst[3*i+2] = b
219	}
220	n := log2Lookup[size]
221	if n > len(p) {
222		// Pad with black.
223		fill := dst[3*len(p) : 3*n]
224		for i := range fill {
225			fill[i] = 0
226		}
227	}
228	return 3 * n, nil
229}
230
231func (e *encoder) colorTablesMatch(localLen, transparentIndex int) bool {
232	localSize := 3 * localLen
233	if transparentIndex >= 0 {
234		trOff := 3 * transparentIndex
235		return bytes.Equal(e.globalColorTable[:trOff], e.localColorTable[:trOff]) &&
236			bytes.Equal(e.globalColorTable[trOff+3:localSize], e.localColorTable[trOff+3:localSize])
237	}
238	return bytes.Equal(e.globalColorTable[:localSize], e.localColorTable[:localSize])
239}
240
241func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
242	if e.err != nil {
243		return
244	}
245
246	if len(pm.Palette) == 0 {
247		e.err = errors.New("gif: cannot encode image block with empty palette")
248		return
249	}
250
251	b := pm.Bounds()
252	if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 {
253		e.err = errors.New("gif: image block is too large to encode")
254		return
255	}
256	if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) {
257		e.err = errors.New("gif: image block is out of bounds")
258		return
259	}
260
261	transparentIndex := -1
262	for i, c := range pm.Palette {
263		if c == nil {
264			e.err = errors.New("gif: cannot encode color table with nil entries")
265			return
266		}
267		if _, _, _, a := c.RGBA(); a == 0 {
268			transparentIndex = i
269			break
270		}
271	}
272
273	if delay > 0 || disposal != 0 || transparentIndex != -1 {
274		e.buf[0] = sExtension  // Extension Introducer.
275		e.buf[1] = gcLabel     // Graphic Control Label.
276		e.buf[2] = gcBlockSize // Block Size.
277		if transparentIndex != -1 {
278			e.buf[3] = 0x01 | disposal<<2
279		} else {
280			e.buf[3] = 0x00 | disposal<<2
281		}
282		writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
283
284		// Transparent color index.
285		if transparentIndex != -1 {
286			e.buf[6] = uint8(transparentIndex)
287		} else {
288			e.buf[6] = 0x00
289		}
290		e.buf[7] = 0x00 // Block Terminator.
291		e.write(e.buf[:8])
292	}
293	e.buf[0] = sImageDescriptor
294	writeUint16(e.buf[1:3], uint16(b.Min.X))
295	writeUint16(e.buf[3:5], uint16(b.Min.Y))
296	writeUint16(e.buf[5:7], uint16(b.Dx()))
297	writeUint16(e.buf[7:9], uint16(b.Dy()))
298	e.write(e.buf[:9])
299
300	// To determine whether or not this frame's palette is the same as the
301	// global palette, we can check a couple things. First, do they actually
302	// point to the same []color.Color? If so, they are equal so long as the
303	// frame's palette is not longer than the global palette...
304	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
305	if gp, ok := e.g.Config.ColorModel.(color.Palette); ok && len(pm.Palette) <= len(gp) && &gp[0] == &pm.Palette[0] {
306		e.writeByte(0) // Use the global color table.
307	} else {
308		ct, err := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
309		if err != nil {
310			if e.err == nil {
311				e.err = err
312			}
313			return
314		}
315		// This frame's palette is not the very same slice as the global
316		// palette, but it might be a copy, possibly with one value turned into
317		// transparency by DecodeAll.
318		if ct <= e.globalCT && e.colorTablesMatch(len(pm.Palette), transparentIndex) {
319			e.writeByte(0) // Use the global color table.
320		} else {
321			// Use a local color table.
322			e.writeByte(fColorTable | uint8(paddedSize))
323			e.write(e.localColorTable[:ct])
324		}
325	}
326
327	litWidth := paddedSize + 1
328	if litWidth < 2 {
329		litWidth = 2
330	}
331	e.writeByte(uint8(litWidth)) // LZW Minimum Code Size.
332
333	bw := blockWriter{e: e}
334	bw.setup()
335	lzww := lzw.NewWriter(bw, lzw.LSB, litWidth)
336	if dx := b.Dx(); dx == pm.Stride {
337		_, e.err = lzww.Write(pm.Pix[:dx*b.Dy()])
338		if e.err != nil {
339			lzww.Close()
340			return
341		}
342	} else {
343		for i, y := 0, b.Min.Y; y < b.Max.Y; i, y = i+pm.Stride, y+1 {
344			_, e.err = lzww.Write(pm.Pix[i : i+dx])
345			if e.err != nil {
346				lzww.Close()
347				return
348			}
349		}
350	}
351	lzww.Close() // flush to bw
352	bw.close()   // flush to e.w
353}
354
355// Options are the encoding parameters.
356type Options struct {
357	// NumColors is the maximum number of colors used in the image.
358	// It ranges from 1 to 256.
359	NumColors int
360
361	// Quantizer is used to produce a palette with size NumColors.
362	// palette.Plan9 is used in place of a nil Quantizer.
363	Quantizer draw.Quantizer
364
365	// Drawer is used to convert the source image to the desired palette.
366	// draw.FloydSteinberg is used in place of a nil Drawer.
367	Drawer draw.Drawer
368}
369
370// EncodeAll writes the images in g to w in GIF format with the
371// given loop count and delay between frames.
372func EncodeAll(w io.Writer, g *GIF) error {
373	if len(g.Image) == 0 {
374		return errors.New("gif: must provide at least one image")
375	}
376
377	if len(g.Image) != len(g.Delay) {
378		return errors.New("gif: mismatched image and delay lengths")
379	}
380
381	e := encoder{g: *g}
382	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
383	// in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted
384	// in a GIF struct literal, should still produce valid GIFs.
385	if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) {
386		return errors.New("gif: mismatched image and disposal lengths")
387	}
388	if e.g.Config == (image.Config{}) {
389		p := g.Image[0].Bounds().Max
390		e.g.Config.Width = p.X
391		e.g.Config.Height = p.Y
392	} else if e.g.Config.ColorModel != nil {
393		if _, ok := e.g.Config.ColorModel.(color.Palette); !ok {
394			return errors.New("gif: GIF color model must be a color.Palette")
395		}
396	}
397
398	if ww, ok := w.(writer); ok {
399		e.w = ww
400	} else {
401		e.w = bufio.NewWriter(w)
402	}
403
404	e.writeHeader()
405	for i, pm := range g.Image {
406		disposal := uint8(0)
407		if g.Disposal != nil {
408			disposal = g.Disposal[i]
409		}
410		e.writeImageBlock(pm, g.Delay[i], disposal)
411	}
412	e.writeByte(sTrailer)
413	e.flush()
414	return e.err
415}
416
417// Encode writes the Image m to w in GIF format.
418func Encode(w io.Writer, m image.Image, o *Options) error {
419	// Check for bounds and size restrictions.
420	b := m.Bounds()
421	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 {
422		return errors.New("gif: image is too large to encode")
423	}
424
425	opts := Options{}
426	if o != nil {
427		opts = *o
428	}
429	if opts.NumColors < 1 || 256 < opts.NumColors {
430		opts.NumColors = 256
431	}
432	if opts.Drawer == nil {
433		opts.Drawer = draw.FloydSteinberg
434	}
435
436	pm, _ := m.(*image.Paletted)
437	if pm == nil {
438		if cp, ok := m.ColorModel().(color.Palette); ok {
439			pm = image.NewPaletted(b, cp)
440			for y := b.Min.Y; y < b.Max.Y; y++ {
441				for x := b.Min.X; x < b.Max.X; x++ {
442					pm.Set(x, y, cp.Convert(m.At(x, y)))
443				}
444			}
445		}
446	}
447	if pm == nil || len(pm.Palette) > opts.NumColors {
448		// Set pm to be a palettedized copy of m, including its bounds, which
449		// might not start at (0, 0).
450		//
451		// TODO: Pick a better sub-sample of the Plan 9 palette.
452		pm = image.NewPaletted(b, palette.Plan9[:opts.NumColors])
453		if opts.Quantizer != nil {
454			pm.Palette = opts.Quantizer.Quantize(make(color.Palette, 0, opts.NumColors), m)
455		}
456		opts.Drawer.Draw(pm, b, m, b.Min)
457	}
458
459	// When calling Encode instead of EncodeAll, the single-frame image is
460	// translated such that its top-left corner is (0, 0), so that the single
461	// frame completely fills the overall GIF's bounds.
462	if pm.Rect.Min != (image.Point{}) {
463		dup := *pm
464		dup.Rect = dup.Rect.Sub(dup.Rect.Min)
465		pm = &dup
466	}
467
468	return EncodeAll(w, &GIF{
469		Image: []*image.Paletted{pm},
470		Delay: []int{0},
471		Config: image.Config{
472			ColorModel: pm.Palette,
473			Width:      b.Dx(),
474			Height:     b.Dy(),
475		},
476	})
477}
478