package thumbnail import ( "fmt" "image" "image/jpeg" "image/png" "os" "strings" "sync" ) type Thumbnailer struct { Width int Height int MaxCacheSize int cacheMtx sync.RWMutex thumbCache map[string][]byte } func NewThumbnailer() *Thumbnailer { return &Thumbnailer{ Width: 100, Height: 100, MaxCacheSize: 10, thumbCache: make(map[string][]byte, 0), } } func (this *Thumbnailer) RenderFile(absPath string) ([]byte, error) { this.cacheMtx.RLock() tcache, ok := this.thumbCache[absPath] this.cacheMtx.RUnlock() if ok { return tcache, nil } // Add to cache tcache, err := this.RenderFile_NoCache(absPath) if err != nil { return nil, err } this.cacheMtx.Lock() // FIXME prune old cached thumbnails this.thumbCache[absPath] = tcache this.cacheMtx.Unlock() return tcache, nil } func (this *Thumbnailer) RenderFile_NoCache(absPath string) ([]byte, error) { fh, err := os.OpenFile(absPath, os.O_RDONLY, 0400) if err != nil { return nil, err } defer fh.Close() var src image.Image err = fmt.Errorf("No thumbnailer for file type") comparePath := strings.ToLower(absPath) if strings.HasSuffix(comparePath, "jpg") { src, err = jpeg.Decode(fh) } else if strings.HasSuffix(comparePath, "png") { src, err = png.Decode(fh) } if err != nil { return nil, err } return this.RenderScaledImage(src) }