Dokumentation (canvas.quaese.de)
 

Anwendungen - blur für <canvas>

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.

Beispiel


Download

Script und Initialisierung

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.

Syntax

objAPI = qpCanvas(optionen);

Optionen

  • id

    ID des canvas-Elements

    Datentyp: string

  • w

    Gewünschte Breite des canvas-Elements (optional)

    Datentyp: integer

  • h

    Gewünschte Höhe des canvas-Elements (optional)

    Datentyp: integer

  • init

    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

API

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.

  • blur()

    zum Blurren des canvas-Inhalts

    Datentyp: function

  • insertImg(strSrc, x, y)

    Einfügen eines Bildes in den Kontext, dessen Quelle in strSrc übergeben wird. Ausserdem werden die Startkoordinaten in x und y übergeben.

    Datentyp: function

  • getPixel(x, y)

    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

  • restoreCtx()

    Macht schrittweise die Blur-Schritte rückgängig

    Datentyp: function

Beispiel: Initialisieren des Objekts

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(&quot;distel.jpg&quot;, 0, 0);
}

Beispiel: Zugriff auf die API

Über die zurückgegebene Referenz objAPI kann später auf die API zugegriffen werden, zum Beispiel:

objAPI.blur();

Quellcode des Scripts

/* ****************************************************************************************** *
 * 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;
}

Browserkompatibilität

Das Script wurde in folgenden Browsern erfolgreich getestet.

  • Firefox 2+
  • Opera 9+
  • Safari (Win) 3+
  • Google Chrome

Internet Explorer

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;
 
Dokument zuletzt modifiziert: 16.08.2010, 23:08 Uhr
<canvas>-Dokumentation Ver. 0.1 | Quaese, Jan 2008 | Datenschutz | Sitemap