thumbnail/scaler.go

123 lines
2.6 KiB
Go

package thumbnail
import (
"bytes"
"image"
"image/jpeg"
"image/png"
"golang.org/x/image/bmp"
"golang.org/x/image/draw"
)
func (this *DirectThumbnailer) scaleImage(src image.Image) (image.Image, error) {
srcW := src.Bounds().Max.X
srcH := src.Bounds().Max.Y
var srcCopyPosition, destCopyPosition image.Rectangle
switch this.cfg.Aspect {
case FitInside:
var destW, destH int
if srcW > srcH {
destW = this.cfg.Width
destH = this.cfg.Height * srcH / srcW
} else {
destW = this.cfg.Width * srcW / srcH
destH = this.cfg.Height
}
offsetX := (this.cfg.Width - destW) / 2
offsetY := (this.cfg.Height - destH) / 2
srcCopyPosition = src.Bounds()
destCopyPosition = image.Rect(offsetX, offsetY, destW+offsetX, destH+offsetY)
case FitOutside:
var srcSmallestDim, offsetX, offsetY int
if srcW > srcH {
// Landscape
srcSmallestDim = srcH
offsetY = 0
offsetX = (srcW - srcH) / 2
} else {
// Portrait (or square)
srcSmallestDim = srcW
offsetY = (srcH - srcW) / 2
offsetX = 0
}
srcCopyPosition = image.Rect(offsetX, offsetY, srcSmallestDim+offsetX, srcSmallestDim+offsetY)
destCopyPosition = image.Rect(0, 0, this.cfg.Width, this.cfg.Height)
case Stretch:
srcCopyPosition = src.Bounds()
destCopyPosition = image.Rect(0, 0, this.cfg.Width, this.cfg.Height)
default:
return nil, ErrInvalidOption
}
//
dest := image.NewRGBA(image.Rect(0, 0, this.cfg.Width, this.cfg.Height))
// For a transparent destination, Op.Src is faster than Op.Over
switch this.cfg.Scale {
case NearestNeighbour:
draw.NearestNeighbor.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)
case BilinearFast:
draw.ApproxBiLinear.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)
case BilinearAccurate:
draw.BiLinear.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)
case Bicubic:
draw.CatmullRom.Scale(dest, destCopyPosition, src, srcCopyPosition, draw.Src, nil)
}
return dest, nil
}
func (this *DirectThumbnailer) encode(dest image.Image) ([]byte, error) {
switch this.cfg.Output {
case Png:
buff := bytes.Buffer{}
err := png.Encode(&buff, dest)
if err != nil {
return nil, err
}
return buff.Bytes(), nil
case PngCrush:
return crushFast(dest)
case Jpeg:
buff := bytes.Buffer{}
err := jpeg.Encode(&buff, dest, &jpeg.Options{Quality: jpeg.DefaultQuality})
if err != nil {
return nil, err
}
return buff.Bytes(), nil
case Bmp:
buff := bytes.Buffer{}
err := bmp.Encode(&buff, dest)
if err != nil {
return nil, err
}
return buff.Bytes(), nil
default:
return nil, ErrInvalidOption
}
}