Beispiel:JS-canvas-pixel-manipulation-2.html
Aus SELFHTML-Wiki
<!DOCTYPE html> <html lang="de"> <head>
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" > <link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css" > <title>Bildmanipulation über Canvas</title> <style>
figure {
background: white; display: inline-block; text-align: center; border: 1px solid black; padding: 2px 5px; border-radius: 0 8px 8px; margin: 1em 0
}
figcaption {
font-family: "Arial", sans; font-size: 1.4em; font-weight: bold;
}
- notice {
background: #fcc; border: 2px solid red; border-radius: 0.3em; color: red; padding: 1em; text-align: center;
}
</style> <script>
document.addEventListener("DOMContentLoaded", function () {
"use strict";
var img = new Image(), imgData, main = document.querySelector("body > main:first-of-type"), notice = document.querySelector("#notice");
img.src = "//wiki.selfhtml.org/images/9/98/Nbg-drahtziehmuehle.png";
// Fehlermeldung img.addEventListener("error", function() { var p = document.createElement("p");
p.id = "notice"; p.innerHTML = "Die erforderliche Bilddatei konnte nicht geladen werden!";
main.appendChild(p); });
// Funktionalität einrichten img.addEventListener("load", function() {
var canvas = document.createElement("canvas"), cap = document.createElement("figcaption"), context, fig = document.createElement("figure"), p = document.createElement("p"), sel = document.createElement("select");
// Optionen ins <select> schreiben [ "Original", "Verrauscht", "Schwarzweiß", "Negativ", "Differenziert", "Rot", "Grün", "Blau", "Pixelig" ].forEach(function (val) { var op = document.createElement("option");
op.innerHTML = val; op.value = val;
sel.appendChild(op); });
// Auswahldialog p.innerHTML = "Sie können die Darstellung des Bildes durch folgende Filter verändern: ";
p.appendChild(sel);
// Dokumentinhalte aufbauen main.appendChild(p); main.appendChild(fig); fig.appendChild(cap); fig.appendChild(canvas);
// Bildfläche einrichten canvas.height = img.height; canvas.width = img.width;
context = canvas.getContext("2d");
// Originalbild zeichnen context.drawImage(img, 0, 0, img.width, img.height);
// originale Bilddaten speichern imgData = context.getImageData(0, 0, img.width, img.height);
// reduziere auf Ganzzahl zwischen 0 und 255 function byteRange (a) {
if (a > 255) { a = 255; }
if (a < 0) { a = 0; }
return Math.floor(a); }
// Bildmanipulation ausführen function applyFilter () { var data, mod, x, y, r, g, b, a, l, offset, delta, n;
// Bildüberschrift anpassen cap.innerHTML = sel.options[sel.selectedIndex].value;
// neue Bilddaten anlegen mod = context.createImageData(img.width, img.height);
// Bilddaten pixelweise abarbeiten for (x = 0; x < imgData.width; x++) {
for (y = 0; y < imgData.height; y++) {
offset = (imgData.width * y + x) * 4; r = imgData.data[offset]; // rot g = imgData.data[offset + 1]; // grün b = imgData.data[offset + 2]; // blau a = imgData.data[offset + 3]; // Transparenz l = 0.299*r + 0.587*g + 0.114*b; // (NTSC-Standard für Luminanz)
// jeweiligen Filter anwenden switch (sel.options[sel.selectedIndex].value) {
default: mod.data[offset] = r; mod.data[offset + 1] = g; mod.data[offset + 2] = b; mod.data[offset + 3] = a; break;
case "Verrauscht": mod.data[offset] = byteRange(r*.8 + 150*Math.random()); mod.data[offset + 1] = byteRange(g*.8 + 150*Math.random()); mod.data[offset + 2] = byteRange(b*.8 + 150*Math.random()); mod.data[offset + 3] = a; break;
case "Schwarzweiß": mod.data[offset] = byteRange(l); mod.data[offset + 1] = byteRange(l); mod.data[offset + 2] = byteRange(l); mod.data[offset + 3] = byteRange(a); break;
case "Negativ": mod.data[offset] = byteRange(255 - r); mod.data[offset + 1] = byteRange(255 - g); mod.data[offset + 2] = byteRange(255 - b); mod.data[offset + 3] = byteRange(a); break;
case "Differenziert": // 0 = r, 1 = g, 2= b [0, 1, 2].forEach(function (rgb) {
// 2*(rgb-rechts - rgb-links + rgb-oben - rgb-unten) +128 mod.data[offset + rgb] = byteRange( 2 * ( // rgb-rechts imgData.data[(imgData.width * (y-1) + x) * 4 + rgb] // rgb-links - imgData.data[(imgData.width * (y+1) + x) * 4 + rgb] // rgb-oben + imgData.data[(imgData.width * y + x-1) * 4 + rgb] // rgb-unten - imgData.data[(imgData.width * y + x+1) * 4 + rgb] ) + 128 ); });
// Transparenz mod.data[offset + 3] = imgData.data[offset + 3]; break;
case "Rot": mod.data[offset] = r; mod.data[offset + 1] = 0; mod.data[offset + 2] = 0; mod.data[offset + 3] = a; break;
case "Grün": mod.data[offset] = 0; mod.data[offset + 1] = g; mod.data[offset + 2] = 0; mod.data[offset + 3] = a; break;
case "Blau": mod.data[offset] = 0; mod.data[offset + 1] = 0; mod.data[offset + 2] = b; mod.data[offset + 3] = a; break;
case "Pixelig": // Pixel in Gruppen von n*n behandeln und // jedem Pixel den durchschnittlichen RGBa-Wert // dieser Gruppe geben: n = 5;
delta = { // Zähler für die tatsächliche Anzahl der Pixel im n*n-Quadrat c: 0, // Abstand zur linken oberen Ecke des n*n-Quadrates dx: 0, dy: 0, // RGBa-Werte r: 0, g: 0, b: 0, a: 0, // Offset in imgData für originalen RGB-Wert o: 0, // X-Koordinate der linken oberen Ecke des n*n-Quadrates x: Math.floor(x / n) * n, // Y-Koordinate der linken oberen Ecke des n*n-Quadrates y: Math.floor(y / n) * n };
while (delta.dy < n) {
while (delta.dx < n) {
// RGB-Werte dieses Pixels aufaddieren if (delta.x + delta.dx < imgData.width && delta.y + delta.dy < imgData.height ) {
// Offset eines Pixels im n*n-Raster delta.o = ( imgData.width * (delta.y + delta.dy) + delta.dx + delta.x ) * 4;
delta.c++;
delta.r += imgData.data[delta.o]; delta.g += imgData.data[delta.o + 1]; delta.b += imgData.data[delta.o + 2]; delta.a += imgData.data[delta.o + 3]; }
delta.dx++; }
delta.dx = 0; delta.dy++; }
mod.data[offset] = byteRange(delta.r / delta.c); mod.data[offset + 1] = byteRange(delta.g / delta.c); mod.data[offset + 2] = byteRange(delta.b / delta.c); mod.data[offset + 3] = byteRange(delta.a / delta.c); break; } } }
// veränderte Bilddaten ins Bild schreiben context.putImageData(mod, 0, 0); }
// auf Nutzereingaben reagieren sel.addEventListener("change", applyFilter);
applyFilter(); });
// Hinweis entfernen notice.parentNode.removeChild(notice);
});
</script>
</head>
<body>
Bildmanipulation über Canvas
<main>
Dieses Beispiel funktioniert nur mit JavaScript!
</main>
</body> </html>