diff --git a/examples/inventory_corporate.html b/examples/inventory_corporate.html
index 5496187..ed0e692 100644
--- a/examples/inventory_corporate.html
+++ b/examples/inventory_corporate.html
@@ -1203,6 +1203,40 @@ input.invalid, select.invalid, textarea.invalid {
reader.readAsDataURL(file);
}
+ // Compress image for email (much smaller)
+ function compressImageForEmail(dataUrl, callback) {
+ const img = new Image();
+ img.onload = function() {
+ const canvas = document.createElement('canvas');
+ const maxSize = 300; // Max 300x300 for email
+ let width = img.width;
+ let height = img.height;
+
+ // Scale down to max 300px
+ if (width > height) {
+ if (width > maxSize) {
+ height = height * (maxSize / width);
+ width = maxSize;
+ }
+ } else {
+ if (height > maxSize) {
+ width = width * (maxSize / height);
+ height = maxSize;
+ }
+ }
+
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0, width, height);
+
+ // Very low quality for email
+ callback(canvas.toDataURL('image/jpeg', 0.3));
+ };
+ img.src = dataUrl;
+ }
+
// Remove photo
window.removePhoto = function(fieldId) {
const preview = document.getElementById(fieldId);
@@ -1262,7 +1296,7 @@ input.invalid, select.invalid, textarea.invalid {
}
// Use setTimeout to allow UI to update before heavy processing
- setTimeout(function() {
+ setTimeout(async function() {
const data = getFormData();
// Build subject
@@ -1283,8 +1317,9 @@ input.invalid, select.invalid, textarea.invalid {
body += 'Versie: ' + CONFIG.version + '\n';
body += 'Datum: ' + formatDateTime(new Date()) + '\n\n';
- // Collect photos separately
+ // Collect photos separately and compress them
const photos = [];
+ const photoPromises = [];
Object.entries(data).forEach(([key, value]) => {
if (value && value !== '') {
@@ -1292,14 +1327,18 @@ input.invalid, select.invalid, textarea.invalid {
if (typeof value === 'string' && value.startsWith('data:image/')) {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
- // Extract extension from data URL (e.g., data:image/jpeg;base64,...)
- const mimeMatch = value.match(/data:image\/([a-z]+);/);
- const ext = mimeMatch ? mimeMatch[1] : 'jpg';
- photos.push({
- name: labelText,
- extension: ext,
- data: value
+
+ // Compress photo for email
+ const promise = new Promise((resolve) => {
+ compressImageForEmail(value, function(compressedData) {
+ resolve({
+ name: labelText,
+ extension: 'jpg',
+ data: compressedData
+ });
+ });
});
+ photoPromises.push(promise);
} else {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
@@ -1309,17 +1348,19 @@ input.invalid, select.invalid, textarea.invalid {
}
});
+ // Wait for all photos to be compressed
+ const compressedPhotos = await Promise.all(photoPromises);
+
body += '\n========================\n';
// Add photos section only if there are photos
- if (photos.length > 0) {
- body += '\nFOTO BIJLAGEN (BASE64)\n';
- body += '========================\n';
- body += 'Onderstaande foto\'s zijn gecodeerd in base64 formaat.\n';
- body += 'Kopieer de tekst tussen START en EINDE naar een base64 decoder\n';
- body += 'of gebruik een online tool zoals base64-image.de\n\n';
+ if (compressedPhotos.length > 0) {
+ body += '\nFOTO BIJLAGEN (BASE64 - verkleind voor email)\n';
+ body += '==============================================\n';
+ body += 'Foto\'s zijn verkleind naar 300x300px voor email.\n';
+ body += 'Voor originele kwaliteit, gebruik CSV export.\n\n';
- photos.forEach((photo, index) => {
+ compressedPhotos.forEach((photo, index) => {
const filename = photo.name.replace(/[^a-zA-Z0-9]/g, '_') + '.' + photo.extension;
body += '--- FOTO ' + (index + 1) + ': ' + filename + ' ---\n';
body += '>>> START BASE64 >>>\n';
@@ -1338,9 +1379,9 @@ input.invalid, select.invalid, textarea.invalid {
button.disabled = false;
}
- // Check if mailto URL is too long (most clients support ~2000 chars)
- if (mailto.length > 100000) {
- showToast('Email te groot door foto. Gebruik CSV export.', 'error');
+ // Check if mailto URL is too long
+ if (mailto.length > 64000) {
+ showToast('Email nog steeds te groot. Verklein foto of gebruik CSV.', 'error');
return;
}
diff --git a/examples/inventory_minimal.html b/examples/inventory_minimal.html
index 488ce79..e0e6af6 100644
--- a/examples/inventory_minimal.html
+++ b/examples/inventory_minimal.html
@@ -1234,6 +1234,40 @@ select {
reader.readAsDataURL(file);
}
+ // Compress image for email (much smaller)
+ function compressImageForEmail(dataUrl, callback) {
+ const img = new Image();
+ img.onload = function() {
+ const canvas = document.createElement('canvas');
+ const maxSize = 300; // Max 300x300 for email
+ let width = img.width;
+ let height = img.height;
+
+ // Scale down to max 300px
+ if (width > height) {
+ if (width > maxSize) {
+ height = height * (maxSize / width);
+ width = maxSize;
+ }
+ } else {
+ if (height > maxSize) {
+ width = width * (maxSize / height);
+ height = maxSize;
+ }
+ }
+
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0, width, height);
+
+ // Very low quality for email
+ callback(canvas.toDataURL('image/jpeg', 0.3));
+ };
+ img.src = dataUrl;
+ }
+
// Remove photo
window.removePhoto = function(fieldId) {
const preview = document.getElementById(fieldId);
@@ -1293,7 +1327,7 @@ select {
}
// Use setTimeout to allow UI to update before heavy processing
- setTimeout(function() {
+ setTimeout(async function() {
const data = getFormData();
// Build subject
@@ -1314,8 +1348,9 @@ select {
body += 'Versie: ' + CONFIG.version + '\n';
body += 'Datum: ' + formatDateTime(new Date()) + '\n\n';
- // Collect photos separately
+ // Collect photos separately and compress them
const photos = [];
+ const photoPromises = [];
Object.entries(data).forEach(([key, value]) => {
if (value && value !== '') {
@@ -1323,14 +1358,18 @@ select {
if (typeof value === 'string' && value.startsWith('data:image/')) {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
- // Extract extension from data URL (e.g., data:image/jpeg;base64,...)
- const mimeMatch = value.match(/data:image\/([a-z]+);/);
- const ext = mimeMatch ? mimeMatch[1] : 'jpg';
- photos.push({
- name: labelText,
- extension: ext,
- data: value
+
+ // Compress photo for email
+ const promise = new Promise((resolve) => {
+ compressImageForEmail(value, function(compressedData) {
+ resolve({
+ name: labelText,
+ extension: 'jpg',
+ data: compressedData
+ });
+ });
});
+ photoPromises.push(promise);
} else {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
@@ -1340,17 +1379,19 @@ select {
}
});
+ // Wait for all photos to be compressed
+ const compressedPhotos = await Promise.all(photoPromises);
+
body += '\n========================\n';
// Add photos section only if there are photos
- if (photos.length > 0) {
- body += '\nFOTO BIJLAGEN (BASE64)\n';
- body += '========================\n';
- body += 'Onderstaande foto\'s zijn gecodeerd in base64 formaat.\n';
- body += 'Kopieer de tekst tussen START en EINDE naar een base64 decoder\n';
- body += 'of gebruik een online tool zoals base64-image.de\n\n';
+ if (compressedPhotos.length > 0) {
+ body += '\nFOTO BIJLAGEN (BASE64 - verkleind voor email)\n';
+ body += '==============================================\n';
+ body += 'Foto\'s zijn verkleind naar 300x300px voor email.\n';
+ body += 'Voor originele kwaliteit, gebruik CSV export.\n\n';
- photos.forEach((photo, index) => {
+ compressedPhotos.forEach((photo, index) => {
const filename = photo.name.replace(/[^a-zA-Z0-9]/g, '_') + '.' + photo.extension;
body += '--- FOTO ' + (index + 1) + ': ' + filename + ' ---\n';
body += '>>> START BASE64 >>>\n';
@@ -1369,9 +1410,9 @@ select {
button.disabled = false;
}
- // Check if mailto URL is too long (most clients support ~2000 chars)
- if (mailto.length > 100000) {
- showToast('Email te groot door foto. Gebruik CSV export.', 'error');
+ // Check if mailto URL is too long
+ if (mailto.length > 64000) {
+ showToast('Email nog steeds te groot. Verklein foto of gebruik CSV.', 'error');
return;
}
diff --git a/examples/inventory_modern.html b/examples/inventory_modern.html
index c7ac6fb..20c76ef 100644
--- a/examples/inventory_modern.html
+++ b/examples/inventory_modern.html
@@ -1265,6 +1265,40 @@ input.invalid, select.invalid, textarea.invalid {
reader.readAsDataURL(file);
}
+ // Compress image for email (much smaller)
+ function compressImageForEmail(dataUrl, callback) {
+ const img = new Image();
+ img.onload = function() {
+ const canvas = document.createElement('canvas');
+ const maxSize = 300; // Max 300x300 for email
+ let width = img.width;
+ let height = img.height;
+
+ // Scale down to max 300px
+ if (width > height) {
+ if (width > maxSize) {
+ height = height * (maxSize / width);
+ width = maxSize;
+ }
+ } else {
+ if (height > maxSize) {
+ width = width * (maxSize / height);
+ height = maxSize;
+ }
+ }
+
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0, width, height);
+
+ // Very low quality for email
+ callback(canvas.toDataURL('image/jpeg', 0.3));
+ };
+ img.src = dataUrl;
+ }
+
// Remove photo
window.removePhoto = function(fieldId) {
const preview = document.getElementById(fieldId);
@@ -1324,7 +1358,7 @@ input.invalid, select.invalid, textarea.invalid {
}
// Use setTimeout to allow UI to update before heavy processing
- setTimeout(function() {
+ setTimeout(async function() {
const data = getFormData();
// Build subject
@@ -1345,8 +1379,9 @@ input.invalid, select.invalid, textarea.invalid {
body += 'Versie: ' + CONFIG.version + '\n';
body += 'Datum: ' + formatDateTime(new Date()) + '\n\n';
- // Collect photos separately
+ // Collect photos separately and compress them
const photos = [];
+ const photoPromises = [];
Object.entries(data).forEach(([key, value]) => {
if (value && value !== '') {
@@ -1354,14 +1389,18 @@ input.invalid, select.invalid, textarea.invalid {
if (typeof value === 'string' && value.startsWith('data:image/')) {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
- // Extract extension from data URL (e.g., data:image/jpeg;base64,...)
- const mimeMatch = value.match(/data:image\/([a-z]+);/);
- const ext = mimeMatch ? mimeMatch[1] : 'jpg';
- photos.push({
- name: labelText,
- extension: ext,
- data: value
+
+ // Compress photo for email
+ const promise = new Promise((resolve) => {
+ compressImageForEmail(value, function(compressedData) {
+ resolve({
+ name: labelText,
+ extension: 'jpg',
+ data: compressedData
+ });
+ });
});
+ photoPromises.push(promise);
} else {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
@@ -1371,17 +1410,19 @@ input.invalid, select.invalid, textarea.invalid {
}
});
+ // Wait for all photos to be compressed
+ const compressedPhotos = await Promise.all(photoPromises);
+
body += '\n========================\n';
// Add photos section only if there are photos
- if (photos.length > 0) {
- body += '\nFOTO BIJLAGEN (BASE64)\n';
- body += '========================\n';
- body += 'Onderstaande foto\'s zijn gecodeerd in base64 formaat.\n';
- body += 'Kopieer de tekst tussen START en EINDE naar een base64 decoder\n';
- body += 'of gebruik een online tool zoals base64-image.de\n\n';
+ if (compressedPhotos.length > 0) {
+ body += '\nFOTO BIJLAGEN (BASE64 - verkleind voor email)\n';
+ body += '==============================================\n';
+ body += 'Foto\'s zijn verkleind naar 300x300px voor email.\n';
+ body += 'Voor originele kwaliteit, gebruik CSV export.\n\n';
- photos.forEach((photo, index) => {
+ compressedPhotos.forEach((photo, index) => {
const filename = photo.name.replace(/[^a-zA-Z0-9]/g, '_') + '.' + photo.extension;
body += '--- FOTO ' + (index + 1) + ': ' + filename + ' ---\n';
body += '>>> START BASE64 >>>\n';
@@ -1400,9 +1441,9 @@ input.invalid, select.invalid, textarea.invalid {
button.disabled = false;
}
- // Check if mailto URL is too long (most clients support ~2000 chars)
- if (mailto.length > 100000) {
- showToast('Email te groot door foto. Gebruik CSV export.', 'error');
+ // Check if mailto URL is too long
+ if (mailto.length > 64000) {
+ showToast('Email nog steeds te groot. Verklein foto of gebruik CSV.', 'error');
return;
}
diff --git a/src/templates.py b/src/templates.py
index 86bdc42..742c3fc 100644
--- a/src/templates.py
+++ b/src/templates.py
@@ -1469,6 +1469,40 @@ JAVASCRIPT = """
reader.readAsDataURL(file);
}
+ // Compress image for email (much smaller)
+ function compressImageForEmail(dataUrl, callback) {
+ const img = new Image();
+ img.onload = function() {
+ const canvas = document.createElement('canvas');
+ const maxSize = 300; // Max 300x300 for email
+ let width = img.width;
+ let height = img.height;
+
+ // Scale down to max 300px
+ if (width > height) {
+ if (width > maxSize) {
+ height = height * (maxSize / width);
+ width = maxSize;
+ }
+ } else {
+ if (height > maxSize) {
+ width = width * (maxSize / height);
+ height = maxSize;
+ }
+ }
+
+ canvas.width = width;
+ canvas.height = height;
+
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(img, 0, 0, width, height);
+
+ // Very low quality for email
+ callback(canvas.toDataURL('image/jpeg', 0.3));
+ };
+ img.src = dataUrl;
+ }
+
// Remove photo
window.removePhoto = function(fieldId) {
const preview = document.getElementById(fieldId);
@@ -1528,7 +1562,7 @@ JAVASCRIPT = """
}
// Use setTimeout to allow UI to update before heavy processing
- setTimeout(function() {
+ setTimeout(async function() {
const data = getFormData();
// Build subject
@@ -1549,8 +1583,9 @@ JAVASCRIPT = """
body += 'Versie: ' + CONFIG.version + '\\n';
body += 'Datum: ' + formatDateTime(new Date()) + '\\n\\n';
- // Collect photos separately
+ // Collect photos separately and compress them
const photos = [];
+ const photoPromises = [];
Object.entries(data).forEach(([key, value]) => {
if (value && value !== '') {
@@ -1558,14 +1593,18 @@ JAVASCRIPT = """
if (typeof value === 'string' && value.startsWith('data:image/')) {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
- // Extract extension from data URL (e.g., data:image/jpeg;base64,...)
- const mimeMatch = value.match(/data:image\\/([a-z]+);/);
- const ext = mimeMatch ? mimeMatch[1] : 'jpg';
- photos.push({
- name: labelText,
- extension: ext,
- data: value
+
+ // Compress photo for email
+ const promise = new Promise((resolve) => {
+ compressImageForEmail(value, function(compressedData) {
+ resolve({
+ name: labelText,
+ extension: 'jpg',
+ data: compressedData
+ });
+ });
});
+ photoPromises.push(promise);
} else {
const label = document.querySelector(`label[for="${key}"]`);
const labelText = label ? label.textContent.replace('*', '').trim() : key;
@@ -1575,17 +1614,19 @@ JAVASCRIPT = """
}
});
+ // Wait for all photos to be compressed
+ const compressedPhotos = await Promise.all(photoPromises);
+
body += '\\n========================\\n';
// Add photos section only if there are photos
- if (photos.length > 0) {
- body += '\\nFOTO BIJLAGEN (BASE64)\\n';
- body += '========================\\n';
- body += 'Onderstaande foto\\'s zijn gecodeerd in base64 formaat.\\n';
- body += 'Kopieer de tekst tussen START en EINDE naar een base64 decoder\\n';
- body += 'of gebruik een online tool zoals base64-image.de\\n\\n';
+ if (compressedPhotos.length > 0) {
+ body += '\\nFOTO BIJLAGEN (BASE64 - verkleind voor email)\\n';
+ body += '==============================================\\n';
+ body += 'Foto\\'s zijn verkleind naar 300x300px voor email.\\n';
+ body += 'Voor originele kwaliteit, gebruik CSV export.\\n\\n';
- photos.forEach((photo, index) => {
+ compressedPhotos.forEach((photo, index) => {
const filename = photo.name.replace(/[^a-zA-Z0-9]/g, '_') + '.' + photo.extension;
body += '--- FOTO ' + (index + 1) + ': ' + filename + ' ---\\n';
body += '>>> START BASE64 >>>\\n';
@@ -1604,9 +1645,9 @@ JAVASCRIPT = """
button.disabled = false;
}
- // Check if mailto URL is too long (most clients support ~2000 chars)
- if (mailto.length > 100000) {
- showToast('Email te groot door foto. Gebruik CSV export.', 'error');
+ // Check if mailto URL is too long
+ if (mailto.length > 64000) {
+ showToast('Email nog steeds te groot. Verklein foto of gebruik CSV.', 'error');
return;
}