From 3a50367270fcf96f77e173c84156851347913489 Mon Sep 17 00:00:00 2001 From: Taylan Sahin Date: Thu, 26 Dec 2024 03:12:40 +0000 Subject: [PATCH 1/2] fix: avoid unnecessary image processing when the preview panel is closed --- src/internal/model_render.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/internal/model_render.go b/src/internal/model_render.go index a4b3e157..ec16cf95 100644 --- a/src/internal/model_render.go +++ b/src/internal/model_render.go @@ -613,6 +613,9 @@ func (m model) filePreviewPanelRender() string { } if isImageFile(itemPath) { + if !m.fileModel.filePreview.open { + return box.Render("\n --- Preview panel is closed ---") + } ansiRender, err := filepreview.ImagePreview(itemPath, m.fileModel.filePreview.width, previewLine, theme.FilePanelBG) if err == image.ErrFormat { return box.Render("\n --- " + icon.Error + " Unsupported image formats ---") From a48762d3fdebba6abdf073f30bfd70ef45292d06 Mon Sep 17 00:00:00 2001 From: Taylan Sahin Date: Fri, 27 Dec 2024 15:26:45 +0000 Subject: [PATCH 2/2] perf: optimize color conversion with caching --- src/pkg/file_preview/image_preview.go | 42 +++++++++++++++++++-------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/pkg/file_preview/image_preview.go b/src/pkg/file_preview/image_preview.go index fb412b4c..7910f532 100644 --- a/src/pkg/file_preview/image_preview.go +++ b/src/pkg/file_preview/image_preview.go @@ -14,19 +14,46 @@ import ( "github.com/nfnt/resize" ) +type colorCache struct { + rgbaToTermenv map[color.RGBA]termenv.RGBColor +} + +func newColorCache() *colorCache { + return &colorCache{ + rgbaToTermenv: make(map[color.RGBA]termenv.RGBColor), + } +} + +func (c *colorCache) getTermenvColor(col color.Color, fallbackColor string) termenv.RGBColor { + rgba := color.RGBAModel.Convert(col).(color.RGBA) + if rgba.A == 0 { + return termenv.RGBColor(fallbackColor) + } + + if termenvColor, exists := c.rgbaToTermenv[rgba]; exists { + return termenvColor + } + + termenvColor := termenv.RGBColor(fmt.Sprintf("#%02x%02x%02x", rgba.R, rgba.G, rgba.B)) + c.rgbaToTermenv[rgba] = termenvColor + return termenvColor +} + // ConvertImageToANSI converts an image to ANSI escape codes with proper aspect ratio func ConvertImageToANSI(img image.Image, defaultBGColor color.Color) string { width := img.Bounds().Dx() height := img.Bounds().Dy() output := "" + cache := newColorCache() + defaultBGHex := colorToHex(defaultBGColor) for y := 0; y < height; y += 2 { for x := 0; x < width; x++ { - upperColor := colorToTermenv(img.At(x, y), colorToHex(defaultBGColor)) - lowerColor := colorToTermenv(defaultBGColor, "") + upperColor := cache.getTermenvColor(img.At(x, y), defaultBGHex) + lowerColor := cache.getTermenvColor(defaultBGColor, "") if y + 1 < height { - lowerColor = colorToTermenv(img.At(x, y + 1), colorToHex(defaultBGColor)) + lowerColor = cache.getTermenvColor(img.At(x, y+1), defaultBGHex) } // Using the "▄" character which fills the lower half @@ -39,15 +66,6 @@ func ConvertImageToANSI(img image.Image, defaultBGColor color.Color) string { return output } -// colorToTermenv converts a color.Color to a termenv.RGBColor -func colorToTermenv(c color.Color, fallbackColor string) termenv.RGBColor { - r, g, b, a := c.RGBA() - if a == 0 { - return termenv.RGBColor(fallbackColor) - } - return termenv.RGBColor(fmt.Sprintf("#%02x%02x%02x", uint8(r>>8), uint8(g>>8), uint8(b>>8))) -} - // Return image preview ansi string func ImagePreview(path string, maxWidth, maxHeight int, defaultBGColor string) (string, error) { // Load image file