Compress ID/Schufa photos client-side before upload, raise server limit further
Server-side testing showed the 30mb express.json limit itself was fine for payloads up to 30MB, but real phone photos (15-25MB each, ×3 files) can still exceed that. Adds readFileAsCompressedDataUrl: downscales image uploads to max 1800px on the long edge at 0.82 JPEG quality via canvas before converting to a data URL — typically shrinks a multi-MB phone photo to a few hundred KB, which is more than sufficient resolution for a legible ID/Schufa scan. PDFs pass through uncompressed. Also raises the raw pre-upload size check to 25MB/file and the server body limit to 50mb as a safety margin for PDF-heavy cases the client-side compression doesn't touch.
This commit is contained in:
parent
8f4b985f79
commit
48fb4118fd
@ -39,7 +39,7 @@ export function createApp() {
|
||||
// versendet werden (keine separate Objekt-Storage-Anbindung in diesem
|
||||
// Demo-Stand). 10mb reichte für einzelne Fotos, war aber zu knapp für drei
|
||||
// hochauflösende Handyfotos in einem Request (HTTP 413).
|
||||
app.use(express.json({ limit: '30mb' }));
|
||||
app.use(express.json({ limit: '50mb' }));
|
||||
app.use('/v1', paymentsRouter);
|
||||
app.use('/v1', cockpitRouter);
|
||||
app.use('/v1', authRouter);
|
||||
|
||||
@ -1209,18 +1209,18 @@
|
||||
const password = document.getElementById('acceptPassword').value;
|
||||
const body = { fullName, password };
|
||||
if (isTenant) {
|
||||
const MAX_UPLOAD_BYTES = 8 * 1024 * 1024; // 8MB je Datei, reichlich Luft unter dem 30mb-Server-Limit für alle 3 Dateien zusammen
|
||||
const MAX_RAW_UPLOAD_BYTES = 25 * 1024 * 1024; // Rohdatei vor Komprimierung — Fotos werden verkleinert, PDFs bleiben wie sie sind
|
||||
const tooLarge = [idFrontInput.files[0], idBackInput.files[0], schufaInput.files[0]]
|
||||
.filter(f => f && f.size > MAX_UPLOAD_BYTES);
|
||||
.filter(f => f && f.size > MAX_RAW_UPLOAD_BYTES);
|
||||
if (tooLarge.length) {
|
||||
throw new Error(`Datei zu groß (max. 8 MB): ${tooLarge.map(f => f.name).join(', ')}. Bitte kleineres Foto/Scan wählen.`);
|
||||
throw new Error(`Datei zu groß (max. 25 MB): ${tooLarge.map(f => f.name).join(', ')}. Bitte kleineres Foto/Scan wählen.`);
|
||||
}
|
||||
body.phoneNumber = document.getElementById('acceptPhone').value.trim();
|
||||
body.firstResidenceAddress = document.getElementById('acceptFirstResidence').value.trim();
|
||||
body.idDocumentFrontUrl = await readFileAsDataUrl(idFrontInput.files[0]);
|
||||
body.idDocumentBackUrl = await readFileAsDataUrl(idBackInput.files[0]);
|
||||
body.idDocumentFrontUrl = await readFileAsCompressedDataUrl(idFrontInput.files[0], 1800, 0.82);
|
||||
body.idDocumentBackUrl = await readFileAsCompressedDataUrl(idBackInput.files[0], 1800, 0.82);
|
||||
if (schufaInput.files.length) {
|
||||
body.schufaDocumentUrl = await readFileAsDataUrl(schufaInput.files[0]);
|
||||
body.schufaDocumentUrl = await readFileAsCompressedDataUrl(schufaInput.files[0], 1800, 0.82);
|
||||
body.schufaDocumentDate = schufaDateInput.value;
|
||||
}
|
||||
}
|
||||
@ -2203,6 +2203,34 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Handyfotos (Ausweis, Schufa-Scan) können 15-25MB pro Bild groß sein —
|
||||
// als Data-URL im JSON-Body summiert sich das schnell über jedes sinnvolle
|
||||
// Server-Limit. Bilder werden daher vor dem Versand auf eine für Dokumente
|
||||
// mehr als ausreichende Auflösung herunterskaliert (PDFs bleiben unangetastet,
|
||||
// die sind i. d. R. schon kompakt).
|
||||
function readFileAsCompressedDataUrl(file, maxDimension, quality) {
|
||||
if (file.type === 'application/pdf') return readFileAsDataUrl(file);
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
let { width, height } = img;
|
||||
if (width > maxDimension || height > maxDimension) {
|
||||
const scale = maxDimension / Math.max(width, height);
|
||||
width = Math.round(width * scale);
|
||||
height = Math.round(height * scale);
|
||||
}
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
canvas.getContext('2d').drawImage(img, 0, 0, width, height);
|
||||
URL.revokeObjectURL(img.src);
|
||||
resolve(canvas.toDataURL('image/jpeg', quality || 0.82));
|
||||
};
|
||||
img.onerror = () => reject(new Error('Bild konnte nicht gelesen werden'));
|
||||
img.src = URL.createObjectURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
function renderInventoryPhotoPreview() {
|
||||
const preview = document.getElementById('inventoryPhotoPreview');
|
||||
preview.innerHTML = '';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user