Add thumbnailing for photo grids
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
_ "image/gif"
|
||||
"image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
)
|
||||
|
||||
func init() {
|
||||
thumbnailers = append(thumbnailers, &imageThumbnailer{})
|
||||
}
|
||||
|
||||
type imageThumbnailer struct{}
|
||||
|
||||
func (it *imageThumbnailer) CanHandle(ext string) bool {
|
||||
switch ext {
|
||||
case ".jpg", ".jpeg", ".png", ".gif":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (it *imageThumbnailer) Generate(src io.Reader, dst io.Writer, width int) error {
|
||||
img, _, err := image.Decode(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return jpeg.Encode(dst, resizeBox(img, width), &jpeg.Options{Quality: 80})
|
||||
}
|
||||
|
||||
// resizeBox downsamples src to the requested width using a box filter.
|
||||
// Aspect ratio is preserved. Upscaling is a no-op (returns src unchanged).
|
||||
// Each source pixel is visited exactly once; alpha is discarded.
|
||||
func resizeBox(src image.Image, width int) image.Image {
|
||||
b := src.Bounds()
|
||||
srcW, srcH := b.Dx(), b.Dy()
|
||||
if srcW <= width {
|
||||
return src
|
||||
}
|
||||
dstW := width
|
||||
dstH := srcH * width / srcW
|
||||
if dstH < 1 {
|
||||
dstH = 1
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
for y := 0; y < dstH; y++ {
|
||||
sy0 := y * srcH / dstH
|
||||
sy1 := (y + 1) * srcH / dstH
|
||||
if sy1 == sy0 {
|
||||
sy1 = sy0 + 1
|
||||
}
|
||||
for x := 0; x < dstW; x++ {
|
||||
sx0 := x * srcW / dstW
|
||||
sx1 := (x + 1) * srcW / dstW
|
||||
if sx1 == sx0 {
|
||||
sx1 = sx0 + 1
|
||||
}
|
||||
var r, g, bl, n uint64
|
||||
for sy := sy0; sy < sy1; sy++ {
|
||||
for sx := sx0; sx < sx1; sx++ {
|
||||
sr, sg, sb, _ := src.At(b.Min.X+sx, b.Min.Y+sy).RGBA()
|
||||
r += uint64(sr >> 8)
|
||||
g += uint64(sg >> 8)
|
||||
bl += uint64(sb >> 8)
|
||||
n++
|
||||
}
|
||||
}
|
||||
dst.SetRGBA(x, y, color.RGBA{
|
||||
R: uint8(r / n),
|
||||
G: uint8(g / n),
|
||||
B: uint8(bl / n),
|
||||
A: 255,
|
||||
})
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
Reference in New Issue
Block a user