2024-09-24 11:01:33 +00:00
|
|
|
package mediaprovider
|
|
|
|
|
|
|
|
import (
|
2024-09-25 15:08:43 +00:00
|
|
|
"bytes"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"image"
|
|
|
|
"image/jpeg"
|
|
|
|
"image/png"
|
2024-09-24 11:01:33 +00:00
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/gabriel-vasile/mimetype"
|
2024-09-25 15:08:43 +00:00
|
|
|
"github.com/gen2brain/avif"
|
|
|
|
"golang.org/x/image/draw"
|
|
|
|
"golang.org/x/image/webp"
|
2024-09-24 11:01:33 +00:00
|
|
|
)
|
|
|
|
|
2024-09-25 15:08:43 +00:00
|
|
|
var ErrUnknownImageType = errors.New("unknown image format")
|
|
|
|
|
2024-09-24 11:01:33 +00:00
|
|
|
func Compress(dataReader io.Reader, mimeType *string) (io.Reader, error) {
|
2024-10-30 15:05:20 +00:00
|
|
|
// TODO: Get inspired by GTS and use wasm ffmpeg (https://codeberg.org/gruf/go-ffmpreg) for compression
|
2024-09-24 11:01:33 +00:00
|
|
|
data, err := io.ReadAll(dataReader)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if mimeType == nil {
|
|
|
|
*mimeType = mimetype.Detect(data).String()
|
|
|
|
}
|
|
|
|
uberType, subType, _ := strings.Cut(*mimeType, "/")
|
|
|
|
var dataOut []byte
|
|
|
|
switch uberType {
|
|
|
|
case "text":
|
|
|
|
case "application":
|
|
|
|
case "image":
|
2024-09-25 15:08:43 +00:00
|
|
|
dataOut, err = compressImage(data, subType, 1280, 720)
|
2024-09-24 11:01:33 +00:00
|
|
|
case "video":
|
|
|
|
dataOut, err = compressVideo(data, subType)
|
|
|
|
case "audio":
|
|
|
|
case "font":
|
|
|
|
default:
|
|
|
|
}
|
2024-09-25 15:08:43 +00:00
|
|
|
if err != nil && err != ErrUnknownImageType {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
dataOut = compressBase64(dataOut)
|
|
|
|
return bytes.NewReader(dataOut), nil
|
2024-09-24 11:01:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func compressVideo(dataIn []byte, subType string) (dataOut []byte, err error) {
|
|
|
|
// TODO: Implement me
|
|
|
|
panic("Implement me")
|
|
|
|
}
|
2024-09-25 15:08:43 +00:00
|
|
|
|
2024-10-30 15:05:20 +00:00
|
|
|
func compressImage(
|
|
|
|
dataIn []byte,
|
|
|
|
subType string,
|
|
|
|
maxSizeX, maxSizeY uint,
|
|
|
|
) (dataOut []byte, err error) {
|
2024-09-25 15:08:43 +00:00
|
|
|
imageSize := image.Rect(0, 0, int(maxSizeX), int(maxSizeY))
|
|
|
|
dst := image.NewRGBA(imageSize)
|
|
|
|
var sourceImage image.Image
|
|
|
|
switch subType {
|
|
|
|
case "png":
|
|
|
|
sourceImage, err = png.Decode(bytes.NewReader(dataIn))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case "jpg", "jpeg":
|
|
|
|
sourceImage, err = jpeg.Decode(bytes.NewReader(dataIn))
|
|
|
|
case "webp":
|
|
|
|
sourceImage, err = webp.Decode(bytes.NewReader(dataIn))
|
|
|
|
case "avif":
|
|
|
|
sourceImage, err = avif.Decode(bytes.NewReader(dataIn))
|
|
|
|
default:
|
|
|
|
return nil, ErrUnknownImageType
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
draw.CatmullRom.Scale(dst, imageSize, sourceImage, sourceImage.Bounds(), draw.Src, nil)
|
|
|
|
return dst.Pix, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func compressBase64(dataIn []byte) []byte {
|
|
|
|
result := []byte{}
|
|
|
|
base64.StdEncoding.Encode(result, dataIn)
|
|
|
|
return result
|
|
|
|
}
|