package artwork
import (
"bytes"
"encoding/binary"
)
func isAnimatedGIF(data []byte) bool {
if !bytes.HasPrefix(data, []byte("GIF")) {
return false
}
pos := 13
if pos >= len(data) {
return false
}
if len(data) > 10 && data[10]&0x80 != 0 {
gctSize := 3 * (1 << ((data[10] & 0x07) + 1))
pos += gctSize
}
frameCount := 0
for pos < len(data) {
switch data[pos] {
case 0x2C:
frameCount++
if frameCount > 1 {
return true
}
pos++
if pos+8 >= len(data) {
return false
}
pos += 8
packed := data[pos]
pos++
if packed&0x80 != 0 {
lctSize := 3 * (1 << ((packed & 0x07) + 1))
pos += lctSize
}
pos++
pos = skipGIFSubBlocks(data, pos)
case 0x21:
pos++
if pos >= len(data) {
return false
}
pos++
pos = skipGIFSubBlocks(data, pos)
case 0x3B:
return false
default:
return false
}
}
return false
}
func skipGIFSubBlocks(data []byte, pos int) int {
for pos < len(data) {
blockSize := int(data[pos])
pos++
if blockSize == 0 {
break
}
pos += blockSize
}
return pos
}
func isAnimatedWebP(data []byte) bool {
if !bytes.HasPrefix(data, []byte("RIFF")) || len(data) < 12 {
return false
}
if !bytes.Equal(data[8:12], []byte("WEBP")) {
return false
}
return bytes.Contains(data[12:], []byte("ANMF"))
}
func isAnimatedPNG(data []byte) bool {
pngSig := []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}
if !bytes.HasPrefix(data, pngSig) {
return false
}
pos := uint64(8)
dataLen := uint64(len(data))
for pos+8 <= dataLen {
chunkLen := uint64(binary.BigEndian.Uint32(data[pos : pos+4]))
chunkType := string(data[pos+4 : pos+8])
if chunkType == "acTL" {
return true
}
pos += 12 + chunkLen
}
return false
}