summaryrefslogtreecommitdiff
path: root/src/post/asset/loader_image.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/post/asset/loader_image.go')
-rw-r--r--src/post/asset/loader_image.go85
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)
+ }
+
+}