Javascript Canvas: Bildpaket erzeugen
Mit Hilfe von Canvas kann JavaScript aus einem großen Bild ein Paket von kleineren Versionen erzeugen. Dafür wird das Bild in den Canvas geladen und dann in die verschiedenen Größen skaliert.
Responsives Bild-Paket mit Canvas erzeugen
Das HTML ist das Eingabefeld für den File-Upload sowie ein canvas-Element mit ein div-Element mit der id="output", in dem die verkleinerten Bilder angezeigt werden.
<input type="file" id="uploadedFile" name="" accept="image/*"> <canvas id="canvas"></canvas> <div id="output"></div>
Bild-Paket für img mit srcset und sizes
Diese Webseite ist wie folgt aufgebaut:
- Kleine Monitore bis 920px: Bilder in voller Breite.
- Dann drei Spalten, die Spalte für Bilder ist 880px breit.
- Ab Zwei Spalten können zu einer breiten Spalte zusammengelegt werden.
Bildschirmgröße | Bildbreite |
---|---|
Bis 920px | 100 % der Viewport-Breite |
Ab 921px+ | Bildbereich ist 880 px breit |
Ab 1440px+ | Bildbereich mit bis zu 1440px |
Das Skript
Das Originalbild wird eingelesen und davon vier Bildgrößen erzeugt. Jedes der vier erzeugten Bilder wird in einem HTML-Canvas-Element angezeigt und ein Download-Link für das Bild erzeugt.
Im Anschluß wird ein Button für den Download des Bildpakets als ZIP-Datei angezeigt. Verantwortlich für das Erzeugen des ZIP-Pakets ist JSZip v3.7.1 - A JavaScript class for generating and reading zip files <http://stuartk.com/jszip>
const sizes = [1360, 920, 640, 420]; // Bildgröße des Pakets geändert? Abfangen mit event delegation // und im array sizes ändern const imgsizes = document.querySelector(".imgsizes"); imgsizes.addEventListener ("change", (evt) => { if (evt.target.className === "sizes") { sizes[parseInt(evt.target.getAttribute("data-s-id"))] = parseInt(evt.target.value); } }) // Qualitätsfaktor für JPG-Komprimierung setzen let qualityFactor = 0.6; const quality = document.querySelector("#quality"); quality.addEventListener ("change", () => { qualityFactor = parseFloat(quality.value); }) const imageSources = []; // Hol das Datei-Input-Element const fileInput = document.getElementById('fileInput'); const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); function downloadAllImages() { // Array mit Bildquellen (URLs oder Daten-URLs) var zip = new JSZip(); const imgUrls = document.querySelectorAll("#output img"); imgUrls.forEach (elem => { imageSources.push(elem.src) }) console.log ("imageSources", imageSources); let count = 0; // Für jedes Bild einen Download-Prozess starten imageSources.forEach((src, index) => { // Erstellen eines unsichtbaren Link-Elements fetch (src) .then(response => response.blob()) .then(blob => { zip.file("image" + (index + 1) + ".jpg", blob); count++; if (count === imgUrls.length) { zip.generateAsync({ type: "blob"}) .then (function (content) { var link = document.createElement("a"); link.href = URL.createObjectURL(content); link.download = "images.zip"; link.click(); }); } }); }); } // Überwache die Änderungen des Datei-Inputs fileInput.addEventListener('change', (event) => { const file = event.target.files[0]; // Überprüfe, ob eine gültige Bilddatei hochgeladen wurde if (file && file.type.startsWith('image/')) { // Erzeuge eine temporäre URL für das Bild const imageURL = URL.createObjectURL(file); const fileName = file.name.split(".")[0]; // Erstelle ein neues Bild-Element const img = new Image(); img.src = imageURL; img.onload = () => { // Originalgröße des Bildes const originalWidth = img.width; const originalHeight = img.height; const collection = []; const ar = originalHeight / originalWidth; sizes.forEach(size => { const newWidth = size // neue Breite const newHeight = size * ar; // Höhe anhand Aspect Ratio console.log ("neue Größen", newWidth, newHeight); canvas.width = newWidth; canvas.height = newHeight; ctx.drawImage(img, 0, 0, newWidth, newHeight); URL.revokeObjectURL(imageURL); // Wenn die Breite des Bildes als Watermark ins Bild gesetzt werden soll if (document.querySelector("#sizing").checked) { const theString = size; ctx.fillStyle = 'cornflowerblue'; const fontSize = size / 20; ctx.font = `italic ${fontSize}pt Arial`; ctx.fillText(theString, 50,100); } // Canvas zu Data URL (JPG) konvertieren und anzeigen const dataUrl = canvas.toDataURL("image/jpeg", qualityFactor); // "0.6" ist die Bildqualität (zB 0.6 für 60%) console.log ("dataUrl", dataUrl, qualityFactor) // Größe der Base64-Zeichenkette berechnen, um Bildgröße anzuzeigen const fileSizeInBytes = Math.round((dataUrl.length * (3/4)) - ((dataUrl.match(/==$/) || dataUrl.match(/=$/)) ? 2 : 0)); // Berechnung der Dateigröße const fileSizeInKB = (fileSizeInBytes / 1024).toFixed(2); // Größe in KB berechnen // Neues Image-Element erzeugen und die Quelle auf die JPG-Data URL setzen const div = document.createElement("div"); const imgElement = document.createElement("img"); imgElement.src = dataUrl; imgElement.alt = `Bild in Größe ${size}x${newHeight}`; imgElement.width = size; imgElement.height = parseInt(newHeight); // Neues Bild ins Output-Div setzen div.appendChild(imgElement); const br = document.createElement("br"); div.appendChild(br); // Link für den Bilder-Download erzeugen // mit dem download-Attribut kann ein Dateiname für das Bild vergeben werden const downloadLink = document.createElement("a"); downloadLink.href = dataUrl; downloadLink.download = `${fileName}-${parseInt(size)}x${parseInt(newHeight)}.jpg`; // Dateiname festlegen downloadLink.textContent = `${fileName}-${parseInt(size)}x${parseInt(newHeight)}.jpg herunterladen (${fileSizeInKB} KB)`; div.appendChild(downloadLink); document.getElementById("output").appendChild(div); // Zeilenumbruch }); // Jetzt den Download-Link für ein zip-gepacktes Paket der Bilder einspielen document.querySelector(".download").style = "display:block"; document.querySelector("#download").addEventListener ("click", downloadAllImages); //document.getElementById('download').addEventListener('click', downloadZip); }; img.onerror = () => { console.error('Bild konnte nicht geladen werden.'); }; } else { console.log('Bitte eine gültige Bilddatei auswählen.'); } });