From c6f18e91235d8757c5fd975f33f430c4171731c8 Mon Sep 17 00:00:00 2001
From: Travis Ralston <travpc@gmail.com>
Date: Thu, 10 Feb 2022 19:36:38 -0700
Subject: [PATCH] Support JPEG XL

Fixes https://github.com/turt2live/matrix-media-repo/issues/355
---
 CHANGELOG.md             |  1 +
 thumbnailing/i/jpegxl.go | 69 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 thumbnailing/i/jpegxl.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9223991e..c3cd6854 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 ### Added
 
 * New config option to set user agent when requesting URL previews.
+* Added support for `image/jxl` thumbnailing.
 
 ### Fixed
 
diff --git a/thumbnailing/i/jpegxl.go b/thumbnailing/i/jpegxl.go
new file mode 100644
index 00000000..7c46f0a3
--- /dev/null
+++ b/thumbnailing/i/jpegxl.go
@@ -0,0 +1,69 @@
+package i
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path"
+
+	"github.com/turt2live/matrix-media-repo/common/rcontext"
+	"github.com/turt2live/matrix-media-repo/thumbnailing/m"
+	"github.com/turt2live/matrix-media-repo/util"
+	"github.com/turt2live/matrix-media-repo/util/cleanup"
+)
+
+type jpegxlGenerator struct {
+}
+
+func (d jpegxlGenerator) supportedContentTypes() []string {
+	return []string{"image/jxl"}
+}
+
+func (d jpegxlGenerator) supportsAnimation() bool {
+	return false
+}
+
+func (d jpegxlGenerator) matches(img []byte, contentType string) bool {
+	return contentType == "image/jxl"
+}
+
+func (d jpegxlGenerator) GetOriginDimensions(b []byte, contentType string, ctx rcontext.RequestContext) (bool, int, int, error) {
+	return false, 0, 0, nil
+}
+
+func (d jpegxlGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) {
+	key, err := util.GenerateRandomString(16)
+	if err != nil {
+		return nil, errors.New("jpegxl: error generating temp key: " + err.Error())
+	}
+
+	tempFile1 := path.Join(os.TempDir(), "media_repo."+key+".1.jpegxl")
+	tempFile2 := path.Join(os.TempDir(), "media_repo."+key+".2.png")
+
+	defer os.Remove(tempFile1)
+	defer os.Remove(tempFile2)
+
+	f, err := os.OpenFile(tempFile1, os.O_RDWR|os.O_CREATE, 0640)
+	if err != nil {
+		return nil, errors.New("jpegxl: error writing temp jpegxl file: " + err.Error())
+	}
+	_, _ = f.Write(b)
+	cleanup.DumpAndCloseStream(f)
+
+	err = exec.Command("convert", tempFile1, tempFile2).Run()
+	if err != nil {
+		return nil, errors.New("jpegxl: error converting jpegxl file: " + err.Error())
+	}
+
+	b, err = ioutil.ReadFile(tempFile2)
+	if err != nil {
+		return nil, errors.New("jpegxl: error reading temp png file: " + err.Error())
+	}
+
+	return pngGenerator{}.GenerateThumbnail(b, "image/png", width, height, method, false, ctx)
+}
+
+func init() {
+	generators = append(generators, jpegxlGenerator{})
+}
-- 
GitLab