webp.go 2.2 KB

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