package thumbnail import ( "errors" "image/gif" "image/jpeg" "image/png" "mime" "os" "path/filepath" "strings" lru "github.com/hashicorp/golang-lru" ) type OutputFormat uint8 type AspectFormat uint8 type ScaleFormat uint8 const ( OUTPUT_PNG_CRUSH OutputFormat = 2 OUTPUT_JPG OutputFormat = 3 OUTPUT__DEFAULT = OUTPUT_PNG_CRUSH ASPECT_PAD_TO_DIMENSIONS AspectFormat = 80 ASPECT_RESPECT_MAX_DIMENSION_ONLY AspectFormat = 81 ASPECT_CROP_TO_DIMENSIONS AspectFormat = 82 ASPECT__DEFAULT = ASPECT_PAD_TO_DIMENSIONS SCALEFMT_NN ScaleFormat = 120 SCALEFMT_BILINEAR ScaleFormat = 121 SCALEFMT__DEFAULT = SCALEFMT_BILINEAR ) var ( ErrInvalidOption error = errors.New("Invalid format parameter") ErrUnsupportedFiletype error = errors.New("Unsupported filetype") ) type Thumbnailer struct { width int height int ofmt OutputFormat afmt AspectFormat sfmt ScaleFormat thumbCache *lru.Cache // threadsafe, might be nil } func NewThumbnailer(Width, Height int, MaxCacheSize uint) *Thumbnailer { return NewThumbnailerEx(Width, Height, MaxCacheSize, OUTPUT__DEFAULT, ASPECT__DEFAULT, SCALEFMT__DEFAULT) } func NewThumbnailerEx(Width, Height int, MaxCacheSize uint, of OutputFormat, af AspectFormat, sf ScaleFormat) *Thumbnailer { ret := &Thumbnailer{ width: Width, height: Height, ofmt: of, afmt: af, sfmt: sf, thumbCache: nil, } if MaxCacheSize > 0 { thumbCache, err := lru.New(int(MaxCacheSize)) if err != nil { panic(err) } ret.thumbCache = thumbCache } return ret } func (this *Thumbnailer) RenderFile(absPath string) ([]byte, error) { if this.thumbCache != nil { thumb, ok := this.thumbCache.Get(absPath) if ok { return thumb.([]byte), nil } } // Add to cache thumb, err := this.RenderFile_NoCache(absPath) if err != nil { return nil, err } if this.thumbCache != nil { this.thumbCache.Add(absPath, thumb) } return thumb, nil } func FiletypeSupported(ext string) bool { switch strings.ToLower(ext) { case ".jpg", ".jpeg", ".png", ".gif", ".avi", ".mkv", ".mp4", ".ogm", ".wmv", ".flv", ".rm", ".rmvb": return true default: return false } } func (this *Thumbnailer) RenderFile_NoCache(absPath string) ([]byte, error) { return this.RenderFile_NoCache_MimeType(absPath, mime.TypeByExtension(filepath.Ext(absPath))) } func (this *Thumbnailer) RenderFile_NoCache_MimeType(absPath, mimeType string) ([]byte, error) { fh, err := os.OpenFile(absPath, os.O_RDONLY, 0400) if err != nil { return nil, err } defer fh.Close() if mimeType == `image/jpeg` { src, err := jpeg.Decode(fh) if err != nil { return nil, err } return this.RenderScaledImage(src) } else if mimeType == `image/png` { src, err := png.Decode(fh) if err != nil { return nil, err } return this.RenderScaledImage(src) } else if mimeType == `image/gif` { src, err := gif.Decode(fh) if err != nil { return nil, err } return this.RenderScaledImage(src) } else if strings.HasPrefix(mimeType, `video/`) { return this.RenderScaledFfmpeg(absPath) } else { return nil, ErrUnsupportedFiletype } }