79 lines
3.7 KiB
JavaScript
79 lines
3.7 KiB
JavaScript
/**
|
||
* Verkleinert große Fotos, bevor sie hochgeladen werden (Handy-Fotos haben oft 5–15 MB).
|
||
* Das macht den Upload deutlich schneller. Ist etwas nicht möglich, wird die Originaldatei unverändert hochgeladen.
|
||
* Gilt für alle <input type="file"> auf der Seite; nur JPG/PNG über 1 MB, längste Seite höchstens 2400 px.
|
||
*/
|
||
(function () {
|
||
var MAX_SIDE = 2400, MIN_BYTES = 1024 * 1024, QUALITY = 0.82;
|
||
if (!window.DataTransfer || !window.HTMLCanvasElement || !window.URL) return;
|
||
|
||
function note(input, text) {
|
||
var el = input.parentNode && input.parentNode.querySelector('.upload-note');
|
||
if (!el) {
|
||
el = document.createElement('div');
|
||
el.className = 'upload-note';
|
||
el.style.cssText = 'font-size:.8rem;color:#64748b;margin-top:4px';
|
||
input.insertAdjacentElement('afterend', el);
|
||
}
|
||
el.textContent = text;
|
||
}
|
||
|
||
function shrink(file) {
|
||
return new Promise(function (resolve) {
|
||
if (!/^image\/(jpeg|png)$/.test(file.type) || file.size < MIN_BYTES) return resolve(file);
|
||
var url = URL.createObjectURL(file), img = new Image();
|
||
img.onerror = function () { URL.revokeObjectURL(url); resolve(file); };
|
||
img.onload = function () {
|
||
URL.revokeObjectURL(url);
|
||
var w = img.naturalWidth, h = img.naturalHeight, k = Math.min(1, MAX_SIDE / Math.max(w, h));
|
||
var c = document.createElement('canvas');
|
||
c.width = Math.round(w * k); c.height = Math.round(h * k);
|
||
var ctx = c.getContext('2d');
|
||
if (!ctx) return resolve(file);
|
||
ctx.fillStyle = '#fff';
|
||
ctx.fillRect(0, 0, c.width, c.height);
|
||
ctx.drawImage(img, 0, 0, c.width, c.height);
|
||
c.toBlob(function (blob) {
|
||
if (!blob || blob.size >= file.size) return resolve(file);
|
||
var name = file.name.replace(/\.(png|jpe?g)$/i, '') + '.jpg';
|
||
resolve(new File([blob], name, { type: 'image/jpeg', lastModified: file.lastModified }));
|
||
}, 'image/jpeg', QUALITY);
|
||
};
|
||
img.src = url;
|
||
});
|
||
}
|
||
|
||
document.addEventListener('change', function (e) {
|
||
var input = e.target;
|
||
if (!input || input.type !== 'file' || input.dataset.shrunk === '1' || !input.files || !input.files.length) return;
|
||
var files = Array.prototype.slice.call(input.files);
|
||
if (!files.some(function (f) { return /^image\/(jpeg|png)$/.test(f.type) && f.size >= MIN_BYTES; })) return;
|
||
note(input, 'Bilder werden für einen schnelleren Upload verkleinert …');
|
||
Promise.all(files.map(shrink)).then(function (out) {
|
||
try {
|
||
var dt = new DataTransfer();
|
||
out.forEach(function (f) { dt.items.add(f); });
|
||
input.dataset.shrunk = '1';
|
||
input.files = dt.files;
|
||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||
input.dataset.shrunk = '';
|
||
var before = files.reduce(function (s, f) { return s + f.size; }, 0), after = out.reduce(function (s, f) { return s + f.size; }, 0);
|
||
note(input, after < before ? 'Bilder verkleinert: ' + (before / 1048576).toFixed(1) + ' MB → ' + (after / 1048576).toFixed(1) + ' MB' : '');
|
||
} catch (err) { note(input, ''); }
|
||
});
|
||
}, true);
|
||
|
||
// Beim Absenden: Knopf sperren, damit nicht doppelt hochgeladen wird, und Fortschritt anzeigen
|
||
document.addEventListener('submit', function (e) {
|
||
var form = e.target;
|
||
if (!form || !form.querySelector || !form.querySelector('input[type=file]')) return;
|
||
var has = Array.prototype.some.call(form.querySelectorAll('input[type=file]'), function (i) { return i.files && i.files.length; });
|
||
if (!has) return;
|
||
setTimeout(function () {
|
||
if (e.defaultPrevented) return;
|
||
var b = form.querySelector('button[type=submit]');
|
||
if (b) { b.disabled = true; b.textContent = 'Wird hochgeladen …'; }
|
||
}, 0);
|
||
});
|
||
})();
|