diff --git a/internal/parser/heic/constants.go b/internal/parser/heic/constants.go index 816f11c..2390a86 100644 --- a/internal/parser/heic/constants.go +++ b/internal/parser/heic/constants.go @@ -31,11 +31,16 @@ const ( ) // Valid HEIC/HEIF major brands -var validBrands = []string{ +var heicBrands = []string{ "heic", "heif", "heix", "hevc", "heim", "heis", "mif1", "msf1", "heiv", "hevx", } +// Valid AVIF major brands +var avifBrands = []string{ + "avif", "avis", "av01", +} + // Box header sizes const ( boxHeaderSize = 8 // Standard box header (size + type) diff --git a/internal/parser/heic/heic.go b/internal/parser/heic/heic.go index 654e790..fa4244c 100644 --- a/internal/parser/heic/heic.go +++ b/internal/parser/heic/heic.go @@ -1,8 +1,10 @@ -// Package heic implements a parser for HEIC/HEIF image files. +// Package heic implements a parser for HEIC/HEIF and AVIF image files. // -// HEIC (High Efficiency Image Container) is based on the ISO Base Media File -// Format (ISOBMFF). This parser extracts EXIF, XMP, and ICC metadata from -// HEIC/HEIF files by parsing the box structure and building an item index. +// HEIC (High Efficiency Image Container) and AVIF (AV1 Image File Format) +// are both based on the ISO Base Media File Format (ISOBMFF). They share the +// same container structure, differing only in the image codec used (HEVC vs AV1). +// This parser extracts EXIF, XMP, and ICC metadata from both formats by parsing +// the box structure and building an item index. package heic import ( @@ -18,7 +20,8 @@ import ( // maxBoxScan is the maximum number of bytes to scan when searching for boxes. const maxBoxScan = 100 * 1024 * 1024 // 100MB -// Parser parses HEIC/HEIF image files. +// Parser parses HEIC/HEIF and AVIF image files. +// Both formats use the ISO Base Media File Format (ISOBMFF) container. type Parser struct { tiff *tiff.Parser xmp *xmp.Parser @@ -35,11 +38,13 @@ func New() *Parser { } // Name returns the parser name. +// This parser handles both HEIC/HEIF and AVIF formats. func (p *Parser) Name() string { return "HEIC" } -// Detect checks if the data is a HEIC/HEIF file. +// Detect checks if the data is a HEIC/HEIF or AVIF file. +// Both formats use the same ISOBMFF container structure. func (p *Parser) Detect(r io.ReaderAt) bool { buf := make([]byte, 12) if _, err := r.ReadAt(buf[:12], 0); err != nil { @@ -51,9 +56,14 @@ func (p *Parser) Detect(r io.ReaderAt) bool { return false } - // Check major brand + // Check major brand (HEIC or AVIF) brand := string(buf[8:12]) - for _, valid := range validBrands { + for _, valid := range heicBrands { + if brand == valid { + return true + } + } + for _, valid := range avifBrands { if brand == valid { return true } diff --git a/internal/parser/heic/heic_test.go b/internal/parser/heic/heic_test.go index 9a27dd4..dd0ed1a 100644 --- a/internal/parser/heic/heic_test.go +++ b/internal/parser/heic/heic_test.go @@ -73,12 +73,23 @@ func TestParser_Detect(t *testing.T) { func TestParser_Detect_AllBrands(t *testing.T) { p := New() - for _, brand := range validBrands { - t.Run(brand, func(t *testing.T) { + // Test HEIC brands + for _, brand := range heicBrands { + t.Run("HEIC_"+brand, func(t *testing.T) { data := []byte{0, 0, 0, 24, 'f', 't', 'y', 'p', brand[0], brand[1], brand[2], brand[3]} r := bytes.NewReader(data) if !p.Detect(r) { - t.Errorf("Detect() should recognize brand %s", brand) + t.Errorf("Detect() should recognize HEIC brand %s", brand) + } + }) + } + // Test AVIF brands + for _, brand := range avifBrands { + t.Run("AVIF_"+brand, func(t *testing.T) { + data := []byte{0, 0, 0, 24, 'f', 't', 'y', 'p', brand[0], brand[1], brand[2], brand[3]} + r := bytes.NewReader(data) + if !p.Detect(r) { + t.Errorf("Detect() should recognize AVIF brand %s", brand) } }) }