Das HTML5-Element <canvas>
enthält keine Methode zum Blurren. Soll die
Funktionalität hinzugefügt werden, muss hierfür eine eigene Routine implementiert werden.
Im Folgenden wird ein mögliche Umsetzung vorgestellt.
Das Script stellt ein Objekt zur Verfügung über das die blur-Funktionalität erreichbar ist.
Beim Initialisieren wird ein Options-Objekt übergeben, über das verschiedene Eigenschaften beeinflusst werden können.
objAPI = qpCanvas(optionen);
ID des canvas-Elements
Datentyp: string
Gewünschte Breite des canvas-Elements (optional)
Datentyp: integer
Gewünschte Höhe des canvas-Elements (optional)
Datentyp: integer
true = es werden die Optionen zum Initialisieren des canvas-Elements verwendet (w
, h
),
false = es werden externe Eigenschaften verwendet (CSS, Attribute width/height usw.)
Datentyp: boolean
Beim Initialisieren wird eine Referenz zurückgeliefert. Diese bietet Zugriff auf die API des Objektes.
Zugriff auf die API kann auch über die Punktnotation erfolgen.
zum Blurren des canvas-Inhalts
Datentyp: function
Einfügen eines Bildes in den Kontext, dessen Quelle in strSrc
übergeben wird.
Ausserdem werden die Startkoordinaten in x
und y
übergeben.
Datentyp: function
Ermitteln eines Pixels mit den Koordinaten (x
, y
).
Rückgabe ist ein Array mit [0]:rot, [1]:grün, [2]:blau, [3]:alpha
Datentyp: function
Macht schrittweise die Blur-Schritte rückgängig
Datentyp: function
Der nachstehende Quellcode zeigt, wie das Objekt im onload
-Event initialisiert wird.
window.onload = function(){ objAPI = qpCanvas({ id: 'canvas_id', w: 100, h: 100 }).insertImg("distel.jpg", 0, 0); }
Über die zurückgegebene Referenz objAPI
kann später auf die API zugegriffen werden, zum Beispiel:
objAPI.blur();
/* ****************************************************************************************** * * Das Script kann frei verwendet werden, dieser Kommentar sowie die Nennung des Nicks * müssen jedoch erhalten bleiben. * * Quaese (www.quaese.de), 2010 * ****************************************************************************************** */ function qpCanvas(objOpts){ var opts = { cvs: null, ctx: null, w: 400, h: 300, id: null, init: true, stack: [] }; for(strKey in objOpts){ opts[strKey] = objOpts[strKey]; } var _this = this; var init = function(){ if((typeof opts.id == "undefined") || (opts.id==null) || (document.getElementById(opts.id)==null)){ alert('keine gültige ID'); return; } opts.cvs = document.getElementById(opts.id); if(opts.cvs.getContext){ opts.ctx = opts.cvs.getContext("2d"); // Falls das canvas-Element über die Optionen initialisiert werden soll if(opts.init){ opts.cvs.style.width = opts.w + "px"; opts.cvs.style.height = opts.h + "px"; }else{ if(window.getComputedStyle){ opts.w = parseInt(window.getComputedStyle(opts.cvs, null)['width']); opts.h = parseInt(window.getComputedStyle(opts.cvs, null)['height']); }else if(opts.cvs.currentStyle){ opts.w = parseInt(opts.cvs.currentStyle['width']); opts.h = parseInt(opts.cvs.currentStyle['height']); } } opts.cvs.width = opts.w; opts.cvs.height = opts.h; // Context bequemer zugänglich machen ctx = opts.ctx; // Hilfskomponente für Contextinhalt initialisieren opts.tmp = null; } } // Methode zum Ermitteln eines Pixels (weniger performant als nachfolgende Variante) // x - (integer) Spaltenwert // y - (integer) Zeilenwert // Rückgabe: (array) Pixel, mit [0]:rot, [1]:grün, [2]:blau, [3]:alpha opts.getPixel__ = function(x, y){ // Falls die benötigte Methode nicht verfügbar ist if(typeof ctx.getImageData != "function") return opts; var objImageData = ctx.getImageData(x, y, 1, 1); return objImageData.data; } // Methode zum Ermitteln eines Pixels (performanter als obige Variante) // x - Spaltenwert // y - Zeilenwert // Rückgabe: (array) Pixel, mit [0]:rot, [1]:grün, [2]:blau, [3]:alpha opts.getPixel = function(x, y){ var blnNull = false; // Falls kein ImageData-Objekt existiert if(opts.tmp == null){ // Falls die benötigte Methode nicht verfügbar ist if(typeof ctx.getImageData != "function") return opts; // Temp. ImageData-Objekt erstellen opts.tmp = ctx.getImageData(0, 0, opts.cvs.width, opts.cvs.height); // Markieren, dass ein temp. ImageData-Objekt erstellt wurde blnNull = true; } //var z = y*(opts.w-1)*4; var z = y*opts.w*4; var s = 4*x; var oPxl = [opts.tmp.data[z + s], opts.tmp.data[z + s +1], opts.tmp.data[z + s + 2], opts.tmp.data[z + s + 3]]; // Falls ein temp. ImageData-Objekt erstellt wurde if(blnNull){ // Temp. ImageData-Objekt wieder zerstören und neu initialiseren delete opts.tmp; opts.tmp = null; } return oPxl; } // Methode zum Berechnen des Blur-Wertes eines Pixels // x - (integer) Spaltenwert // y - (integer) Zeilenwert // Rückgabe: (object) Basisobjekt, um Kette nicht zu unterbrechen opts.blurPixel = function(x, y){ // Umliegende Pixel ermitteln var oPxl = { xminus_yminus: opts.getPixel(x-1, y-1), xminus_y: opts.getPixel(x-1, y), xminus_yplus: opts.getPixel(x-1, y+1), x_yminus: opts.getPixel(x, y-1), x_yplus: opts.getPixel(x, y+1), xplus_yminus: opts.getPixel(x+1, y-1), xplus_y: opts.getPixel(x+1, y), xplus_yplus: opts.getPixel(x+1, y+1) }; // Umliegende Pixel summieren var intRed = oPxl.xminus_yminus[0]+oPxl.xminus_y[0]+oPxl.xminus_yplus[0]+oPxl.x_yminus[0]+oPxl.x_yplus[0]+oPxl.xplus_yminus[0]+oPxl.xplus_y[0]+oPxl.xplus_yplus[0]; var intGreen = oPxl.xminus_yminus[1]+oPxl.xminus_y[1]+oPxl.xminus_yplus[1]+oPxl.x_yminus[1]+oPxl.x_yplus[1]+oPxl.xplus_yminus[1]+oPxl.xplus_y[1]+oPxl.xplus_yplus[1]; var intBlue = oPxl.xminus_yminus[2]+oPxl.xminus_y[2]+oPxl.xminus_yplus[2]+oPxl.x_yminus[2]+oPxl.x_yplus[2]+oPxl.xplus_yminus[2]+oPxl.xplus_y[2]+oPxl.xplus_yplus[2]; // Errechnen der mittleren Farben pBlurRed = intRed/8; pBlurGreen = intGreen/8; pBlurBlue = intBlue/8; // Zeilen- und Spaltenwert zum Ermitteln des Offsets des aktuellen Pixels im ImageData-Objekt berechnen var z = y*opts.w*4; var s = 4*x; // Pixel setzen opts.tmp.data[z + s] = pBlurRed; opts.tmp.data[z + s + 1] = pBlurGreen; opts.tmp.data[z + s + 2] = pBlurBlue; return opts; }; // Methode zum Blurren des Context-Inhaltes // Rückgabe: (object) Basisobjekt, um Kette nicht zu unterbrechen opts.blur = function(){ // Falls die benötigte Methode nicht verfügbar ist if(typeof ctx.getImageData != "function"){ alert("Ihr Browser unterstützt die angeforderte Funktion nicht."); return opts; } // Temp. ImageData-Objekt erstellen opts.tmp = ctx.getImageData(0, 0, opts.w, opts.h); // Zeilen (Vorsicht wegen Rand) for(var m=1; m<opts.h-1; m++){ // Spalten (Vorsicht wegen Rand) for(var n=1; n<opts.w-1; n++){ // Pixel blurren opts.blurPixel(n, m); } } // Aktuellen Kontext speichern opts.stack[opts.stack.length] = ctx.getImageData(0, 0, opts.w, opts.h); // Kontext leeren ctx.clearRect(0, 0, opts.w, opts.h); // Temp. ImageData-Objekt in Context rendern ctx.putImageData(opts.tmp, 0, 0); // Temp. ImageData-Objekt zerstören und neu initialisieren delete opts.tmp; opts.tmp = null; // Kette nicht unterbrechen return opts; }; // Undo-Methode // Rückgabe: (object) Basisobjekt, um Kette nicht zu unterbrechen opts.restoreCtx = function(){ if(opts.stack.length > 0){ // Kontext leeren ctx.clearRect(0, 0, opts.w, opts.h); // Gesichertes ImageData-Objekt in Context rendern ctx.putImageData(opts.stack[opts.stack.length-1], 0, 0); opts.stack.pop(); } // Kette nicht unterbrechen return opts; } // Methode zum Einfügen eines Bildes // strSrc - (string) Bildquelle // x - (integer) Horizontale Startkoordinate // y - (integer) Vertikale Startkoordinate // Rückgabe: (object) Basisobjekt, um Kette nicht zu unterbrechen opts.insertImg = function(strSrc, x, y){ var objImg = new Image(); objImg.src = strSrc; objImg.onload = function(){ ctx.drawImage(this, x, y); }; // Kette nicht unterbrechen return opts; } // Initialisierungsfunktion init(); // Kette nicht unterbrechen return opts; }
Das Script wurde in folgenden Browsern erfolgreich getestet.
Im Internet Explorer kann ein blur-Effekt über die CSS-Eigenschaft filter
erreicht werden
filter:Alpha(opacity=20) Gray() Blur(direction=90, strength=70);opacity:0.2;