Compare commits

...

4 Commits

4 changed files with 52 additions and 10 deletions

23
src/lib/server/image.ts Normal file
View File

@ -0,0 +1,23 @@
import sharp from "sharp";
/**
* Convert any [ArrayBuffer] containing image data to an [avif] [Blob].
* Also allows downscaling and lossy compression.
* Set either [width] or [height] to downscale while keeping the aspect ratio.
*/
export const image_to_avif = async (
data: ArrayBuffer,
width: number | undefined = undefined,
height: number | undefined = undefined,
quality: number = 50,
effort: number = 4,
): Promise<Blob> => {
const compressed: Buffer = await sharp(data)
.resize(width, height)
.avif({ quality: quality, effort: effort })
.toBuffer();
console.log(`image_to_avif: ${data.byteLength} Bytes -> ${compressed.length} Bytes`);
return new Blob([compressed]);
};

View File

@ -5,14 +5,12 @@
import type { LayoutData } from "./$types";
import { page } from "$app/stores";
import { Button, MenuDrawerIcon, UserIcon, Input, PasswordIcon, Card } from "$lib/components";
import { get_avatar_preview_event_handler, get_image_preview_event_handler } from "$lib/image";
import { Button, MenuDrawerIcon, UserIcon, Input, PasswordIcon } from "$lib/components";
import { get_avatar_preview_event_handler } from "$lib/image";
import {
AppBar,
popup,
storePopup,
type PopupSettings,
initializeStores,
Drawer,
getDrawerStore,

View File

@ -1,7 +1,7 @@
import { form_data_clean, form_data_ensure_keys, form_data_get_and_remove_id } from "$lib/form";
import { error, redirect } from "@sveltejs/kit";
import type { Actions } from "./$types";
import type { User } from "$lib/schema";
import { image_to_avif } from "$lib/server/image";
export const actions = {
create_profile: async ({ request, locals }): Promise<void> => {
@ -9,7 +9,7 @@ export const actions = {
form_data_ensure_keys(data, ["username", "password", "redirect_url"]);
// Confirm password lol
const record = await locals.pb.collection("users").create({
await locals.pb.collection("users").create({
username: data.get("username")?.toString(),
password: data.get("password")?.toString(),
passwordConfirm: data.get("password")?.toString(),
@ -30,7 +30,23 @@ export const actions = {
form_data_ensure_keys(data, ["redirect_url"]);
const id: string = form_data_get_and_remove_id(data);
const record: User = await locals.pb.collection("users").update(id, data);
if (data.has("avatar")) {
// Compress image
const compressed: Blob = await image_to_avif(
await (data.get("avatar") as File).arrayBuffer(),
256,
256,
);
// At most 20kB
if (compressed.size > 20000) {
error(400, "Avatar too large!");
}
data.set("avatar", compressed);
}
await locals.pb.collection("users").update(id, data);
redirect(303, data.get("redirect_url")?.toString() ?? "/");
},

View File

@ -1,6 +1,11 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit()]
plugins: [sveltekit()],
build: {
rollupOptions: {
external: ["sharp"],
},
},
});