webp.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2011 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. // Original code was cropped and fixed by @DarthSim for imgproxy needs
  5. package imagemeta
  6. import (
  7. "errors"
  8. "io"
  9. "golang.org/x/image/riff"
  10. "golang.org/x/image/vp8"
  11. "golang.org/x/image/vp8l"
  12. )
  13. var ErrWebpInvalidFormat = errors.New("webp: invalid format")
  14. var (
  15. webpFccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
  16. webpFccVP8 = riff.FourCC{'V', 'P', '8', ' '}
  17. webpFccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
  18. webpFccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
  19. webpFccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
  20. )
  21. func DecodeWebpMeta(r io.Reader) (Meta, error) {
  22. formType, riffReader, err := riff.NewReader(r)
  23. if err != nil {
  24. return nil, err
  25. }
  26. if formType != webpFccWEBP {
  27. return nil, ErrWebpInvalidFormat
  28. }
  29. var buf [10]byte
  30. for {
  31. chunkID, chunkLen, chunkData, err := riffReader.Next()
  32. if err == io.EOF {
  33. err = ErrWebpInvalidFormat
  34. }
  35. if err != nil {
  36. return nil, err
  37. }
  38. switch chunkID {
  39. case webpFccALPH:
  40. // Ignore
  41. case webpFccVP8:
  42. if int32(chunkLen) < 0 {
  43. return nil, ErrWebpInvalidFormat
  44. }
  45. d := vp8.NewDecoder()
  46. d.Init(chunkData, int(chunkLen))
  47. fh, err := d.DecodeFrameHeader()
  48. return &meta{
  49. format: "webp",
  50. width: fh.Width,
  51. height: fh.Height,
  52. }, err
  53. case webpFccVP8L:
  54. conf, err := vp8l.DecodeConfig(chunkData)
  55. if err != nil {
  56. return nil, err
  57. }
  58. return &meta{
  59. format: "webp",
  60. width: conf.Width,
  61. height: conf.Height,
  62. }, nil
  63. case webpFccVP8X:
  64. if chunkLen != 10 {
  65. return nil, ErrWebpInvalidFormat
  66. }
  67. if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
  68. return nil, err
  69. }
  70. widthMinusOne := uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
  71. heightMinusOne := uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
  72. return &meta{
  73. format: "webp",
  74. width: int(widthMinusOne) + 1,
  75. height: int(heightMinusOne) + 1,
  76. }, nil
  77. default:
  78. return nil, ErrWebpInvalidFormat
  79. }
  80. }
  81. }
  82. func init() {
  83. RegisterFormat("RIFF????WEBPVP8", DecodeWebpMeta)
  84. }