diff options
author | Brian Picciano <mediocregopher@gmail.com> | 2023-04-15 21:35:06 +0200 |
---|---|---|
committer | Brian Picciano <mediocregopher@gmail.com> | 2023-04-17 04:17:45 +0200 |
commit | 5559e0134382a141f5edabdacf1dc81f12b55c27 (patch) | |
tree | 0cd897880e52572f1e12334dfe94535a140549ce /src/post/asset/loader_image.go | |
parent | 7872296b838f4d1b26c6a0a01d79d27fe5ab44cc (diff) |
Implement asset.Loader
This moved a bunch of logic out of http and into the asset package,
making it available for gmit too.
Diffstat (limited to 'src/post/asset/loader_image.go')
-rw-r--r-- | src/post/asset/loader_image.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/post/asset/loader_image.go b/src/post/asset/loader_image.go new file mode 100644 index 0000000..dc996a9 --- /dev/null +++ b/src/post/asset/loader_image.go @@ -0,0 +1,85 @@ +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) + } + +} |