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