webp.go 2.2 KB

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