mirror of
https://github.com/stashapp/stash.git
synced 2026-04-29 21:19:24 -05:00
Bugfix: AVIF Image PHash Support (#6556)
* AVIF phash support * add avif check for zips
This commit is contained in:
+4
-4
@@ -27,11 +27,11 @@ func printPhash(ff *ffmpeg.FFMpeg, ffp *ffmpeg.FFProbe, inputfile string, quiet
|
||||
|
||||
// Common image extensions
|
||||
imageExts := map[string]bool{
|
||||
"jpg": true, "jpeg": true, "png": true, "gif": true, "webp": true, "bmp": true,
|
||||
"jpg": true, "jpeg": true, "png": true, "gif": true, "webp": true, "bmp": true, "avif": true,
|
||||
}
|
||||
|
||||
if imageExts[ext] {
|
||||
return printImagePhash(inputfile, quiet)
|
||||
return printImagePhash(ff, inputfile, quiet)
|
||||
}
|
||||
|
||||
return printVideoPhash(ff, ffp, inputfile, quiet)
|
||||
@@ -65,12 +65,12 @@ func printVideoPhash(ff *ffmpeg.FFMpeg, ffp *ffmpeg.FFProbe, inputfile string, q
|
||||
return nil
|
||||
}
|
||||
|
||||
func printImagePhash(inputfile string, quiet *bool) error {
|
||||
func printImagePhash(ff *ffmpeg.FFMpeg, inputfile string, quiet *bool) error {
|
||||
imgFile := &models.ImageFile{
|
||||
BaseFile: &models.BaseFile{Path: inputfile},
|
||||
}
|
||||
|
||||
phash, err := imagephash.Generate(imgFile)
|
||||
phash, err := imagephash.Generate(ff, imgFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func (t *GenerateImagePhashTask) Start(ctx context.Context) {
|
||||
}
|
||||
|
||||
if !set {
|
||||
generated, err := imagephash.Generate(t.File)
|
||||
generated, err := imagephash.Generate(instance.FFMpeg, t.File)
|
||||
if err != nil {
|
||||
logger.Errorf("Error generating phash for %q: %v", t.File.Path, err)
|
||||
logErrorOutput(err)
|
||||
|
||||
@@ -2,17 +2,22 @@ package imagephash
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/corona10/goimagehash"
|
||||
"github.com/stashapp/stash/pkg/ffmpeg"
|
||||
"github.com/stashapp/stash/pkg/ffmpeg/transcoder"
|
||||
"github.com/stashapp/stash/pkg/file"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
// Generate computes a perceptual hash for an image file.
|
||||
func Generate(imageFile *models.ImageFile) (*uint64, error) {
|
||||
img, err := loadImage(imageFile)
|
||||
func Generate(encoder *ffmpeg.FFMpeg, imageFile *models.ImageFile) (*uint64, error) {
|
||||
img, err := loadImage(encoder, imageFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading image: %w", err)
|
||||
}
|
||||
@@ -27,7 +32,17 @@ func Generate(imageFile *models.ImageFile) (*uint64, error) {
|
||||
}
|
||||
|
||||
// loadImage loads an image from disk and decodes it.
|
||||
func loadImage(imageFile *models.ImageFile) (image.Image, error) {
|
||||
// For AVIF files, ffmpeg is used to convert to BMP first since Go has no built-in AVIF decoder.
|
||||
func loadImage(encoder *ffmpeg.FFMpeg, imageFile *models.ImageFile) (image.Image, error) {
|
||||
ext := strings.ToLower(filepath.Ext(imageFile.Path))
|
||||
if ext == ".avif" {
|
||||
// AVIF in zip files is not supported - ffmpeg cannot read files inside zips
|
||||
if imageFile.Base().ZipFileID != nil {
|
||||
return nil, fmt.Errorf("AVIF images in zip files are not supported for phash generation")
|
||||
}
|
||||
return loadImageFFmpeg(encoder, imageFile.Path)
|
||||
}
|
||||
|
||||
reader, err := imageFile.Open(&file.OsFS{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -46,3 +61,24 @@ func loadImage(imageFile *models.ImageFile) (image.Image, error) {
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// loadImageFFmpeg uses ffmpeg to convert an image to BMP and then decodes it.
|
||||
func loadImageFFmpeg(encoder *ffmpeg.FFMpeg, path string) (image.Image, error) {
|
||||
options := transcoder.ScreenshotOptions{
|
||||
OutputPath: "-",
|
||||
OutputType: transcoder.ScreenshotOutputTypeBMP,
|
||||
}
|
||||
|
||||
args := transcoder.ScreenshotTime(path, 0, options)
|
||||
data, err := encoder.GenerateOutput(context.Background(), args, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting image with ffmpeg: %w", err)
|
||||
}
|
||||
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding ffmpeg output: %w", err)
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user