Skip to content

Commit

Permalink
resize image before storing (calcom#831)
Browse files Browse the repository at this point in the history
* resize image fn

* wip

* simplify transform

* comment

* fix

* rm log

* allow pass-through for non-base-64

Co-authored-by: Alex van Andel <[email protected]>
  • Loading branch information
KATT and emrysal authored Sep 30, 2021
1 parent e339626 commit 60298f6
Show file tree
Hide file tree
Showing 5 changed files with 511 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"handlebars": "^4.7.7",
"ical.js": "^1.4.0",
"ics": "^2.31.0",
"jimp": "^0.16.1",
"lodash.debounce": "^4.0.8",
"lodash.merge": "^4.6.2",
"lodash.throttle": "^4.1.1",
Expand Down
4 changes: 3 additions & 1 deletion pages/api/user/profile.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { resizeBase64Image } from "@server/lib/resizeBase64Image";
import { pick } from "lodash";
import type { NextApiRequest, NextApiResponse } from "next";

Expand All @@ -13,6 +14,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}

try {
const avatar = req.body.avatar ? await resizeBase64Image(req.body.avatar) : undefined;
await prisma.user.update({
where: {
id: session.user.id,
Expand All @@ -21,14 +23,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...pick(req.body, [
"username",
"name",
"avatar",
"timeZone",
"weekStart",
"hideBranding",
"theme",
"completedOnboarding",
"locale",
]),
avatar,
bio: req.body.description,
},
});
Expand Down
36 changes: 36 additions & 0 deletions server/lib/resizeBase64Image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import jimp from "jimp";

export async function resizeBase64Image(
base64OrUrl: string,
opts?: {
maxSize?: number;
}
) {
if (!base64OrUrl.startsWith("data:")) {
// might be a `https://` or something
return base64OrUrl;
}
const mimeMatch = base64OrUrl.match(/^data:(\w+\/\w+);/);
const mimetype = mimeMatch?.[1];
if (!mimetype) {
throw new Error(`Could not distinguish mimetype`);
}
const buffer = Buffer.from(base64OrUrl.replace(/^data:image\/\w+;base64,/, ""), "base64");

const {
// 96px is the height of the image on https://cal.com/peer
maxSize = 96 * 4,
} = opts ?? {};
const image = await jimp.read(buffer);
if (image.getHeight() !== image.getHeight()) {
// this could be handled later
throw new Error("Image is not a square");
}
const currentSize = Math.max(image.getWidth(), image.getHeight());
if (currentSize > maxSize) {
image.resize(jimp.AUTO, maxSize);
}
const newBuffer = await image.getBufferAsync(mimetype);

return `data:${mimetype};base64,${newBuffer.toString("base64")}`;
}
4 changes: 4 additions & 0 deletions server/routers/viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { checkRegularUsername } from "@lib/core/checkRegularUsername";
import slugify from "@lib/slugify";

import { createProtectedRouter } from "../createRouter";
import { resizeBase64Image } from "../lib/resizeBase64Image";

const checkUsername =
process.env.NEXT_PUBLIC_APP_URL === "https://cal.com" ? checkPremiumUsername : checkRegularUsername;
Expand Down Expand Up @@ -119,6 +120,9 @@ export const viewerRouter = createProtectedRouter()
}
}
}
if (input.avatar) {
data.avatar = await resizeBase64Image(input.avatar);
}

await prisma.user.update({
where: {
Expand Down
Loading

0 comments on commit 60298f6

Please sign in to comment.