More work on image previews

This commit is contained in:
Kovid Goyal
2025-10-07 13:30:28 +05:30
parent 1f37f065ab
commit f0040edff2
2 changed files with 79 additions and 9 deletions

View File

@@ -21,21 +21,89 @@ var preview_cache = sync.OnceValues(func() (*disk_cache.DiskCache, error) {
return disk_cache.NewDiskCache(cdir, dc_size.Load()) return disk_cache.NewDiskCache(cdir, dc_size.Load())
}) })
type PreviewRenderer interface {
Render(string) (map[string][]byte, error)
Show(h *Handler, abspath string, metadata fs.FileInfo, x, y, width, height int, cached_data map[string]string)
}
type render_data struct {
cached_data map[string]string
err error
}
type ImagePreview struct { type ImagePreview struct {
abspath, cache_key string abspath, cache_key string
disk_cache *disk_cache.DiskCache metadata fs.FileInfo
disk_cache *disk_cache.DiskCache
cached_data map[string]string
render_err Preview
render_channel chan render_data
renderer PreviewRenderer
file_metadata_preview Preview
WakeupMainThread func() bool
} }
func (p ImagePreview) IsValidForColorScheme(bool) bool { return true } func (p ImagePreview) IsValidForColorScheme(bool) bool { return true }
func (p ImagePreview) Render(h *Handler, x, y, width, height int) { func (p ImagePreview) Render(h *Handler, x, y, width, height int) {
offset := 0 if p.render_channel == nil {
offset += h.render_wrapped_text_in_region("Rendering image, please wait...", x, y, width, height, true) if p.render_err == nil {
p.renderer.Show(h, p.abspath, p.metadata, x, y, width, height, p.cached_data)
} else {
p.render_err.Render(h, x, y, width, height)
}
return
}
select {
case hd := <-p.render_channel:
p.render_channel = nil
p.cached_data = hd.cached_data
p.render_err = NewErrorPreview(fmt.Errorf("Failed to render the preview with error: %w", hd.err))
p.Render(h, x, y, width, height)
return
default:
}
if p.file_metadata_preview == nil {
p.file_metadata_preview = NewFileMetadataPreview(p.abspath, p.metadata)
}
p.file_metadata_preview.Render(h, x, y, width, height)
} }
func NewImagePreview(abspath string, metadata fs.FileInfo, opts Settings) (Preview, error) { func (p *ImagePreview) start_rendering() {
defer func() {
p.WakeupMainThread()
}()
ans := p.disk_cache.Get(p.cache_key)
if len(ans) > 0 {
p.render_channel <- render_data{ans, nil}
return
}
rdata, err := p.renderer.Render(p.abspath)
if err != nil {
p.render_channel <- render_data{nil, err}
} else {
ans, err = p.disk_cache.Add(p.cache_key, rdata)
p.render_channel <- render_data{utils.IfElse(err == nil, ans, nil), err}
}
}
type ImagePreviewRenderer uint
func (p ImagePreviewRenderer) Render(abspath string) (ans map[string][]byte, err error) {
return
}
func (p ImagePreviewRenderer) Show(h *Handler, abspath string, metadata fs.FileInfo, x, y, width, height int, cached_data map[string]string) {
}
func NewImagePreview(
abspath string, metadata fs.FileInfo, opts Settings, WakeupMainThread func() bool, r PreviewRenderer,
) (Preview, error) {
dc_size.Store(opts.DiskCacheSize()) dc_size.Store(opts.DiskCacheSize())
ans := &ImagePreview{abspath: abspath} ans := &ImagePreview{
abspath: abspath, metadata: metadata, render_channel: make(chan render_data),
WakeupMainThread: WakeupMainThread, renderer: r,
}
if dc, err := preview_cache(); err != nil { if dc, err := preview_cache(); err != nil {
return nil, err return nil, err
} else { } else {
@@ -46,5 +114,6 @@ func NewImagePreview(abspath string, metadata fs.FileInfo, opts Settings) (Previ
} else { } else {
ans.cache_key = key ans.cache_key = key
} }
go ans.start_rendering()
return ans, nil return ans, nil
} }

View File

@@ -298,11 +298,12 @@ func (pm *PreviewManager) preview_for(abspath string, ftype fs.FileMode) (ans Pr
return NewTextFilePreview(abspath, s, ch, pm.highlighter.Sanitize) return NewTextFilePreview(abspath, s, ch, pm.highlighter.Sanitize)
} }
if strings.HasPrefix(mt, "image/") { if strings.HasPrefix(mt, "image/") {
ans, err := NewImagePreview(abspath, s, pm.settings) var r ImagePreviewRenderer
if err != nil { if ans, err := NewImagePreview(abspath, s, pm.settings, pm.WakeupMainThread, r); err == nil {
return ans
} else {
return NewErrorPreview(err) return NewErrorPreview(err)
} }
return ans
} }
return NewFileMetadataPreview(abspath, s) return NewFileMetadataPreview(abspath, s)
} }