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 ---") 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