2020-06-08 03:29:51 +03:00
|
|
|
package webp
|
|
|
|
|
|
|
|
// https://developers.google.com/speed/webp/docs/riff_container
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2021-08-17 13:06:32 +03:00
|
|
|
|
|
|
|
"github.com/wader/fq/format"
|
|
|
|
"github.com/wader/fq/pkg/decode"
|
2022-07-16 19:39:57 +03:00
|
|
|
"github.com/wader/fq/pkg/interp"
|
2021-12-02 00:48:25 +03:00
|
|
|
"github.com/wader/fq/pkg/scalar"
|
2020-06-08 03:29:51 +03:00
|
|
|
)
|
|
|
|
|
2021-11-17 18:46:10 +03:00
|
|
|
var vp8Frame decode.Group
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
func init() {
|
2022-07-16 19:39:57 +03:00
|
|
|
interp.RegisterFormat(decode.Format{
|
2020-06-08 03:29:51 +03:00
|
|
|
Name: format.WEBP,
|
|
|
|
Description: "WebP image",
|
|
|
|
Groups: []string{format.PROBE, format.IMAGE},
|
|
|
|
DecodeFn: webpDecode,
|
|
|
|
Dependencies: []decode.Dependency{
|
2021-11-17 18:46:10 +03:00
|
|
|
{Names: []string{format.VP8_FRAME}, Group: &vp8Frame},
|
2020-06-08 03:29:51 +03:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-05-20 16:10:41 +03:00
|
|
|
func decodeChunk(d *decode.D, expectedChunkID string, fn func(d *decode.D)) bool {
|
2022-05-07 13:46:34 +03:00
|
|
|
trimChunkID := d.FieldUTF8("id", 4, scalar.ActualTrimSpace)
|
2020-06-08 03:29:51 +03:00
|
|
|
if expectedChunkID != "" && trimChunkID != expectedChunkID {
|
|
|
|
return false
|
|
|
|
}
|
2021-12-04 21:15:54 +03:00
|
|
|
chunkLen := int64(d.FieldU32("size"))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
if fn != nil {
|
2022-01-13 20:34:59 +03:00
|
|
|
d.FramedFn(chunkLen*8, fn)
|
2020-06-08 03:29:51 +03:00
|
|
|
} else {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldRawLen("data", chunkLen*8)
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-05-20 16:10:41 +03:00
|
|
|
func webpDecode(d *decode.D, in any) any {
|
2021-12-04 21:15:54 +03:00
|
|
|
d.Endian = decode.LittleEndian
|
|
|
|
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldUTF8("riff_id", 4, d.AssertStr("RIFF"))
|
2021-12-04 21:15:54 +03:00
|
|
|
riffLength := d.FieldU32("riff_length")
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldUTF8("webp_id", 4, d.AssertStr("WEBP"))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
2022-01-13 20:34:59 +03:00
|
|
|
d.FramedFn(int64(riffLength-4)*8, func(d *decode.D) {
|
2020-06-08 03:29:51 +03:00
|
|
|
p := d.PeekBytes(4)
|
|
|
|
|
|
|
|
// TODO: VP8X
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case bytes.Equal(p, []byte("VP8 ")):
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldStruct("image", func(d *decode.D) {
|
2020-06-08 03:29:51 +03:00
|
|
|
decodeChunk(d, "VP8", func(d *decode.D) {
|
2021-09-16 16:29:11 +03:00
|
|
|
d.Format(vp8Frame, nil)
|
2020-06-08 03:29:51 +03:00
|
|
|
})
|
|
|
|
})
|
|
|
|
case bytes.Equal(p, []byte("VP8L")):
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldStruct("image", func(d *decode.D) {
|
2020-06-08 03:29:51 +03:00
|
|
|
decodeChunk(d, "VP8L", func(d *decode.D) {
|
|
|
|
// TODO
|
|
|
|
})
|
|
|
|
})
|
|
|
|
default:
|
2021-11-17 18:26:13 +03:00
|
|
|
d.Fatalf("could not find VP8 or VP8L chunk")
|
2020-06-08 03:29:51 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|