diff --git a/api/features/feature_routes.go b/api/features/feature_routes.go index 644f1ad2818cd5b37a3302c228c02aa900171e7e..2bd328ae8ead810c2c181c2be8cf0f37a8bd9159 100644 --- a/api/features/feature_routes.go +++ b/api/features/feature_routes.go @@ -5,6 +5,7 @@ import ( ) const MSC2448UploadRoute = "/_matrix/media/unstable/xyz.amorgan/upload" +const MSC2448AltRenderRoute = "/_matrix/media/unstable/io.t2bot.msc2448/blurhash/{blurhash:[^/]+}" func IsRoute(r *http.Request, route string) bool { uri := r.URL.Path diff --git a/api/unstable/blurhash_render.go b/api/unstable/blurhash_render.go new file mode 100644 index 0000000000000000000000000000000000000000..9c46c78c17bb6bb63094471ab6e5d720d0af77b3 --- /dev/null +++ b/api/unstable/blurhash_render.go @@ -0,0 +1,68 @@ +package unstable + +import ( + "bytes" + "image/png" + "net/http" + "strconv" + + "github.com/buckket/go-blurhash" + "github.com/gorilla/mux" + "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/api/r0" + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/util" +) + +func RenderBlurhash(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { + params := mux.Vars(r) + + hash := params["blurhash"] + + width := rctx.Config.Features.MSC2448Blurhash.MaxRenderWidth / 2 + height := rctx.Config.Features.MSC2448Blurhash.MaxRenderHeight / 2 + + wstr := r.URL.Query().Get("width") + hstr := r.URL.Query().Get("height") + + if wstr != "" { + i, err := strconv.Atoi(wstr) + if err != nil { + return api.BadRequest("width must be an integer") + } + width = i + } + if hstr != "" { + i, err := strconv.Atoi(hstr) + if err != nil { + return api.BadRequest("height must be an integer") + } + height = i + } + + if width > rctx.Config.Features.MSC2448Blurhash.MaxRenderWidth { + width = rctx.Config.Features.MSC2448Blurhash.MaxRenderWidth + } + if height > rctx.Config.Features.MSC2448Blurhash.MaxRenderHeight { + height = rctx.Config.Features.MSC2448Blurhash.MaxRenderHeight + } + + img, err := blurhash.Decode(hash, width, height, rctx.Config.Features.MSC2448Blurhash.Punch) + if err != nil { + rctx.Log.Error(err) + return api.InternalServerError("Unexpected error rendering blurhash") + } + buf := &bytes.Buffer{} + err = png.Encode(buf, img) + if err != nil { + rctx.Log.Error(err) + return api.InternalServerError("Unexpected error rendering blurhash") + } + + return &r0.DownloadMediaResponse{ + ContentType: "image/png", + Filename: "blurhash.png", + SizeBytes: int64(buf.Len()), + Data: util.BufferToStream(buf), // convert to stream to avoid console spam + } +} diff --git a/api/webserver/webserver.go b/api/webserver/webserver.go index 8b8506ffa7f75424c6ee946ac8d4516679ed4329..f2fa2f0f03b3505b63ff5c528a15281c56e5cc30 100644 --- a/api/webserver/webserver.go +++ b/api/webserver/webserver.go @@ -74,6 +74,7 @@ func Init() *sync.WaitGroup { appendToImportHandler := handler{api.RepoAdminRoute(custom.AppendToImport), "append_to_import", counter, false} stopImportHandler := handler{api.RepoAdminRoute(custom.StopImport), "stop_import", counter, false} versionHandler := handler{api.AccessTokenOptionalRoute(custom.GetVersion), "get_version", counter, false} + blurhashRenderHandler := handler{api.AccessTokenRequiredRoute(unstable.RenderBlurhash), "render_blurhash", counter, false} routes := make(map[string]route) // r0 is typically clients and v1 is typically servers. v1 is deprecated. @@ -140,6 +141,7 @@ func Init() *sync.WaitGroup { if config.Get().Features.MSC2448Blurhash.Enabled { routes[features.MSC2448UploadRoute] = route{"POST", uploadHandler} + routes[features.MSC2448AltRenderRoute] = route{"GET", blurhashRenderHandler} } for routePath, route := range routes { diff --git a/config.sample.yaml b/config.sample.yaml index 4b0f87f5bcc298b7fbcb7f3eb05525f517f29647..74c207757413688b46848643f224ead3ce2253da 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -402,7 +402,8 @@ featureSupport: # Whether or not this MSC is enabled for use in the media repo enabled: false - # Maximum dimensions for converting a blurhash to an image + # Maximum dimensions for converting a blurhash to an image. When no width and + # height options are supplied, the default will be half these values. maxWidth: 1024 maxHeight: 1024