16 Commits

Author SHA1 Message Date
bd09f93af1 make_archive.sh 2018-06-04 18:22:11 +12:00
f76b46a0d1 hgignore 2018-06-04 18:22:07 +12:00
6b2240f56e doc: update README 2018-06-04 17:56:56 +12:00
9a1d999cbd Removed tag release-1.0 2018-06-04 17:55:40 +12:00
db7e21a63c Added tag v0.1.0 for changeset efd7b4071770 2018-06-04 17:55:29 +12:00
5603cdd393 add compiletime build tag 'disableimagecrush' to remove cgo dependency 2018-06-04 17:41:07 +12:00
f0fe3685c2 Added tag v0.2.0 for changeset 292439a79182 2018-06-04 17:40:24 +12:00
394427d1b8 doc: README 2017-11-18 14:33:11 +13:00
9e7eca86b7 add height/width accessor methods 2017-11-18 13:26:07 +13:00
3378948eb2 doc: README 2017-11-18 13:10:52 +13:00
fb04e02c99 move files into top-level directory 2017-11-18 13:03:21 +13:00
05744a728e update tags 2017-11-17 12:01:43 +00:00
2791bc2cd7 thumbnailer: allow passing 0 as cache size 2017-11-18 12:52:53 +13:00
f89726198b thumbnailer: rename (unused) ASPECT_ constants 2017-11-18 12:52:42 +13:00
5b7b22bd95 thumbnailer: imports for previous 2017-11-18 12:52:24 +13:00
3905686363 thumbnailer: option to set custom mime type for file decoding 2017-11-18 12:52:17 +13:00
12 changed files with 102 additions and 30 deletions

2
.hgignore Normal file
View File

@@ -0,0 +1,2 @@
_dist/

5
.hgtags Normal file
View File

@@ -0,0 +1,5 @@
efd7b407177086c57e8c086605c2c8d1cee23840 release-1.0
292439a79182796c2f6277ef13ca179379b0fb88 v0.2.0
efd7b407177086c57e8c086605c2c8d1cee23840 v0.1.0
efd7b407177086c57e8c086605c2c8d1cee23840 release-1.0
0000000000000000000000000000000000000000 release-1.0

View File

@@ -5,6 +5,7 @@ import (
"image/gif"
"image/jpeg"
"image/png"
"mime"
"os"
"path/filepath"
"strings"
@@ -21,9 +22,10 @@ const (
OUTPUT_JPG OutputFormat = 3
OUTPUT__DEFAULT = OUTPUT_PNG_CRUSH
ASPECT_PADDED AspectFormat = 80
ASPECT_SVELTE AspectFormat = 81
ASPECT__DEFAULT = ASPECT_PADDED
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
@@ -42,35 +44,51 @@ type Thumbnailer struct {
afmt AspectFormat
sfmt ScaleFormat
thumbCache *lru.Cache // threadsafe
thumbCache *lru.Cache // threadsafe, might be nil
}
func NewThumbnailer(Width, Height, MaxCacheSize int) *Thumbnailer {
func NewThumbnailer(Width, Height int, MaxCacheSize uint) *Thumbnailer {
return NewThumbnailerEx(Width, Height, MaxCacheSize, OUTPUT__DEFAULT, ASPECT__DEFAULT, SCALEFMT__DEFAULT)
}
func NewThumbnailerEx(Width, Height, MaxCacheSize int, of OutputFormat, af AspectFormat, sf ScaleFormat) *Thumbnailer {
thumbCache, err := lru.New(MaxCacheSize)
if err != nil {
panic(err)
}
func NewThumbnailerEx(Width, Height int, MaxCacheSize uint, of OutputFormat, af AspectFormat, sf ScaleFormat) *Thumbnailer {
return &Thumbnailer{
ret := &Thumbnailer{
width: Width,
height: Height,
ofmt: of,
afmt: af,
sfmt: sf,
thumbCache: thumbCache,
thumbCache: nil,
}
if MaxCacheSize > 0 {
thumbCache, err := lru.New(int(MaxCacheSize))
if err != nil {
panic(err)
}
ret.thumbCache = thumbCache
}
return ret
}
func (this *Thumbnailer) Width() int {
return this.width
}
func (this *Thumbnailer) Height() int {
return this.height
}
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)
@@ -78,8 +96,11 @@ func (this *Thumbnailer) RenderFile(absPath string) ([]byte, error) {
return nil, err
}
if this.thumbCache != nil {
this.thumbCache.Add(absPath, thumb)
return thumb.([]byte), nil
}
return thumb, nil
}
func FiletypeSupported(ext string) bool {
@@ -92,18 +113,18 @@ func FiletypeSupported(ext string) bool {
}
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()
extension := strings.ToLower(filepath.Ext(absPath))
switch extension {
case ".jpg", ".jpeg":
if mimeType == `image/jpeg` {
src, err := jpeg.Decode(fh)
if err != nil {
return nil, err
@@ -111,7 +132,7 @@ func (this *Thumbnailer) RenderFile_NoCache(absPath string) ([]byte, error) {
return this.RenderScaledImage(src)
case ".png":
} else if mimeType == `image/png` {
src, err := png.Decode(fh)
if err != nil {
return nil, err
@@ -119,7 +140,7 @@ func (this *Thumbnailer) RenderFile_NoCache(absPath string) ([]byte, error) {
return this.RenderScaledImage(src)
case ".gif":
} else if mimeType == `image/gif` {
src, err := gif.Decode(fh)
if err != nil {
return nil, err
@@ -127,10 +148,10 @@ func (this *Thumbnailer) RenderFile_NoCache(absPath string) ([]byte, error) {
return this.RenderScaledImage(src)
case ".avi", ".mkv", ".mp4", ".ogm", ".wmv", ".flv", ".rm", ".rmvb":
} else if strings.HasPrefix(mimeType, `video/`) {
return this.RenderScaledFfmpeg(absPath)
default:
} else {
return nil, ErrUnsupportedFiletype
}

27
_dist/README.txt Normal file
View File

@@ -0,0 +1,27 @@
A thumbnailing library for Go.
Written in Go
Earlier versions of this project were vendored into `webdir`.
- Supports jpeg / png / gif files (internally) and video files (requires `ffmpeg` in `$PATH`)
- LRU cache of recent thumbnails for performance
- Scaling algorithms: Nearest-neighbour or bilinear
- Aspect ratio preserving (fit outside with image crop; fit inside with transparent background; fit inside with dimension reduction)
- Output formats: JPG (internal) or transparent PNG (via `go-imagequant`)
A standalone binary `mkthumb` is provided as a sample utility.
=CHANGELOG=
2018-05-04 0.2.1
- Add `disableimagecrush` build tag option to exclude cgo library dependency
2017-11-18 0.2.0
- Initial standalone release
- Feature: Decode input with specified mime type
- Feature: Allow passing zero as thumbnail cache size
2017-01-03 0.1.0
- Version of `thumbnail` vendored with `webdir` 1.0 (previously tagged as `release-1.0`)

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"os"
"code.ivysaur.me/webdir/thumbnail"
"code.ivysaur.me/thumbnail"
)
func main() {

View File

@@ -4,8 +4,6 @@ import (
"bytes"
"image"
"image/jpeg"
"code.ivysaur.me/imagequant"
)
func (this *Thumbnailer) RenderScaledImage(src image.Image) ([]byte, error) {
@@ -60,7 +58,7 @@ func (this *Thumbnailer) RenderScaledImage(src image.Image) ([]byte, error) {
switch this.ofmt {
case OUTPUT_PNG_CRUSH:
return crush(dest, imagequant.SPEED_FASTEST)
return crushFast(dest)
case OUTPUT_JPG:
buff := bytes.Buffer{}

View File

@@ -1,3 +1,5 @@
//+build !disableimagecrush
package thumbnail
import (
@@ -51,6 +53,10 @@ func rgb8PaletteToGoImage(w, h int, rgb8data []byte, pal color.Palette) image.Im
return ret
}
func crushFast(img image.Image) ([]byte, error) {
return crush(img, imagequant.SPEED_FASTEST)
}
func crush(img image.Image, speed int) ([]byte, error) {
width := img.Bounds().Max.X

12
imagecrush_disabled.go Normal file
View File

@@ -0,0 +1,12 @@
// +build disableimagecrush
package thumbnail
import (
"errors"
"image"
)
func crushFast(img image.Image) ([]byte, error) {
return nil, errors.New("Pngquant not compiled in")
}

1
make_archive.sh Executable file
View File

@@ -0,0 +1 @@
hg archive out.zip