forked from imgproxy/imgproxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
webp.go
111 lines (89 loc) · 2.41 KB
/
webp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Original code was cropped and fixed by @DarthSim for imgproxy needs
package main
import (
"errors"
"image"
"image/color"
"io"
"golang.org/x/image/riff"
"golang.org/x/image/vp8"
"golang.org/x/image/vp8l"
)
var errInvalidFormat = errors.New("webp: invalid format")
var (
fccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
fccVP8 = riff.FourCC{'V', 'P', '8', ' '}
fccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
fccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
)
// Since we need this only for type detecting, we can return fake image
func decodeWebp(r io.Reader) (image.Image, error) {
return image.NewRGBA(image.Rect(0, 0, 1, 1)), nil
}
func decodeWebpConfig(r io.Reader) (image.Config, error) {
formType, riffReader, err := riff.NewReader(r)
if err != nil {
return image.Config{}, err
}
if formType != fccWEBP {
return image.Config{}, errInvalidFormat
}
var (
wantAlpha bool
buf [10]byte
)
for {
chunkID, chunkLen, chunkData, err := riffReader.Next()
if err == io.EOF {
err = errInvalidFormat
}
if err != nil {
return image.Config{}, err
}
switch chunkID {
case fccALPH:
// Ignore
case fccVP8:
if wantAlpha || int32(chunkLen) < 0 {
return image.Config{}, errInvalidFormat
}
d := vp8.NewDecoder()
d.Init(chunkData, int(chunkLen))
fh, err := d.DecodeFrameHeader()
return image.Config{
ColorModel: color.YCbCrModel,
Width: fh.Width,
Height: fh.Height,
}, err
case fccVP8L:
if wantAlpha {
return image.Config{}, errInvalidFormat
}
return vp8l.DecodeConfig(chunkData)
case fccVP8X:
if chunkLen != 10 {
return image.Config{}, errInvalidFormat
}
if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
return image.Config{}, err
}
const alphaBit = 1 << 4
widthMinusOne := uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
heightMinusOne := uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
return image.Config{
ColorModel: color.NYCbCrAModel,
Width: int(widthMinusOne) + 1,
Height: int(heightMinusOne) + 1,
}, nil
default:
return image.Config{}, errInvalidFormat
}
}
}
func init() {
image.RegisterFormat("webp", "RIFF????WEBPVP8", decodeWebp, decodeWebpConfig)
}