Skip to content

Commit

Permalink
Add support for Meta request
Browse files Browse the repository at this point in the history
  • Loading branch information
n0vad3v committed Dec 7, 2024
1 parent 26f6b4a commit 7b62794
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 12 deletions.
17 changes: 16 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,22 @@ var (
DefaultAllowedTypes = []string{"jpg", "png", "jpeg", "bmp", "gif", "svg", "nef", "heic", "webp", "avif", "jxl"} // Default allowed image types
)

type ImageMeta struct {
Width int `json:"width"`
Height int `json:"height"`
Format string `json:"format"`
Size int `json:"size"`
NumPages int `json:"num_pages"`
Blurhash string `json:"blurhash"`
Colorspace string `json:"colorspace"`
}

type MetaFile struct {
Id string `json:"id"` // hash of below path️, also json file name id.webp
Path string `json:"path"` // local: path with width and height, proxy: full url
Checksum string `json:"checksum"` // hash of original file or hash(etag). Use this to identify changes

ImageMeta
}

type WebpConfig struct {
Expand Down Expand Up @@ -96,12 +108,15 @@ type WebpConfig struct {
}

func NewWebPConfig() *WebpConfig {
// Copy DefaultAllowedTypes to avoid modification
defaultAllowedTypes := make([]string, len(DefaultAllowedTypes))
copy(defaultAllowedTypes, DefaultAllowedTypes)
return &WebpConfig{
Host: "0.0.0.0",
Port: "3333",
ImgPath: "./pics",
Quality: 80,
AllowedTypes: DefaultAllowedTypes,
AllowedTypes: defaultAllowedTypes,
ConvertTypes: []string{"webp"},
ImageMap: map[string]string{},
ExhaustPath: "./exhaust",
Expand Down
17 changes: 9 additions & 8 deletions encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ func init() {
intMinusOne.Set(-1)
}

func LoadImage(filename string) (*vips.ImageRef, error) {
img, err := vips.LoadImageFromFile(filename, &vips.ImportParams{
FailOnError: boolFalse,
NumPages: intMinusOne,
})
return img, err
}

func ConvertFilter(rawPath, jxlPath, avifPath, webpPath string, extraParams config.ExtraParams, supportedFormats map[string]bool, c chan int) {
// Wait for the conversion to complete and return the converted image
retryDelay := 100 * time.Millisecond // Initial retry delay
Expand Down Expand Up @@ -122,14 +130,7 @@ func convertImage(rawPath, optimizedPath, imageType string, extraParams config.E
}

// Image is only opened here
img, err := vips.LoadImageFromFile(rawPath, &vips.ImportParams{
FailOnError: boolFalse,
NumPages: intMinusOne,
})
if err != nil {
log.Warnf("Can't open source image: %v", err)
return err
}
img, err := LoadImage(rawPath)
defer img.Close()

// Pre-process image(auto rotate, resize, etc.)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module webp_server_go
go 1.23

require (
github.com/buckket/go-blurhash v1.1.0
github.com/cespare/xxhash v1.1.0
github.com/davidbyttow/govips/v2 v2.15.0
github.com/gofiber/fiber/v2 v2.52.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
Expand Down
17 changes: 17 additions & 0 deletions handler/router.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package handler

import (
"fmt"
"net/http"
"net/url"
"regexp"
Expand Down Expand Up @@ -45,6 +46,8 @@ func Convert(c *fiber.Ctx) error {
proxyMode = config.ProxyMode
mapMode = false

meta = c.Query("meta") // Meta request

width, _ = strconv.Atoi(c.Query("width")) // Extra Params
height, _ = strconv.Atoi(c.Query("height")) // Extra Params
maxHeight, _ = strconv.Atoi(c.Query("max_height")) // Extra Params
Expand All @@ -70,6 +73,7 @@ func Convert(c *fiber.Ctx) error {
// Check if the file extension is allowed and not with image extension
// In this case we will serve the file directly
if helper.CheckAllowedExtension(filename) && !helper.CheckImageExtension(filename) {
fmt.Println("File extension is allowed and not with image extension")
return c.SendFile(path.Join(config.Config.ImgPath, reqURI))
}

Expand Down Expand Up @@ -147,6 +151,19 @@ func Convert(c *fiber.Ctx) error {
}
}

// If meta request, return the metadata
if meta == "full" {
return c.JSON(fiber.Map{
"height": metadata.ImageMeta.Height,
"width": metadata.ImageMeta.Width,
"size": metadata.ImageMeta.Size,
"format": metadata.ImageMeta.Format,
"colorspace": metadata.ImageMeta.Colorspace,
"num_pages": metadata.ImageMeta.NumPages,
"blurhash": metadata.ImageMeta.Blurhash,
})
}

supportedFormats := helper.GuessSupportedFormat(reqHeader)
// resize itself and return if only raw(original format) is supported
if supportedFormats["raw"] == true &&
Expand Down
6 changes: 6 additions & 0 deletions helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"slices"

"github.com/davidbyttow/govips/v2/vips"
"github.com/h2non/filetype"
"github.com/mileusna/useragent"

Expand All @@ -21,6 +22,11 @@ import (
log "github.com/sirupsen/logrus"
)

var (
boolFalse vips.BoolParameter
intMinusOne vips.IntParameter
)

var _ = filetype.AddMatcher(filetype.NewType("svg", "image/svg+xml"), svgMatcher)

func svgMatcher(buf []byte) bool {
Expand Down
21 changes: 18 additions & 3 deletions helper/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ func TestGuessSupportedFormat(t *testing.T) {
"raw": true,
"webp": true,
"avif": true,
"jxl": true,
"jxl": false,
"heic": true,
},
},
{
Expand All @@ -74,6 +75,7 @@ func TestGuessSupportedFormat(t *testing.T) {
"webp": true,
"avif": false,
"jxl": false,
"heic": false,
},
},
{
Expand All @@ -85,19 +87,32 @@ func TestGuessSupportedFormat(t *testing.T) {
"webp": true,
"avif": false,
"jxl": false,
"heic": false,
},
},
{
name: "Both Supported",
userAgent: "iPhone OS 16",
accept: "image/webp, image/avif",
expected: map[string]bool{"raw": true, "webp": true, "avif": true, "jxl": false},
expected: map[string]bool{
"raw": true,
"webp": true,
"avif": true,
"jxl": false,
"heic": false,
},
},
{
name: "No Supported Formats",
userAgent: "Unknown OS",
accept: "image/jpeg, image/gif",
expected: map[string]bool{"raw": true, "webp": false, "avif": false, "jxl": false},
expected: map[string]bool{
"raw": true,
"webp": false,
"avif": false,
"jxl": false,
"heic": false,
},
},
}

Expand Down
95 changes: 95 additions & 0 deletions helper/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"path"
"webp_server_go/config"

"github.com/buckket/go-blurhash"
"github.com/davidbyttow/govips/v2/vips"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -65,11 +67,104 @@ func WriteMetadata(p, etag string, subdir string) config.MetaFile {
data.Checksum = HashFile(filepath)
}

imageMeta := GetImageMeta(filepath)
data.ImageMeta = imageMeta

buf, _ := json.Marshal(data)
_ = os.WriteFile(path.Join(config.Config.MetadataPath, subdir, data.Id+".json"), buf, 0644)
return data
}

func GetImageMeta(filePath string) (metadata config.ImageMeta) {
boolFalse.Set(false)
intMinusOne.Set(-1)
img, err := vips.LoadImageFromFile(filePath, &vips.ImportParams{
FailOnError: boolFalse,
NumPages: intMinusOne,
})
if err != nil {
log.Warnf("Could not load %s: %s", filePath, err)
return metadata
}
defer img.Close()
var colorspace string
switch img.Interpretation() {
case vips.InterpretationSRGB:
colorspace = "sRGB"
case vips.InterpretationYXY:
colorspace = "YXY"
case vips.InterpretationFourier:
colorspace = "Fourier"
case vips.InterpretationGrey16:
colorspace = "Grey16"
case vips.InterpretationMatrix:
colorspace = "Matrix"
case vips.InterpretationScRGB:
colorspace = "scRGB"
case vips.InterpretationHSV:
colorspace = "HSV"
default:
colorspace = "Unknown"
}
// Get image size
height := img.Metadata().Height
width := img.Metadata().Width
numPages := img.Metadata().Pages
if numPages > 1 {
height = height / numPages
}
var imgFormat string
switch img.Format() {
case vips.ImageTypeJPEG:
imgFormat = "jpeg"
case vips.ImageTypePNG:
imgFormat = "png"
case vips.ImageTypeWEBP:
imgFormat = "webp"
case vips.ImageTypeAVIF:
imgFormat = "avif"
case vips.ImageTypeGIF:
imgFormat = "gif"
case vips.ImageTypeBMP:
imgFormat = "bmp"
default:
imgFormat = "unknown"
}

imgBytes, err := img.ToBytes()
if err != nil {
log.Error("Error in img.ToBytes", err)
return
}

metadata = config.ImageMeta{
Width: width,
Height: height,
Format: imgFormat,
Colorspace: colorspace,
NumPages: numPages,
Size: len(imgBytes),
}

// Get blurhash
_ = img.Thumbnail(32, 32, vips.InterestingAttention)
imageImage, err := img.ToImage(vips.NewDefaultExportParams())
if err != nil {
log.Error("Error in img.ToImage", err)
return
}

blurHash, err := blurhash.Encode(4, 3, imageImage)
if err != nil {
log.Error("Error in blurhash", err)
return
}

metadata.Blurhash = blurHash

return metadata
}

func DeleteMetadata(p string, subdir string) {
var id, _, _ = getId(p)
metadataPath := path.Join(config.Config.MetadataPath, subdir, id+".json")
Expand Down

0 comments on commit 7b62794

Please sign in to comment.