Logo in der Mitte des QR-Codes

Zur Wahl stehen zwei Quellen: das Logo der Installation aus dem
Erscheinungsbild oder ein eigenes je Code. Die Groesse ist zwischen 10 und
25 Prozent der Kantenlaenge einstellbar, hinter dem Bild liegt eine Flaeche
in der Hintergrundfarbe.

Mit Logo gilt die Fehlerkorrektur H, unabhaengig von der Auswahl — was das
Bild verdeckt, muss sie ausgleichen. Die Auswahl steht dann fest auf H und
sagt auch warum; heimlich geschieht das nicht. Ab 22 Prozent kommt eine
Warnung dazu.

Gerendert wird weiterhin serverseitig, damit Vorschau und Download
uebereinstimmen: das SVG bekommt ein eingebettetes Bild, das PNG wird mit
sharp zusammengesetzt. sharp lag ohnehin als Abhaengigkeit von Next im
Baum und steht jetzt ausdruecklich in der package.json.

Ein eigenes Logo gehoert zur Gestaltung, nicht zum Inhalt — es muss
trotzdem an den Code gehaengt werden. Sonst raeumt die Aufraeumroutine es
nach einem Tag weg und der Code verliert sein Bild.

Refs #8
This commit is contained in:
Florian Wilde
2026-08-21 03:22:36 +02:00
parent b96e9ddbe5
commit c06f87e6d9
21 changed files with 611 additions and 28 deletions
+25 -2
View File
@@ -13,7 +13,7 @@ import { assertDynamicPossible } from "@/lib/qr/request";
import { describeSlugProblem, normalizeSlug } from "@/lib/slug";
import { assertSlugAvailable } from "@/lib/slug-resolve";
import { getSettings } from "@/lib/settings";
import { attachUploads } from "@/lib/uploads";
import { attachUpload, attachUploads, detachUpload } from "@/lib/uploads";
import { QrRequestError } from "@/lib/qr/type-module";
export const dynamic = "force-dynamic";
@@ -133,6 +133,18 @@ export async function PATCH(
Object.assign(update, parsed.data.design);
}
// Ein eigenes Logo gehört zur Gestaltung, nicht zum Inhalt. Es muss
// trotzdem an den Code gehängt werden — sonst liegt die Datei herrenlos
// herum und wird nach einem Tag weggeräumt, mitsamt dem Logo im Code.
const logoVorher =
existing.logoSource === "upload" ? existing.logoUploadId : null;
const logoNachher =
parsed.data.design === undefined
? logoVorher
: parsed.data.design.logoSource === "upload"
? parsed.data.design.logoUploadId
: null;
/* ------------------------------------------------------- Kurz-Link */
const neuerSlug = parsed.data.slug?.trim();
@@ -225,7 +237,18 @@ export async function PATCH(
// Eine ausgetauschte Datei verliert dabei ihren Bezug zum Code und wird
// später als verwaist weggeräumt.
if (neueDateien !== null) {
await attachUploads(updated.id, neueDateien);
await attachUploads(
updated.id,
logoNachher ? [...neueDateien, logoNachher] : neueDateien,
);
} else if (logoNachher && logoNachher !== logoVorher) {
await attachUpload(updated.id, logoNachher);
}
// Ein abgelegtes oder ausgetauschtes Logo verliert seinen Bezug und wird
// später weggeräumt.
if (logoVorher && logoVorher !== logoNachher) {
await detachUpload(updated.id, logoVorher);
}
return Response.json({ code: toQrCodeDto(updated) });