github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/utils/imgutils/gif.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 // This is a modified version, the original copyright was: Copyright (c) 2011 5 // The Go Authors. 6 7 package imgutils 8 9 // This contains a portion of Go's image/go library, modified to count the number of frames in a gif without loading 10 // the entire image into memory. 11 12 import ( 13 "bufio" 14 "compress/lzw" 15 "errors" 16 "fmt" 17 "image" 18 "image/color" 19 "io" 20 ) 21 22 var ( 23 errNotEnough = errors.New("gif: not enough image data") 24 errTooMuch = errors.New("gif: too much image data") 25 ) 26 27 // If the io.Reader does not also have ReadByte, then decode will introduce its own buffering. 28 type reader interface { 29 io.Reader 30 io.ByteReader 31 } 32 33 // Masks etc. 34 const ( 35 // Fields. 36 fColorTable = 1 << 7 37 fColorTableBitsMask = 7 38 39 // Graphic control flags. 40 gcTransparentColorSet = 1 << 0 41 gcDisposalMethodMask = 7 << 2 42 ) 43 44 // Disposal Methods. 45 const ( 46 DisposalNone = 0x01 47 DisposalBackground = 0x02 48 DisposalPrevious = 0x03 49 ) 50 51 // Section indicators. 52 const ( 53 sExtension = 0x21 54 sImageDescriptor = 0x2C 55 sTrailer = 0x3B 56 ) 57 58 // Extensions. 59 const ( 60 eText = 0x01 // Plain Text 61 eGraphicControl = 0xF9 // Graphic Control 62 eComment = 0xFE // Comment 63 eApplication = 0xFF // Application 64 ) 65 66 func readFull(r io.Reader, b []byte) error { 67 _, err := io.ReadFull(r, b) 68 if err == io.EOF { 69 err = io.ErrUnexpectedEOF 70 } 71 return err 72 } 73 74 func readByte(r io.ByteReader) (byte, error) { 75 b, err := r.ReadByte() 76 if err == io.EOF { 77 err = io.ErrUnexpectedEOF 78 } 79 return b, err 80 } 81 82 // decoder is the type used to decode a GIF file. 83 type decoder struct { 84 r reader 85 86 // From header. 87 vers string 88 width int 89 height int 90 loopCount int 91 delayTime int 92 backgroundIndex byte 93 disposalMethod byte 94 95 // From image descriptor. 96 imageFields byte 97 98 // From graphics control. 99 transparentIndex byte 100 hasTransparentIndex bool 101 102 // Computed. 103 globalColorTable color.Palette 104 105 // Used when decoding. 106 imageCount int 107 tmp [1024]byte // must be at least 768 so we can read color table 108 } 109 110 // blockReader parses the block structure of GIF image data, which comprises 111 // (n, (n bytes)) blocks, with 1 <= n <= 255. It is the reader given to the 112 // LZW decoder, which is thus immune to the blocking. After the LZW decoder 113 // completes, there will be a 0-byte block remaining (0, ()), which is 114 // consumed when checking that the blockReader is exhausted. 115 // 116 // To avoid the allocation of a bufio.Reader for the lzw Reader, blockReader 117 // implements io.ReadByte and buffers blocks into the decoder's "tmp" buffer. 118 type blockReader struct { 119 d *decoder 120 i, j uint8 // d.tmp[i:j] contains the buffered bytes 121 err error 122 } 123 124 func (b *blockReader) fill() { 125 if b.err != nil { 126 return 127 } 128 b.j, b.err = readByte(b.d.r) 129 if b.j == 0 && b.err == nil { 130 b.err = io.EOF 131 } 132 if b.err != nil { 133 return 134 } 135 136 b.i = 0 137 b.err = readFull(b.d.r, b.d.tmp[:b.j]) 138 if b.err != nil { 139 b.j = 0 140 } 141 } 142 143 func (b *blockReader) ReadByte() (byte, error) { 144 if b.i == b.j { 145 b.fill() 146 if b.err != nil { 147 return 0, b.err 148 } 149 } 150 151 c := b.d.tmp[b.i] 152 b.i++ 153 return c, nil 154 } 155 156 // blockReader must implement io.Reader, but its Read shouldn't ever actually 157 // be called in practice. The compress/lzw package will only call ReadByte. 158 func (b *blockReader) Read(p []byte) (int, error) { 159 if len(p) == 0 || b.err != nil { 160 return 0, b.err 161 } 162 if b.i == b.j { 163 b.fill() 164 if b.err != nil { 165 return 0, b.err 166 } 167 } 168 169 n := copy(p, b.d.tmp[b.i:b.j]) 170 b.i += uint8(n) 171 return n, nil 172 } 173 174 // close primarily detects whether or not a block terminator was encountered 175 // after reading a sequence of data sub-blocks. It allows at most one trailing 176 // sub-block worth of data. I.e., if some number of bytes exist in one sub-block 177 // following the end of LZW data, the very next sub-block must be the block 178 // terminator. If the very end of LZW data happened to fill one sub-block, at 179 // most one more sub-block of length 1 may exist before the block-terminator. 180 // These accommodations allow us to support GIFs created by less strict encoders. 181 // See https://golang.org/issue/16146. 182 func (b *blockReader) close() error { 183 if b.err == io.EOF { 184 // A clean block-sequence terminator was encountered while reading. 185 return nil 186 } else if b.err != nil { 187 // Some other error was encountered while reading. 188 return b.err 189 } 190 191 if b.i == b.j { 192 // We reached the end of a sub block reading LZW data. We'll allow at 193 // most one more sub block of data with a length of 1 byte. 194 b.fill() 195 if b.err == io.EOF { 196 return nil 197 } else if b.err != nil { 198 return b.err 199 } else if b.j > 1 { 200 return errTooMuch 201 } 202 } 203 204 // Part of a sub-block remains buffered. We expect that the next attempt to 205 // buffer a sub-block will reach the block terminator. 206 b.fill() 207 if b.err == io.EOF { 208 return nil 209 } else if b.err != nil { 210 return b.err 211 } 212 213 return errTooMuch 214 } 215 216 // decode reads a GIF image from r and stores the result in d. 217 func (d *decoder) decode(r io.Reader, configOnly bool) error { 218 // Add buffering if r does not provide ReadByte. 219 if rr, ok := r.(reader); ok { 220 d.r = rr 221 } else { 222 d.r = bufio.NewReader(r) 223 } 224 225 d.loopCount = -1 226 227 err := d.readHeaderAndScreenDescriptor() 228 if err != nil { 229 return err 230 } 231 if configOnly { 232 return nil 233 } 234 235 for { 236 c, err := readByte(d.r) 237 if err != nil { 238 return fmt.Errorf("gif: reading frames: %v", err) 239 } 240 switch c { 241 case sExtension: 242 if err = d.readExtension(); err != nil { 243 return err 244 } 245 246 case sImageDescriptor: 247 if err = d.readImageDescriptor(); err != nil { 248 return err 249 } 250 251 case sTrailer: 252 if d.imageCount == 0 { 253 return fmt.Errorf("gif: missing image data") 254 } 255 return nil 256 257 default: 258 return fmt.Errorf("gif: unknown block type: 0x%.2x", c) 259 } 260 } 261 } 262 263 func (d *decoder) readHeaderAndScreenDescriptor() error { 264 err := readFull(d.r, d.tmp[:13]) 265 if err != nil { 266 return fmt.Errorf("gif: reading header: %v", err) 267 } 268 d.vers = string(d.tmp[:6]) 269 if d.vers != "GIF87a" && d.vers != "GIF89a" { 270 return fmt.Errorf("gif: can't recognize format %q", d.vers) 271 } 272 d.width = int(d.tmp[6]) + int(d.tmp[7])<<8 273 d.height = int(d.tmp[8]) + int(d.tmp[9])<<8 274 if fields := d.tmp[10]; fields&fColorTable != 0 { 275 d.backgroundIndex = d.tmp[11] 276 // readColorTable overwrites the contents of d.tmp, but that's OK. 277 if d.globalColorTable, err = d.readColorTable(fields); err != nil { 278 return err 279 } 280 } 281 // d.tmp[12] is the Pixel Aspect Ratio, which is ignored. 282 return nil 283 } 284 285 func (d *decoder) readColorTable(fields byte) (color.Palette, error) { 286 n := 1 << (1 + uint(fields&fColorTableBitsMask)) 287 err := readFull(d.r, d.tmp[:3*n]) 288 if err != nil { 289 return nil, fmt.Errorf("gif: reading color table: %s", err) 290 } 291 j, p := 0, make(color.Palette, n) 292 for i := range p { 293 p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF} 294 j += 3 295 } 296 return p, nil 297 } 298 299 func (d *decoder) readExtension() error { 300 extension, err := readByte(d.r) 301 if err != nil { 302 return fmt.Errorf("gif: reading extension: %v", err) 303 } 304 size := 0 305 switch extension { 306 case eText: 307 size = 13 308 case eGraphicControl: 309 return d.readGraphicControl() 310 case eComment: 311 // nothing to do but read the data. 312 case eApplication: 313 b, err := readByte(d.r) 314 if err != nil { 315 return fmt.Errorf("gif: reading extension: %v", err) 316 } 317 // The spec requires size be 11, but Adobe sometimes uses 10. 318 size = int(b) 319 default: 320 return fmt.Errorf("gif: unknown extension 0x%.2x", extension) 321 } 322 if size > 0 { 323 if err := readFull(d.r, d.tmp[:size]); err != nil { 324 return fmt.Errorf("gif: reading extension: %v", err) 325 } 326 } 327 328 // Application Extension with "NETSCAPE2.0" as string and 1 in data means 329 // this extension defines a loop count. 330 if extension == eApplication && string(d.tmp[:size]) == "NETSCAPE2.0" { 331 n, err := d.readBlock() 332 if err != nil { 333 return fmt.Errorf("gif: reading extension: %v", err) 334 } 335 if n == 0 { 336 return nil 337 } 338 if n == 3 && d.tmp[0] == 1 { 339 d.loopCount = int(d.tmp[1]) | int(d.tmp[2])<<8 340 } 341 } 342 for { 343 n, err := d.readBlock() 344 if err != nil { 345 return fmt.Errorf("gif: reading extension: %v", err) 346 } 347 if n == 0 { 348 return nil 349 } 350 } 351 } 352 353 func (d *decoder) readGraphicControl() error { 354 if err := readFull(d.r, d.tmp[:6]); err != nil { 355 return fmt.Errorf("gif: can't read graphic control: %s", err) 356 } 357 if d.tmp[0] != 4 { 358 return fmt.Errorf("gif: invalid graphic control extension block size: %d", d.tmp[0]) 359 } 360 flags := d.tmp[1] 361 d.disposalMethod = (flags & gcDisposalMethodMask) >> 2 362 d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8 363 if flags&gcTransparentColorSet != 0 { 364 d.transparentIndex = d.tmp[4] 365 d.hasTransparentIndex = true 366 } 367 if d.tmp[5] != 0 { 368 return fmt.Errorf("gif: invalid graphic control extension block terminator: %d", d.tmp[5]) 369 } 370 return nil 371 } 372 373 func (d *decoder) readImageDescriptor() error { 374 m, err := d.newImageFromDescriptor() 375 if err != nil { 376 return err 377 } 378 useLocalColorTable := d.imageFields&fColorTable != 0 379 if useLocalColorTable { 380 m.Palette, err = d.readColorTable(d.imageFields) 381 if err != nil { 382 return err 383 } 384 } else { 385 if d.globalColorTable == nil { 386 return errors.New("gif: no color table") 387 } 388 m.Palette = d.globalColorTable 389 } 390 if d.hasTransparentIndex { 391 if !useLocalColorTable { 392 // Clone the global color table. 393 m.Palette = append(color.Palette(nil), d.globalColorTable...) 394 } 395 if ti := int(d.transparentIndex); ti < len(m.Palette) { 396 m.Palette[ti] = color.RGBA{} 397 } else { 398 // The transparentIndex is out of range, which is an error 399 // according to the spec, but Firefox and Google Chrome 400 // seem OK with this, so we enlarge the palette with 401 // transparent colors. See golang.org/issue/15059. 402 p := make(color.Palette, ti+1) 403 copy(p, m.Palette) 404 for i := len(m.Palette); i < len(p); i++ { 405 p[i] = color.RGBA{} 406 } 407 m.Palette = p 408 } 409 } 410 litWidth, err := readByte(d.r) 411 if err != nil { 412 return fmt.Errorf("gif: reading image data: %v", err) 413 } 414 if litWidth < 2 || litWidth > 8 { 415 return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth) 416 } 417 // A wonderfully Go-like piece of magic. 418 br := &blockReader{d: d} 419 lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth)) 420 defer lzwr.Close() 421 if err = readFull(lzwr, m.Pix); err != nil { 422 if err != io.ErrUnexpectedEOF { 423 return fmt.Errorf("gif: reading image data: %v", err) 424 } 425 return errNotEnough 426 } 427 // In theory, both lzwr and br should be exhausted. Reading from them 428 // should yield (0, io.EOF). 429 // 430 // The spec (Appendix F - Compression), says that "An End of 431 // Information code... must be the last code output by the encoder 432 // for an image". In practice, though, giflib (a widely used C 433 // library) does not enforce this, so we also accept lzwr returning 434 // io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF 435 // before the LZW decoder saw an explicit end code), provided that 436 // the io.ReadFull call above successfully read len(m.Pix) bytes. 437 // See https://golang.org/issue/9856 for an example GIF. 438 if n, err := lzwr.Read(d.tmp[256:257]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) { 439 if err != nil { 440 return fmt.Errorf("gif: reading image data: %v", err) 441 } 442 return errTooMuch 443 } 444 445 // In practice, some GIFs have an extra byte in the data sub-block 446 // stream, which we ignore. See https://golang.org/issue/16146. 447 if err := br.close(); err == errTooMuch { 448 return errTooMuch 449 } else if err != nil { 450 return fmt.Errorf("gif: reading image data: %v", err) 451 } 452 453 d.imageCount += 1 454 455 return nil 456 } 457 458 func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) { 459 if err := readFull(d.r, d.tmp[:9]); err != nil { 460 return nil, fmt.Errorf("gif: can't read image descriptor: %s", err) 461 } 462 left := int(d.tmp[0]) + int(d.tmp[1])<<8 463 top := int(d.tmp[2]) + int(d.tmp[3])<<8 464 width := int(d.tmp[4]) + int(d.tmp[5])<<8 465 height := int(d.tmp[6]) + int(d.tmp[7])<<8 466 d.imageFields = d.tmp[8] 467 468 // The GIF89a spec, Section 20 (Image Descriptor) says: "Each image must 469 // fit within the boundaries of the Logical Screen, as defined in the 470 // Logical Screen Descriptor." 471 // 472 // This is conceptually similar to testing 473 // frameBounds := image.Rect(left, top, left+width, top+height) 474 // imageBounds := image.Rect(0, 0, d.width, d.height) 475 // if !frameBounds.In(imageBounds) { etc } 476 // but the semantics of the Go image.Rectangle type is that r.In(s) is true 477 // whenever r is an empty rectangle, even if r.Min.X > s.Max.X. Here, we 478 // want something stricter. 479 // 480 // Note that, by construction, left >= 0 && top >= 0, so we only have to 481 // explicitly compare frameBounds.Max (left+width, top+height) against 482 // imageBounds.Max (d.width, d.height) and not frameBounds.Min (left, top) 483 // against imageBounds.Min (0, 0). 484 if left+width > d.width || top+height > d.height { 485 return nil, errors.New("gif: frame bounds larger than image bounds") 486 } 487 return image.NewPaletted(image.Rectangle{ 488 Min: image.Point{left, top}, 489 Max: image.Point{left + width, top + height}, 490 }, nil), nil 491 } 492 493 func (d *decoder) readBlock() (int, error) { 494 n, err := readByte(d.r) 495 if n == 0 || err != nil { 496 return 0, err 497 } 498 if err := readFull(d.r, d.tmp[:n]); err != nil { 499 return 0, err 500 } 501 return int(n), nil 502 } 503 504 func CountFrames(r io.Reader) (int, error) { 505 var d decoder 506 if err := d.decode(r, false); err != nil { 507 return -1, err 508 } 509 return d.imageCount, nil 510 }