Bitmaps – PNG und JPEG – Bildbearbeitung in Canvas

Javascript lädt Bilder in zwei Schritten in ein HTML-Canvas-Element: (1) Das Bild wird als neues DOM-Element geladen, (2) sobald das Bild geladen ist, kann es im Canvas gerendert werden.

PNG und JPEG in Canvas laden und manipulieren
23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Bitmap in Canvas laden

Wenn das Canvas-Script mit Bitmaps arbeitet, werden die Bilder vor dem Rendern des Bildes geladen.

Der Ladevorgang nimmt Zeit in Anspruch. Wenn die Bitmaps sehr groß sind, werden sie u.U. noch nicht geladen sein, wenn das canvas-Element in das DOM eingefügt wird (die Zeichnung im Canvas ist kein Teil des DOM, wohl aber das Canvas-Element). Ein Event Listener für onload entdeckt, wann das Bild tatsächlich geladen ist.

Script zum Aufhellen und Abdunkeln von RGB-Werten von Stackoverflow

<canvas id="canvas" width="800" height="573"></canvas>
… 

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let imageData, numPixels, pixels, buffer;

let image = new Image();

image.addEventListener ( "load", function (){
   ctx.drawImage (image, 0, 0);
   imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
   buffer = ctx.createImageData(imageData); // Buffer, um die Pixel wieder auf das Original zu setzen
   numPixels = imageData.width * imageData.height;
   pixels = imageData.data;
   …
});

image.src = "img/sable.png";

ctx.drawImage (image, 0, 0): Das zweite und dritte Argument von drawImage sind die Start-Koordinaten des Bildes – also die Position der linken oberen Ecke.

SVG als Bild in canvas

In einen Canvas können nicht nur Bitmaps (JPG und PNG), sondern auch SVG-Grafiken direkt geladen werden.

Das Verfahren beim Laden eines SVG in ein canvas-Element ist dabei nicht anders als bei Bitmap-Bildern. Die Grafik wird in allen modernen Browsern angezeigt, auch in IE11 und Microsoft Edge.

let img = new Image();
img.addEventListener ("load", function () {
   ctx.drawImage(img, 0, 0);
});

img.src = "wave-abs.svg";

Canvas drawImage: scale und clip

Mit zwei weiteren Argumenten bestimmt der Canvas Breite und Höhe des Bildes, um das Original zu vergrößern oder zu verkleinern.

Die nächsten beiden Argumente verschieben den Ausschnitt im Canvas.

Einen vergrößerten oder verkleinerten Ausschnitt des Bildes zeigt HTML Canvas mit insgesamt 8 Argumenten:

sx, sy
Linke obere Ecke des Bildausschnitts
sw, sh
Breite und Höhe des Ausschnitts aus dem Originalbild
dx, dy
Linke obere Ecke des Bildausschnitts im Canvas
dw, dh
Breite und Höhe des Ausschnitts im Canvas
Ausschnitt im Javascript Canvas
// ctx.drawImage ( image, sx, sy, sw, sh, dx, dy, dw, dh );
h = canvas.height;
w = canvas.width; 

// Vergrößern um Faktor 2
ctx.clearRect ( 0 , 0 , w , h );
ctx.drawImage (image, 100, 100, w/2, h/2, 0, 0, w, h );

// Verkleinern um Faktor 2
ctx.clearRect ( 0 , 0 , w , h );
ctx.drawImage ( image, 0, 0, w, h, 100, 100, w/2, h/2 );

// Reset
ctx.clearRect ( 0 , 0 , w , h );
ctx.drawImage ( image, 0, 0, w, h );

Verkleinern und Vergrößern arbeitet ohne Weiteres auf den Pixeln des Originalbildes, auch wenn die Pixel durch das Script verändert wurden.

Werden die Pixel geändert, reicht ein einfaches Reset des Canvas nicht aus: Um wieder an die Pixel des Originalbildes zu kommen, müssen die Pixel am Anfang des Scripts in einem Puffer gespeichert werden und beim Reset muss der Puffer die Original-Pixel wieder herstellen. Das einfache Reset wie im Codebeispiel reicht nicht aus.

Javascript Canvas Sicherheit

Aus Sicherheitsgründen darf Javascript nur Bilder innerhalb der selben Domaine / desselben Verzeichnisses manipulieren. Die Pixel eines Bildes auf einem Remote Server können also nicht analysiert und manipuliert werden (eigentlich schade … ).

IE analysiert und manipuliert sogar nur Bilder innerhalb einer Server-Umgebung, nicht aber im lokalen Verzeichnis des Rechners.

Javascript Zugriff auf Canvas-Pixel

Um die Pixel eines Bildes zu manipulieren – z.B. aufzuhellen oder zu invertieren – müssen die Pixel linearisiert werden. Aus ist es mit der schönen Pixelmatrix eines Bildes: Wir erreichen einen Pixel nicht über »gibt mir Pixel 10 in Reihe 3«. Alle Pixel liegen in einem einfachen eindimensionalen Array.

let imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
let data = imageData.data;

gibt ein CanvasPixelArray mit den Farbwerten der Pixel des Bildausschnitts zurück.

Das heißt aber immer noch nicht, dass der Pixel 10 in Reihe 3 jetzt auf dem Index 3*10 - 1 liegt, sondern nur, dass der Pixel auf dieser Position beginnt.

RGB und Alpha: Take 4

Javascript Canvas stellt alle Pixel des Bildes durch vier Werte dar: Rot, Grün, Blau und Alpha.

Pixel manipulieren
Wenn schon ein Winzling mit 3x3 Pixeln mit 36 Helligkeitswerten dasteht – die Manipulation von Pixelbildern ist zeitintensiv.

Der Index des ersten Pixels ist 0, der Index des zweiten Pixels ist 4, der Index des dritten Pixels ist 12, …. Jedes Pixel beginnt also auf einem Vielfachen von 4.

Der mittlere Pixel einer 3x3 Matrix beginnt auf Index 16 und enthält die RGB-Werte auf 16+1 (Grün), 16+2 (Blau), 16+3 (Alpha)

let red = ((y-1) * (width * 4)) + ((x - 1) * 4);
let blue = ((y-1) * (width * 4)) + ((x - 1) * 4) + 1;
let green = ((y-1) * (width * 4)) + ((x - 1) * 4) + 2;
let alpha = ((y-1) * (width * 4)) + ((x - 1) * 4) + 3;
$('#alpha').click(function () {
for (let x=0; x<numPixels; x++) {
   if (parseInt(pixels[x*4+3]) == 0 ) {
      pixels[x*4] = 0;
      pixels[x*4+1] = 0;
      pixels[x*4+2] = 0;
      pixels[x*4+3] = 255;
	}
}
ctx.clearRect ( 0 , 0 , canvasWidth , canvasHeight );
ctx.putImageData(imageData, 0, 0);