From 124b6d34a93298bd84cb3a317855bd2f55af6a7d Mon Sep 17 00:00:00 2001 From: Kostiantyn <32730812+kkovaletp@users.noreply.github.com> Date: Fri, 11 Jul 2025 13:21:28 +0300 Subject: [PATCH] Auto-orient image during processing (#1242) * Auto-orient image during processing * Detect if thumb was rotated 90 degrees and switch dimentions * Consistently auto-rotate images * fix incorrect path for the original photo dimensions reading * Swap the dimensions if needed and call the `wand.ThumbnailImage()` unconditionally * revert unnecessary line split --------- Co-authored-by: Konstantin Koval --- api/scanner/media_encoding/encode_photo.go | 9 ++++++++ .../executable_worker/magickwand.go | 23 +++++++++++++++++++ .../processing_tasks/process_photo_task.go | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/api/scanner/media_encoding/encode_photo.go b/api/scanner/media_encoding/encode_photo.go index a7fff3fd..64c9fa68 100644 --- a/api/scanner/media_encoding/encode_photo.go +++ b/api/scanner/media_encoding/encode_photo.go @@ -81,6 +81,15 @@ func EncodeThumbnail(db *gorm.DB, inputPath string, outputPath string) (Dimensio return Dimension{}, fmt.Errorf("can't generate thumbnail of file %q: %w", inputPath, err) } + w, h, err = executable_worker.Magick.IdentifyDimension(outputPath) + if err != nil { + return Dimension{}, fmt.Errorf("can't generate thumbnail of file %q: %w", inputPath, err) + } + thumbnail = Dimension{ + Width: int(w), + Height: int(h), + } + return thumbnail, nil } diff --git a/api/scanner/media_encoding/executable_worker/magickwand.go b/api/scanner/media_encoding/executable_worker/magickwand.go index 249b4ef3..fc19bd02 100644 --- a/api/scanner/media_encoding/executable_worker/magickwand.go +++ b/api/scanner/media_encoding/executable_worker/magickwand.go @@ -44,6 +44,14 @@ func (cli *MagickWand) EncodeJpeg(inputPath string, outputPath string, jpegQuali return fmt.Errorf("ImagickWand read %q error: %w", inputPath, err) } + if err := wand.AutoOrientImage(); err != nil { + return fmt.Errorf("ImagickWand auto-orient %q error: %w", inputPath, err) + } + // Reset EXIF orientation to 1 (top-left) since image is now properly oriented + if err := wand.SetImageOrientation(imagick.ORIENTATION_TOP_LEFT); err != nil { + return fmt.Errorf("ImagickWand set orientation for %q error: %w", inputPath, err) + } + if err := wand.SetFormat("JPEG"); err != nil { return fmt.Errorf("ImagickWand set JPEG format for %q error: %w", inputPath, err) } @@ -71,6 +79,21 @@ func (cli *MagickWand) GenerateThumbnail(inputPath string, outputPath string, wi return fmt.Errorf("ImagickWand read %q error: %w", inputPath, err) } + originalWidth := wand.GetImageWidth() + originalHeight := wand.GetImageHeight() + + if err := wand.AutoOrientImage(); err != nil { + return fmt.Errorf("ImagickWand auto-orient %q error: %w", inputPath, err) + } + // Reset EXIF orientation to 1 (top-left) since image is now properly oriented + if err := wand.SetImageOrientation(imagick.ORIENTATION_TOP_LEFT); err != nil { + return fmt.Errorf("ImagickWand set orientation for %q error: %w", inputPath, err) + } + + // If the original image is rotated by 90 degrees, swap width and height for thumbnail generation + if originalWidth != wand.GetImageWidth() && originalHeight != wand.GetImageHeight() { + width, height = height, width + } if err := wand.ThumbnailImage(width, height); err != nil { return fmt.Errorf("ImagickWand generate thumbnail for %q error: %w", inputPath, err) } diff --git a/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go b/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go index 7699c045..1c28e3d1 100644 --- a/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go +++ b/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go @@ -86,7 +86,7 @@ func (t ProcessPhotoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * if origURL == nil { // Make sure photo dimensions is set - photoDimensions, err := media_encoding.GetPhotoDimensions(baseImagePath) + photoDimensions, err := media_encoding.GetPhotoDimensions(photo.Path) if err != nil { return []*models.MediaURL{}, err }