Bilder Rotieren

This commit is contained in:
Moritz Utcke
2024-03-16 11:01:25 +07:00
parent c3d9913cc7
commit b45206290f
7 changed files with 71 additions and 27 deletions

View File

@@ -1,15 +1,16 @@
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { Enums } from "@ibcornelsen/database/client";
import { addNotification, updateNotification } from "@ibcornelsen/ui"; import { addNotification, updateNotification } from "@ibcornelsen/ui";
import { client } from "src/trpc"; import { client } from "src/trpc";
export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude: GebaeudeClient) { export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?: string })[], gebaeude_uid: string) {
if (images.length == 0) { if (images.length == 0) {
return images; return images;
} }
// Wenn Bilder hochgeladen werden konvertieren wir sie zu base64, das heißt, dass die base64 Eigenschaft bei diesen Bildern // Wenn Bilder hochgeladen werden konvertieren wir sie zu base64, das heißt, dass die base64 Eigenschaft bei diesen Bildern
// existiert. Das müssen wir TypeScript nur wissen lassen, damit es uns in Ruhe lässt. // existiert. Das müssen wir TypeScript nur wissen lassen, damit es uns in Ruhe lässt.
const imagesToUpload = images.filter(image => !image.uid) as unknown as { base64: string, kategorie: string, uid?: string }[]; const imagesToUpload = images.filter(image => !image.uid || image.update) as unknown as { base64: string, kategorie: string, uid?: string, update: boolean }[];
if (imagesToUpload.length == 0) { if (imagesToUpload.length == 0) {
return images; return images;
@@ -27,13 +28,21 @@ export async function bilderHochladen(images: (UploadedGebaeudeBild & { base64?:
const image = imagesToUpload[i]; const image = imagesToUpload[i];
try { try {
const response = await client.v1.bilder.upload.mutate({ if (image.update) {
base64: image.base64, await client.v1.bilder.update.mutate({
kategorie: image.kategorie, uid: image.uid as string,
gebaeude_uid: gebaeude.uid base64: image.base64,
}) kategorie: image.kategorie as Enums.BilderKategorie
})
image.uid = response.uid } else {
const response = await client.v1.bilder.upload.mutate({
base64: image.base64,
kategorie: image.kategorie as Enums.BilderKategorie,
gebaeude_uid
})
image.uid = response.uid
}
updateNotification(notification, { updateNotification(notification, {
dismissable: true, dismissable: true,

View File

@@ -37,7 +37,7 @@ export async function verbrauchsausweisWohnenSpeichern(
}, },
}); });
images = await bilderHochladen(images, gebaeude); images = await bilderHochladen(images, gebaeude.uid);
return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid }; return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
} catch (e) { } catch (e) {
@@ -57,7 +57,7 @@ export async function verbrauchsausweisWohnenSpeichern(
}, },
}); });
images = await bilderHochladen(images, gebaeude); images = await bilderHochladen(images, response.gebaeude_uid);
return response; return response;
} catch (e: any) { } catch (e: any) {

View File

@@ -270,7 +270,7 @@
</div> </div>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<div class="column"> <div class="column">
<span>Verbrauch</span> <span>Verbrauch *</span>
<input <input
name="verbrauch_1" name="verbrauch_1"
type="number" type="number"
@@ -280,7 +280,7 @@
/> />
</div> </div>
<div class="column"> <div class="column">
<span>Verbrauch</span> <span>Verbrauch *</span>
<input <input
name="verbrauch_2" name="verbrauch_2"
type="number" type="number"
@@ -290,7 +290,7 @@
/> />
</div> </div>
<div class="column"> <div class="column">
<span>Verbrauch</span> <span>Verbrauch *</span>
<input <input
name="verbrauch_3" name="verbrauch_3"
type="number" type="number"

View File

@@ -4,7 +4,7 @@ import { inferProcedureInput, inferProcedureOutput } from "@trpc/server";
export type UploadedGebaeudeBild = inferProcedureOutput< export type UploadedGebaeudeBild = inferProcedureOutput<
AppRouter["v1"]["verbrauchsausweisWohnen"]["get"] AppRouter["v1"]["verbrauchsausweisWohnen"]["get"]
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string }; >["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string, update?: boolean };
/** /**

View File

@@ -2,6 +2,7 @@
import UploadImages from "./UploadImages.svelte"; import UploadImages from "./UploadImages.svelte";
import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client"; import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client";
import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "./Ausweis/types"; import { GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "./Ausweis/types";
import { RotateCounterClockwise, Trash } from "radix-svelte-icons";
export let images: UploadedGebaeudeBild[] = []; export let images: UploadedGebaeudeBild[] = [];
export let max: number = 4; export let max: number = 4;
@@ -10,8 +11,24 @@
export let gebaeude: GebaeudeClient; export let gebaeude: GebaeudeClient;
export let kategorie: Enums.BilderKategorie export let kategorie: Enums.BilderKategorie
console.log(images); async function rotateImage(image: UploadedGebaeudeBild): Promise<UploadedGebaeudeBild> {
return new Promise((resolve, reject) => {
let img = new Image();
img.src = image.base64 ? image.base64 : `/bilder/${image.uid}.webp`;
img.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = img.height;
canvas.height = img.width;
ctx?.translate(img.height / 2, img.width / 2);
ctx?.rotate((-90 * Math.PI) / 180);
ctx?.drawImage(img, -img.width / 2, -img.height / 2);
image.base64 = canvas.toDataURL("image/webp");
image.update = true;
resolve(image)
};
})
}
</script> </script>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
@@ -23,20 +40,33 @@
<img <img
src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`} src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
alt={kategorie} alt={kategorie}
class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all" class="h-full max-h-96 w-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
/> />
<button <div class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-row gap-2">
<button
type="button" type="button"
class="invisible group-hover:visible absolute left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] rounded-full w-[30px] h-[30px] p-2 bg-[rgba(0,0,0,0.4)]" class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={() => { on:click={() => {
delete images[i]; delete images[i];
images = images.filter((x) => x); images = images.filter((x) => x);
}} }}
> >
R <Trash size={20} color="#fff"></Trash>
</button> </button>
<button
type="button"
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={async () => {
let image = await rotateImage(images[i]);
images[i] = image;
images = images
}}
>
<RotateCounterClockwise size={20} color="#fff"></RotateCounterClockwise>
</button>
</div>
</div> </div>
{/if} {/if}
{/each} {/each}
</div> </div>
</div> </div>

View File

@@ -26,6 +26,8 @@
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types"; import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types";
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern"; import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern";
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
// wenn gebaeude_aufnahme_allgemein oder gebaeude_stammdaten nicht existiert...
export let ausweis: VerbrauchsausweisWohnenClient; export let ausweis: VerbrauchsausweisWohnenClient;
export let user: BenutzerClient = {} as BenutzerClient; export let user: BenutzerClient = {} as BenutzerClient;

View File

@@ -1,24 +1,27 @@
--- ---
import AusweisLayout from "#layouts/AusweisLayout.astro"; import AusweisLayout from "#layouts/AusweisLayout.astro";
import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte"; import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte";
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { createCaller } from "#lib/caller"; import { createCaller } from "#lib/caller";
const uid = Astro.url.searchParams.get("uid"); const uid = Astro.url.searchParams.get("uid");
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient; let ausweis: VerbrauchsausweisWohnenClient = {
gebaeude_aufnahme_allgemein: { gebaeude_stammdaten: {} },
} as VerbrauchsausweisWohnenClient;
const caller = createCaller(Astro); const caller = createCaller(Astro);
if (uid) { if (uid) {
ausweis = await caller.v1.verbrauchsausweisWohnen.get({ ausweis = await caller.v1.verbrauchsausweisWohnen.get({
uid: uid uid: uid,
}) });
if (!ausweis) { if (!ausweis) {
// Der Ausweis scheint nicht zu existieren. // Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter. // Wir leiten auf die generische Ausweisseite ohne UID weiter.
return Astro.redirect("/energieausweis-erstellen/verbrauchsausweis-wohnen"); return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohnen"
);
} }
} }
--- ---