Compare commits
4 Commits
fcf0ad4ad0
...
00a4019ae5
| Author | SHA1 | Date | |
|---|---|---|---|
| 00a4019ae5 | |||
| 5136946053 | |||
| 65b5a84379 | |||
| 1f8945235c |
23
src/lib/server/image.ts
Normal file
23
src/lib/server/image.ts
Normal 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]);
|
||||||
|
};
|
||||||
@ -5,14 +5,12 @@
|
|||||||
import type { LayoutData } from "./$types";
|
import type { LayoutData } from "./$types";
|
||||||
import { page } from "$app/stores";
|
import { page } from "$app/stores";
|
||||||
|
|
||||||
import { Button, MenuDrawerIcon, UserIcon, Input, PasswordIcon, Card } from "$lib/components";
|
import { Button, MenuDrawerIcon, UserIcon, Input, PasswordIcon } from "$lib/components";
|
||||||
import { get_avatar_preview_event_handler, get_image_preview_event_handler } from "$lib/image";
|
import { get_avatar_preview_event_handler } from "$lib/image";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AppBar,
|
AppBar,
|
||||||
popup,
|
|
||||||
storePopup,
|
storePopup,
|
||||||
type PopupSettings,
|
|
||||||
initializeStores,
|
initializeStores,
|
||||||
Drawer,
|
Drawer,
|
||||||
getDrawerStore,
|
getDrawerStore,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { form_data_clean, form_data_ensure_keys, form_data_get_and_remove_id } from "$lib/form";
|
import { form_data_clean, form_data_ensure_keys, form_data_get_and_remove_id } from "$lib/form";
|
||||||
import { error, redirect } from "@sveltejs/kit";
|
import { error, redirect } from "@sveltejs/kit";
|
||||||
import type { Actions } from "./$types";
|
import type { Actions } from "./$types";
|
||||||
import type { User } from "$lib/schema";
|
import { image_to_avif } from "$lib/server/image";
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
create_profile: async ({ request, locals }): Promise<void> => {
|
create_profile: async ({ request, locals }): Promise<void> => {
|
||||||
@ -9,7 +9,7 @@ export const actions = {
|
|||||||
form_data_ensure_keys(data, ["username", "password", "redirect_url"]);
|
form_data_ensure_keys(data, ["username", "password", "redirect_url"]);
|
||||||
|
|
||||||
// Confirm password lol
|
// Confirm password lol
|
||||||
const record = await locals.pb.collection("users").create({
|
await locals.pb.collection("users").create({
|
||||||
username: data.get("username")?.toString(),
|
username: data.get("username")?.toString(),
|
||||||
password: data.get("password")?.toString(),
|
password: data.get("password")?.toString(),
|
||||||
passwordConfirm: data.get("password")?.toString(),
|
passwordConfirm: data.get("password")?.toString(),
|
||||||
@ -30,7 +30,23 @@ export const actions = {
|
|||||||
form_data_ensure_keys(data, ["redirect_url"]);
|
form_data_ensure_keys(data, ["redirect_url"]);
|
||||||
const id: string = form_data_get_and_remove_id(data);
|
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() ?? "/");
|
redirect(303, data.get("redirect_url")?.toString() ?? "/");
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from "@sveltejs/kit/vite";
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit()],
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
external: ["sharp"],
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user