A fast and simple blog backend.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
mediocre-blog/src/post/asset/loader_image.go

85 lines
1.7 KiB

package asset
import (
"bytes"
"fmt"
"image"
"image/jpeg"
"image/png"
"io"
"path/filepath"
"strings"
"golang.org/x/image/draw"
)
// IsImageResizable returns whether or not an image can be resized, based on its
// extension.
func IsImageResizable(path string) bool {
switch strings.ToLower(filepath.Ext(path)) {
case ".jpg", ".jpeg", ".png":
return true
default:
return false
}
}
type imageLoader struct {
loader Loader
}
// NewImageLoader wraps an existing Loader in order to perform various
// image-related transformations on any image assets being loaded. Non-image
// assets are loaded as-is.
func NewImageLoader(loader Loader) Loader {
return &imageLoader{loader}
}
func (l *imageLoader) Load(path string, into io.Writer, opts LoadOpts) error {
if opts.ImageWidth == 0 {
return l.loader.Load(path, into, opts)
}
if !IsImageResizable(path) {
return ErrCannotResize
}
buf := new(bytes.Buffer)
if err := l.loader.Load(path, buf, opts); err != nil {
return fmt.Errorf("loading image into buffer: %w", err)
}
img, format, err := image.Decode(buf)
if err != nil {
return fmt.Errorf("decoding image: %w", err)
}
maxWidth := float64(opts.ImageWidth)
imgRect := img.Bounds()
imgW, imgH := float64(imgRect.Dx()), float64(imgRect.Dy())
if imgW > maxWidth {
newH := imgH * maxWidth / imgW
newImg := image.NewRGBA(image.Rect(0, 0, int(maxWidth), int(newH)))
// Resize
draw.BiLinear.Scale(
newImg, newImg.Bounds(), img, img.Bounds(), draw.Over, nil,
)
img = newImg
}
switch format {
case "jpeg":
return jpeg.Encode(into, img, nil)
case "png":
return png.Encode(into, img)
default:
return fmt.Errorf("unknown image format %q", format)
}
}