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