104 lines
2.6 KiB
Go
104 lines
2.6 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/davidbyttow/govips/v2/vips"
|
|
log "github.com/sirupsen/logrus"
|
|
"reichard.io/imagini/graph/model"
|
|
)
|
|
|
|
/**
|
|
* Responsible for serving up static images / videos
|
|
**/
|
|
func (api *API) mediaHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
if path.Dir(r.URL.Path) != "/media" {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
// Acquire Width & Height Parameters
|
|
width, _ := strconv.Atoi(r.URL.Query().Get("width"))
|
|
|
|
// Pull out userID
|
|
authContext := r.Context().Value("auth").(*model.AuthContext)
|
|
rawUserID, _ := (*authContext.AccessToken).Get("sub")
|
|
userID := rawUserID.(string)
|
|
|
|
// Derive Path
|
|
fileName := path.Base(r.URL.Path)
|
|
folderPath := path.Join("/" + api.Config.DataPath + "/media/" + userID)
|
|
mediaPath := path.Join(folderPath + "/" + fileName)
|
|
|
|
// Check if File Exists
|
|
_, err := os.Stat(mediaPath)
|
|
if os.IsNotExist(err) {
|
|
log.Warn("[media] Image does not exist on disk")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
mediaFile, err := resizeAndConvertImage(mediaPath, width)
|
|
if err != nil {
|
|
log.Warn("[media] Image conversion failed:", err)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// TODO: Cache mediaFile
|
|
|
|
http.ServeContent(w, r, fileName, time.Time{}, bytes.NewReader(mediaFile))
|
|
}
|
|
|
|
func resizeAndConvertImage(path string, desiredWidth int) ([]byte, error) {
|
|
inputImage, err := vips.NewImageFromFile(path)
|
|
if err != nil {
|
|
return nil, errors.New("[media] Unable to read image")
|
|
}
|
|
|
|
// If we're viewing full image, we want full quality
|
|
desiredQuality := 100
|
|
|
|
// Do we need to scale?
|
|
if desiredWidth != 0 && inputImage.Width() > desiredWidth {
|
|
desiredQuality = 50
|
|
desiredScale := float64(desiredWidth) / float64(inputImage.Width())
|
|
err := inputImage.Resize(desiredScale, vips.KernelLanczos3)
|
|
if err != nil {
|
|
return nil, errors.New("[media] Unable to resize")
|
|
}
|
|
} else if inputImage.Format() == vips.ImageTypeJPEG {
|
|
// Return raw file
|
|
return ioutil.ReadFile(path)
|
|
}
|
|
|
|
// Return non-converted but scaled image
|
|
if inputImage.Format() == vips.ImageTypeJPEG {
|
|
imageBytes, _, err := inputImage.ExportNative()
|
|
return imageBytes, err
|
|
}
|
|
|
|
// Convert Alpha Channel to White (if applicable)
|
|
if inputImage.HasAlpha() {
|
|
inputImage.Flatten(&vips.Color{R: 255, G: 255, B: 255})
|
|
}
|
|
|
|
// Convert
|
|
ep := vips.NewJpegExportParams()
|
|
ep.Quality = desiredQuality
|
|
imageBytes, _, err := inputImage.ExportJpeg(ep)
|
|
return imageBytes, err
|
|
}
|