Added support for several image formats

This includes:
- Gif
- jpeg
- avif
- webp
This commit is contained in:
SG-O 2022-07-08 04:13:17 +02:00
parent df1df4d110
commit 49da8a60f7
2 changed files with 105 additions and 3 deletions

View File

@ -36,6 +36,15 @@ export class MatrixLiteClient {
return baseUrl + `/_matrix/media/r0/thumbnail/${serverName}/${contentId}?width=${width}&height=${height}&method=${method}&animated=${isAnimated}`;
}
public async getMediaUrl(serverName: string, contentId: string): Promise<string> {
let baseUrl = config.homeserver.mediaUrl;
if (!baseUrl) baseUrl = config.homeserver.clientServerUrl;
if (baseUrl.endsWith("/")) baseUrl = baseUrl.substring(0, baseUrl.length - 1);
// DO NOT RETURN THE ACCESS TOKEN.
return baseUrl + `/_matrix/media/r0/download/${serverName}/${contentId}`;
}
public async whoAmI(): Promise<string> {
const response = await doClientApiCall(
"GET",
@ -106,6 +115,7 @@ export class MatrixLiteClient {
}
public async upload(content: Buffer, contentType: string): Promise<string> {
LogService.info("MatrixLiteClient", "Uploading file (type:" + contentType + ")");
return doClientApiCall(
"POST",
"/_matrix/media/r0/upload",
@ -126,6 +136,7 @@ export class MatrixLiteClient {
method: "GET",
url: url,
encoding: null,
headers: {},
}, (err, res, _body) => {
if (err) {
LogService.error("MatrixLiteClient", "Error downloading file from " + url);
@ -140,4 +151,48 @@ export class MatrixLiteClient {
});
});
}
public async parseMediaMIME(url: string): Promise<any> {
return new Promise((resolve, reject) => {
request({
method: "GET",
url: url,
encoding: null,
headers: {
'Range': 'bytes=0-16'
},
}, (err, res, _body) => {
if (err) {
LogService.error("MatrixLiteClient", "Error downloading file from " + url);
LogService.error("MatrixLiteClient", err);
reject(err);
} else if (res.statusCode !== 200) {
if (res.statusCode !== 206) {
LogService.error("MatrixLiteClient", "Got status code " + res.statusCode + " while calling url " + url);
reject(new Error("Error in request: invalid status code"));
}
} else {
return this.parseFileHeaderMIME(res.body);
}
});
});
}
public parseFileHeaderMIME(data: Buffer): string {
const s = data.slice(0,12);
if (s.slice(0,8).includes(Buffer.from("89504E470D0A1A0A", "hex"))) {
return("image/png");
} else if (s.slice(0,3).includes(Buffer.from("474946", "hex"))) {
return("image/gif");
} else if (s.slice(0,3).includes(Buffer.from("FFD8FF", "hex"))) {
return("image/jpeg");
} else if (s.slice(0,12).includes(Buffer.from("000000206674797061766966", "hex"))) {
return("image/avif");
} else if (s.slice(0,12).includes(Buffer.from("000000206674797061766973", "hex"))) {
return("image/avif-sequence");
} else if (s.slice(0,4).includes(Buffer.from("52494646", "hex")) && s.slice(8,12).includes(Buffer.from("57454250", "hex"))) {
return("image/webp");
}
return;
}
}

View File

@ -12,6 +12,7 @@ import { MatrixLiteClient } from "./MatrixLiteClient";
import { Cache, CACHE_STICKERS } from "../MemoryCache";
import { LicenseMap } from "../utils/LicenseMap";
import { OpenId } from "../models/OpenId";
import * as sharp from "sharp";
class _MatrixStickerBot {
@ -113,7 +114,53 @@ class _MatrixStickerBot {
const serverName = mxc.substring("mxc://".length).split("/")[0];
const contentId = mxc.substring("mxc://".length).split("/")[1];
stickerEvent.thumbMxc = await mx.uploadFromUrl(await mx.getThumbnailUrl(serverName, contentId, 512, 512, "scale", false), "image/png");
const url = await mx.getMediaUrl(serverName, contentId);
const downImage = await mx.downloadFromUrl(url);
var mime = mx.parseFileHeaderMIME(downImage);
if (!mime) continue;
const origImage = await sharp(downImage, {animated: true});
const metadata = await origImage.metadata();
var size = metadata.height;
if (metadata.width > metadata.height) {
metadata.width;
}
if (size > 512) size = 512;
const resizedImage = await origImage.resize({
width: size,
height: size,
fit: 'contain',
background: 'rgba(0,0,0,0)',
});
var imageUpload;
var thumbUpload;
if (mime === "image/png") {
imageUpload = await resizedImage.png().toBuffer();
thumbUpload = imageUpload;
}
if (mime === "image/gif" || mime === "image/webp" || mime === "image/avif-sequence") {
imageUpload = await resizedImage.webp({nearLossless: true, quality: 60}).toBuffer();
thumbUpload = await sharp(downImage, {animated: false}).resize({
width: size,
height: size,
fit: 'contain',
background: 'rgba(0,0,0,0)',
}).webp({quality: 60}).toBuffer();
mime = "image/webp";
}
if (mime === "image/avif") {
imageUpload = await resizedImage.clone().avif({quality: 70}).toBuffer();
thumbUpload = await resizedImage.avif({quality: 50, chromaSubsampling: '4:2:0'}).toBuffer();;
}
if (mime === "image/jpeg") {
imageUpload = await resizedImage.clone().jpeg({quality: 80, chromaSubsampling: '4:4:4'}).toBuffer();
thumbUpload = await resizedImage.avif({quality: 60, chromaSubsampling: '4:2:0'}).toBuffer();;
}
stickerEvent.contentUri = await mx.upload(imageUpload, mime);
stickerEvent.mimetype = mime;
stickerEvent.thumbMxc = await mx.upload(thumbUpload, mime);
stickerEvents.push(stickerEvent);
}
@ -142,7 +189,7 @@ class _MatrixStickerBot {
pack.description = "Matrix sticker pack created by " + authorDisplayName;
pack.license = license.name;
pack.licensePath = license.url;
if (stickerEvents.length > 0) pack.avatarUrl = stickerEvents[0].contentUri;
if (stickerEvents.length > 0) pack.avatarUrl = stickerEvents[0].thumbMxc;
await pack.save();
const existingStickers = await Sticker.findAll({where: {packId: pack.id}});
@ -157,7 +204,7 @@ class _MatrixStickerBot {
thumbnailMxc: stickerEvent.thumbMxc,
thumbnailWidth: 512,
thumbnailHeight: 512,
mimetype: "image/png",
mimetype: stickerEvent.mimetype,
});
}
}