mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
feat: replace sharp with client-side icon resize (#1951)
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
"@tanstack/react-query": "^5.90.17",
|
||||
"alfaaz": "^1.1.0",
|
||||
"axios": "^1.13.5",
|
||||
"blueimp-load-image": "^5.16.0",
|
||||
"clsx": "^2.1.1",
|
||||
"emoji-mart": "^5.6.0",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -59,6 +60,7 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.16.0",
|
||||
"@tanstack/eslint-plugin-query": "^5.62.1",
|
||||
"@types/blueimp-load-image": "^5.16.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/katex": "^0.16.7",
|
||||
|
||||
@@ -1,20 +1,62 @@
|
||||
import api from "@/lib/api-client";
|
||||
import loadImage from "blueimp-load-image";
|
||||
import {
|
||||
AvatarIconType,
|
||||
IAttachment,
|
||||
} from "@/features/attachments/types/attachment.types.ts";
|
||||
|
||||
async function compressAndResizeIcon(
|
||||
file: File,
|
||||
type: AvatarIconType,
|
||||
): Promise<File> {
|
||||
const isPng = file.type === "image/png";
|
||||
|
||||
const { image: canvas } = await loadImage(file, {
|
||||
maxWidth: 300,
|
||||
maxHeight: 300,
|
||||
canvas: true,
|
||||
orientation: true,
|
||||
imageSmoothingQuality: "high",
|
||||
});
|
||||
|
||||
if (type === AvatarIconType.AVATAR || !isPng) {
|
||||
const ctx = (canvas as HTMLCanvasElement).getContext("2d")!;
|
||||
ctx.globalCompositeOperation = "destination-over";
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
}
|
||||
|
||||
const outputType = isPng ? "image/png" : "image/jpeg";
|
||||
|
||||
return new Promise<File>((resolve, reject) => {
|
||||
(canvas as HTMLCanvasElement).toBlob(
|
||||
(blob) => {
|
||||
if (!blob) {
|
||||
reject(new Error("Failed to compress image"));
|
||||
return;
|
||||
}
|
||||
resolve(new File([blob], file.name, { type: outputType }));
|
||||
},
|
||||
outputType,
|
||||
isPng ? undefined : 0.85,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export async function uploadIcon(
|
||||
file: File,
|
||||
type: AvatarIconType,
|
||||
spaceId?: string,
|
||||
): Promise<IAttachment> {
|
||||
const processed = await compressAndResizeIcon(file, type);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("type", type);
|
||||
if (spaceId) {
|
||||
formData.append("spaceId", spaceId);
|
||||
}
|
||||
formData.append("image", file);
|
||||
formData.append("image", processed);
|
||||
|
||||
return await api.post("/attachments/upload-image", formData, {
|
||||
headers: {
|
||||
|
||||
Reference in New Issue
Block a user